github.com/dim4egster/coreth@v0.10.2/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/dim4egster/coreth/consensus/dummy" 35 "github.com/dim4egster/coreth/core/rawdb" 36 "github.com/dim4egster/coreth/core/types" 37 "github.com/dim4egster/coreth/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 four elems, got zero") 108 } 109 txdata := it.Value() 110 // Check that uncles exist 111 if !it.Next() { 112 t.Fatal("expected four elems, got one") 113 } 114 // Check that version exist 115 if !it.Next() { 116 t.Fatal("expected four elems, got two") 117 } 118 // Check that extdata exist 119 if !it.Next() { 120 t.Fatal("expected four elems, got three") 121 } 122 // No more after that 123 if it.Next() { 124 t.Fatal("expected only four elems, got more") 125 } 126 txIt, err := rlp.NewListIterator(txdata) 127 if err != nil { 128 t.Fatal(err) 129 } 130 var gotHashes []common.Hash 131 var expHashes []common.Hash 132 for txIt.Next() { 133 gotHashes = append(gotHashes, crypto.Keccak256Hash(txIt.Value())) 134 } 135 136 var expBody types.Body 137 err = rlp.DecodeBytes(bodyRlp, &expBody) 138 if err != nil { 139 t.Fatal(err) 140 } 141 for _, tx := range expBody.Transactions { 142 expHashes = append(expHashes, tx.Hash()) 143 } 144 if gotLen, expLen := len(gotHashes), len(expHashes); gotLen != expLen { 145 t.Fatalf("testcase %v: length wrong, got %d exp %d", desc, gotLen, expLen) 146 } 147 // also sanity check against input 148 if gotLen := len(gotHashes); gotLen != txs { 149 t.Fatalf("testcase %v: length wrong, got %d exp %d", desc, gotLen, txs) 150 } 151 for i, got := range gotHashes { 152 if exp := expHashes[i]; got != exp { 153 t.Errorf("testcase %v: hash wrong, got %x, exp %x", desc, got, exp) 154 } 155 } 156 } 157 158 // BenchmarkHashing compares the speeds of hashing a rlp raw data directly 159 // without the unmarshalling/marshalling step 160 func BenchmarkHashing(b *testing.B) { 161 // Make a pretty fat block 162 var ( 163 bodyRlp []byte 164 blockRlp []byte 165 ) 166 { 167 block := getBlock(200, 2, 50) 168 bodyRlp, _ = rlp.EncodeToBytes(block.Body()) 169 blockRlp, _ = rlp.EncodeToBytes(block) 170 } 171 var got common.Hash 172 var hasher = sha3.NewLegacyKeccak256() 173 b.Run("iteratorhashing", func(b *testing.B) { 174 b.ResetTimer() 175 for i := 0; i < b.N; i++ { 176 var hash common.Hash 177 it, err := rlp.NewListIterator(bodyRlp) 178 if err != nil { 179 b.Fatal(err) 180 } 181 it.Next() 182 txs := it.Value() 183 txIt, err := rlp.NewListIterator(txs) 184 if err != nil { 185 b.Fatal(err) 186 } 187 for txIt.Next() { 188 hasher.Reset() 189 hasher.Write(txIt.Value()) 190 hasher.Sum(hash[:0]) 191 got = hash 192 } 193 } 194 }) 195 var exp common.Hash 196 b.Run("fullbodyhashing", func(b *testing.B) { 197 b.ResetTimer() 198 for i := 0; i < b.N; i++ { 199 var body types.Body 200 rlp.DecodeBytes(bodyRlp, &body) 201 for _, tx := range body.Transactions { 202 exp = tx.Hash() 203 } 204 } 205 }) 206 b.Run("fullblockhashing", func(b *testing.B) { 207 b.ResetTimer() 208 for i := 0; i < b.N; i++ { 209 var block types.Block 210 rlp.DecodeBytes(blockRlp, &block) 211 for _, tx := range block.Transactions() { 212 tx.Hash() 213 } 214 } 215 }) 216 if got != exp { 217 b.Fatalf("hash wrong, got %x exp %x", got, exp) 218 } 219 }