Skip to content

Commit

Permalink
Update Carmen to get proof steps in correct order
Browse files Browse the repository at this point in the history
  • Loading branch information
HerbertJordan committed Nov 29, 2024
1 parent ec3be9d commit 27c3baa
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 21 deletions.
8 changes: 3 additions & 5 deletions ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -745,22 +745,20 @@ func (s *PublicBlockChainAPI) GetProof(ctx context.Context, address common.Addre

storageProof := make([]StorageResult, len(keys))
for i, key := range keys {
elements, _, _ := proof.GetStorageElements(cc.Hash(header.Root), cc.Address(address), cc.Key(keys[i]))
elements, _ := proof.GetStorageElements(cc.Hash(header.Root), cc.Address(address), cc.Key(keys[i]))
storageProof[i] = StorageResult{
Key: key.Hex(),
Value: (*hexutil.Big)(state.GetState(address, key).Big()),
Proof: toHexSlice(elements),
}
}

_, storageHash, _ := proof.GetStorageElements(cc.Hash(header.Root), cc.Address(address))
accountProof, storageHash, _ := proof.GetAccountElements(cc.Hash(header.Root), cc.Address(address))
codeHash := state.GetCodeHash(address)

accountProof, _ := proof.Extract(cc.Hash(header.Root), cc.Address(address))

return &AccountResult{
Address: address,
AccountProof: toHexSlice(accountProof.GetElements()),
AccountProof: toHexSlice(accountProof),
Balance: (*hexutil.U256)(state.GetBalance(address)),
CodeHash: codeHash,
Nonce: hexutil.Uint64(state.GetNonce(address)),
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.22.0
toolchain go1.22.3

require (
github.com/Fantom-foundation/Carmen/go v0.0.0-20241128114701-34dad37b5648
github.com/Fantom-foundation/Carmen/go v0.0.0-20241129202153-690bc10fa624
github.com/Fantom-foundation/Tosca v0.0.0-20241028082205-7b33705a4675
github.com/Fantom-foundation/lachesis-base v0.0.0-20240116072301-a75735c4ef00
github.com/cespare/cp v1.1.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
github.com/DataDog/zstd v1.5.6 h1:LbEglqepa/ipmmQJUDnSsfvA8e8IStVcGaFWDuxvGOY=
github.com/DataDog/zstd v1.5.6/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/Fantom-foundation/Carmen/go v0.0.0-20241128114701-34dad37b5648 h1:gVmZHEjmw9/JAyaU28MOWkbDzLPZ+Qfu1WTHOuE26UU=
github.com/Fantom-foundation/Carmen/go v0.0.0-20241128114701-34dad37b5648/go.mod h1:vNRGm/b21hDlF8kYyKHkXq1s+jLMKpV4jGwXHylXIIg=
github.com/Fantom-foundation/Carmen/go v0.0.0-20241129202153-690bc10fa624 h1:9bFojtY5KoLFUtLYZGc1GNf0oIdBIOarlLr4+a/DA7U=
github.com/Fantom-foundation/Carmen/go v0.0.0-20241129202153-690bc10fa624/go.mod h1:vNRGm/b21hDlF8kYyKHkXq1s+jLMKpV4jGwXHylXIIg=
github.com/Fantom-foundation/Tosca v0.0.0-20241028082205-7b33705a4675 h1:Meqtt0eM9UAw1ceQ1tGiD497V0IVfqj8c6UrFJhkFNE=
github.com/Fantom-foundation/Tosca v0.0.0-20241028082205-7b33705a4675/go.mod h1:8i7r+dUOkXjEC61SaFoRet6JYjRaSoiM/PhviP6K4Y8=
github.com/Fantom-foundation/go-ethereum-sonic v0.0.0-20241022121122-7063a6b506bd h1:WoAkgzLLlyh3Zpnd/3gW8Ym5sHtugLCA4rQdT5udVF8=
Expand Down
41 changes: 28 additions & 13 deletions tests/block_header_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -481,14 +481,14 @@ func testHeaders_StateRootsMatchActualStateRoots(t *testing.T, headers []*types.
// root we see in the database. To get access to the database, we request
// a witness proof for an account at the given block. From this proof we
// we have a list of state-root candidates which we can test for.
steps, err := getWitnessProofSteps(client, int(header.Number.Int64()))
want, err := getStateRoot(client, int(header.Number.Int64()))
require.NoError(err, "failed to get witness proof for block %d", i)
got := header.Root
require.Contains(steps, got, "state root mismatch for block %d", i)
require.Equal(want, got, "state root mismatch for block %d", i)
}
}

func getWitnessProofSteps(client *ethclient.Client, blockNumber int) ([]common.Hash, error) {
func getStateRoot(client *ethclient.Client, blockNumber int) (common.Hash, error) {
var result struct {
AccountProof []string
}
Expand All @@ -500,18 +500,19 @@ func getWitnessProofSteps(client *ethclient.Client, blockNumber int) ([]common.H
fmt.Sprintf("0x%x", blockNumber),
)
if err != nil {
return nil, fmt.Errorf("failed to get witness proof; %v", err)
return common.Hash{}, fmt.Errorf("failed to get witness proof; %v", err)
}

res := []common.Hash{}
for _, proof := range result.AccountProof {
data, err := hexutil.Decode(proof)
if err != nil {
return nil, err
}
res = append(res, common.BytesToHash(crypto.Keccak256(data)))
// The hash of the first element of the account proof is the state root.
if len(result.AccountProof) == 0 {
return common.Hash{}, fmt.Errorf("no account proof found")
}
return res, nil

data, err := hexutil.Decode(result.AccountProof[0])
if err != nil {
return common.Hash{}, err
}
return common.BytesToHash(crypto.Keccak256(data)), nil
}

func testHeaders_SystemContractsHaveNonZeroNonce(t *testing.T, headers []*types.Header, client *ethclient.Client) {
Expand Down Expand Up @@ -708,6 +709,7 @@ func getVerifiedCounterState(
require := require.New(t)
var result struct {
AccountProof []string
StorageHash common.Hash
StorageProof []struct {
Value string
Proof []string
Expand All @@ -722,6 +724,7 @@ func getVerifiedCounterState(
)
require.NoError(err, "failed to get witness proof")
require.Equal(1, len(result.StorageProof), "expected exactly one storage proof")
require.GreaterOrEqual(len(result.StorageProof[0].Proof), 1, "expected at least one proof element")

// Verify the proof.
elements := []carmen.Bytes{}
Expand All @@ -733,13 +736,25 @@ func getVerifiedCounterState(
}
}
proof := carmen.CreateWitnessProofFromNodes(elements...)
require.True(proof.IsValid(), "proof is invalid")
require.True(proof.IsValid())

// Extract the storage value from the proof.
value, present, err := proof.GetState(carmen.Hash(stateRoot), carmen.Address(counterAddress), carmen.Key{})
require.NoError(err, "failed to get state from proof")
require.True(present, "slot not found in proof")

// Check that the storage root hash is consistent.
_, storageRoot, complete := proof.GetAccountElements(carmen.Hash(stateRoot), carmen.Address(counterAddress))
require.True(complete, "proof is not complete")
require.Equal(common.Hash(storageRoot), result.StorageHash, "storage root mismatch")

// Check that the storage proof starts with an element that corresponds to
// the storage root.
hash := crypto.Keccak256(hexutil.MustDecode(result.StorageProof[0].Proof[0]))
firstElementHash := carmen.Hash{}
copy(firstElementHash[:], hash)
require.Equal(storageRoot, firstElementHash, "storage proof does not start with the storage root")

// Compare the proof value with the value in the RPC result.
fromProof := int(new(big.Int).SetBytes(value[:]).Uint64())
fromResult, err := hexutil.DecodeUint64(result.StorageProof[0].Value)
Expand Down

0 comments on commit 27c3baa

Please sign in to comment.