Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core/state: fix snapshot recovery #123

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading