Skip to content
This repository was archived by the owner on Jul 5, 2024. It is now read-only.

Commit 4c239d8

Browse files
committed
adding more testings and refactor getNodeFromBranchRLP
1 parent 3bbc757 commit 4c239d8

File tree

2 files changed

+145
-83
lines changed

2 files changed

+145
-83
lines changed

geth-utils/gethutil/mpt/trie/stacktrie.go

Lines changed: 38 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -551,50 +551,49 @@ func (st *StackTrie) Commit() (common.Hash, error) {
551551
return common.BytesToHash(st.val), nil
552552
}
553553

554-
func (st *StackTrie) getNodeFromBranchRLP(branch []byte, ind byte) []byte {
555-
start := 2 // when branch[0] == 248
556-
if branch[0] == 249 {
557-
start = 3
558-
}
559-
560-
i := 0
561-
insideInd := -1
562-
cInd := byte(0)
563-
for {
564-
if start+i == len(branch)-1 { // -1 because of the last 128 (branch value)
565-
return []byte{0}
566-
}
567-
b := branch[start+i]
568-
if insideInd == -1 && b == 128 {
569-
if cInd == ind {
554+
const RLP_SHORT_STR_FLAG = 128
555+
const RLP_LONG_LIST_FLAG = 248
556+
const LEN_OF_HASH = 32
557+
558+
// Note:
559+
// In RLP encoding, if the value is between [0x80, 0xb7] ([128, 183]),
560+
// it means following data is a short string (0 - 55bytes).
561+
// Which implies if the value is 128, it's an empty string.
562+
func (st *StackTrie) getNodeFromBranchRLP(branch []byte, idx int) []byte {
563+
// (branch[0] - RLP_LONG_LIST_FLAG) means the length in bytes of the length of the payload
564+
// and the payload is right after the length.
565+
// That's why we add `2` here
566+
// e.g. [248 81 128 160 ...]
567+
// `81` is the length of the payload and payload starts from `128`
568+
start := int(branch[0]) - RLP_LONG_LIST_FLAG + 2
569+
570+
// If 1st node is not 128(empty node) or 160, it should be a leaf
571+
b := int(branch[start])
572+
if b != RLP_SHORT_STR_FLAG || b != (RLP_SHORT_STR_FLAG+LEN_OF_HASH) {
573+
return []byte{0}
574+
}
575+
576+
current_idx := 0
577+
for i := start; i < len(branch); i++ {
578+
b = int(branch[i])
579+
switch b {
580+
case RLP_SHORT_STR_FLAG: // 128
581+
// if the current index is we're looking for, return an empty node directly
582+
if current_idx == idx {
570583
return []byte{128}
571-
} else {
572-
cInd += 1
573584
}
574-
} else if insideInd == -1 && b != 128 {
575-
if b == 160 {
576-
if cInd == ind {
577-
return branch[start+i+1 : start+i+1+32]
578-
}
579-
insideInd = 32
580-
} else {
581-
// non-hashed node
582-
if cInd == ind {
583-
return branch[start+i+1 : start+i+1+int(b)-192]
584-
}
585-
insideInd = int(b) - 192
586-
}
587-
cInd += 1
588-
} else {
589-
if insideInd == 1 {
590-
insideInd = -1
591-
} else {
592-
insideInd--
585+
current_idx++
586+
case RLP_SHORT_STR_FLAG + LEN_OF_HASH: // 160
587+
if current_idx == idx {
588+
return branch[i+1 : i+1+LEN_OF_HASH]
593589
}
590+
// jump to next encoded element
591+
i += LEN_OF_HASH
592+
current_idx++
594593
}
595594

596-
i++
597595
}
596+
return []byte{0}
598597
}
599598

600599
type StackProof struct {
@@ -700,7 +699,7 @@ func (st *StackTrie) GetProof(db ethdb.KeyValueReader, key []byte) ([][]byte, er
700699
}
701700

702701
proof = append(proof, c_rlp)
703-
branchChild := st.getNodeFromBranchRLP(c_rlp, k[i])
702+
branchChild := st.getNodeFromBranchRLP(c_rlp, int(k[i]))
704703

705704
// branchChild is of length 1 when there is no child at this position in the branch
706705
// (`branchChild = [128]` in this case), but it is also of length 1 when `c_rlp` is a leaf.

geth-utils/gethutil/mpt/witness/gen_witness_transactions_test.go

Lines changed: 107 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,40 @@ import (
88
"testing"
99

1010
"github.com/ethereum/go-ethereum/common"
11-
"github.com/ethereum/go-ethereum/common/math"
1211
"github.com/ethereum/go-ethereum/core/rawdb"
1312
"github.com/ethereum/go-ethereum/crypto"
1413
"github.com/ethereum/go-ethereum/params"
1514
"github.com/ethereum/go-ethereum/rlp"
1615
)
1716

17+
func makeTransactions(n int) []*types.Transaction {
18+
txs := make([]*types.Transaction, n)
19+
key, _ := crypto.GenerateKey()
20+
signer := types.LatestSigner(params.TestChainConfig)
21+
22+
for i := range txs {
23+
amount := big.NewInt(int64(i)*10 ^ 9)
24+
gas_price := big.NewInt(300_000)
25+
data := make([]byte, 100)
26+
// randomly assigned for debugging
27+
data[3] = 3
28+
data[4] = 3
29+
data[5] = 3
30+
data[6] = 3
31+
data[7] = 3
32+
tx := types.NewTransaction(uint64(i), common.Address{}, amount, 10*10^6, gas_price, data)
33+
signedTx, err := types.SignTx(tx, signer, key)
34+
if err != nil {
35+
panic(err)
36+
}
37+
txs[i] = signedTx
38+
}
39+
return txs
40+
}
41+
1842
/*
19-
TestNonHashedTransactionsStackTrieGetProof inserts 70 transactions into a stacktrie.
20-
For each of the 70 modifications of the trie it asks for a proof - GetProof is called before
43+
transactionsStackTrieInsertionTemplate inserts n transactions into a stacktrie.
44+
For each of the n modifications of the trie it asks for a proof - GetProof is called before
2145
and after the modification. The transactions in the trie are not hashed and thus GetProof
2246
does not require to query a database to get the preimages.
2347
@@ -62,23 +86,9 @@ The first proof element is a branch with children at position 0 (branch B) and 1
6286
The second element is the 16-th transaction. For example, the third byte (16) represents
6387
the transaction index.
6488
*/
65-
func TestNonHashedTransactionsStackTrieGetProof(t *testing.T) {
66-
txs := make([]*types.Transaction, 70)
67-
key, _ := crypto.GenerateKey()
68-
signer := types.LatestSigner(params.TestChainConfig)
69-
70-
for i := range txs {
71-
amount := math.BigPow(2, int64(i))
72-
price := big.NewInt(300000)
73-
data := make([]byte, 100)
74-
tx := types.NewTransaction(uint64(i), common.Address{}, amount, 123457, price, data)
75-
signedTx, err := types.SignTx(tx, signer, key)
76-
if err != nil {
77-
panic(err)
78-
}
79-
txs[i] = signedTx
80-
}
8189

90+
func transactionsStackTrieInsertionTemplate(n int) {
91+
txs := makeTransactions(n)
8292
db := rawdb.NewMemoryDatabase()
8393
stackTrie := trie.NewStackTrie(db)
8494

@@ -87,34 +97,59 @@ func TestNonHashedTransactionsStackTrieGetProof(t *testing.T) {
8797
fmt.Println("===")
8898
}
8999

100+
func TestStackTrieInsertion_1Tx(t *testing.T) {
101+
// Only one leaf
102+
transactionsStackTrieInsertionTemplate(1)
103+
}
104+
105+
func TestStackTrieInsertion_2Txs(t *testing.T) {
106+
// One ext. node and one leaf
107+
transactionsStackTrieInsertionTemplate(2)
108+
}
109+
110+
func TestStackTrieInsertion_3Txs(t *testing.T) {
111+
// One ext. node, one branch and one leaf
112+
transactionsStackTrieInsertionTemplate(3)
113+
}
114+
115+
func TestStackTrieInsertion_4Txs(t *testing.T) {
116+
// One ext. node, one branch and two leaves
117+
transactionsStackTrieInsertionTemplate(4)
118+
}
119+
120+
func TestStackTrieInsertion_16Txs(t *testing.T) {
121+
// One ext. node and one branch with full leaves (16 leaves)
122+
transactionsStackTrieInsertionTemplate(16)
123+
}
124+
125+
func TestStackTrieInsertion_17Txs(t *testing.T) {
126+
// One ext. node, 3 branches and 17 leaves.
127+
// The original ext. node turns into a branch (B1) which has children at position 0 and 1.
128+
// At position 0 of B1, it has a branch with full leaves
129+
// At position 1 of B1, it has a newly leaf
130+
transactionsStackTrieInsertionTemplate(17)
131+
}
132+
133+
func TestStackTrieInsertion_33Txs(t *testing.T) {
134+
// Follow above test and have one more branch generated
135+
transactionsStackTrieInsertionTemplate(33)
136+
}
137+
138+
func TestStackTrieInsertion_ManyTxs(t *testing.T) {
139+
// Just randomly picking a large number.
140+
// The cap of block gas limit is 30M, the minimum gas cost of a tx is 21k
141+
// 30M / 21k ~= 1429
142+
transactionsStackTrieInsertionTemplate(2000)
143+
}
144+
90145
/*
91-
TestHashedTransactionsStackTrieGetProof inserts 2 transactions into a stacktrie,
146+
batchedTransactionsStackTrieProofTemplate inserts n transactions into a stacktrie,
92147
the trie is then hashed (DeriveSha call).
93-
The proof is asked for one of the two transactions. The transactions in the trie are hashed and thus
148+
The proof is asked for one of the n transactions. The transactions in the trie are hashed and thus
94149
GetProof requires to query a database to get the preimages.
95150
*/
96-
func TestHashedTransactionsStackTrieGetProof(t *testing.T) {
97-
txs := make([]*types.Transaction, 2)
98-
key, _ := crypto.GenerateKey()
99-
signer := types.LatestSigner(params.TestChainConfig)
100-
101-
for i := range txs {
102-
amount := math.BigPow(2, int64(i))
103-
price := big.NewInt(300000)
104-
data := make([]byte, 100)
105-
data[3] = 3
106-
data[4] = 3
107-
data[5] = 3
108-
data[6] = 3
109-
data[7] = 3
110-
tx := types.NewTransaction(uint64(i), common.Address{}, amount, 123457, price, data)
111-
signedTx, err := types.SignTx(tx, signer, key)
112-
if err != nil {
113-
panic(err)
114-
}
115-
txs[i] = signedTx
116-
}
117-
151+
func batchedTransactionsStackTrieProofTemplate(n int) {
152+
txs := makeTransactions(n)
118153
db := rawdb.NewMemoryDatabase()
119154
stackTrie := trie.NewStackTrie(db)
120155

@@ -131,6 +166,34 @@ func TestHashedTransactionsStackTrieGetProof(t *testing.T) {
131166
}
132167

133168
fmt.Println(proofS)
134-
135169
fmt.Println("===")
136170
}
171+
172+
func TestBatchedTxsProof_1Tx(t *testing.T) {
173+
batchedTransactionsStackTrieProofTemplate(1)
174+
}
175+
176+
func TestBatchedTxsProof_2Txs(t *testing.T) {
177+
batchedTransactionsStackTrieProofTemplate(2)
178+
}
179+
180+
func TestBatchedTxsProof_3Txs(t *testing.T) {
181+
batchedTransactionsStackTrieProofTemplate(3)
182+
}
183+
func TestBatchedTxsProof_4Txs(t *testing.T) {
184+
batchedTransactionsStackTrieProofTemplate(4)
185+
}
186+
187+
func TestBatchedTxsProof_16Txs(t *testing.T) {
188+
batchedTransactionsStackTrieProofTemplate(16)
189+
}
190+
191+
func TestBatchedTxsProof_17Txs(t *testing.T) {
192+
batchedTransactionsStackTrieProofTemplate(17)
193+
}
194+
func TestBatchedTxsProof_33Txs(t *testing.T) {
195+
batchedTransactionsStackTrieProofTemplate(33)
196+
}
197+
func TestBatchedTxsProof_ManyTxs(t *testing.T) {
198+
batchedTransactionsStackTrieProofTemplate(2000)
199+
}

0 commit comments

Comments
 (0)