github.com/core-coin/go-core/v2@v2.1.9/core/rlp_test.go (about) 1 // Copyright 2020 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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-core 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-core 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/core-coin/go-core/v2/consensus/cryptore" 27 28 "github.com/core-coin/go-core/v2/common" 29 "github.com/core-coin/go-core/v2/core/rawdb" 30 "github.com/core-coin/go-core/v2/core/types" 31 "github.com/core-coin/go-core/v2/crypto" 32 "github.com/core-coin/go-core/v2/params" 33 "github.com/core-coin/go-core/v2/rlp" 34 ) 35 36 func getBlock(transactions int, uncles int, dataSize int) *types.Block { 37 aa, err := common.HexToAddress("cb21000000000000000000000000000000000000aaaa") 38 if err != nil { 39 panic(err) 40 } 41 var ( 42 // Generate a canonical chain to act as the main dataset 43 engine = cryptore.NewFaker() 44 db = rawdb.NewMemoryDatabase() 45 // A sender who makes transactions, has some funds 46 key, _ = crypto.UnmarshalPrivateKeyHex("89bdfaa2b6f9c30b94ee98fec96c58ff8507fabf49d36a6267e6cb5516eaa2a9e854eccc041f9f67e109d0eb4f653586855355c5b2b87bb313") 47 funds = big.NewInt(1000000000) 48 gspec = &Genesis{ 49 Config: params.MainnetChainConfig, 50 Alloc: GenesisAlloc{key.Address(): {Balance: funds}}, 51 } 52 genesis = gspec.MustCommit(db) 53 ) 54 55 // We need to generate as many blocks +1 as uncles 56 blocks, _ := GenerateChain(params.MainnetChainConfig, genesis, engine, db, uncles+1, 57 func(n int, b *BlockGen) { 58 if n == uncles { 59 // Add transactions and stuff on the last block 60 for i := 0; i < transactions; i++ { 61 tx, _ := types.SignTx(types.NewTransaction(uint64(i), aa, 62 big.NewInt(0), 50000, big.NewInt(1), make([]byte, dataSize)), types.NewNucleusSigner(big.NewInt(1)), key) 63 b.AddTx(tx) 64 } 65 for i := 0; i < uncles; i++ { 66 b.AddUncle(&types.Header{ParentHash: b.PrevBlock(n - 1 - i).Hash(), Number: big.NewInt(int64(n - i))}) 67 } 68 } 69 }) 70 block := blocks[len(blocks)-1] 71 return block 72 } 73 74 // TestRlpIterator tests that individual transactions can be picked out 75 // from blocks without full unmarshalling/marshalling 76 func TestRlpIterator(t *testing.T) { 77 for _, tt := range []struct { 78 txs int 79 uncles int 80 datasize int 81 }{ 82 {0, 0, 0}, 83 {0, 2, 0}, 84 {10, 0, 0}, 85 {10, 2, 0}, 86 {10, 2, 50}, 87 } { 88 testRlpIterator(t, tt.txs, tt.uncles, tt.datasize) 89 } 90 } 91 92 func testRlpIterator(t *testing.T, txs, uncles, datasize int) { 93 desc := fmt.Sprintf("%d txs [%d datasize] and %d uncles", txs, datasize, uncles) 94 bodyRlp, _ := rlp.EncodeToBytes(getBlock(txs, uncles, datasize).Body()) 95 it, err := rlp.NewListIterator(bodyRlp) 96 if err != nil { 97 t.Fatal(err) 98 } 99 // Check that txs exist 100 if !it.Next() { 101 t.Fatal("expected two elems, got zero") 102 } 103 txdata := it.Value() 104 // Check that uncles exist 105 if !it.Next() { 106 t.Fatal("expected two elems, got one") 107 } 108 // No more after that 109 if it.Next() { 110 t.Fatal("expected only two elems, got more") 111 } 112 txIt, err := rlp.NewListIterator(txdata) 113 if err != nil { 114 t.Fatal(err) 115 } 116 var gotHashes []common.Hash 117 var expHashes []common.Hash 118 for txIt.Next() { 119 gotHashes = append(gotHashes, crypto.SHA3Hash(txIt.Value())) 120 } 121 122 var expBody types.Body 123 err = rlp.DecodeBytes(bodyRlp, &expBody) 124 if err != nil { 125 t.Fatal(err) 126 } 127 for _, tx := range expBody.Transactions { 128 expHashes = append(expHashes, tx.Hash()) 129 } 130 if gotLen, expLen := len(gotHashes), len(expHashes); gotLen != expLen { 131 t.Fatalf("testcase %v: length wrong, got %d exp %d", desc, gotLen, expLen) 132 } 133 // also sanity check against input 134 if gotLen := len(gotHashes); gotLen != txs { 135 t.Fatalf("testcase %v: length wrong, got %d exp %d", desc, gotLen, txs) 136 } 137 for i, got := range gotHashes { 138 if exp := expHashes[i]; got != exp { 139 t.Errorf("testcase %v: hash wrong, got %x, exp %x", desc, got, exp) 140 } 141 } 142 } 143 144 // BenchmarkHashing compares the speeds of hashing a rlp raw data directly 145 // without the unmarshalling/marshalling step 146 func BenchmarkHashing(b *testing.B) { 147 // Make a pretty fat block 148 var ( 149 bodyRlp []byte 150 blockRlp []byte 151 ) 152 { 153 block := getBlock(200, 2, 50) 154 bodyRlp, _ = rlp.EncodeToBytes(block.Body()) 155 blockRlp, _ = rlp.EncodeToBytes(block) 156 } 157 var got common.Hash 158 var hasher = sha3.New256() 159 b.Run("iteratorhashing", func(b *testing.B) { 160 b.ResetTimer() 161 for i := 0; i < b.N; i++ { 162 var hash common.Hash 163 it, err := rlp.NewListIterator(bodyRlp) 164 if err != nil { 165 b.Fatal(err) 166 } 167 it.Next() 168 txs := it.Value() 169 txIt, err := rlp.NewListIterator(txs) 170 if err != nil { 171 b.Fatal(err) 172 } 173 for txIt.Next() { 174 hasher.Reset() 175 hasher.Write(txIt.Value()) 176 hasher.Sum(hash[:0]) 177 got = hash 178 } 179 } 180 }) 181 var exp common.Hash 182 b.Run("fullbodyhashing", func(b *testing.B) { 183 b.ResetTimer() 184 for i := 0; i < b.N; i++ { 185 var body types.Body 186 rlp.DecodeBytes(bodyRlp, &body) 187 for _, tx := range body.Transactions { 188 exp = tx.Hash() 189 } 190 } 191 }) 192 b.Run("fullblockhashing", func(b *testing.B) { 193 b.ResetTimer() 194 for i := 0; i < b.N; i++ { 195 var block types.Block 196 rlp.DecodeBytes(blockRlp, &block) 197 for _, tx := range block.Transactions() { 198 tx.Hash() 199 } 200 } 201 }) 202 if got != exp { 203 b.Fatalf("hash wrong, got %x exp %x", got, exp) 204 } 205 }