github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/core/rlp_test.go (about) 1 // Copyright 2019 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "fmt" 21 "math/big" 22 "testing" 23 24 "golang.org/x/crypto/sha3" 25 26 "github.com/scroll-tech/go-ethereum/common" 27 "github.com/scroll-tech/go-ethereum/consensus/ethash" 28 "github.com/scroll-tech/go-ethereum/core/rawdb" 29 "github.com/scroll-tech/go-ethereum/core/types" 30 "github.com/scroll-tech/go-ethereum/crypto" 31 "github.com/scroll-tech/go-ethereum/params" 32 "github.com/scroll-tech/go-ethereum/rlp" 33 ) 34 35 func getBlock(transactions int, uncles int, dataSize int) *types.Block { 36 var ( 37 aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") 38 // Generate a canonical chain to act as the main dataset 39 engine = ethash.NewFaker() 40 db = rawdb.NewMemoryDatabase() 41 // A sender who makes transactions, has some funds 42 key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 43 address = crypto.PubkeyToAddress(key.PublicKey) 44 funds = big.NewInt(1_000_000_000_000_000_000) 45 gspec = &Genesis{ 46 Config: params.TestChainConfig, 47 Alloc: GenesisAlloc{address: {Balance: funds}}, 48 } 49 genesis = gspec.MustCommit(db) 50 ) 51 52 // We need to generate as many blocks +1 as uncles 53 blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, uncles+1, 54 func(n int, b *BlockGen) { 55 if n == uncles { 56 // Add transactions and stuff on the last block 57 for i := 0; i < transactions; i++ { 58 tx, _ := types.SignTx(types.NewTransaction(uint64(i), aa, 59 big.NewInt(0), 50000, b.header.BaseFee, make([]byte, dataSize)), types.HomesteadSigner{}, key) 60 b.AddTx(tx) 61 } 62 for i := 0; i < uncles; i++ { 63 b.AddUncle(&types.Header{ParentHash: b.PrevBlock(n - 1 - i).Hash(), Number: big.NewInt(int64(n - i))}) 64 } 65 } 66 }) 67 block := blocks[len(blocks)-1] 68 return block 69 } 70 71 // TestRlpIterator tests that individual transactions can be picked out 72 // from blocks without full unmarshalling/marshalling 73 func TestRlpIterator(t *testing.T) { 74 for _, tt := range []struct { 75 txs int 76 uncles int 77 datasize int 78 }{ 79 {0, 0, 0}, 80 {0, 2, 0}, 81 {10, 0, 0}, 82 {10, 2, 0}, 83 {10, 2, 50}, 84 } { 85 testRlpIterator(t, tt.txs, tt.uncles, tt.datasize) 86 } 87 } 88 89 func testRlpIterator(t *testing.T, txs, uncles, datasize int) { 90 desc := fmt.Sprintf("%d txs [%d datasize] and %d uncles", txs, datasize, uncles) 91 bodyRlp, _ := rlp.EncodeToBytes(getBlock(txs, uncles, datasize).Body()) 92 it, err := rlp.NewListIterator(bodyRlp) 93 if err != nil { 94 t.Fatal(err) 95 } 96 // Check that txs exist 97 if !it.Next() { 98 t.Fatal("expected two elems, got zero") 99 } 100 txdata := it.Value() 101 // Check that uncles exist 102 if !it.Next() { 103 t.Fatal("expected two elems, got one") 104 } 105 // No more after that 106 if it.Next() { 107 t.Fatal("expected only two elems, got more") 108 } 109 txIt, err := rlp.NewListIterator(txdata) 110 if err != nil { 111 t.Fatal(err) 112 } 113 var gotHashes []common.Hash 114 var expHashes []common.Hash 115 for txIt.Next() { 116 gotHashes = append(gotHashes, crypto.Keccak256Hash(txIt.Value())) 117 } 118 119 var expBody types.Body 120 err = rlp.DecodeBytes(bodyRlp, &expBody) 121 if err != nil { 122 t.Fatal(err) 123 } 124 for _, tx := range expBody.Transactions { 125 expHashes = append(expHashes, tx.Hash()) 126 } 127 if gotLen, expLen := len(gotHashes), len(expHashes); gotLen != expLen { 128 t.Fatalf("testcase %v: length wrong, got %d exp %d", desc, gotLen, expLen) 129 } 130 // also sanity check against input 131 if gotLen := len(gotHashes); gotLen != txs { 132 t.Fatalf("testcase %v: length wrong, got %d exp %d", desc, gotLen, txs) 133 } 134 for i, got := range gotHashes { 135 if exp := expHashes[i]; got != exp { 136 t.Errorf("testcase %v: hash wrong, got %x, exp %x", desc, got, exp) 137 } 138 } 139 } 140 141 // BenchmarkHashing compares the speeds of hashing a rlp raw data directly 142 // without the unmarshalling/marshalling step 143 func BenchmarkHashing(b *testing.B) { 144 // Make a pretty fat block 145 var ( 146 bodyRlp []byte 147 blockRlp []byte 148 ) 149 { 150 block := getBlock(200, 2, 50) 151 bodyRlp, _ = rlp.EncodeToBytes(block.Body()) 152 blockRlp, _ = rlp.EncodeToBytes(block) 153 } 154 var got common.Hash 155 var hasher = sha3.NewLegacyKeccak256() 156 b.Run("iteratorhashing", func(b *testing.B) { 157 b.ResetTimer() 158 for i := 0; i < b.N; i++ { 159 var hash common.Hash 160 it, err := rlp.NewListIterator(bodyRlp) 161 if err != nil { 162 b.Fatal(err) 163 } 164 it.Next() 165 txs := it.Value() 166 txIt, err := rlp.NewListIterator(txs) 167 if err != nil { 168 b.Fatal(err) 169 } 170 for txIt.Next() { 171 hasher.Reset() 172 hasher.Write(txIt.Value()) 173 hasher.Sum(hash[:0]) 174 got = hash 175 } 176 } 177 }) 178 var exp common.Hash 179 b.Run("fullbodyhashing", func(b *testing.B) { 180 b.ResetTimer() 181 for i := 0; i < b.N; i++ { 182 var body types.Body 183 rlp.DecodeBytes(bodyRlp, &body) 184 for _, tx := range body.Transactions { 185 exp = tx.Hash() 186 } 187 } 188 }) 189 b.Run("fullblockhashing", func(b *testing.B) { 190 b.ResetTimer() 191 for i := 0; i < b.N; i++ { 192 var block types.Block 193 rlp.DecodeBytes(blockRlp, &block) 194 for _, tx := range block.Transactions() { 195 tx.Hash() 196 } 197 } 198 }) 199 if got != exp { 200 b.Fatalf("hash wrong, got %x exp %x", got, exp) 201 } 202 }