@ -680,3 +680,50 @@ func TestDeleteCreateRevert(t *testing.T) {
t . Fatalf ( "self-destructed contract came alive" )
}
}
// TestMissingTrieNodes tests that if the statedb fails to load parts of the trie,
// the Commit operation fails with an error
// If we are missing trie nodes, we should not continue writing to the trie
func TestMissingTrieNodes ( t * testing . T ) {
// Create an initial state with a few accounts
memDb := rawdb . NewMemoryDatabase ( )
db := NewDatabase ( memDb )
var root common . Hash
state , _ := New ( common . Hash { } , db , nil )
addr := toAddr ( [ ] byte ( "so" ) )
{
state . SetBalance ( addr , big . NewInt ( 1 ) )
state . SetCode ( addr , [ ] byte { 1 , 2 , 3 } )
a2 := toAddr ( [ ] byte ( "another" ) )
state . SetBalance ( a2 , big . NewInt ( 100 ) )
state . SetCode ( a2 , [ ] byte { 1 , 2 , 4 } )
root , _ = state . Commit ( false )
t . Logf ( "root: %x" , root )
// force-flush
state . Database ( ) . TrieDB ( ) . Cap ( 0 )
}
// Create a new state on the old root
state , _ = New ( root , db , nil )
// Now we clear out the memdb
it := memDb . NewIterator ( nil , nil )
for it . Next ( ) {
k := it . Key ( )
// Leave the root intact
if ! bytes . Equal ( k , root [ : ] ) {
t . Logf ( "key: %x" , k )
memDb . Delete ( k )
}
}
balance := state . GetBalance ( addr )
// The removed elem should lead to it returning zero balance
if exp , got := uint64 ( 0 ) , balance . Uint64 ( ) ; got != exp {
t . Errorf ( "expected %d, got %d" , exp , got )
}
// Modify the state
state . SetBalance ( addr , big . NewInt ( 2 ) )
root , err := state . Commit ( false )
if err == nil {
t . Fatalf ( "expected error, got root :%x" , root )
}
}