aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/block_processor.go73
-rw-r--r--core/block_processor_test.go32
-rw-r--r--core/blocks.go1
-rw-r--r--core/chain_manager.go85
-rw-r--r--core/state/log.go21
-rw-r--r--core/types/receipt.go29
6 files changed, 182 insertions, 59 deletions
diff --git a/core/block_processor.go b/core/block_processor.go
index 6cd1c8aa3..ca205ee86 100644
--- a/core/block_processor.go
+++ b/core/block_processor.go
@@ -40,11 +40,6 @@ type BlockProcessor struct {
txpool *TxPool
- // The last attempted block is mainly used for debugging purposes
- // This does not have to be a valid block and will be set during
- // 'Process' & canonical validation.
- lastAttemptedBlock *types.Block
-
events event.Subscription
eventMux *event.TypeMux
@@ -188,8 +183,6 @@ func (sm *BlockProcessor) Process(block *types.Block) (logs state.Logs, err erro
}
func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs state.Logs, err error) {
- sm.lastAttemptedBlock = block
-
// Create a new state based on the parent's root (e.g., create copy)
state := state.New(parent.Root(), sm.db)
@@ -255,6 +248,12 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
return
}
+ // store the receipts
+ err = putReceipts(sm.extraDb, block.Hash(), receipts)
+ if err != nil {
+ return nil, err
+ }
+
// Calculate the td for this block
//td = CalculateTD(block, parent)
// Sync the current block's state to the database
@@ -268,23 +267,9 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
putTx(sm.extraDb, tx, block, uint64(i))
}
- receiptsRlp := block.Receipts().RlpEncode()
- sm.extraDb.Put(append(receiptsPre, block.Hash().Bytes()...), receiptsRlp)
-
return state.Logs(), nil
}
-func (self *BlockProcessor) GetBlockReceipts(bhash common.Hash) (receipts types.Receipts, err error) {
- var rdata []byte
- rdata, err = self.extraDb.Get(append(receiptsPre, bhash[:]...))
-
- if err == nil {
- err = rlp.DecodeBytes(rdata, &receipts)
- }
- return
-
-}
-
// See YP section 4.3.4. "Block Header Validity"
// Validates a block. Returns an error if the block is invalid.
func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header, checkPow bool) error {
@@ -391,13 +376,25 @@ func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *ty
return nil
}
+// GetBlockReceipts returns the receipts beloniging to the block hash
+func (sm *BlockProcessor) GetBlockReceipts(bhash common.Hash) (receipts types.Receipts, err error) {
+ return getBlockReceipts(sm.extraDb, bhash)
+}
+
+// GetLogs returns the logs of the given block. This method is using a two step approach
+// where it tries to get it from the (updated) method which gets them from the receipts or
+// the depricated way by re-processing the block.
func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err error) {
- if !sm.bc.HasBlock(block.Header().ParentHash) {
- return nil, ParentError(block.Header().ParentHash)
+ receipts, err := sm.GetBlockReceipts(block.Hash())
+ if err == nil && len(receipts) > 0 {
+ // coalesce logs
+ for _, receipt := range receipts {
+ logs = append(logs, receipt.Logs()...)
+ }
+ return
}
- sm.lastAttemptedBlock = block
-
+ // TODO: remove backward compatibility
var (
parent = sm.bc.GetBlock(block.Header().ParentHash)
state = state.New(parent.Root(), sm.db)
@@ -408,6 +405,16 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err erro
return state.Logs(), nil
}
+func getBlockReceipts(db common.Database, bhash common.Hash) (receipts types.Receipts, err error) {
+ var rdata []byte
+ rdata, err = db.Get(append(receiptsPre, bhash[:]...))
+
+ if err == nil {
+ err = rlp.DecodeBytes(rdata, &receipts)
+ }
+ return
+}
+
func putTx(db common.Database, tx *types.Transaction, block *types.Block, i uint64) {
rlpEnc, err := rlp.EncodeToBytes(tx)
if err != nil {
@@ -431,3 +438,19 @@ func putTx(db common.Database, tx *types.Transaction, block *types.Block, i uint
}
db.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta)
}
+
+func putReceipts(db common.Database, hash common.Hash, receipts types.Receipts) error {
+ storageReceipts := make([]*types.ReceiptForStorage, len(receipts))
+ for i, receipt := range receipts {
+ storageReceipts[i] = (*types.ReceiptForStorage)(receipt)
+ }
+
+ bytes, err := rlp.EncodeToBytes(storageReceipts)
+ if err != nil {
+ return err
+ }
+
+ db.Put(append(receiptsPre, hash[:]...), bytes)
+
+ return nil
+}
diff --git a/core/block_processor_test.go b/core/block_processor_test.go
index e0aa5fb4c..72b173a71 100644
--- a/core/block_processor_test.go
+++ b/core/block_processor_test.go
@@ -5,6 +5,8 @@ import (
"testing"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/state"
+ "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/pow/ezp"
@@ -35,3 +37,33 @@ func TestNumber(t *testing.T) {
t.Errorf("didn't expect block number error")
}
}
+
+func TestPutReceipt(t *testing.T) {
+ db, _ := ethdb.NewMemDatabase()
+
+ var addr common.Address
+ addr[0] = 1
+ var hash common.Hash
+ hash[0] = 2
+
+ receipt := new(types.Receipt)
+ receipt.SetLogs(state.Logs{&state.Log{
+ Address: addr,
+ Topics: []common.Hash{hash},
+ Data: []byte("hi"),
+ Number: 42,
+ TxHash: hash,
+ TxIndex: 0,
+ BlockHash: hash,
+ Index: 0,
+ }})
+
+ putReceipts(db, hash, types.Receipts{receipt})
+ receipts, err := getBlockReceipts(db, hash)
+ if err != nil {
+ t.Error("got err:", err)
+ }
+ if len(receipts) != 1 {
+ t.Error("expected to get 1 receipt, got", len(receipts))
+ }
+}
diff --git a/core/blocks.go b/core/blocks.go
index 35e170af3..83727ff62 100644
--- a/core/blocks.go
+++ b/core/blocks.go
@@ -6,4 +6,5 @@ import "github.com/ethereum/go-ethereum/common"
var BadHashes = map[common.Hash]bool{
common.HexToHash("f269c503aed286caaa0d114d6a5320e70abbc2febe37953207e76a2873f2ba79"): true,
common.HexToHash("38f5bbbffd74804820ffa4bab0cd540e9de229725afb98c1a7e57936f4a714bc"): true,
+ common.HexToHash("7064455b364775a16afbdecd75370e912c6e2879f202eda85b9beae547fff3ac"): true,
}
diff --git a/core/chain_manager.go b/core/chain_manager.go
index 3408b5030..088ca8d5b 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -548,18 +548,21 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
tstart = time.Now()
)
- // check the nonce in parallel to the block processing
- // this speeds catching up significantly
- nonceErrCh := make(chan error)
- go func() {
- nonceErrCh <- verifyNonces(self.pow, chain)
- }()
-
for i, block := range chain {
if block == nil {
continue
}
+ if BadHashes[block.Hash()] {
+ err := fmt.Errorf("Found known bad hash in chain %x", block.Hash())
+ blockErr(block, err)
+ return i, err
+ }
+
+ // create a nonce channel for parallisation of the nonce check
+ nonceErrCh := make(chan error)
+ go verifyBlockNonce(self.pow, block, nonceErrCh)
+
// Setting block.Td regardless of error (known for example) prevents errors down the line
// in the protocol handler
block.Td = new(big.Int).Set(CalcTD(block, self.GetBlock(block.ParentHash())))
@@ -568,13 +571,14 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
// all others will fail too (unless a known block is returned).
logs, err := self.processor.Process(block)
if err != nil {
+ // empty the nonce channel
+ <-nonceErrCh
+
if IsKnownBlockErr(err) {
stats.ignored++
continue
}
- // Do not penelise on future block. We'll need a block queue eventually that will queue
- // future block for future use
if err == BlockFutureErr {
block.SetQueued(true)
self.futureBlocks.Push(block)
@@ -593,18 +597,23 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
return i, err
}
+ // Wait and check nonce channel and make sure it checks out fine
+ // otherwise return the error
+ if err := <-nonceErrCh; err != nil {
+ return i, err
+ }
cblock := self.currentBlock
- // Write block to database. Eventually we'll have to improve on this and throw away blocks that are
- // not in the canonical chain.
- self.write(block)
// Compare the TD of the last known block in the canonical chain to make sure it's greater.
// At this point it's possible that a different chain (fork) becomes the new canonical chain.
if block.Td.Cmp(self.td) > 0 {
// chain fork
if block.ParentHash() != cblock.Hash() {
// during split we merge two different chains and create the new canonical chain
- self.merge(cblock, block)
+ err := self.merge(cblock, block)
+ if err != nil {
+ return i, err
+ }
queue[i] = ChainSplitEvent{block, logs}
queueEvent.splitCount++
@@ -637,19 +646,16 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
queue[i] = ChainSideEvent{block, logs}
queueEvent.sideCount++
}
+ // Write block to database. Eventually we'll have to improve on this and throw away blocks that are
+ // not in the canonical chain.
+ self.write(block)
+ // Delete from future blocks
self.futureBlocks.Delete(block.Hash())
stats.processed++
}
- // check and wait for the nonce error channel and
- // make sure no nonce error was thrown in the process
- err := <-nonceErrCh
- if err != nil {
- return 0, err
- }
-
if (stats.queued > 0 || stats.processed > 0 || stats.ignored > 0) && bool(glog.V(logger.Info)) {
tend := time.Since(tstart)
start, end := chain[0], chain[len(chain)-1]
@@ -663,7 +669,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
// diff takes two blocks, an old chain and a new chain and will reconstruct the blocks and inserts them
// to be part of the new canonical chain.
-func (self *ChainManager) diff(oldBlock, newBlock *types.Block) types.Blocks {
+func (self *ChainManager) diff(oldBlock, newBlock *types.Block) (types.Blocks, error) {
var (
newChain types.Blocks
commonBlock *types.Block
@@ -674,14 +680,20 @@ func (self *ChainManager) diff(oldBlock, newBlock *types.Block) types.Blocks {
// first reduce whoever is higher bound
if oldBlock.NumberU64() > newBlock.NumberU64() {
// reduce old chain
- for oldBlock = oldBlock; oldBlock.NumberU64() != newBlock.NumberU64(); oldBlock = self.GetBlock(oldBlock.ParentHash()) {
+ for oldBlock = oldBlock; oldBlock != nil && oldBlock.NumberU64() != newBlock.NumberU64(); oldBlock = self.GetBlock(oldBlock.ParentHash()) {
}
} else {
// reduce new chain and append new chain blocks for inserting later on
- for newBlock = newBlock; newBlock.NumberU64() != oldBlock.NumberU64(); newBlock = self.GetBlock(newBlock.ParentHash()) {
+ for newBlock = newBlock; newBlock != nil && newBlock.NumberU64() != oldBlock.NumberU64(); newBlock = self.GetBlock(newBlock.ParentHash()) {
newChain = append(newChain, newBlock)
}
}
+ if oldBlock == nil {
+ return nil, fmt.Errorf("Invalid old chain")
+ }
+ if newBlock == nil {
+ return nil, fmt.Errorf("Invalid new chain")
+ }
numSplit := newBlock.Number()
for {
@@ -692,6 +704,12 @@ func (self *ChainManager) diff(oldBlock, newBlock *types.Block) types.Blocks {
newChain = append(newChain, newBlock)
oldBlock, newBlock = self.GetBlock(oldBlock.ParentHash()), self.GetBlock(newBlock.ParentHash())
+ if oldBlock == nil {
+ return nil, fmt.Errorf("Invalid old chain")
+ }
+ if newBlock == nil {
+ return nil, fmt.Errorf("Invalid new chain")
+ }
}
if glog.V(logger.Info) {
@@ -699,17 +717,22 @@ func (self *ChainManager) diff(oldBlock, newBlock *types.Block) types.Blocks {
glog.Infof("Fork detected @ %x. Reorganising chain from #%v %x to %x", commonHash[:4], numSplit, oldStart.Hash().Bytes()[:4], newStart.Hash().Bytes()[:4])
}
- return newChain
+ return newChain, nil
}
// merge merges two different chain to the new canonical chain
-func (self *ChainManager) merge(oldBlock, newBlock *types.Block) {
- newChain := self.diff(oldBlock, newBlock)
+func (self *ChainManager) merge(oldBlock, newBlock *types.Block) error {
+ newChain, err := self.diff(oldBlock, newBlock)
+ if err != nil {
+ return fmt.Errorf("chain reorg failed: %v", err)
+ }
// insert blocks. Order does not matter. Last block will be written in ImportChain itself which creates the new head properly
for _, block := range newChain {
self.insert(block)
}
+
+ return nil
}
func (self *ChainManager) update() {
@@ -802,9 +825,17 @@ func verifyNonces(pow pow.PoW, blocks []*types.Block) error {
func verifyNonce(pow pow.PoW, in <-chan *types.Block, done chan<- error) {
for block := range in {
if !pow.Verify(block) {
- done <- ValidationError("Block(#%v) nonce is invalid (= %x)", block.Number(), block.Nonce)
+ done <- ValidationError("Block (#%v / %x) nonce is invalid (= %x)", block.Number(), block.Hash(), block.Nonce)
} else {
done <- nil
}
}
}
+
+func verifyBlockNonce(pow pow.PoW, block *types.Block, done chan<- error) {
+ if !pow.Verify(block) {
+ done <- ValidationError("Block (#%v / %x) nonce is invalid (= %x)", block.Number(), block.Hash(), block.Nonce)
+ } else {
+ done <- nil
+ }
+}
diff --git a/core/state/log.go b/core/state/log.go
index a7aa784e2..882977061 100644
--- a/core/state/log.go
+++ b/core/state/log.go
@@ -29,15 +29,22 @@ func (self *Log) EncodeRLP(w io.Writer) error {
}
func (self *Log) String() string {
- return fmt.Sprintf(`log: %x %x %x`, self.Address, self.Topics, self.Data)
+ return fmt.Sprintf(`log: %x %x %x %x %d %x %d`, self.Address, self.Topics, self.Data, self.TxHash, self.TxIndex, self.BlockHash, self.Index)
}
type Logs []*Log
-func (self Logs) String() (ret string) {
- for _, log := range self {
- ret += fmt.Sprintf("%v", log)
- }
-
- return "[" + ret + "]"
+type LogForStorage Log
+
+func (self *LogForStorage) EncodeRLP(w io.Writer) error {
+ return rlp.Encode(w, []interface{}{
+ self.Address,
+ self.Topics,
+ self.Data,
+ self.Number,
+ self.TxHash,
+ self.TxIndex,
+ self.BlockHash,
+ self.Index,
+ })
}
diff --git a/core/types/receipt.go b/core/types/receipt.go
index 414e4d364..6b4024ada 100644
--- a/core/types/receipt.go
+++ b/core/types/receipt.go
@@ -26,10 +26,39 @@ func (self *Receipt) SetLogs(logs state.Logs) {
self.logs = logs
}
+func (self *Receipt) Logs() state.Logs {
+ return self.logs
+}
+
func (self *Receipt) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs})
}
+func (self *Receipt) DecodeRLP(s *rlp.Stream) error {
+ var r struct {
+ PostState []byte
+ CumulativeGasUsed *big.Int
+ Bloom Bloom
+ Logs state.Logs
+ }
+ if err := s.Decode(&r); err != nil {
+ return err
+ }
+ self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs = r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs
+
+ return nil
+}
+
+type ReceiptForStorage Receipt
+
+func (self *ReceiptForStorage) EncodeRLP(w io.Writer) error {
+ storageLogs := make([]*state.LogForStorage, len(self.logs))
+ for i, log := range self.logs {
+ storageLogs[i] = (*state.LogForStorage)(log)
+ }
+ return rlp.Encode(w, []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, storageLogs})
+}
+
func (self *Receipt) RlpEncode() []byte {
bytes, err := rlp.EncodeToBytes(self)
if err != nil {