Skip to content

Commit 3027c06

Browse files
committed
resolve review comments from Diego
1 parent b0efc3f commit 3027c06

File tree

2 files changed

+39
-55
lines changed

2 files changed

+39
-55
lines changed

cmd/mel-replay/receipt_fetcher.go

Lines changed: 37 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package main
66
import (
77
"bytes"
88
"context"
9+
"errors"
910
"fmt"
1011

1112
"github.com/ethereum/go-ethereum/common"
@@ -57,16 +58,11 @@ func fetchReceiptFromBlock(
5758
switch len(node) {
5859
case 17:
5960
// We hit a branch node, which has 16 children and a value.
60-
if len(currentPath) >= len(targetNibbles) {
61+
if len(currentPath) == len(targetNibbles) {
6162
// A branch node's 17th item could be the value, so we check if it contains the receipt.
6263
if valueBytes, ok := node[16].([]byte); ok && len(valueBytes) > 0 {
6364
// This branch node has the actual value as the last item, so we decode the receipt
64-
receipt := new(types.Receipt)
65-
receiptData := bytes.NewBuffer(valueBytes)
66-
if err = rlp.Decode(receiptData, &receipt); err != nil {
67-
return nil, fmt.Errorf("failed to decode receipt: %w", err)
68-
}
69-
return receipt, nil
65+
return decodeReceipt(valueBytes)
7066
}
7167
return nil, fmt.Errorf("no receipt found at target key")
7268
}
@@ -85,37 +81,30 @@ func fetchReceiptFromBlock(
8581
return nil, fmt.Errorf("invalid key path in node")
8682
}
8783
// Check if it is a leaf or extension node.
88-
if isLeaf(keyPath) {
84+
leafKey := extractKeyNibbles(keyPath)
85+
expectedPath := make([]byte, 0)
86+
expectedPath = append(expectedPath, currentPath...)
87+
expectedPath = append(expectedPath, leafKey...)
88+
89+
leaf, err := isLeaf(keyPath)
90+
if err != nil {
91+
return nil, err
92+
}
93+
if leaf {
8994
// Check that the keyPath matches the target nibbles,
9095
// otherwise, the receipt does not exist in the trie.
91-
leafKey := extractKeyNibbles(keyPath)
92-
expectedPath := make([]byte, 0)
93-
expectedPath = append(expectedPath, currentPath...)
94-
expectedPath = append(expectedPath, leafKey...)
9596
if !bytes.Equal(expectedPath, targetNibbles) {
9697
return nil, fmt.Errorf("leaf key does not match target nibbles")
9798
}
98-
99-
receipt := new(types.Receipt)
10099
rawData, ok := node[1].([]byte)
101100
if !ok {
102101
return nil, fmt.Errorf("invalid receipt data in leaf node")
103102
}
104-
receiptData := bytes.NewBuffer(rawData)
105-
if err = rlp.Decode(receiptData, &receipt); err != nil {
106-
return nil, fmt.Errorf("failed to decode receipt: %w", err)
107-
}
108-
return receipt, nil
103+
return decodeReceipt(rawData)
109104
}
110105
// If the node is not a leaf node, it is an extension node.
111-
// We extract the extension key path and append it to our current path.
112-
extKey := extractKeyNibbles(keyPath)
113-
newPath := make([]byte, 0)
114-
newPath = append(newPath, currentPath...)
115-
newPath = append(newPath, extKey...)
116-
117106
// Check if our target key matches this extension path.
118-
if len(newPath) > len(targetNibbles) || !bytes.Equal(newPath, targetNibbles[:len(newPath)]) {
107+
if len(expectedPath) > len(targetNibbles) || !bytes.Equal(expectedPath, targetNibbles[:len(expectedPath)]) {
119108
return nil, fmt.Errorf("extension path mismatch")
120109
}
121110
nextNodeBytes, ok := node[1].([]byte)
@@ -124,14 +113,15 @@ func fetchReceiptFromBlock(
124113
}
125114
// We navigate to the next node in the trie.
126115
currentNodeHash = common.BytesToHash(nextNodeBytes)
127-
currentPath = newPath
116+
currentPath = expectedPath
128117
default:
129118
return nil, fmt.Errorf("invalid node structure: unexpected length %d", len(node))
130119
}
131120
}
132121
}
133122

134123
// Converts a byte slice key into a slice of nibbles (4-bit values).
124+
// Keys are encoded in big endian format, which is required by Ethereum MPTs.
135125
func keyToNibbles(key []byte) []byte {
136126
nibbles := make([]byte, len(key)*2)
137127
for i, b := range key {
@@ -146,30 +136,30 @@ func extractKeyNibbles(keyPath []byte) []byte {
146136
if len(keyPath) == 0 {
147137
return nil
148138
}
149-
150-
firstByte := keyPath[0]
151-
isOdd := (firstByte & 0x10) != 0
152-
153-
var nibbles []byte
154-
if isOdd {
155-
// Odd length: first nibble is in the first byte.
156-
nibbles = append(nibbles, firstByte&0x0f)
157-
keyPath = keyPath[1:]
158-
} else {
159-
keyPath = keyPath[1:]
160-
}
161-
// Convert remaining bytes to nibbles.
162-
for _, b := range keyPath {
163-
nibbles = append(nibbles, b>>4)
164-
nibbles = append(nibbles, b&0x0f)
139+
nibbles := keyToNibbles(keyPath)
140+
if nibbles[0]&1 != 0 {
141+
return nibbles[1:]
165142
}
166-
167-
return nibbles
143+
return nibbles[2:]
168144
}
169145

170-
func isLeaf(keyPath []byte) bool {
146+
func isLeaf(keyPath []byte) (bool, error) {
171147
firstByte := keyPath[0]
172148
firstNibble := firstByte >> 4
173149
// 2 or 3 indicates leaf, while 0 or 1 indicates extension nodes in the Ethereum MPT specification.
174-
return firstNibble >= 2
150+
if firstNibble > 3 {
151+
return false, errors.New("first nibble cannot be greater than 3")
152+
}
153+
return firstNibble >= 2, nil
154+
}
155+
156+
func decodeReceipt(data []byte) (*types.Receipt, error) {
157+
if len(data) == 0 {
158+
return nil, errors.New("empty data cannot be decoded into receipt")
159+
}
160+
rpt := new(types.Receipt)
161+
if err := rpt.UnmarshalBinary(data); err != nil {
162+
return nil, err
163+
}
164+
return rpt, nil
175165
}

cmd/mel-replay/receipt_fetcher_test.go

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package main
55

66
import (
77
"context"
8-
"crypto/rand"
98
"fmt"
109
"math/big"
1110
"testing"
@@ -14,6 +13,7 @@ import (
1413
"github.com/ethereum/go-ethereum/core/types"
1514
"github.com/ethereum/go-ethereum/crypto"
1615
"github.com/ethereum/go-ethereum/trie"
16+
"github.com/ethereum/go-ethereum/trie/testutil"
1717
"github.com/offchainlabs/nitro/arbutil"
1818
"github.com/stretchr/testify/require"
1919
)
@@ -108,7 +108,7 @@ func createTestReceipts(count int) types.Receipts {
108108
receipt := &types.Receipt{
109109
Status: 1,
110110
CumulativeGasUsed: 50_000 + uint64(i), // #nosec G115
111-
TxHash: randomHash(),
111+
TxHash: testutil.RandomHash(),
112112
ContractAddress: common.Address{},
113113
Logs: []*types.Log{},
114114
BlockHash: common.BytesToHash([]byte("foobar")),
@@ -120,9 +120,3 @@ func createTestReceipts(count int) types.Receipts {
120120
}
121121
return receipts
122122
}
123-
124-
func randomHash() common.Hash {
125-
var hash common.Hash
126-
rand.Read(hash[:])
127-
return hash
128-
}

0 commit comments

Comments
 (0)