forked from cerc-io/plugeth
internal/ethapi: prevent unnecessary resource usage in eth_getProof implementation (#27310)
Deserialize hex keys early to shortcut on invalid input, and re-use the account storageTrie for each proof for each proof in the account, preventing repeated deep-copying of the trie. Closes #27308 -------- Co-authored-by: Martin Holst Swende <martin@swende.se> Co-authored-by: Marius van der Wijden <m.vanderwijden@live.de>
This commit is contained in:
parent
8013a494fe
commit
61dcf76230
@ -655,43 +655,62 @@ type StorageResult struct {
|
|||||||
Proof []string `json:"proof"`
|
Proof []string `json:"proof"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// proofList implements ethdb.KeyValueWriter and collects the proofs as
|
||||||
|
// hex-strings for delivery to rpc-caller.
|
||||||
|
type proofList []string
|
||||||
|
|
||||||
|
func (n *proofList) Put(key []byte, value []byte) error {
|
||||||
|
*n = append(*n, hexutil.Encode(value))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *proofList) Delete(key []byte) error {
|
||||||
|
panic("not supported")
|
||||||
|
}
|
||||||
|
|
||||||
// GetProof returns the Merkle-proof for a given account and optionally some storage keys.
|
// GetProof returns the Merkle-proof for a given account and optionally some storage keys.
|
||||||
func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) {
|
func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) {
|
||||||
|
var (
|
||||||
|
keys = make([]common.Hash, len(storageKeys))
|
||||||
|
storageProof = make([]StorageResult, len(storageKeys))
|
||||||
|
storageTrie state.Trie
|
||||||
|
storageHash = types.EmptyRootHash
|
||||||
|
codeHash = types.EmptyCodeHash
|
||||||
|
)
|
||||||
|
// Greedily deserialize all keys. This prevents state access on invalid input
|
||||||
|
for i, hexKey := range storageKeys {
|
||||||
|
if key, err := decodeHash(hexKey); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
keys[i] = key
|
||||||
|
}
|
||||||
|
}
|
||||||
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||||
if state == nil || err != nil {
|
if state == nil || err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
storageTrie, err := state.StorageTrie(address)
|
if storageTrie, err = state.StorageTrie(address); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
storageHash := types.EmptyRootHash
|
// if we have a storageTrie, the account exists and we must update
|
||||||
codeHash := state.GetCodeHash(address)
|
// the storage root hash and the code hash.
|
||||||
storageProof := make([]StorageResult, len(storageKeys))
|
|
||||||
|
|
||||||
// if we have a storageTrie, (which means the account exists), we can update the storagehash
|
|
||||||
if storageTrie != nil {
|
if storageTrie != nil {
|
||||||
storageHash = storageTrie.Hash()
|
storageHash = storageTrie.Hash()
|
||||||
} else {
|
codeHash = state.GetCodeHash(address)
|
||||||
// no storageTrie means the account does not exist, so the codeHash is the hash of an empty bytearray.
|
|
||||||
codeHash = crypto.Keccak256Hash(nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the proof for the storageKeys
|
// create the proof for the storageKeys
|
||||||
for i, hexKey := range storageKeys {
|
for i, key := range keys {
|
||||||
key, err := decodeHash(hexKey)
|
if storageTrie == nil {
|
||||||
if err != nil {
|
storageProof[i] = StorageResult{storageKeys[i], &hexutil.Big{}, []string{}}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var proof proofList
|
||||||
|
if err := storageTrie.Prove(crypto.Keccak256(key.Bytes()), 0, &proof); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if storageTrie != nil {
|
storageProof[i] = StorageResult{storageKeys[i],
|
||||||
proof, storageError := state.GetStorageProof(address, key)
|
(*hexutil.Big)(state.GetState(address, key).Big()),
|
||||||
if storageError != nil {
|
proof}
|
||||||
return nil, storageError
|
|
||||||
}
|
|
||||||
storageProof[i] = StorageResult{hexKey, (*hexutil.Big)(state.GetState(address, key).Big()), toHexSlice(proof)}
|
|
||||||
} else {
|
|
||||||
storageProof[i] = StorageResult{hexKey, &hexutil.Big{}, []string{}}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the accountProof
|
// create the accountProof
|
||||||
|
Loading…
Reference in New Issue
Block a user