mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-31 16:21:21 +00:00
80530e10a9
This PR completes the implementation of `eth_getProof` by adding support for storage proofs. Because storage proofs are potentially overlapping, the existing strategy of simply aggregating all proofs together into a single result was challenging. Instead, this commit rewires things to introduce a ProofRetainer, which aggregates proofs and their corresponding nibble encoded paths in the trie. Once all of the proofs have been aggregated, the caller requests the proof result, which then iterates over the aggregated proofs, placing each into the relevant proof array into the result. Although there are tests for `eth_getProof` as an RPC and for the new `ProofRetainer` code, the code coverage for the proof generation over complex tries is lacking. But, since this is not a new problem I'll plan to follow up this PR with an additional one adding more coverage into `turbo/trie`. --------- Co-authored-by: Jason Yellick <jason@enya.ai>
107 lines
3.2 KiB
Go
107 lines
3.2 KiB
Go
package trie
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/holiman/uint256"
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
|
"github.com/ledgerwatch/erigon/core/types/accounts"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestProofRetainerConstruction(t *testing.T) {
|
|
rl := NewRetainList(0)
|
|
pr, err := NewProofRetainer(
|
|
libcommon.Address{0x1},
|
|
&accounts.Account{
|
|
Initialised: true,
|
|
Nonce: 2,
|
|
Balance: *uint256.NewInt(6e9),
|
|
CodeHash: libcommon.Hash{3},
|
|
Incarnation: 3,
|
|
},
|
|
[]libcommon.Hash{{1}, {2}, {3}},
|
|
rl,
|
|
)
|
|
require.NoError(t, err)
|
|
require.Len(t, rl.hexes, 4)
|
|
|
|
validKeys := [][]byte{
|
|
{},
|
|
pr.accHexKey[:15],
|
|
pr.accHexKey[:],
|
|
pr.storageHexKeys[0][:85],
|
|
pr.storageHexKeys[0][:],
|
|
pr.storageHexKeys[1][:90],
|
|
pr.storageHexKeys[1][:],
|
|
pr.storageHexKeys[2][:98],
|
|
pr.storageHexKeys[2][:95],
|
|
pr.storageHexKeys[2][:],
|
|
}
|
|
|
|
invalidKeys := [][]byte{
|
|
pr.accHexKey[1:16],
|
|
pr.storageHexKeys[0][12:80],
|
|
pr.storageHexKeys[2][19:90],
|
|
}
|
|
|
|
for _, key := range validKeys {
|
|
pe := pr.ProofElement(key)
|
|
require.NotNil(t, pe)
|
|
require.Equal(t, pe.hexKey, key)
|
|
switch len(key) {
|
|
case 64: // Account leaf key
|
|
pe.storageRoot = libcommon.Hash{3}
|
|
case 144: // Storage leaf key
|
|
pe.storageValue = uint256.NewInt(5)
|
|
}
|
|
pe.proof.Write(key)
|
|
}
|
|
for _, key := range invalidKeys {
|
|
pe := pr.ProofElement(key)
|
|
require.Nil(t, pe)
|
|
}
|
|
require.Equal(t, len(validKeys), len(pr.proofs))
|
|
|
|
accProof, err := pr.ProofResult()
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, accProof.AccountProof, 3)
|
|
require.Equal(t, []byte(nil), []byte(accProof.AccountProof[0]))
|
|
require.Equal(t, validKeys[1], []byte(accProof.AccountProof[1]))
|
|
require.Equal(t, validKeys[2], []byte(accProof.AccountProof[2]))
|
|
|
|
require.Len(t, accProof.StorageProof, 3)
|
|
require.Equal(t, accProof.StorageProof[0].Key, libcommon.Hash{1})
|
|
require.Len(t, accProof.StorageProof[0].Proof, 2)
|
|
require.Equal(t, validKeys[3], []byte(accProof.StorageProof[0].Proof[0]))
|
|
require.Equal(t, validKeys[4], []byte(accProof.StorageProof[0].Proof[1]))
|
|
|
|
require.Equal(t, accProof.StorageProof[1].Key, libcommon.Hash{2})
|
|
require.Len(t, accProof.StorageProof[1].Proof, 2)
|
|
require.Equal(t, validKeys[5], []byte(accProof.StorageProof[1].Proof[0]))
|
|
require.Equal(t, validKeys[6], []byte(accProof.StorageProof[1].Proof[1]))
|
|
|
|
require.Equal(t, accProof.StorageProof[2].Key, libcommon.Hash{3})
|
|
require.Len(t, accProof.StorageProof[2].Proof, 3)
|
|
require.Equal(t, validKeys[7], []byte(accProof.StorageProof[2].Proof[0]))
|
|
require.Equal(t, validKeys[8], []byte(accProof.StorageProof[2].Proof[1]))
|
|
require.Equal(t, validKeys[9], []byte(accProof.StorageProof[2].Proof[2]))
|
|
|
|
t.Run("missingStorageRoot", func(t *testing.T) {
|
|
oldStorageHash := pr.proofs[2].storageRoot
|
|
pr.proofs[2].storageRoot = libcommon.Hash{}
|
|
defer func() { pr.proofs[2].storageRoot = oldStorageHash }()
|
|
_, err := pr.ProofResult()
|
|
require.Error(t, err, "did not find storage root in proof elements")
|
|
})
|
|
|
|
t.Run("missingStorageValue", func(t *testing.T) {
|
|
oldKey := pr.proofs[4].storageValue
|
|
pr.proofs[4].storageValue = nil
|
|
defer func() { pr.proofs[4].storageValue = oldKey }()
|
|
_, err := pr.ProofResult()
|
|
require.Error(t, err, "no storage value for storage key 0x%x", validKeys[4])
|
|
})
|
|
}
|