github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/miner/worker_test.go (about) 1 // Copyright 2018 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 "math/rand" 22 "sync/atomic" 23 "testing" 24 "time" 25 26 "github.com/stretchr/testify/assert" 27 28 "github.com/scroll-tech/go-ethereum/accounts" 29 "github.com/scroll-tech/go-ethereum/common" 30 "github.com/scroll-tech/go-ethereum/consensus" 31 "github.com/scroll-tech/go-ethereum/consensus/clique" 32 "github.com/scroll-tech/go-ethereum/consensus/ethash" 33 "github.com/scroll-tech/go-ethereum/core" 34 "github.com/scroll-tech/go-ethereum/core/rawdb" 35 "github.com/scroll-tech/go-ethereum/core/types" 36 "github.com/scroll-tech/go-ethereum/core/vm" 37 "github.com/scroll-tech/go-ethereum/crypto" 38 "github.com/scroll-tech/go-ethereum/ethdb" 39 "github.com/scroll-tech/go-ethereum/event" 40 "github.com/scroll-tech/go-ethereum/params" 41 "github.com/scroll-tech/go-ethereum/rollup/circuitcapacitychecker" 42 "github.com/scroll-tech/go-ethereum/rollup/sync_service" 43 ) 44 45 const ( 46 // testCode is the testing contract binary code which will initialises some 47 // variables in constructor 48 testCode = "0x60806040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0060005534801561003457600080fd5b5060fc806100436000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80630c4dae8814603757806398a213cf146053575b600080fd5b603d607e565b6040518082815260200191505060405180910390f35b607c60048036036020811015606757600080fd5b81019080803590602001909291905050506084565b005b60005481565b806000819055507fe9e44f9f7da8c559de847a3232b57364adc0354f15a2cd8dc636d54396f9587a6000546040518082815260200191505060405180910390a15056fea265627a7a723058208ae31d9424f2d0bc2a3da1a5dd659db2d71ec322a17db8f87e19e209e3a1ff4a64736f6c634300050a0032" 49 50 // testGas is the gas required for contract deployment. 51 testGas = 144109 52 ) 53 54 var ( 55 // Test chain configurations 56 testTxPoolConfig core.TxPoolConfig 57 ethashChainConfig *params.ChainConfig 58 cliqueChainConfig *params.ChainConfig 59 60 // Test accounts 61 testBankKey, _ = crypto.GenerateKey() 62 testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) 63 testBankFunds = big.NewInt(1000000000000000000) 64 65 testUserKey, _ = crypto.GenerateKey() 66 testUserAddress = crypto.PubkeyToAddress(testUserKey.PublicKey) 67 68 // Test transactions 69 pendingTxs []*types.Transaction 70 newTxs []*types.Transaction 71 72 testConfig = &Config{ 73 Recommit: time.Second, 74 GasCeil: params.GenesisGasLimit, 75 } 76 ) 77 78 func init() { 79 testTxPoolConfig = core.DefaultTxPoolConfig 80 testTxPoolConfig.Journal = "" 81 ethashChainConfig = new(params.ChainConfig) 82 *ethashChainConfig = *params.TestChainConfig 83 cliqueChainConfig = new(params.ChainConfig) 84 *cliqueChainConfig = *params.TestChainConfig 85 cliqueChainConfig.Clique = ¶ms.CliqueConfig{ 86 Period: 10, 87 Epoch: 30000, 88 } 89 90 signer := types.LatestSigner(params.TestChainConfig) 91 tx1 := types.MustSignNewTx(testBankKey, signer, &types.AccessListTx{ 92 ChainID: params.TestChainConfig.ChainID, 93 Nonce: 0, 94 To: &testUserAddress, 95 Value: big.NewInt(1000), 96 Gas: params.TxGas, 97 GasPrice: big.NewInt(params.InitialBaseFee), 98 }) 99 pendingTxs = append(pendingTxs, tx1) 100 101 tx2 := types.MustSignNewTx(testBankKey, signer, &types.LegacyTx{ 102 Nonce: 1, 103 To: &testUserAddress, 104 Value: big.NewInt(1000), 105 Gas: params.TxGas, 106 GasPrice: big.NewInt(params.InitialBaseFee), 107 }) 108 newTxs = append(newTxs, tx2) 109 110 rand.Seed(time.Now().UnixNano()) 111 } 112 113 // testWorkerBackend implements worker.Backend interfaces and wraps all information needed during the testing. 114 type testWorkerBackend struct { 115 db ethdb.Database 116 txPool *core.TxPool 117 chain *core.BlockChain 118 testTxFeed event.Feed 119 genesis *core.Genesis 120 uncleBlock *types.Block 121 } 122 123 func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, n int) *testWorkerBackend { 124 var gspec = core.Genesis{ 125 Config: chainConfig, 126 Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, 127 } 128 129 switch e := engine.(type) { 130 case *clique.Clique: 131 gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) 132 copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes()) 133 e.Authorize(testBankAddress, func(account accounts.Account, s string, data []byte) ([]byte, error) { 134 return crypto.Sign(crypto.Keccak256(data), testBankKey) 135 }) 136 case *ethash.Ethash: 137 default: 138 t.Fatalf("unexpected consensus engine type: %T", engine) 139 } 140 genesis := gspec.MustCommit(db) 141 142 chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{ 143 Debug: true, 144 Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true})}, nil, nil, false) 145 txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain) 146 147 // Generate a small n-block chain and an uncle block for it 148 if n > 0 { 149 blocks, _ := core.GenerateChain(chainConfig, genesis, engine, db, n, func(i int, gen *core.BlockGen) { 150 gen.SetCoinbase(testBankAddress) 151 }) 152 if _, err := chain.InsertChain(blocks); err != nil { 153 t.Fatalf("failed to insert origin chain: %v", err) 154 } 155 } 156 parent := genesis 157 if n > 0 { 158 parent = chain.GetBlockByHash(chain.CurrentBlock().ParentHash()) 159 } 160 blocks, _ := core.GenerateChain(chainConfig, parent, engine, db, 1, func(i int, gen *core.BlockGen) { 161 gen.SetCoinbase(testUserAddress) 162 }) 163 164 return &testWorkerBackend{ 165 db: db, 166 chain: chain, 167 txPool: txpool, 168 genesis: &gspec, 169 uncleBlock: blocks[0], 170 } 171 } 172 173 func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain } 174 func (b *testWorkerBackend) TxPool() *core.TxPool { return b.txPool } 175 func (b *testWorkerBackend) ChainDb() ethdb.Database { return b.db } 176 func (b *testWorkerBackend) SyncService() *sync_service.SyncService { return nil } 177 178 func (b *testWorkerBackend) newRandomUncle() *types.Block { 179 var parent *types.Block 180 cur := b.chain.CurrentBlock() 181 if cur.NumberU64() == 0 { 182 parent = b.chain.Genesis() 183 } else { 184 parent = b.chain.GetBlockByHash(b.chain.CurrentBlock().ParentHash()) 185 } 186 blocks, _ := core.GenerateChain(b.chain.Config(), parent, b.chain.Engine(), b.db, 1, func(i int, gen *core.BlockGen) { 187 var addr = make([]byte, common.AddressLength) 188 rand.Read(addr) 189 gen.SetCoinbase(common.BytesToAddress(addr)) 190 }) 191 return blocks[0] 192 } 193 194 func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction { 195 var tx *types.Transaction 196 gasPrice := big.NewInt(10 * params.InitialBaseFee) 197 if creation { 198 tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(testBankAddress), big.NewInt(0), testGas, gasPrice, common.FromHex(testCode)), types.HomesteadSigner{}, testBankKey) 199 } else { 200 tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(testBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, gasPrice, nil), types.HomesteadSigner{}, testBankKey) 201 } 202 return tx 203 } 204 205 func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int) (*worker, *testWorkerBackend) { 206 backend := newTestWorkerBackend(t, chainConfig, engine, db, blocks) 207 backend.txPool.AddLocals(pendingTxs) 208 w := newWorker(testConfig, chainConfig, engine, backend, new(event.TypeMux), nil, false) 209 w.setEtherbase(testBankAddress) 210 return w, backend 211 } 212 213 func TestGenerateBlockAndImportEthash(t *testing.T) { 214 testGenerateBlockAndImport(t, false) 215 } 216 217 func TestGenerateBlockAndImportClique(t *testing.T) { 218 testGenerateBlockAndImport(t, true) 219 } 220 221 func testGenerateBlockAndImport(t *testing.T, isClique bool) { 222 var ( 223 engine consensus.Engine 224 chainConfig *params.ChainConfig 225 db = rawdb.NewMemoryDatabase() 226 ) 227 if isClique { 228 chainConfig = params.AllCliqueProtocolChanges 229 chainConfig.Clique = ¶ms.CliqueConfig{Period: 1, Epoch: 30000} 230 engine = clique.New(chainConfig.Clique, db) 231 } else { 232 chainConfig = params.AllEthashProtocolChanges 233 engine = ethash.NewFaker() 234 } 235 236 chainConfig.LondonBlock = big.NewInt(0) 237 w, b := newTestWorker(t, chainConfig, engine, db, 0) 238 defer w.close() 239 240 // This test chain imports the mined blocks. 241 db2 := rawdb.NewMemoryDatabase() 242 b.genesis.MustCommit(db2) 243 chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{ 244 Debug: true, 245 Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true, EnableReturnData: true})}, nil, nil, false) 246 defer chain.Stop() 247 248 // Ignore empty commit here for less noise. 249 w.skipSealHook = func(task *task) bool { 250 return len(task.receipts) == 0 251 } 252 253 // Wait for mined blocks. 254 sub := w.mux.Subscribe(core.NewMinedBlockEvent{}) 255 defer sub.Unsubscribe() 256 257 // Start mining! 258 w.start() 259 260 for i := 0; i < 5; i++ { 261 b.txPool.AddLocal(b.newRandomTx(true)) 262 b.txPool.AddLocal(b.newRandomTx(false)) 263 w.postSideBlock(core.ChainSideEvent{Block: b.newRandomUncle()}) 264 w.postSideBlock(core.ChainSideEvent{Block: b.newRandomUncle()}) 265 266 select { 267 case ev := <-sub.Chan(): 268 block := ev.Data.(core.NewMinedBlockEvent).Block 269 if _, err := chain.InsertChain([]*types.Block{block}); err != nil { 270 t.Fatalf("failed to insert new mined block %d: %v", block.NumberU64(), err) 271 } 272 case <-time.After(3 * time.Second): // Worker needs 1s to include new changes. 273 t.Fatalf("timeout") 274 } 275 } 276 } 277 278 func TestEmptyWorkEthash(t *testing.T) { 279 testEmptyWork(t, ethashChainConfig, ethash.NewFaker()) 280 } 281 func TestEmptyWorkClique(t *testing.T) { 282 testEmptyWork(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) 283 } 284 285 func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { 286 defer engine.Close() 287 288 w, _ := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) 289 defer w.close() 290 291 var ( 292 taskIndex int 293 taskCh = make(chan struct{}, 2) 294 ) 295 checkEqual := func(t *testing.T, task *task, index int) { 296 // The first empty work without any txs included 297 receiptLen, balance := 0, big.NewInt(0) 298 if index == 1 { 299 // The second full work with 1 tx included 300 receiptLen, balance = 1, big.NewInt(1000) 301 } 302 if len(task.receipts) != receiptLen { 303 t.Fatalf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen) 304 } 305 if task.state.GetBalance(testUserAddress).Cmp(balance) != 0 { 306 t.Fatalf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance) 307 } 308 } 309 w.newTaskHook = func(task *task) { 310 if task.block.NumberU64() == 1 { 311 checkEqual(t, task, taskIndex) 312 taskIndex += 1 313 taskCh <- struct{}{} 314 } 315 } 316 w.skipSealHook = func(task *task) bool { return true } 317 w.fullTaskHook = func() { 318 time.Sleep(100 * time.Millisecond) 319 } 320 w.start() // Start mining! 321 for i := 0; i < 2; i += 1 { 322 select { 323 case <-taskCh: 324 case <-time.NewTimer(3 * time.Second).C: 325 t.Error("new task timeout") 326 } 327 } 328 } 329 330 func TestStreamUncleBlock(t *testing.T) { 331 ethash := ethash.NewFaker() 332 defer ethash.Close() 333 334 w, b := newTestWorker(t, ethashChainConfig, ethash, rawdb.NewMemoryDatabase(), 1) 335 defer w.close() 336 337 var taskCh = make(chan struct{}) 338 339 taskIndex := 0 340 w.newTaskHook = func(task *task) { 341 if task.block.NumberU64() == 2 { 342 // The first task is an empty task, the second 343 // one has 1 pending tx, the third one has 1 tx 344 // and 1 uncle. 345 if taskIndex == 2 { 346 have := task.block.Header().UncleHash 347 want := types.CalcUncleHash([]*types.Header{b.uncleBlock.Header()}) 348 if have != want { 349 t.Errorf("uncle hash mismatch: have %s, want %s", have.Hex(), want.Hex()) 350 } 351 } 352 taskCh <- struct{}{} 353 taskIndex += 1 354 } 355 } 356 w.skipSealHook = func(task *task) bool { 357 return true 358 } 359 w.fullTaskHook = func() { 360 time.Sleep(100 * time.Millisecond) 361 } 362 w.start() 363 364 for i := 0; i < 2; i += 1 { 365 select { 366 case <-taskCh: 367 case <-time.NewTimer(time.Second).C: 368 t.Error("new task timeout") 369 } 370 } 371 372 w.postSideBlock(core.ChainSideEvent{Block: b.uncleBlock}) 373 374 select { 375 case <-taskCh: 376 case <-time.NewTimer(time.Second).C: 377 t.Error("new task timeout") 378 } 379 } 380 381 func TestRegenerateMiningBlockEthash(t *testing.T) { 382 testRegenerateMiningBlock(t, ethashChainConfig, ethash.NewFaker()) 383 } 384 385 func TestRegenerateMiningBlockClique(t *testing.T) { 386 testRegenerateMiningBlock(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) 387 } 388 389 func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { 390 defer engine.Close() 391 392 w, b := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) 393 defer w.close() 394 395 var taskCh = make(chan struct{}) 396 397 taskIndex := 0 398 w.newTaskHook = func(task *task) { 399 if task.block.NumberU64() == 1 { 400 // The first task is an empty task, the second 401 // one has 1 pending tx, the third one has 2 txs 402 if taskIndex == 2 { 403 receiptLen, balance := 2, big.NewInt(2000) 404 if len(task.receipts) != receiptLen { 405 t.Errorf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen) 406 } 407 if task.state.GetBalance(testUserAddress).Cmp(balance) != 0 { 408 t.Errorf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance) 409 } 410 } 411 taskCh <- struct{}{} 412 taskIndex += 1 413 } 414 } 415 w.skipSealHook = func(task *task) bool { 416 return true 417 } 418 w.fullTaskHook = func() { 419 time.Sleep(100 * time.Millisecond) 420 } 421 422 w.start() 423 // Ignore the first two works 424 for i := 0; i < 2; i += 1 { 425 select { 426 case <-taskCh: 427 case <-time.NewTimer(time.Second).C: 428 t.Error("new task timeout") 429 } 430 } 431 b.txPool.AddLocals(newTxs) 432 time.Sleep(time.Second) 433 434 select { 435 case <-taskCh: 436 case <-time.NewTimer(time.Second).C: 437 t.Error("new task timeout") 438 } 439 } 440 441 func TestAdjustIntervalEthash(t *testing.T) { 442 testAdjustInterval(t, ethashChainConfig, ethash.NewFaker()) 443 } 444 445 func TestAdjustIntervalClique(t *testing.T) { 446 testAdjustInterval(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) 447 } 448 449 func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { 450 defer engine.Close() 451 452 w, _ := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) 453 defer w.close() 454 455 w.skipSealHook = func(task *task) bool { 456 return true 457 } 458 w.fullTaskHook = func() { 459 time.Sleep(100 * time.Millisecond) 460 } 461 var ( 462 progress = make(chan struct{}, 10) 463 result = make([]float64, 0, 10) 464 index = 0 465 start uint32 466 ) 467 w.resubmitHook = func(minInterval time.Duration, recommitInterval time.Duration) { 468 // Short circuit if interval checking hasn't started. 469 if atomic.LoadUint32(&start) == 0 { 470 return 471 } 472 var wantMinInterval, wantRecommitInterval time.Duration 473 474 switch index { 475 case 0: 476 wantMinInterval, wantRecommitInterval = 3*time.Second, 3*time.Second 477 case 1: 478 origin := float64(3 * time.Second.Nanoseconds()) 479 estimate := origin*(1-intervalAdjustRatio) + intervalAdjustRatio*(origin/0.8+intervalAdjustBias) 480 wantMinInterval, wantRecommitInterval = 3*time.Second, time.Duration(estimate)*time.Nanosecond 481 case 2: 482 estimate := result[index-1] 483 min := float64(3 * time.Second.Nanoseconds()) 484 estimate = estimate*(1-intervalAdjustRatio) + intervalAdjustRatio*(min-intervalAdjustBias) 485 wantMinInterval, wantRecommitInterval = 3*time.Second, time.Duration(estimate)*time.Nanosecond 486 case 3: 487 wantMinInterval, wantRecommitInterval = time.Second, time.Second 488 } 489 490 // Check interval 491 if minInterval != wantMinInterval { 492 t.Errorf("resubmit min interval mismatch: have %v, want %v ", minInterval, wantMinInterval) 493 } 494 if recommitInterval != wantRecommitInterval { 495 t.Errorf("resubmit interval mismatch: have %v, want %v", recommitInterval, wantRecommitInterval) 496 } 497 result = append(result, float64(recommitInterval.Nanoseconds())) 498 index += 1 499 progress <- struct{}{} 500 } 501 w.start() 502 503 time.Sleep(time.Second) // Ensure two tasks have been summitted due to start opt 504 atomic.StoreUint32(&start, 1) 505 506 w.setRecommitInterval(3 * time.Second) 507 select { 508 case <-progress: 509 case <-time.NewTimer(time.Second).C: 510 t.Error("interval reset timeout") 511 } 512 513 w.resubmitAdjustCh <- &intervalAdjust{inc: true, ratio: 0.8} 514 select { 515 case <-progress: 516 case <-time.NewTimer(time.Second).C: 517 t.Error("interval reset timeout") 518 } 519 520 w.resubmitAdjustCh <- &intervalAdjust{inc: false} 521 select { 522 case <-progress: 523 case <-time.NewTimer(time.Second).C: 524 t.Error("interval reset timeout") 525 } 526 527 w.setRecommitInterval(500 * time.Millisecond) 528 select { 529 case <-progress: 530 case <-time.NewTimer(time.Second).C: 531 t.Error("interval reset timeout") 532 } 533 } 534 535 func TestGenerateBlockWithL1MsgEthash(t *testing.T) { 536 testGenerateBlockWithL1Msg(t, false) 537 } 538 539 func TestGenerateBlockWithL1MsgClique(t *testing.T) { 540 testGenerateBlockWithL1Msg(t, true) 541 } 542 543 func testGenerateBlockWithL1Msg(t *testing.T, isClique bool) { 544 assert := assert.New(t) 545 var ( 546 engine consensus.Engine 547 chainConfig *params.ChainConfig 548 db = rawdb.NewMemoryDatabase() 549 ) 550 msgs := []types.L1MessageTx{ 551 {QueueIndex: 0, Gas: 21016, To: &common.Address{3}, Data: []byte{0x01}, Sender: common.Address{4}}, 552 {QueueIndex: 1, Gas: 21016, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{2}}} 553 rawdb.WriteL1Messages(db, msgs) 554 555 if isClique { 556 chainConfig = params.AllCliqueProtocolChanges 557 chainConfig.Clique = ¶ms.CliqueConfig{Period: 1, Epoch: 30000} 558 engine = clique.New(chainConfig.Clique, db) 559 } else { 560 chainConfig = params.AllEthashProtocolChanges 561 engine = ethash.NewFaker() 562 } 563 chainConfig.Scroll.L1Config = ¶ms.L1Config{ 564 NumL1MessagesPerBlock: 1, 565 } 566 567 chainConfig.LondonBlock = big.NewInt(0) 568 w, b := newTestWorker(t, chainConfig, engine, db, 0) 569 defer w.close() 570 571 // This test chain imports the mined blocks. 572 b.genesis.MustCommit(db) 573 chain, _ := core.NewBlockChain(db, nil, b.chain.Config(), engine, vm.Config{ 574 Debug: true, 575 Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true, EnableReturnData: true})}, nil, nil, false) 576 defer chain.Stop() 577 578 // Ignore empty commit here for less noise. 579 w.skipSealHook = func(task *task) bool { 580 return len(task.receipts) == 0 581 } 582 583 // Wait for mined blocks. 584 sub := w.mux.Subscribe(core.NewMinedBlockEvent{}) 585 defer sub.Unsubscribe() 586 587 // Start mining! 588 w.start() 589 590 for i := 0; i < 2; i++ { 591 592 select { 593 case ev := <-sub.Chan(): 594 block := ev.Data.(core.NewMinedBlockEvent).Block 595 if _, err := chain.InsertChain([]*types.Block{block}); err != nil { 596 t.Fatalf("failed to insert new mined block %d: %v", block.NumberU64(), err) 597 } 598 assert.Equal(1, len(block.Transactions())) 599 600 queueIndex := rawdb.ReadFirstQueueIndexNotInL2Block(db, block.Hash()) 601 assert.NotNil(queueIndex) 602 assert.Equal(uint64(i+1), *queueIndex) 603 case <-time.After(3 * time.Second): 604 t.Fatalf("timeout") 605 } 606 } 607 } 608 609 func TestAcceptableTxlimit(t *testing.T) { 610 assert := assert.New(t) 611 var ( 612 engine consensus.Engine 613 chainConfig *params.ChainConfig 614 db = rawdb.NewMemoryDatabase() 615 ) 616 chainConfig = params.AllCliqueProtocolChanges 617 chainConfig.Clique = ¶ms.CliqueConfig{Period: 1, Epoch: 30000} 618 engine = clique.New(chainConfig.Clique, db) 619 620 // Set maxTxPerBlock = 4, which >= non-l1msg + non-skipped l1msg txs 621 maxTxPerBlock := 4 622 chainConfig.Scroll.MaxTxPerBlock = &maxTxPerBlock 623 chainConfig.Scroll.L1Config = ¶ms.L1Config{ 624 NumL1MessagesPerBlock: 3, 625 } 626 627 // Insert 3 l1msgs, with one be skipped. 628 l1msgs := []types.L1MessageTx{ 629 {QueueIndex: 0, Gas: 10000000, To: &common.Address{3}, Data: []byte{0x01}, Sender: common.Address{4}}, // over gas limit 630 {QueueIndex: 1, Gas: 21016, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{4}}, 631 {QueueIndex: 2, Gas: 21016, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{2}}} 632 rawdb.WriteL1Messages(db, l1msgs) 633 634 chainConfig.LondonBlock = big.NewInt(0) 635 w, b := newTestWorker(t, chainConfig, engine, db, 0) 636 defer w.close() 637 638 // This test chain imports the mined blocks. 639 b.genesis.MustCommit(db) 640 chain, _ := core.NewBlockChain(db, nil, b.chain.Config(), engine, vm.Config{ 641 Debug: true, 642 Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true, EnableReturnData: true})}, nil, nil, false) 643 defer chain.Stop() 644 645 // Ignore empty commit here for less noise. 646 w.skipSealHook = func(task *task) bool { 647 return len(task.receipts) == 0 648 } 649 650 // Wait for mined blocks. 651 sub := w.mux.Subscribe(core.NewMinedBlockEvent{}) 652 defer sub.Unsubscribe() 653 654 // Insert 2 non-l1msg txs 655 b.txPool.AddLocal(b.newRandomTx(true)) 656 b.txPool.AddLocal(b.newRandomTx(false)) 657 658 // Start mining! 659 w.start() 660 661 select { 662 case ev := <-sub.Chan(): 663 block := ev.Data.(core.NewMinedBlockEvent).Block 664 if _, err := chain.InsertChain([]*types.Block{block}); err != nil { 665 t.Fatalf("failed to insert new mined block %d: %v", block.NumberU64(), err) 666 } 667 assert.Equal(4, len(block.Transactions())) 668 case <-time.After(3 * time.Second): 669 t.Fatalf("timeout") 670 } 671 } 672 673 func TestUnacceptableTxlimit(t *testing.T) { 674 assert := assert.New(t) 675 var ( 676 engine consensus.Engine 677 chainConfig *params.ChainConfig 678 db = rawdb.NewMemoryDatabase() 679 ) 680 chainConfig = params.AllCliqueProtocolChanges 681 chainConfig.Clique = ¶ms.CliqueConfig{Period: 1, Epoch: 30000} 682 engine = clique.New(chainConfig.Clique, db) 683 684 // Set maxTxPerBlock = 3, which < non-l1msg + l1msg txs 685 maxTxPerBlock := 3 686 chainConfig.Scroll.MaxTxPerBlock = &maxTxPerBlock 687 chainConfig.Scroll.L1Config = ¶ms.L1Config{ 688 NumL1MessagesPerBlock: 2, 689 } 690 691 // Insert 2 l1msgs 692 l1msgs := []types.L1MessageTx{ 693 {QueueIndex: 0, Gas: 21016, To: &common.Address{3}, Data: []byte{0x01}, Sender: common.Address{4}}, 694 {QueueIndex: 1, Gas: 21016, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{2}}} 695 rawdb.WriteL1Messages(db, l1msgs) 696 697 chainConfig.LondonBlock = big.NewInt(0) 698 w, b := newTestWorker(t, chainConfig, engine, db, 0) 699 defer w.close() 700 701 // This test chain imports the mined blocks. 702 b.genesis.MustCommit(db) 703 chain, _ := core.NewBlockChain(db, nil, b.chain.Config(), engine, vm.Config{ 704 Debug: true, 705 Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true, EnableReturnData: true})}, nil, nil, false) 706 defer chain.Stop() 707 708 // Ignore empty commit here for less noise. 709 w.skipSealHook = func(task *task) bool { 710 return len(task.receipts) == 0 711 } 712 713 // Wait for mined blocks. 714 sub := w.mux.Subscribe(core.NewMinedBlockEvent{}) 715 defer sub.Unsubscribe() 716 717 // Insert 2 non-l1msg txs 718 b.txPool.AddLocal(b.newRandomTx(true)) 719 b.txPool.AddLocal(b.newRandomTx(false)) 720 721 // Start mining! 722 w.start() 723 724 select { 725 case ev := <-sub.Chan(): 726 block := ev.Data.(core.NewMinedBlockEvent).Block 727 if _, err := chain.InsertChain([]*types.Block{block}); err != nil { 728 t.Fatalf("failed to insert new mined block %d: %v", block.NumberU64(), err) 729 } 730 assert.Equal(3, len(block.Transactions())) 731 case <-time.After(3 * time.Second): 732 t.Fatalf("timeout") 733 } 734 } 735 736 func TestL1MsgCorrectOrder(t *testing.T) { 737 assert := assert.New(t) 738 var ( 739 engine consensus.Engine 740 chainConfig *params.ChainConfig 741 db = rawdb.NewMemoryDatabase() 742 ) 743 chainConfig = params.AllCliqueProtocolChanges 744 chainConfig.Clique = ¶ms.CliqueConfig{Period: 1, Epoch: 30000} 745 engine = clique.New(chainConfig.Clique, db) 746 747 maxTxPerBlock := 4 748 chainConfig.Scroll.MaxTxPerBlock = &maxTxPerBlock 749 chainConfig.Scroll.L1Config = ¶ms.L1Config{ 750 NumL1MessagesPerBlock: 10, 751 } 752 753 // Insert 3 l1msgs 754 l1msgs := []types.L1MessageTx{ 755 {QueueIndex: 0, Gas: 21016, To: &common.Address{3}, Data: []byte{0x01}, Sender: common.Address{4}}, 756 {QueueIndex: 1, Gas: 21016, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{2}}, 757 {QueueIndex: 2, Gas: 21016, To: &common.Address{3}, Data: []byte{0x01}, Sender: common.Address{4}}} 758 rawdb.WriteL1Messages(db, l1msgs) 759 760 chainConfig.LondonBlock = big.NewInt(0) 761 w, b := newTestWorker(t, chainConfig, engine, db, 0) 762 defer w.close() 763 764 // This test chain imports the mined blocks. 765 b.genesis.MustCommit(db) 766 chain, _ := core.NewBlockChain(db, nil, b.chain.Config(), engine, vm.Config{ 767 Debug: true, 768 Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true, EnableReturnData: true})}, nil, nil, false) 769 defer chain.Stop() 770 771 // Ignore empty commit here for less noise. 772 w.skipSealHook = func(task *task) bool { 773 return len(task.receipts) == 0 774 } 775 776 // Wait for mined blocks. 777 sub := w.mux.Subscribe(core.NewMinedBlockEvent{}) 778 defer sub.Unsubscribe() 779 780 // Insert local tx 781 b.txPool.AddLocal(b.newRandomTx(true)) 782 783 // Start mining! 784 w.start() 785 786 select { 787 case ev := <-sub.Chan(): 788 block := ev.Data.(core.NewMinedBlockEvent).Block 789 if _, err := chain.InsertChain([]*types.Block{block}); err != nil { 790 t.Fatalf("failed to insert new mined block %d: %v", block.NumberU64(), err) 791 } 792 assert.Equal(4, len(block.Transactions())) 793 assert.True(block.Transactions()[0].IsL1MessageTx() && block.Transactions()[1].IsL1MessageTx() && block.Transactions()[2].IsL1MessageTx()) 794 assert.Equal(uint64(0), block.Transactions()[0].AsL1MessageTx().QueueIndex) 795 assert.Equal(uint64(1), block.Transactions()[1].AsL1MessageTx().QueueIndex) 796 assert.Equal(uint64(2), block.Transactions()[2].AsL1MessageTx().QueueIndex) 797 case <-time.After(3 * time.Second): 798 t.Fatalf("timeout") 799 } 800 } 801 802 func l1MessageTest(t *testing.T, msgs []types.L1MessageTx, withL2Tx bool, callback func(i int, block *types.Block, db ethdb.Database, w *worker) bool) { 803 var ( 804 engine consensus.Engine 805 chainConfig *params.ChainConfig 806 db = rawdb.NewMemoryDatabase() 807 ) 808 rawdb.WriteL1Messages(db, msgs) 809 810 chainConfig = params.AllCliqueProtocolChanges 811 chainConfig.Clique = ¶ms.CliqueConfig{Period: 1, Epoch: 30000} 812 engine = clique.New(chainConfig.Clique, db) 813 maxTxPerBlock := 4 814 chainConfig.Scroll.MaxTxPerBlock = &maxTxPerBlock 815 816 maxPayload := 1024 817 chainConfig.Scroll.MaxTxPayloadBytesPerBlock = &maxPayload 818 chainConfig.Scroll.L1Config = ¶ms.L1Config{ 819 NumL1MessagesPerBlock: 3, 820 } 821 822 chainConfig.LondonBlock = big.NewInt(0) 823 w, b := newTestWorker(t, chainConfig, engine, db, 0) 824 defer w.close() 825 826 // This test chain imports the mined blocks. 827 b.genesis.MustCommit(db) 828 chain, _ := core.NewBlockChain(db, nil, b.chain.Config(), engine, vm.Config{ 829 Debug: true, 830 Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true, EnableReturnData: true})}, nil, nil, false) 831 defer chain.Stop() 832 833 // Ignore empty commit here for less noise. 834 w.skipSealHook = func(task *task) bool { 835 return len(task.receipts) == 0 836 } 837 838 // Wait for mined blocks. 839 sub := w.mux.Subscribe(core.NewMinedBlockEvent{}) 840 defer sub.Unsubscribe() 841 842 if withL2Tx { 843 b.txPool.AddLocal(b.newRandomTx(false)) 844 } 845 846 // Start mining! 847 w.start() 848 849 // call once before first block 850 callback(0, nil, db, w) 851 852 // timeout for all blocks 853 globalTimeout := time.After(3 * time.Second) 854 855 for ii := 1; true; ii++ { 856 select { 857 case <-globalTimeout: 858 t.Fatalf("timeout") 859 default: 860 } 861 862 select { 863 case ev := <-sub.Chan(): 864 block := ev.Data.(core.NewMinedBlockEvent).Block 865 866 if done := callback(ii, block, db, w); done { 867 return 868 } 869 870 // timeout for one block 871 case <-time.After(3 * time.Second): 872 t.Fatalf("timeout") 873 } 874 } 875 } 876 877 func TestL1SingleMessageOverGasLimit(t *testing.T) { 878 assert := assert.New(t) 879 880 msgs := []types.L1MessageTx{ 881 {QueueIndex: 0, Gas: 10000000, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{2}}, // over gas limit 882 {QueueIndex: 1, Gas: 21016, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{2}}, // same sender 883 {QueueIndex: 2, Gas: 21016, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{3}}, // different sender 884 } 885 886 l1MessageTest(t, msgs, false, func(blockNum int, block *types.Block, db ethdb.Database, w *worker) bool { 887 switch blockNum { 888 case 0: 889 return false 890 case 1: 891 // skip #0, include #1 and #2 892 assert.Equal(2, len(block.Transactions())) 893 894 assert.True(block.Transactions()[0].IsL1MessageTx()) 895 assert.Equal(uint64(1), block.Transactions()[0].AsL1MessageTx().QueueIndex) 896 assert.True(block.Transactions()[1].IsL1MessageTx()) 897 assert.Equal(uint64(2), block.Transactions()[1].AsL1MessageTx().QueueIndex) 898 899 // db is updated correctly 900 queueIndex := rawdb.ReadFirstQueueIndexNotInL2Block(db, block.Hash()) 901 assert.NotNil(queueIndex) 902 assert.Equal(uint64(3), *queueIndex) 903 904 return true 905 default: 906 return true 907 } 908 }) 909 } 910 911 func TestL1CombinedMessagesOverGasLimit(t *testing.T) { 912 assert := assert.New(t) 913 914 // message #0 is over the gas limit 915 // we should skip #0 but not #1 and #2 916 msgs := []types.L1MessageTx{ 917 {QueueIndex: 0, Gas: 4000000, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{2}}, 918 {QueueIndex: 1, Gas: 4000000, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{2}}, // same sender 919 {QueueIndex: 2, Gas: 21016, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{3}}, // different sender 920 } 921 922 l1MessageTest(t, msgs, false, func(blockNum int, block *types.Block, db ethdb.Database, w *worker) bool { 923 switch blockNum { 924 case 0: 925 return false 926 case 1: 927 // block #1 only includes 1 message 928 assert.Equal(1, len(block.Transactions())) 929 assert.True(block.Transactions()[0].IsL1MessageTx()) 930 assert.Equal(uint64(0), block.Transactions()[0].AsL1MessageTx().QueueIndex) 931 932 // db is updated correctly 933 queueIndex := rawdb.ReadFirstQueueIndexNotInL2Block(db, block.Hash()) 934 assert.NotNil(queueIndex) 935 assert.Equal(uint64(1), *queueIndex) 936 return false 937 case 2: 938 // block #2 includes the other 2 messages 939 assert.Equal(2, len(block.Transactions())) 940 assert.True(block.Transactions()[0].IsL1MessageTx()) 941 assert.Equal(uint64(1), block.Transactions()[0].AsL1MessageTx().QueueIndex) 942 assert.True(block.Transactions()[1].IsL1MessageTx()) 943 assert.Equal(uint64(2), block.Transactions()[1].AsL1MessageTx().QueueIndex) 944 945 // db is updated correctly 946 queueIndex := rawdb.ReadFirstQueueIndexNotInL2Block(db, block.Hash()) 947 assert.NotNil(queueIndex) 948 assert.Equal(uint64(3), *queueIndex) 949 return true 950 default: 951 return true 952 } 953 }) 954 } 955 956 func TestLargeL1MessageSkipPayloadCheck(t *testing.T) { 957 assert := assert.New(t) 958 959 // message #0 is over the L2 block payload size limit 960 msgs := []types.L1MessageTx{ 961 {QueueIndex: 0, Gas: 25100, To: &common.Address{1}, Data: make([]byte, 1025), Sender: common.Address{2}}, 962 {QueueIndex: 1, Gas: 21016, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{2}}, // same sender 963 {QueueIndex: 2, Gas: 21016, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{3}}, // different sender 964 } 965 966 l1MessageTest(t, msgs, true, func(blockNum int, block *types.Block, db ethdb.Database, w *worker) bool { 967 switch blockNum { 968 case 0: 969 return false 970 case 1: 971 // include #0, #1 and #2 + one L2 tx 972 assert.Equal(4, len(block.Transactions())) 973 974 assert.True(block.Transactions()[0].IsL1MessageTx()) 975 assert.Equal(uint64(0), block.Transactions()[0].AsL1MessageTx().QueueIndex) 976 assert.True(block.Transactions()[1].IsL1MessageTx()) 977 assert.Equal(uint64(1), block.Transactions()[1].AsL1MessageTx().QueueIndex) 978 assert.True(block.Transactions()[2].IsL1MessageTx()) 979 assert.Equal(uint64(2), block.Transactions()[2].AsL1MessageTx().QueueIndex) 980 981 // since L1 messages do not count against the block size limit, 982 // we can include additional L2 transaction 983 assert.False(block.Transactions()[3].IsL1MessageTx()) 984 985 // db is updated correctly 986 queueIndex := rawdb.ReadFirstQueueIndexNotInL2Block(db, block.Hash()) 987 assert.NotNil(queueIndex) 988 assert.Equal(uint64(3), *queueIndex) 989 990 return true 991 default: 992 return true 993 } 994 }) 995 } 996 997 func TestSkipMessageWithStrangeError(t *testing.T) { 998 assert := assert.New(t) 999 1000 // message #0 is skipped because of `Value` 1001 // TODO: trigger skipping in some other way after this behaviour is changed 1002 msgs := []types.L1MessageTx{ 1003 {QueueIndex: 0, Gas: 25100, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{2}, Value: big.NewInt(1)}, 1004 {QueueIndex: 1, Gas: 21016, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{2}}, 1005 {QueueIndex: 2, Gas: 21016, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{3}}, 1006 } 1007 1008 l1MessageTest(t, msgs, false, func(blockNum int, block *types.Block, db ethdb.Database, w *worker) bool { 1009 switch blockNum { 1010 case 0: 1011 return false 1012 case 1: 1013 // skip #0, include #1 and #2 1014 assert.Equal(2, len(block.Transactions())) 1015 assert.True(block.Transactions()[0].IsL1MessageTx()) 1016 1017 assert.True(block.Transactions()[0].IsL1MessageTx()) 1018 assert.Equal(uint64(1), block.Transactions()[0].AsL1MessageTx().QueueIndex) 1019 assert.True(block.Transactions()[1].IsL1MessageTx()) 1020 assert.Equal(uint64(2), block.Transactions()[1].AsL1MessageTx().QueueIndex) 1021 1022 // db is updated correctly 1023 queueIndex := rawdb.ReadFirstQueueIndexNotInL2Block(db, block.Hash()) 1024 assert.NotNil(queueIndex) 1025 assert.Equal(uint64(3), *queueIndex) 1026 1027 return true 1028 default: 1029 return false 1030 } 1031 }) 1032 } 1033 1034 func TestSkipAllL1MessagesInBlock(t *testing.T) { 1035 assert := assert.New(t) 1036 1037 // messages are skipped because of `Value` 1038 // TODO: trigger skipping in some other way after this behaviour is changed 1039 msgs := []types.L1MessageTx{ 1040 {QueueIndex: 0, Gas: 25100, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{2}, Value: big.NewInt(1)}, 1041 {QueueIndex: 1, Gas: 21016, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{2}, Value: big.NewInt(1)}, 1042 {QueueIndex: 2, Gas: 21016, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{3}, Value: big.NewInt(1)}, 1043 } 1044 1045 l1MessageTest(t, msgs, true, func(blockNum int, block *types.Block, db ethdb.Database, w *worker) bool { 1046 switch blockNum { 1047 case 0: 1048 return false 1049 case 1: 1050 // skip all 3 L1 messages, include 1 L2 tx 1051 assert.Equal(1, len(block.Transactions())) 1052 assert.False(block.Transactions()[0].IsL1MessageTx()) 1053 1054 // db is updated correctly 1055 // note: this should return 0 but on the signer we store 3 instead so 1056 // that we do not process the same messages again for the next block. 1057 queueIndex := rawdb.ReadFirstQueueIndexNotInL2Block(db, block.Hash()) 1058 assert.NotNil(queueIndex) 1059 assert.Equal(uint64(3), *queueIndex) 1060 1061 return true 1062 default: 1063 return true 1064 } 1065 }) 1066 } 1067 1068 func TestOversizedTxThenNormal(t *testing.T) { 1069 assert := assert.New(t) 1070 1071 msgs := []types.L1MessageTx{ 1072 {QueueIndex: 0, Gas: 25100, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{2}}, 1073 {QueueIndex: 1, Gas: 21016, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{2}}, 1074 {QueueIndex: 2, Gas: 21016, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{3}}, 1075 } 1076 1077 l1MessageTest(t, msgs, false, func(blockNum int, block *types.Block, db ethdb.Database, w *worker) bool { 1078 switch blockNum { 1079 case 0: 1080 // schedule to skip 2nd call to ccc 1081 w.getCCC().ScheduleError(2, circuitcapacitychecker.ErrBlockRowConsumptionOverflow) 1082 return false 1083 case 1: 1084 // include #0, fail on #1, then seal the block 1085 assert.Equal(1, len(block.Transactions())) 1086 1087 assert.True(block.Transactions()[0].IsL1MessageTx()) 1088 assert.Equal(uint64(0), block.Transactions()[0].AsL1MessageTx().QueueIndex) 1089 1090 // db is updated correctly 1091 queueIndex := rawdb.ReadFirstQueueIndexNotInL2Block(db, block.Hash()) 1092 assert.NotNil(queueIndex) 1093 assert.Equal(uint64(1), *queueIndex) 1094 1095 // schedule to skip next call to ccc 1096 w.getCCC().ScheduleError(1, circuitcapacitychecker.ErrBlockRowConsumptionOverflow) 1097 1098 return false 1099 case 2: 1100 // skip #1, include #2, then seal the block 1101 assert.Equal(1, len(block.Transactions())) 1102 1103 assert.True(block.Transactions()[0].IsL1MessageTx()) 1104 assert.Equal(uint64(2), block.Transactions()[0].AsL1MessageTx().QueueIndex) 1105 1106 // db is updated correctly 1107 queueIndex := rawdb.ReadFirstQueueIndexNotInL2Block(db, block.Hash()) 1108 assert.NotNil(queueIndex) 1109 assert.Equal(uint64(3), *queueIndex) 1110 1111 return true 1112 default: 1113 return true 1114 } 1115 }) 1116 } 1117 1118 func TestSkippedTransactionDatabaseEntries(t *testing.T) { 1119 assert := assert.New(t) 1120 1121 msgs := []types.L1MessageTx{ 1122 {QueueIndex: 0, Gas: 10000000, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{2}}, // over gas limit 1123 {QueueIndex: 1, Gas: 21016, To: &common.Address{1}, Data: []byte{0x01}, Sender: common.Address{2}}, 1124 } 1125 1126 l1MessageTest(t, msgs, false, func(blockNum int, block *types.Block, db ethdb.Database, w *worker) bool { 1127 switch blockNum { 1128 case 0: 1129 return false 1130 case 1: 1131 // skip #0, include #1 1132 assert.Equal(1, len(block.Transactions())) 1133 1134 assert.True(block.Transactions()[0].IsL1MessageTx()) 1135 assert.Equal(uint64(1), block.Transactions()[0].AsL1MessageTx().QueueIndex) 1136 1137 // db is updated correctly 1138 queueIndex := rawdb.ReadFirstQueueIndexNotInL2Block(db, block.Hash()) 1139 assert.NotNil(queueIndex) 1140 1141 assert.Equal(uint64(2), *queueIndex) 1142 1143 l1msg := rawdb.ReadL1Message(db, 0) 1144 assert.NotNil(l1msg) 1145 hash := types.NewTx(l1msg).Hash() 1146 1147 stx := rawdb.ReadSkippedTransaction(db, hash) 1148 assert.NotNil(stx) 1149 assert.True(stx.Tx.IsL1MessageTx()) 1150 assert.Equal(uint64(0), stx.Tx.AsL1MessageTx().QueueIndex) 1151 assert.Equal("gas limit exceeded", stx.Reason) 1152 assert.Equal(block.NumberU64(), stx.BlockNumber) 1153 assert.Nil(stx.BlockHash) 1154 1155 numSkipped := rawdb.ReadNumSkippedTransactions(db) 1156 assert.Equal(uint64(1), numSkipped) 1157 1158 hash2 := rawdb.ReadSkippedTransactionHash(db, 0) 1159 assert.NotNil(hash2) 1160 assert.Equal(&hash, hash2) 1161 1162 // iterator API 1163 it := rawdb.IterateSkippedTransactionsFrom(db, 0) 1164 hasMore := it.Next() 1165 assert.True(hasMore) 1166 assert.Equal(uint64(0), it.Index()) 1167 hash3 := it.TransactionHash() 1168 assert.Equal(hash, hash3) 1169 hasMore = it.Next() 1170 assert.False(hasMore) 1171 return true 1172 default: 1173 return true 1174 } 1175 }) 1176 }