Revert "internal/ethapi: fix codehash lookup in eth_getProof (#28357)"

This reverts commit 037c76c9ad.
This commit is contained in:
devopsbo3 2023-11-10 12:27:53 -06:00 committed by GitHub
parent 2ea46eef68
commit 334b699806
2 changed files with 72 additions and 74 deletions

View file

@ -39,12 +39,11 @@ import (
) )
var ( var (
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
testAddr = crypto.PubkeyToAddress(testKey.PublicKey) testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
testContract = common.HexToAddress("0xbeef") testSlot = common.HexToHash("0xdeadbeef")
testSlot = common.HexToHash("0xdeadbeef") testValue = crypto.Keccak256Hash(testSlot[:])
testValue = crypto.Keccak256Hash(testSlot[:]) testBalance = big.NewInt(2e15)
testBalance = big.NewInt(2e15)
) )
func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
@ -79,9 +78,8 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
func generateTestChain() (*core.Genesis, []*types.Block) { func generateTestChain() (*core.Genesis, []*types.Block) {
genesis := &core.Genesis{ genesis := &core.Genesis{
Config: params.AllEthashProtocolChanges, Config: params.AllEthashProtocolChanges,
Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance, Storage: map[common.Hash]common.Hash{testSlot: testValue}}, Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance, Storage: map[common.Hash]common.Hash{testSlot: testValue}}},
testContract: {Nonce: 1, Code: []byte{0x13, 0x37}}},
ExtraData: []byte("test genesis"), ExtraData: []byte("test genesis"),
Timestamp: 9000, Timestamp: 9000,
} }
@ -105,11 +103,8 @@ func TestGethClient(t *testing.T) {
test func(t *testing.T) test func(t *testing.T)
}{ }{
{ {
"TestGetProof1", "TestGetProof",
func(t *testing.T) { testGetProof(t, client, testAddr) }, func(t *testing.T) { testGetProof(t, client) },
}, {
"TestGetProof2",
func(t *testing.T) { testGetProof(t, client, testContract) },
}, { }, {
"TestGetProofCanonicalizeKeys", "TestGetProofCanonicalizeKeys",
func(t *testing.T) { testGetProofCanonicalizeKeys(t, client) }, func(t *testing.T) { testGetProofCanonicalizeKeys(t, client) },
@ -206,41 +201,38 @@ func testAccessList(t *testing.T, client *rpc.Client) {
} }
} }
func testGetProof(t *testing.T, client *rpc.Client, addr common.Address) { func testGetProof(t *testing.T, client *rpc.Client) {
ec := New(client) ec := New(client)
ethcl := ethclient.NewClient(client) ethcl := ethclient.NewClient(client)
result, err := ec.GetProof(context.Background(), addr, []string{testSlot.String()}, nil) result, err := ec.GetProof(context.Background(), testAddr, []string{testSlot.String()}, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if result.Address != addr { if !bytes.Equal(result.Address[:], testAddr[:]) {
t.Fatalf("unexpected address, have: %v want: %v", result.Address, addr) t.Fatalf("unexpected address, want: %v got: %v", testAddr, result.Address)
} }
// test nonce // test nonce
if nonce, _ := ethcl.NonceAt(context.Background(), addr, nil); result.Nonce != nonce { nonce, _ := ethcl.NonceAt(context.Background(), result.Address, nil)
if result.Nonce != nonce {
t.Fatalf("invalid nonce, want: %v got: %v", nonce, result.Nonce) t.Fatalf("invalid nonce, want: %v got: %v", nonce, result.Nonce)
} }
// test balance // test balance
if balance, _ := ethcl.BalanceAt(context.Background(), addr, nil); result.Balance.Cmp(balance) != 0 { balance, _ := ethcl.BalanceAt(context.Background(), result.Address, nil)
if result.Balance.Cmp(balance) != 0 {
t.Fatalf("invalid balance, want: %v got: %v", balance, result.Balance) t.Fatalf("invalid balance, want: %v got: %v", balance, result.Balance)
} }
// test storage // test storage
if len(result.StorageProof) != 1 { if len(result.StorageProof) != 1 {
t.Fatalf("invalid storage proof, want 1 proof, got %v proof(s)", len(result.StorageProof)) t.Fatalf("invalid storage proof, want 1 proof, got %v proof(s)", len(result.StorageProof))
} }
for _, proof := range result.StorageProof { proof := result.StorageProof[0]
if proof.Key != testSlot.String() { slotValue, _ := ethcl.StorageAt(context.Background(), testAddr, testSlot, nil)
t.Fatalf("invalid storage proof key, want: %q, got: %q", testSlot.String(), proof.Key) if !bytes.Equal(slotValue, proof.Value.Bytes()) {
} t.Fatalf("invalid storage proof value, want: %v, got: %v", slotValue, proof.Value.Bytes())
slotValue, _ := ethcl.StorageAt(context.Background(), addr, common.HexToHash(proof.Key), nil)
if have, want := common.BigToHash(proof.Value), common.BytesToHash(slotValue); have != want {
t.Fatalf("addr %x, invalid storage proof value: have: %v, want: %v", addr, have, want)
}
} }
// test code if proof.Key != testSlot.String() {
code, _ := ethcl.CodeAt(context.Background(), addr, nil) t.Fatalf("invalid storage proof key, want: %q, got: %q", testSlot.String(), proof.Key)
if have, want := result.CodeHash, crypto.Keccak256Hash(code); have != want {
t.Fatalf("codehash wrong, have %v want %v ", have, want)
} }
} }

View file

@ -675,6 +675,10 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st
keys = make([]common.Hash, len(storageKeys)) keys = make([]common.Hash, len(storageKeys))
keyLengths = make([]int, len(storageKeys)) keyLengths = make([]int, len(storageKeys))
storageProof = make([]StorageResult, len(storageKeys)) storageProof = make([]StorageResult, len(storageKeys))
storageTrie state.Trie
storageHash = types.EmptyRootHash
codeHash = types.EmptyCodeHash
) )
// Deserialize all keys. This prevents state access on invalid input. // Deserialize all keys. This prevents state access on invalid input.
for i, hexKey := range storageKeys { for i, hexKey := range storageKeys {
@ -684,49 +688,51 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st
return nil, err return nil, err
} }
} }
statedb, header, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) state, header, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
if statedb == nil || err != nil { if state == nil || err != nil {
return nil, err return nil, err
} }
codeHash := statedb.GetCodeHash(address) if storageRoot := state.GetStorageRoot(address); storageRoot != types.EmptyRootHash && storageRoot != (common.Hash{}) {
storageRoot := statedb.GetStorageRoot(address) id := trie.StorageTrieID(header.Root, crypto.Keccak256Hash(address.Bytes()), storageRoot)
tr, err := trie.NewStateTrie(id, state.Database().TrieDB())
if len(keys) > 0 { if err != nil {
var storageTrie state.Trie return nil, err
if storageRoot != types.EmptyRootHash && storageRoot != (common.Hash{}) {
id := trie.StorageTrieID(header.Root, crypto.Keccak256Hash(address.Bytes()), storageRoot)
st, err := trie.NewStateTrie(id, statedb.Database().TrieDB())
if err != nil {
return nil, err
}
storageTrie = st
}
// Create the proofs for the storageKeys.
for i, key := range keys {
// Output key encoding is a bit special: if the input was a 32-byte hash, it is
// returned as such. Otherwise, we apply the QUANTITY encoding mandated by the
// JSON-RPC spec for getProof. This behavior exists to preserve backwards
// compatibility with older client versions.
var outputKey string
if keyLengths[i] != 32 {
outputKey = hexutil.EncodeBig(key.Big())
} else {
outputKey = hexutil.Encode(key[:])
}
if storageTrie == nil {
storageProof[i] = StorageResult{outputKey, &hexutil.Big{}, []string{}}
continue
}
var proof proofList
if err := storageTrie.Prove(crypto.Keccak256(key.Bytes()), &proof); err != nil {
return nil, err
}
value := (*hexutil.Big)(statedb.GetState(address, key).Big())
storageProof[i] = StorageResult{outputKey, value, proof}
} }
storageTrie = tr
} }
// If we have a storageTrie, the account exists and we must update
// the storage root hash and the code hash.
if storageTrie != nil {
storageHash = storageTrie.Hash()
codeHash = state.GetCodeHash(address)
}
// Create the proofs for the storageKeys.
for i, key := range keys {
// Output key encoding is a bit special: if the input was a 32-byte hash, it is
// returned as such. Otherwise, we apply the QUANTITY encoding mandated by the
// JSON-RPC spec for getProof. This behavior exists to preserve backwards
// compatibility with older client versions.
var outputKey string
if keyLengths[i] != 32 {
outputKey = hexutil.EncodeBig(key.Big())
} else {
outputKey = hexutil.Encode(key[:])
}
if storageTrie == nil {
storageProof[i] = StorageResult{outputKey, &hexutil.Big{}, []string{}}
continue
}
var proof proofList
if err := storageTrie.Prove(crypto.Keccak256(key.Bytes()), &proof); err != nil {
return nil, err
}
value := (*hexutil.Big)(state.GetState(address, key).Big())
storageProof[i] = StorageResult{outputKey, value, proof}
}
// Create the accountProof. // Create the accountProof.
tr, err := trie.NewStateTrie(trie.StateTrieID(header.Root), statedb.Database().TrieDB()) tr, err := trie.NewStateTrie(trie.StateTrieID(header.Root), state.Database().TrieDB())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -737,12 +743,12 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st
return &AccountResult{ return &AccountResult{
Address: address, Address: address,
AccountProof: accountProof, AccountProof: accountProof,
Balance: (*hexutil.Big)(statedb.GetBalance(address)), Balance: (*hexutil.Big)(state.GetBalance(address)),
CodeHash: codeHash, CodeHash: codeHash,
Nonce: hexutil.Uint64(statedb.GetNonce(address)), Nonce: hexutil.Uint64(state.GetNonce(address)),
StorageHash: storageRoot, StorageHash: storageHash,
StorageProof: storageProof, StorageProof: storageProof,
}, statedb.Error() }, state.Error()
} }
// decodeHash parses a hex-encoded 32-byte hash. The input may optionally // decodeHash parses a hex-encoded 32-byte hash. The input may optionally