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