From de60e03f0351b72b87b9b8b0ae1d73e27ec671db Mon Sep 17 00:00:00 2001 From: Mark Holt <135143369+mh0lt@users.noreply.github.com> Date: Fri, 17 Nov 2023 19:39:59 +0300 Subject: [PATCH] Bor proof findpath (#8764) Added trie findpath to support bor receipt format. This requires testing against the polygon deployed contracts to confirm parent path format --- cmd/devnet/services/polygon/proofgenerator.go | 6 +-- .../services/polygon/proofgenerator_test.go | 14 ++++-- turbo/trie/trie.go | 49 +++++++++++++++++++ 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/cmd/devnet/services/polygon/proofgenerator.go b/cmd/devnet/services/polygon/proofgenerator.go index da9c356d1..5b8d207af 100644 --- a/cmd/devnet/services/polygon/proofgenerator.go +++ b/cmd/devnet/services/polygon/proofgenerator.go @@ -244,7 +244,7 @@ func (pg *ProofGenerator) buildPayloadForExit(ctx context.Context, burnTxHash li []interface{}{ rootBlockNumber, hexutility.Encode(bytes.Join(blockProofs, []byte{})), - txBlockNum, + block.Number.Uint64(), block.Time, hexutility.Encode(block.TxHash[:]), hexutility.Encode(block.ReceiptHash[:]), @@ -309,7 +309,7 @@ func getReceiptProof(ctx context.Context, node requests.RequestGenerator, receip } path, _ := rlp.EncodeToBytes(receipt.TransactionIndex) - result, ok := receiptsTrie.Get(path) + result, parents, ok := receiptsTrie.FindPath(path) if !ok { return nil, fmt.Errorf("node does not contain the key") @@ -325,7 +325,7 @@ func getReceiptProof(ctx context.Context, node requests.RequestGenerator, receip return &receiptProof{ blockHash: receipt.BlockHash, - parentNodes: nil, //TODO - not sure how to get this result.stack.map(s => s.raw()), + parentNodes: parents, root: block.ReceiptHash[:], path: path, value: nodeValue, diff --git a/cmd/devnet/services/polygon/proofgenerator_test.go b/cmd/devnet/services/polygon/proofgenerator_test.go index e35b68850..78a08bfcf 100644 --- a/cmd/devnet/services/polygon/proofgenerator_test.go +++ b/cmd/devnet/services/polygon/proofgenerator_test.go @@ -14,6 +14,7 @@ import ( "github.com/ledgerwatch/erigon-lib/chain" "github.com/ledgerwatch/erigon-lib/common" libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/common/hexutility" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/kv/memdb" "github.com/ledgerwatch/erigon/accounts/abi/bind" @@ -340,7 +341,7 @@ func TestBlockProof(t *testing.T) { } func TestReceiptProof(t *testing.T) { - sentry, chain, err := generateBlocks(t, 1) + sentry, chain, err := generateBlocks(t, 10) if err != nil { t.Fatal(err) @@ -374,14 +375,19 @@ func TestReceiptProof(t *testing.T) { t.Fatal(err) } - //TODO the receiptProof needs parents formatted from trie - need to confirm format for that - _ /*receiptProof*/, err = getReceiptProof(context.Background(), rg, receipt, block, nil) + receiptProof, err := getReceiptProof(context.Background(), rg, receipt, block, nil) if err != nil { t.Fatal(err) } - //fmt.Println(receiptProof) + parentNodesBytes, err := rlp.EncodeToBytes(receiptProof.parentNodes) + + if err != nil { + t.Fatal(err) + } + + fmt.Println(hexutility.Encode(parentNodesBytes), hexutility.Encode(append([]byte{0}, receiptProof.path...))) } func generateBlocks(t *testing.T, number int) (*mock.MockSentry, *core.ChainPack, error) { diff --git a/turbo/trie/trie.go b/turbo/trie/trie.go index 6587938ec..c8e6ee215 100644 --- a/turbo/trie/trie.go +++ b/turbo/trie/trie.go @@ -94,6 +94,15 @@ func (t *Trie) Get(key []byte) (value []byte, gotValue bool) { return t.get(t.root, hex, 0) } +func (t *Trie) FindPath(key []byte) (value []byte, parents [][]byte, gotValue bool) { + if t.root == nil { + return nil, nil, true + } + + hex := keybytesToHex(key) + return t.getPath(t.root, nil, hex, 0) +} + func (t *Trie) GetAccount(key []byte) (value *accounts.Account, gotValue bool) { if t.root == nil { return nil, true @@ -233,6 +242,46 @@ func (t *Trie) get(origNode node, key []byte, pos int) (value []byte, gotValue b } } +func (t *Trie) getPath(origNode node, parents [][]byte, key []byte, pos int) ([]byte, [][]byte, bool) { + switch n := (origNode).(type) { + case nil: + return nil, parents, true + case valueNode: + return n, parents, true + case *accountNode: + return t.getPath(n.storage, append(parents, n.reference()), key, pos) + case *shortNode: + matchlen := prefixLen(key[pos:], n.Key) + if matchlen == len(n.Key) || n.Key[matchlen] == 16 { + return t.getPath(n.Val, append(parents, n.reference()), key, pos+matchlen) + } else { + return nil, parents, true + } + + case *duoNode: + i1, i2 := n.childrenIdx() + switch key[pos] { + case i1: + return t.getPath(n.child1, append(parents, n.reference()), key, pos+1) + case i2: + return t.getPath(n.child2, append(parents, n.reference()), key, pos+1) + default: + return nil, parents, true + } + case *fullNode: + child := n.Children[key[pos]] + if child == nil { + return nil, parents, true + } + return t.getPath(child, append(parents, n.reference()), key, pos+1) + case hashNode: + return n.hash, parents, false + + default: + panic(fmt.Sprintf("%T: invalid node: %v", origNode, origNode)) + } +} + // Update associates key with value in the trie. Subsequent calls to // Get will return value. If value has length zero, any existing value // is deleted from the trie and calls to Get will return nil.