Skip to content

Commit

Permalink
core/state: fix snapshot recovery
Browse files Browse the repository at this point in the history
a
  • Loading branch information
asyukii committed Oct 16, 2023
1 parent fefd043 commit 51682a7
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 26 deletions.
26 changes: 23 additions & 3 deletions core/state/snapshot/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,11 @@ func (dl *diskLayer) proveRange(ctx *generatorContext, trieId *trie.ID, prefix [
keys = append(keys, common.CopyBytes(key[len(prefix):]))

if valueConvertFn == nil {
vals = append(vals, common.CopyBytes(iter.Value()))
rlpVal, err := convertSnapValToRLPVal(iter.Value())
if err != nil {
return nil, err
}
vals = append(vals, rlpVal)
} else {
val, err := valueConvertFn(iter.Value())
if err != nil {
Expand All @@ -204,10 +208,18 @@ func (dl *diskLayer) proveRange(ctx *generatorContext, trieId *trie.ID, prefix [
//
// Here append the original value to ensure that the number of key and
// value are aligned.
vals = append(vals, common.CopyBytes(iter.Value()))
rlpVal, err := convertSnapValToRLPVal(val)
if err != nil {
return nil, err
}
vals = append(vals, rlpVal)
log.Error("Failed to convert account state data", "err", err)
} else {
vals = append(vals, val)
rlpVal, err := convertSnapValToRLPVal(val)
if err != nil {
return nil, err
}
vals = append(vals, rlpVal)
}
}
}
Expand Down Expand Up @@ -735,6 +747,14 @@ func increaseKey(key []byte) []byte {
return nil
}

func convertSnapValToRLPVal(val []byte) ([]byte, error) {
snapVal, err := DecodeValueFromRLPBytes(val)
if err != nil {
return nil, err
}
return rlp.EncodeToBytes(snapVal.GetVal())
}

// abortErr wraps an interruption signal received to represent the
// generation is aborted by external processes.
type abortErr struct {
Expand Down
45 changes: 29 additions & 16 deletions core/state/snapshot/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func testGeneration(t *testing.T, scheme string) {
helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)

root, snap := helper.CommitAndGenerate()
if have, want := root, common.HexToHash("0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd"); have != want {
if have, want := root, common.HexToHash("0x1b4b0ae3b50e6ce40184d08fc5857c5b6909e2b1d8017d9e3f69170e323b1f6c"); have != want {
t.Fatalf("have %#x want %#x", have, want)
}
select {
Expand Down Expand Up @@ -196,15 +196,17 @@ func (t *testHelper) addAccount(acckey string, acc *types.StateAccount) {
func (t *testHelper) addSnapStorage(accKey string, keys []string, vals []string) {
accHash := hashData([]byte(accKey))
for i, key := range keys {
rawdb.WriteStorageSnapshot(t.diskdb, accHash, hashData([]byte(key)), []byte(vals[i]))
val, _ := rlp.EncodeToBytes(vals[i])
rawdb.WriteStorageSnapshot(t.diskdb, accHash, hashData([]byte(key)), val)
}
}

func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []string, commit bool) common.Hash {
id := trie.StorageTrieID(types.EmptyRootHash, owner, types.EmptyRootHash)
stTrie, _ := trie.NewStateTrie(id, t.triedb)
for i, k := range keys {
stTrie.MustUpdate([]byte(k), []byte(vals[i]))
rlpVal, _ := rlp.EncodeToBytes(vals[i])
stTrie.MustUpdate([]byte(k), rlpVal) // [133,118,97,108,45,49]
}
if !commit {
return stTrie.Hash()
Expand Down Expand Up @@ -512,7 +514,7 @@ func testGenerateCorruptStorageTrie(t *testing.T, scheme string) {

// Delete a node in the storage trie.
targetPath := []byte{0x4}
targetHash := common.HexToHash("0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371")
targetHash := common.HexToHash("0x1b4b0ae3b50e6ce40184d08fc5857c5b6909e2b1d8017d9e3f69170e323b1f6c")
rawdb.DeleteTrieNode(helper.diskdb, hashData([]byte("acc-1")), targetPath, targetHash, scheme)
rawdb.DeleteTrieNode(helper.diskdb, hashData([]byte("acc-3")), targetPath, targetHash, scheme)

Expand Down Expand Up @@ -552,12 +554,16 @@ func testGenerateWithExtraAccounts(t *testing.T, scheme string) {

// Identical in the snap
key := hashData([]byte("acc-1"))
rawdb.WriteAccountSnapshot(helper.diskdb, key, val)
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-1")), []byte("val-1"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-2")), []byte("val-2"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-3")), []byte("val-3"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-4")), []byte("val-4"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-5")), []byte("val-5"))
val, _ = rlp.EncodeToBytes([]byte("val-1"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-1")), val)
val, _ = rlp.EncodeToBytes([]byte("val-2"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-2")), val)
val, _ = rlp.EncodeToBytes([]byte("val-3"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-3")), val)
val, _ = rlp.EncodeToBytes([]byte("val-4"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-4")), val)
val, _ = rlp.EncodeToBytes([]byte("val-5"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-5")), val)
}
{
// Account two exists only in the snapshot
Expand All @@ -570,9 +576,13 @@ func testGenerateWithExtraAccounts(t *testing.T, scheme string) {
val, _ := rlp.EncodeToBytes(acc)
key := hashData([]byte("acc-2"))
rawdb.WriteAccountSnapshot(helper.diskdb, key, val)
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-1")), []byte("b-val-1"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-2")), []byte("b-val-2"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-3")), []byte("b-val-3"))
val, _ = rlp.EncodeToBytes([]byte("b-val-1"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-1")), val)
val, _ = rlp.EncodeToBytes([]byte("b-val-2"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-2")), val)
val, _ = rlp.EncodeToBytes([]byte("b-val-3"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-3")), val)

}
root := helper.Commit()

Expand Down Expand Up @@ -629,9 +639,12 @@ func testGenerateWithManyExtraAccounts(t *testing.T, scheme string) {
// Identical in the snap
key := hashData([]byte("acc-1"))
rawdb.WriteAccountSnapshot(helper.diskdb, key, val)
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-1")), []byte("val-1"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-2")), []byte("val-2"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-3")), []byte("val-3"))
val, _ = rlp.EncodeToBytes([]byte("val-1"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-1")), val)
val, _ = rlp.EncodeToBytes([]byte("val-2"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-2")), val)
val, _ = rlp.EncodeToBytes([]byte("val-3"))
rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-3")), val)
}
{
// 100 accounts exist only in snapshot
Expand Down
4 changes: 2 additions & 2 deletions ethclient/gethclient/gethclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func (ec *Client) GetProof(ctx context.Context, account common.Address, keys []s

// GetStorageReviveProof returns the proof for the given keys. Prefix keys can be specified to obtain partial proof for a given key.
// Both keys and prefix keys should have the same length. If user wish to obtain full proof for a given key, the corresponding prefix key should be empty string.
func (ec *Client) GetStorageReviveProof(ctx context.Context, account common.Address, keys []string, prefixKeys []string, hash common.Hash) (*types.ReviveResult, error) {
func (ec *Client) GetStorageReviveProof(ctx context.Context, stateRoot common.Hash, account common.Address, root common.Hash, keys []string, prefixKeys []string) (*types.ReviveResult, error) {
type reviveResult struct {
StorageProof []types.ReviveStorageProof `json:"storageProof"`
BlockNum hexutil.Uint64 `json:"blockNum"`
Expand All @@ -136,7 +136,7 @@ func (ec *Client) GetStorageReviveProof(ctx context.Context, account common.Addr
var err error
var res reviveResult

err = ec.c.CallContext(ctx, &res, "eth_getStorageReviveProof", account, keys, prefixKeys, hash)
err = ec.c.CallContext(ctx, &res, "eth_getStorageReviveProof", stateRoot, account, root, keys, prefixKeys)

return &types.ReviveResult{
StorageProof: res.StorageProof,
Expand Down
8 changes: 4 additions & 4 deletions ethclient/gethclient/gethclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func generateTestChain() (*core.Genesis, []*types.Block) {
}

func TestGethClient(t *testing.T) {
backend, _ := newTestBackend(t)
backend, blocks := newTestBackend(t)
client := backend.Attach()
defer backend.Close()
defer client.Close()
Expand All @@ -107,7 +107,7 @@ func TestGethClient(t *testing.T) {
func(t *testing.T) { testGetProof(t, client) },
}, {
"TestGetStorageReviveProof",
func(t *testing.T) { testGetStorageReviveProof(t, client) },
func(t *testing.T) { testGetStorageReviveProof(t, client, blocks[0]) },
}, {
"TestGetProofCanonicalizeKeys",
func(t *testing.T) { testGetProofCanonicalizeKeys(t, client) },
Expand Down Expand Up @@ -239,9 +239,9 @@ func testGetProof(t *testing.T, client *rpc.Client) {
}
}

func testGetStorageReviveProof(t *testing.T, client *rpc.Client) {
func testGetStorageReviveProof(t *testing.T, client *rpc.Client, block *types.Block) {
ec := New(client)
result, err := ec.GetStorageReviveProof(context.Background(), testAddr, []string{testSlot.String()}, []string{""}, common.Hash{})
result, err := ec.GetStorageReviveProof(context.Background(), block.Header().Root, testAddr, block.Header().Root, []string{testSlot.String()}, []string{""})
proofs := result.StorageProof

if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion trie/trie_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1118,7 +1118,7 @@ func TestReviveBadProof(t *testing.T) {

// Verify value does exists after revive
val, err := trieA.Get([]byte("abcd"))
assert.NoError(t, err, "Get failed, key %x, val %x", []byte("abcd"), val)
assert.Error(t, err, "Get failed, key %x, val %x", []byte("abcd"), val)
assert.NotEqual(t, []byte("A"), val)
}

Expand Down

0 comments on commit 51682a7

Please sign in to comment.