github.com/ethereum/go-ethereum@v1.16.1/miner/payload_building_test.go (about) 1 // Copyright 2022 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 miner 18 19 import ( 20 "math/big" 21 "reflect" 22 "testing" 23 "time" 24 25 "github.com/ethereum/go-ethereum/beacon/engine" 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/consensus" 28 "github.com/ethereum/go-ethereum/consensus/clique" 29 "github.com/ethereum/go-ethereum/consensus/ethash" 30 "github.com/ethereum/go-ethereum/core" 31 "github.com/ethereum/go-ethereum/core/rawdb" 32 "github.com/ethereum/go-ethereum/core/txpool" 33 "github.com/ethereum/go-ethereum/core/txpool/legacypool" 34 "github.com/ethereum/go-ethereum/core/types" 35 "github.com/ethereum/go-ethereum/crypto" 36 "github.com/ethereum/go-ethereum/ethdb" 37 "github.com/ethereum/go-ethereum/params" 38 ) 39 40 var ( 41 // Test chain configurations 42 testTxPoolConfig legacypool.Config 43 ethashChainConfig *params.ChainConfig 44 cliqueChainConfig *params.ChainConfig 45 46 // Test accounts 47 testBankKey, _ = crypto.GenerateKey() 48 testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) 49 testBankFunds = big.NewInt(1000000000000000000) 50 51 testUserKey, _ = crypto.GenerateKey() 52 testUserAddress = crypto.PubkeyToAddress(testUserKey.PublicKey) 53 54 // Test transactions 55 pendingTxs []*types.Transaction 56 newTxs []*types.Transaction 57 58 testConfig = Config{ 59 PendingFeeRecipient: testBankAddress, 60 Recommit: time.Second, 61 GasCeil: params.GenesisGasLimit, 62 } 63 ) 64 65 func init() { 66 testTxPoolConfig = legacypool.DefaultConfig 67 testTxPoolConfig.Journal = "" 68 ethashChainConfig = new(params.ChainConfig) 69 *ethashChainConfig = *params.TestChainConfig 70 cliqueChainConfig = new(params.ChainConfig) 71 *cliqueChainConfig = *params.TestChainConfig 72 cliqueChainConfig.Clique = ¶ms.CliqueConfig{ 73 Period: 10, 74 Epoch: 30000, 75 } 76 77 signer := types.LatestSigner(params.TestChainConfig) 78 tx1 := types.MustSignNewTx(testBankKey, signer, &types.AccessListTx{ 79 ChainID: params.TestChainConfig.ChainID, 80 Nonce: 0, 81 To: &testUserAddress, 82 Value: big.NewInt(1000), 83 Gas: params.TxGas, 84 GasPrice: big.NewInt(params.InitialBaseFee), 85 }) 86 pendingTxs = append(pendingTxs, tx1) 87 88 tx2 := types.MustSignNewTx(testBankKey, signer, &types.LegacyTx{ 89 Nonce: 1, 90 To: &testUserAddress, 91 Value: big.NewInt(1000), 92 Gas: params.TxGas, 93 GasPrice: big.NewInt(params.InitialBaseFee), 94 }) 95 newTxs = append(newTxs, tx2) 96 } 97 98 // testWorkerBackend implements worker.Backend interfaces and wraps all information needed during the testing. 99 type testWorkerBackend struct { 100 db ethdb.Database 101 txPool *txpool.TxPool 102 chain *core.BlockChain 103 genesis *core.Genesis 104 } 105 106 func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, n int) *testWorkerBackend { 107 var gspec = &core.Genesis{ 108 Config: chainConfig, 109 Alloc: types.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, 110 } 111 switch e := engine.(type) { 112 case *clique.Clique: 113 gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) 114 copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes()) 115 e.Authorize(testBankAddress) 116 case *ethash.Ethash: 117 default: 118 t.Fatalf("unexpected consensus engine type: %T", engine) 119 } 120 chain, err := core.NewBlockChain(db, gspec, engine, &core.BlockChainConfig{ArchiveMode: true}) 121 if err != nil { 122 t.Fatalf("core.NewBlockChain failed: %v", err) 123 } 124 pool := legacypool.New(testTxPoolConfig, chain) 125 txpool, _ := txpool.New(testTxPoolConfig.PriceLimit, chain, []txpool.SubPool{pool}) 126 127 return &testWorkerBackend{ 128 db: db, 129 chain: chain, 130 txPool: txpool, 131 genesis: gspec, 132 } 133 } 134 135 func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain } 136 func (b *testWorkerBackend) TxPool() *txpool.TxPool { return b.txPool } 137 138 func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int) (*Miner, *testWorkerBackend) { 139 backend := newTestWorkerBackend(t, chainConfig, engine, db, blocks) 140 backend.txPool.Add(pendingTxs, true) 141 w := New(backend, testConfig, engine) 142 return w, backend 143 } 144 145 func TestBuildPayload(t *testing.T) { 146 var ( 147 db = rawdb.NewMemoryDatabase() 148 recipient = common.HexToAddress("0xdeadbeef") 149 ) 150 w, b := newTestWorker(t, params.TestChainConfig, ethash.NewFaker(), db, 0) 151 152 timestamp := uint64(time.Now().Unix()) 153 args := &BuildPayloadArgs{ 154 Parent: b.chain.CurrentBlock().Hash(), 155 Timestamp: timestamp, 156 Random: common.Hash{}, 157 FeeRecipient: recipient, 158 } 159 payload, err := w.buildPayload(args, false) 160 if err != nil { 161 t.Fatalf("Failed to build payload %v", err) 162 } 163 verify := func(outer *engine.ExecutionPayloadEnvelope, txs int) { 164 payload := outer.ExecutionPayload 165 if payload.ParentHash != b.chain.CurrentBlock().Hash() { 166 t.Fatal("Unexpected parent hash") 167 } 168 if payload.Random != (common.Hash{}) { 169 t.Fatal("Unexpected random value") 170 } 171 if payload.Timestamp != timestamp { 172 t.Fatal("Unexpected timestamp") 173 } 174 if payload.FeeRecipient != recipient { 175 t.Fatal("Unexpected fee recipient") 176 } 177 if len(payload.Transactions) != txs { 178 t.Fatal("Unexpected transaction set") 179 } 180 } 181 empty := payload.ResolveEmpty() 182 verify(empty, 0) 183 184 full := payload.ResolveFull() 185 verify(full, len(pendingTxs)) 186 187 // Ensure resolve can be called multiple times and the 188 // result should be unchanged 189 dataOne := payload.Resolve() 190 dataTwo := payload.Resolve() 191 if !reflect.DeepEqual(dataOne, dataTwo) { 192 t.Fatal("Unexpected payload data") 193 } 194 } 195 196 func TestPayloadId(t *testing.T) { 197 t.Parallel() 198 ids := make(map[string]int) 199 for i, tt := range []*BuildPayloadArgs{ 200 { 201 Parent: common.Hash{1}, 202 Timestamp: 1, 203 Random: common.Hash{0x1}, 204 FeeRecipient: common.Address{0x1}, 205 }, 206 // Different parent 207 { 208 Parent: common.Hash{2}, 209 Timestamp: 1, 210 Random: common.Hash{0x1}, 211 FeeRecipient: common.Address{0x1}, 212 }, 213 // Different timestamp 214 { 215 Parent: common.Hash{2}, 216 Timestamp: 2, 217 Random: common.Hash{0x1}, 218 FeeRecipient: common.Address{0x1}, 219 }, 220 // Different Random 221 { 222 Parent: common.Hash{2}, 223 Timestamp: 2, 224 Random: common.Hash{0x2}, 225 FeeRecipient: common.Address{0x1}, 226 }, 227 // Different fee-recipient 228 { 229 Parent: common.Hash{2}, 230 Timestamp: 2, 231 Random: common.Hash{0x2}, 232 FeeRecipient: common.Address{0x2}, 233 }, 234 // Different withdrawals (non-empty) 235 { 236 Parent: common.Hash{2}, 237 Timestamp: 2, 238 Random: common.Hash{0x2}, 239 FeeRecipient: common.Address{0x2}, 240 Withdrawals: []*types.Withdrawal{ 241 { 242 Index: 0, 243 Validator: 0, 244 Address: common.Address{}, 245 Amount: 0, 246 }, 247 }, 248 }, 249 // Different withdrawals (non-empty) 250 { 251 Parent: common.Hash{2}, 252 Timestamp: 2, 253 Random: common.Hash{0x2}, 254 FeeRecipient: common.Address{0x2}, 255 Withdrawals: []*types.Withdrawal{ 256 { 257 Index: 2, 258 Validator: 0, 259 Address: common.Address{}, 260 Amount: 0, 261 }, 262 }, 263 }, 264 } { 265 id := tt.Id().String() 266 if prev, exists := ids[id]; exists { 267 t.Errorf("ID collision, case %d and case %d: id %v", prev, i, id) 268 } 269 ids[id] = i 270 } 271 }