Skip to content

Commit a63b92c

Browse files
committed
cmd, consensus, core, eth, tests: return memorized state error
1 parent 241cf62 commit a63b92c

File tree

18 files changed

+142
-82
lines changed

18 files changed

+142
-82
lines changed

cmd/evm/internal/t8ntool/execution.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
200200
if chainConfig.IsByzantium(vmContext.BlockNumber) {
201201
statedb.Finalise(true)
202202
} else {
203-
root = statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber)).Bytes()
203+
// the ignored error will eventually be captured by commit.
204+
hash, _ := statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber))
205+
root = hash.Bytes()
204206
}
205207

206208
// Create a new receipt for the transaction, storing the intermediate root and
@@ -231,7 +233,6 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
231233

232234
txIndex++
233235
}
234-
statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber))
235236
// Add mining reward? (-1 means rewards are disabled)
236237
if miningReward >= 0 {
237238
// Add mining reward. The mining reward may be `0`, which only makes a difference in the cases

cmd/evm/runner.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,11 @@ func runCmd(ctx *cli.Context) error {
274274
output, leftOverGas, stats, err := timedExec(bench, execFunc)
275275

276276
if ctx.Bool(DumpFlag.Name) {
277-
statedb.Commit(true)
278-
statedb.IntermediateRoot(true)
277+
_, err := statedb.Commit(true)
278+
if err != nil {
279+
fmt.Println("failed to commit state changes: ", err)
280+
os.Exit(1)
281+
}
279282
fmt.Println(string(statedb.Dump(nil)))
280283
}
281284

cmd/evm/staterunner.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,21 @@ func stateTestCmd(ctx *cli.Context) error {
102102
_, s, err := test.Run(st, cfg, false)
103103
// print state root for evmlab tracing
104104
if s != nil {
105-
root := s.IntermediateRoot(false)
106-
result.Root = &root
107-
if ctx.Bool(MachineFlag.Name) {
108-
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
105+
root, err := s.IntermediateRoot(false)
106+
if err != nil {
107+
// Test failed(corrupted state shouldn't actually
108+
// occur during tests though), mark as so and dump
109+
// any state to aid debugging.
110+
result.Pass, result.Error = false, err.Error()
111+
if ctx.Bool(DumpFlag.Name) && s != nil {
112+
dump := s.RawDump(nil)
113+
result.State = &dump
114+
}
115+
} else {
116+
result.Root = &root
117+
if ctx.Bool(MachineFlag.Name) {
118+
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
119+
}
109120
}
110121
}
111122
if err != nil {

consensus/beacon/consensus.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -341,9 +341,6 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.
341341
amount = amount.Mul(amount, big.NewInt(params.GWei))
342342
state.AddBalance(w.Address, amount)
343343
}
344-
// The block reward is no longer handled here. It's done by the
345-
// external consensus engine.
346-
header.Root = state.IntermediateRoot(true)
347344
}
348345

349346
// FinalizeAndAssemble implements consensus.Engine, setting the final state and
@@ -367,6 +364,15 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
367364
}
368365
// Finalize and assemble the block.
369366
beacon.Finalize(chain, header, state, txs, uncles, withdrawals)
367+
368+
// Assign the final state root to header.
369+
root, err := state.IntermediateRoot(true)
370+
if err != nil {
371+
return nil, err
372+
}
373+
header.Root = root
374+
375+
// Assemble and return the final block.
370376
return types.NewBlockWithWithdrawals(header, txs, uncles, receipts, withdrawals, trie.NewStackTrie(nil)), nil
371377
}
372378

consensus/clique/clique.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -569,8 +569,6 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header
569569
// rewards given.
570570
func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) {
571571
// No block rewards in PoA, so the state remains as is and uncles are dropped
572-
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
573-
header.UncleHash = types.CalcUncleHash(nil)
574572
}
575573

576574
// FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
@@ -579,11 +577,17 @@ func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *
579577
if len(withdrawals) > 0 {
580578
return nil, errors.New("clique does not support withdrawals")
581579
}
582-
583-
// Finalize block
580+
// Finalize block.
584581
c.Finalize(chain, header, state, txs, uncles, nil)
585582

586-
// Assemble and return the final block for sealing
583+
// Assign the final state root to header.
584+
root, err := state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
585+
if err != nil {
586+
return nil, err
587+
}
588+
header.Root = root
589+
590+
// Assemble and return the final block for sealing.
587591
return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)), nil
588592
}
589593

consensus/consensus.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,16 @@ type Engine interface {
8484
// rules of a particular engine. The changes are executed inline.
8585
Prepare(chain ChainHeaderReader, header *types.Header) error
8686

87-
// Finalize runs any post-transaction state modifications (e.g. block rewards)
88-
// but does not assemble the block.
87+
// Finalize runs any post-transaction state modifications (e.g. block rewards
88+
// or process withdrawals) but does not assemble the block.
8989
//
90-
// Note: The block header and state database might be updated to reflect any
91-
// consensus rules that happen at finalization (e.g. block rewards).
90+
// Note: The state database might be updated to reflect any consensus rules
91+
// that happen at finalization.
9292
Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
9393
uncles []*types.Header, withdrawals []*types.Withdrawal)
9494

9595
// FinalizeAndAssemble runs any post-transaction state modifications (e.g. block
96-
// rewards) and assembles the final block.
96+
// rewards or process withdrawals) and assembles the final block.
9797
//
9898
// Note: The block header and state database might be updated to reflect any
9999
// consensus rules that happen at finalization (e.g. block rewards).

consensus/ethash/consensus.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,6 @@ func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.H
603603
func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) {
604604
// Accumulate any block and uncle rewards and commit the final state root
605605
accumulateRewards(chain.Config(), state, header, uncles)
606-
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
607606
}
608607

609608
// FinalizeAndAssemble implements consensus.Engine, accumulating the block and
@@ -612,10 +611,17 @@ func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
612611
if len(withdrawals) > 0 {
613612
return nil, errors.New("ethash does not support withdrawals")
614613
}
615-
616-
// Finalize block
614+
// Finalize block.
617615
ethash.Finalize(chain, header, state, txs, uncles, nil)
618-
// Header seems complete, assemble into a block and return
616+
617+
// Assign the final state root to header.
618+
root, err := state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
619+
if err != nil {
620+
return nil, err
621+
}
622+
header.Root = root
623+
624+
// Header seems complete, assemble into a block and return.
619625
return types.NewBlock(header, txs, uncles, receipts, trie.NewStackTrie(nil)), nil
620626
}
621627

core/block_validator.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,11 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
109109
}
110110
// Validate the state root against the received state root and throw
111111
// an error if they don't match.
112-
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
112+
root, err := statedb.IntermediateRoot(v.config.IsEIP158(header.Number))
113+
if err != nil {
114+
return fmt.Errorf("failed to derive state root %v", err)
115+
}
116+
if header.Root != root {
113117
return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root)
114118
}
115119
return nil

core/chain_makers.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,8 +352,12 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S
352352
} else {
353353
time = parent.Time() + 10 // block time is fixed at 10 seconds
354354
}
355+
root, err := state.IntermediateRoot(chain.Config().IsEIP158(parent.Number()))
356+
if err != nil {
357+
panic(err) // error shouldn't occur in tests.
358+
}
355359
header := &types.Header{
356-
Root: state.IntermediateRoot(chain.Config().IsEIP158(parent.Number())),
360+
Root: root,
357361
ParentHash: parent.Hash(),
358362
Coinbase: parent.Coinbase(),
359363
Difficulty: engine.CalcDifficulty(chain, time, &types.Header{

core/state/state_object.go

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ func (s Storage) String() (str string) {
4545
for key, value := range s {
4646
str += fmt.Sprintf("%X : %X\n", key, value)
4747
}
48-
4948
return
5049
}
5150

@@ -54,7 +53,6 @@ func (s Storage) Copy() Storage {
5453
for key, value := range s {
5554
cpy[key] = value
5655
}
57-
5856
return cpy
5957
}
6058

@@ -73,8 +71,12 @@ type stateObject struct {
7371
// DB error.
7472
// State objects are used by the consensus core and VM which are
7573
// unable to deal with database-level errors. Any error that occurs
76-
// during a database read is memoized here and will eventually be returned
77-
// by StateDB.Commit.
74+
// during a database read is memoized here and will eventually be
75+
// returned by StateDB.Commit. Specially, this error is used to
76+
// represent a failed operation of:
77+
// - storage trie read
78+
// - contract code read
79+
// - trie node decode
7880
dbErr error
7981

8082
// Write caches.
@@ -86,7 +88,7 @@ type stateObject struct {
8688
dirtyStorage Storage // Storage entries that have been modified in the current transaction execution
8789

8890
// Cache flags.
89-
// When an object is marked suicided it will be delete from the trie
91+
// When an object is marked suicided it will be deleted from the trie
9092
// during the "update" phase of the state transition.
9193
dirtyCode bool // true if the code was updated
9294
suicided bool
@@ -282,6 +284,10 @@ func (s *stateObject) finalise(prefetch bool) {
282284
// It will return nil if the trie has not been loaded and no changes have been
283285
// made. An error will be returned if the trie can't be loaded/updated correctly.
284286
func (s *stateObject) updateTrie(db Database) (Trie, error) {
287+
// Short circuit if any the previous database failure is memorized.
288+
if s.dbErr != nil {
289+
return nil, s.dbErr
290+
}
285291
// Make sure all dirty slots are finalized into the pending storage area
286292
s.finalise(false) // Don't prefetch anymore, pull directly if need be
287293
if len(s.pendingStorage) == 0 {
@@ -298,7 +304,6 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) {
298304
)
299305
tr, err := s.getTrie(db)
300306
if err != nil {
301-
s.setError(err)
302307
return nil, err
303308
}
304309
// Insert all the pending updates into the trie
@@ -313,15 +318,13 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) {
313318
var v []byte
314319
if (value == common.Hash{}) {
315320
if err := tr.TryDelete(key[:]); err != nil {
316-
s.setError(err)
317321
return nil, err
318322
}
319323
s.db.StorageDeleted += 1
320324
} else {
321325
// Encoding []byte cannot fail, ok to ignore the error.
322326
v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:]))
323327
if err := tr.TryUpdate(key[:], v); err != nil {
324-
s.setError(err)
325328
return nil, err
326329
}
327330
s.db.StorageUpdated += 1
@@ -348,35 +351,35 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) {
348351
return tr, nil
349352
}
350353

351-
// UpdateRoot sets the trie root to the current root hash of. An error
352-
// will be returned if trie root hash is not computed correctly.
353-
func (s *stateObject) updateRoot(db Database) {
354+
// updateRoot sets the trie root to the current root hash. An error
355+
// will be returned if case any error occurs because of failed database
356+
// reads.
357+
func (s *stateObject) updateRoot(db Database) error {
354358
tr, err := s.updateTrie(db)
355359
if err != nil {
356-
s.setError(fmt.Errorf("updateRoot (%x) error: %w", s.address, err))
357-
return
360+
return err
358361
}
359362
// If nothing changed, don't bother with hashing anything
360363
if tr == nil {
361-
return
364+
return nil
362365
}
363366
// Track the amount of time wasted on hashing the storage trie
364367
if metrics.EnabledExpensive {
365368
defer func(start time.Time) { s.db.StorageHashes += time.Since(start) }(time.Now())
366369
}
367370
s.data.Root = tr.Hash()
371+
return nil
368372
}
369373

370374
// commitTrie submits the storage changes into the storage trie and re-computes
371-
// the root. Besides, all trie changes will be collected in a nodeset and returned.
375+
// the root. Storage trie changes will be wrapped in nodeset and be returned.
376+
// The error will be non-nil if any error occurs during trie commit operation
377+
// or memorized in stateObject because of failed database reads.
372378
func (s *stateObject) commitTrie(db Database) (*trie.NodeSet, error) {
373379
tr, err := s.updateTrie(db)
374380
if err != nil {
375381
return nil, err
376382
}
377-
if s.dbErr != nil {
378-
return nil, s.dbErr
379-
}
380383
// If nothing changed, don't bother with committing anything
381384
if tr == nil {
382385
return nil, nil
@@ -437,6 +440,7 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject {
437440
stateObject.suicided = s.suicided
438441
stateObject.dirtyCode = s.dirtyCode
439442
stateObject.deleted = s.deleted
443+
stateObject.dbErr = s.dbErr
440444
return stateObject
441445
}
442446

@@ -521,10 +525,3 @@ func (s *stateObject) Balance() *big.Int {
521525
func (s *stateObject) Nonce() uint64 {
522526
return s.data.Nonce
523527
}
524-
525-
// Value is never called, but must be present to allow stateObject to be used
526-
// as a vm.Account interface that also satisfies the vm.ContractRef
527-
// interface. Interfaces are awesome.
528-
func (s *stateObject) Value() *big.Int {
529-
panic("Value on stateObject should never be called")
530-
}

0 commit comments

Comments
 (0)