From b4a61824dd4b9c1130d6d9f7699f75935ff75765 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 3 Apr 2024 15:43:37 +0800 Subject: [PATCH] delete proposeEmptyBlockOp and fix test cases. --- cmd/flags/proposer.go | 20 ++-- internal/testutils/helper.go | 65 ++++++++++- internal/testutils/interfaces.go | 1 - proposer/config.go | 27 +++-- proposer/config_test.go | 6 +- proposer/proposer.go | 115 +++++++++---------- proposer/proposer_test.go | 189 ++++++++++++++----------------- 7 files changed, 237 insertions(+), 186 deletions(-) diff --git a/cmd/flags/proposer.go b/cmd/flags/proposer.go index f2c4196ba..90e99fd70 100644 --- a/cmd/flags/proposer.go +++ b/cmd/flags/proposer.go @@ -66,21 +66,21 @@ var ( Category: proposerCategory, Value: 0, } - BlockMinGasLimit = &cli.Uint64Flag{ - Name: "epoch.minGasLimit", - Usage: "Minimum gas limit for a proposed block", + MinGasUsed = &cli.Uint64Flag{ + Name: "epoch.minGasUsed", + Usage: "Minimum gas used for a transactions list to propose", Category: proposerCategory, Value: 0, } - BlockMinTxListBytes = &cli.Uint64Flag{ + MinTxListBytes = &cli.Uint64Flag{ Name: "epoch.minTxListBytes", - Usage: "Minimum bytes for a proposed transaction list", + Usage: "Minimum bytes for a transactions list to propose", Category: proposerCategory, Value: 0, } - FroceProposingInternal = &cli.DurationFlag{ - Name: "epoch.emptyBlockInterval", - Usage: "Time interval to propose empty blocks", + MinProposingInternal = &cli.DurationFlag{ + Name: "epoch.minProposingInterval", + Usage: "Minimum time interval to force proposing a block, even if there are no transaction in mempool", Category: proposerCategory, Value: 0, } @@ -139,7 +139,9 @@ var ProposerFlags = MergeFlags(CommonFlags, []cli.Flag{ TxPoolLocals, TxPoolLocalsOnly, ExtraData, - FroceProposingInternal, + MinGasUsed, + MinTxListBytes, + MinProposingInternal, MaxProposedTxListsPerEpoch, ProverEndpoints, OptimisticTierFee, diff --git a/internal/testutils/helper.go b/internal/testutils/helper.go index d127ef853..1552b9ed4 100644 --- a/internal/testutils/helper.go +++ b/internal/testutils/helper.go @@ -6,12 +6,14 @@ import ( "crypto/rand" "errors" "fmt" + "math/big" "net/http" "net/url" "os" "time" "github.com/cenkalti/backoff/v4" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" @@ -21,6 +23,7 @@ import ( "github.com/phayes/freeport" "github.com/taikoxyz/taiko-client/bindings" + "github.com/taikoxyz/taiko-client/pkg/rpc" "github.com/taikoxyz/taiko-client/prover/server" ) @@ -30,6 +33,17 @@ func (s *ClientTestSuite) ProposeInvalidTxListBytes(proposer Proposer) { s.Nil(proposer.ProposeTxList(context.Background(), invalidTxListBytes, 1)) } +func (s *ClientTestSuite) proposeEmptyBlockOp(ctx context.Context, proposer Proposer) error { + emptyTxListBytes, err := rlp.EncodeToBytes(types.Transactions{}) + if err != nil { + return err + } + if err = proposer.ProposeTxList(ctx, emptyTxListBytes, 0); err != nil { + return err + } + return nil +} + func (s *ClientTestSuite) ProposeAndInsertEmptyBlocks( proposer Proposer, calldataSyncer CalldataSyncer, @@ -58,7 +72,7 @@ func (s *ClientTestSuite) ProposeAndInsertEmptyBlocks( s.ProposeInvalidTxListBytes(proposer) // Random bytes txList - s.Nil(proposer.ProposeEmptyBlockOp(context.Background())) + s.Nil(s.proposeEmptyBlockOp(context.Background(), proposer)) events = append(events, []*bindings.TaikoL1ClientBlockProposed{<-sink, <-sink, <-sink}...) @@ -299,3 +313,52 @@ func LocalRandomProverEndpoint() *url.URL { func SignatureFromRSV(r, s string, v byte) []byte { return append(append(hexutil.MustDecode(r), hexutil.MustDecode(s)...), v) } + +// MakeDynamicTx creates a dynamic transaction, used for tests. +func MakeDynamicTx( + client *rpc.EthClient, + priv *ecdsa.PrivateKey, + to *common.Address, + value *big.Int, + data []byte, +) (*types.Transaction, error) { + head, err := client.HeaderByNumber(context.Background(), nil) + if err != nil { + return nil, err + } + + auth, err := bind.NewKeyedTransactorWithChainID(priv, client.ChainID) + if err != nil { + return nil, err + } + + nonce, err := client.PendingNonceAt(context.Background(), auth.From) + if err != nil { + return nil, err + } + + gasTipCap, err := client.SuggestGasTipCap(context.Background()) + if err != nil { + return nil, err + } + + tx, err := auth.Signer(auth.From, types.NewTx(&types.DynamicFeeTx{ + To: to, + Nonce: nonce, + Value: value, + GasTipCap: gasTipCap, + GasFeeCap: new(big.Int).Add( + gasTipCap, + new(big.Int).Mul(head.BaseFee, big.NewInt(2)), + ), + Gas: 2100_000, + Data: data, + })) + if err != nil { + return nil, err + } + if err = client.SendTransaction(context.Background(), tx); err != nil { + return nil, err + } + return tx, nil +} diff --git a/internal/testutils/interfaces.go b/internal/testutils/interfaces.go index 08ea83d29..04d5b9ae8 100644 --- a/internal/testutils/interfaces.go +++ b/internal/testutils/interfaces.go @@ -13,7 +13,6 @@ type CalldataSyncer interface { type Proposer interface { utils.SubcommandApplication ProposeOp(ctx context.Context) error - ProposeEmptyBlockOp(ctx context.Context) error ProposeTxList( ctx context.Context, txListBytes []byte, diff --git a/proposer/config.go b/proposer/config.go index 71d054fe3..df0e55bb6 100644 --- a/proposer/config.go +++ b/proposer/config.go @@ -28,9 +28,9 @@ type Config struct { ProposeInterval time.Duration LocalAddresses []common.Address LocalAddressesOnly bool - BlockMinGasLimit uint64 - BlockMinTxListBytes uint64 - FroceProposingInternal time.Duration + MinGasUsed uint64 + MinTxListBytes uint64 + MinProposingInternal time.Duration MaxProposedTxListsPerEpoch uint64 ProposeBlockTxGasLimit uint64 WaitReceiptTimeout time.Duration @@ -88,17 +88,16 @@ func NewConfigFromCliContext(c *cli.Context) (*Config, error) { TaikoTokenAddress: common.HexToAddress(c.String(flags.TaikoTokenAddress.Name)), Timeout: c.Duration(flags.RPCTimeout.Name), }, - AssignmentHookAddress: common.HexToAddress(c.String(flags.ProposerAssignmentHookAddress.Name)), - L1ProposerPrivKey: l1ProposerPrivKey, - L2SuggestedFeeRecipient: common.HexToAddress(l2SuggestedFeeRecipient), - ExtraData: c.String(flags.ExtraData.Name), - ProposeInterval: c.Duration(flags.ProposeInterval.Name), - LocalAddresses: localAddresses, - LocalAddressesOnly: c.Bool(flags.TxPoolLocalsOnly.Name), - - BlockMinGasLimit: c.Uint64(flags.BlockMinGasLimit.Name), - BlockMinTxListBytes: c.Uint64(flags.BlockMinTxListBytes.Name), - FroceProposingInternal: c.Duration(flags.FroceProposingInternal.Name), + AssignmentHookAddress: common.HexToAddress(c.String(flags.ProposerAssignmentHookAddress.Name)), + L1ProposerPrivKey: l1ProposerPrivKey, + L2SuggestedFeeRecipient: common.HexToAddress(l2SuggestedFeeRecipient), + ExtraData: c.String(flags.ExtraData.Name), + ProposeInterval: c.Duration(flags.ProposeInterval.Name), + LocalAddresses: localAddresses, + LocalAddressesOnly: c.Bool(flags.TxPoolLocalsOnly.Name), + MinGasUsed: c.Uint64(flags.MinGasUsed.Name), + MinTxListBytes: c.Uint64(flags.MinTxListBytes.Name), + MinProposingInternal: c.Duration(flags.MinProposingInternal.Name), MaxProposedTxListsPerEpoch: c.Uint64(flags.MaxProposedTxListsPerEpoch.Name), ProposeBlockTxGasLimit: c.Uint64(flags.TxGasLimit.Name), WaitReceiptTimeout: c.Duration(flags.WaitReceiptTimeout.Name), diff --git a/proposer/config_test.go b/proposer/config_test.go index 3bd616dff..8d57d4605 100644 --- a/proposer/config_test.go +++ b/proposer/config_test.go @@ -100,7 +100,7 @@ func (s *ProposerTestSuite) TestNewConfigFromCliContextL2RecipErr() { "TestNewConfigFromCliContextL2RecipErr", "--" + flags.L1ProposerPrivKey.Name, encoding.GoldenTouchPrivKey, "--" + flags.ProposeInterval.Name, proposeInterval, - "--" + flags.FroceProposingInternal.Name, proposeInterval, + "--" + flags.MinProposingInternal.Name, proposeInterval, "--" + flags.L2SuggestedFeeRecipient.Name, "notAnAddress", }), "invalid L2 suggested fee recipient address") } @@ -115,7 +115,7 @@ func (s *ProposerTestSuite) TestNewConfigFromCliContextTxPoolLocalsErr() { "TestNewConfigFromCliContextTxPoolLocalsErr", "--" + flags.L1ProposerPrivKey.Name, encoding.GoldenTouchPrivKey, "--" + flags.ProposeInterval.Name, proposeInterval, - "--" + flags.FroceProposingInternal.Name, proposeInterval, + "--" + flags.MinProposingInternal.Name, proposeInterval, "--" + flags.L2SuggestedFeeRecipient.Name, goldenTouchAddress.Hex(), "--" + flags.TxPoolLocals.Name, "notAnAddress", }), "invalid account in --txpool.locals") @@ -131,7 +131,7 @@ func (s *ProposerTestSuite) SetupApp() *cli.App { &cli.StringFlag{Name: flags.TaikoTokenAddress.Name}, &cli.StringFlag{Name: flags.L1ProposerPrivKey.Name}, &cli.StringFlag{Name: flags.L2SuggestedFeeRecipient.Name}, - &cli.DurationFlag{Name: flags.FroceProposingInternal.Name}, + &cli.DurationFlag{Name: flags.MinProposingInternal.Name}, &cli.DurationFlag{Name: flags.ProposeInterval.Name}, &cli.StringFlag{Name: flags.TxPoolLocals.Name}, &cli.StringFlag{Name: flags.ProverEndpoints.Name}, diff --git a/proposer/proposer.go b/proposer/proposer.go index 4b7e7ac3b..5d712d475 100644 --- a/proposer/proposer.go +++ b/proposer/proposer.go @@ -63,10 +63,13 @@ type Proposer struct { CustomProposeOpHook func() error AfterCommitHook func() error + lastNonEmptyBlockProposedAt time.Time + txmgr *txmgr.SimpleTxManager - ctx context.Context - wg sync.WaitGroup + ctx context.Context + wg sync.WaitGroup + stopCh chan struct{} } // InitFromCli New initializes the given proposer instance based on the command line flags. @@ -84,6 +87,8 @@ func (p *Proposer) InitFromConfig(ctx context.Context, cfg *Config) (err error) p.proposerAddress = crypto.PubkeyToAddress(cfg.L1ProposerPrivKey.PublicKey) p.ctx = ctx p.Config = cfg + p.lastNonEmptyBlockProposedAt = time.Now() + p.stopCh = make(chan struct{}) // RPC clients if p.rpc, err = rpc.NewClient(p.ctx, cfg.ClientConfig); err != nil { @@ -171,65 +176,34 @@ func (p *Proposer) eventLoop() { p.wg.Done() }() - var lastNonEmptyBlockProposedAt = time.Now() for { p.updateProposingTicker() select { + case <-p.stopCh: + return case <-p.ctx.Done(): return // proposing interval timer has been reached case <-p.proposingTimer.C: - metrics.ProposerProposeEpochCounter.Inc(1) // Attempt propose operation - if err := p.ProposeOp(p.ctx); err != nil { - if !errors.Is(err, errNoNewTxs) { - log.Error("Proposing operation error", "error", err) - continue - } - // If there is always no new transaction and the empty block interval has passed, propose an empty block. - if p.FroceProposingInternal != 0 { - if time.Now().Before(lastNonEmptyBlockProposedAt.Add(p.FroceProposingInternal)) { - continue - } - - if err := p.ProposeEmptyBlockOp(p.ctx); err != nil { - log.Error("Proposing an empty block operation error", "error", err) - } - - lastNonEmptyBlockProposedAt = time.Now() - } - - continue + err := p.ProposeOp(p.ctx) + if err != nil && !errors.Is(err, errNoNewTxs) { + log.Error("Proposing operation error", "error", err) } - - lastNonEmptyBlockProposedAt = time.Now() } } } // Close closes the proposer instance. func (p *Proposer) Close() { + close(p.stopCh) p.wg.Wait() } -// ProposeOp performs a proposing operation, fetching transactions -// from L2 execution engine's tx pool, splitting them by proposing constraints, -// and then proposing them to TaikoL1 contract. -func (p *Proposer) ProposeOp(ctx context.Context) error { - if p.CustomProposeOpHook != nil { - return p.CustomProposeOpHook() - } - - // Wait until L2 execution engine is synced at first. - if err := p.rpc.WaitTillL2ExecutionEngineSynced(ctx); err != nil { - return fmt.Errorf("failed to wait until L2 execution engine synced: %w", err) - } - - log.Info("Start fetching L2 execution engine's transaction pool content") - +func (p *Proposer) getTxLists(allowEmpty bool) ([]types.Transactions, error) { preBuiltTxList, err := p.rpc.GetPoolContent( - ctx, + p.ctx, p.proposerAddress, p.protocolConfigs.BlockMaxGasLimit, rpc.BlockMaxTxListBytes, @@ -237,17 +211,20 @@ func (p *Proposer) ProposeOp(ctx context.Context) error { p.MaxProposedTxListsPerEpoch, ) if err != nil { - return fmt.Errorf("failed to fetch transaction pool content: %w", err) + return nil, fmt.Errorf("failed to fetch transaction pool content: %w", err) } txLists := make([]types.Transactions, 0, len(preBuiltTxList)) for _, txs := range preBuiltTxList { - if txs.EstimatedGasUsed < p.BlockMinGasLimit || - txs.BytesLength < p.BlockMinTxListBytes { + if !allowEmpty && + (txs.EstimatedGasUsed < p.MinGasUsed || txs.BytesLength < p.MinTxListBytes) { break } txLists = append(txLists, txs.TxList) } + if allowEmpty && len(txLists) == 0 { + txLists = append(txLists, types.Transactions{}) + } if p.LocalAddressesOnly { var ( @@ -259,7 +236,7 @@ func (p *Proposer) ProposeOp(ctx context.Context) error { for _, tx := range txs { sender, err := types.Sender(signer, tx) if err != nil { - return err + return nil, err } for _, localAddress := range p.LocalAddresses { @@ -278,6 +255,42 @@ func (p *Proposer) ProposeOp(ctx context.Context) error { log.Info("Transactions lists count", "count", len(txLists)) + return txLists, nil +} + +func (p *Proposer) ProposeOp(ctx context.Context) error { + metrics.ProposerProposeEpochCounter.Inc(1) + // Attempt propose operation + if err := p.proposeOp( + ctx, + !time.Now().Before(p.lastNonEmptyBlockProposedAt.Add(p.MinProposingInternal)), + ); err != nil { + return err + } + p.lastNonEmptyBlockProposedAt = time.Now() + return nil +} + +// ProposeOp performs a proposing operation, fetching transactions +// from L2 execution engine's tx pool, splitting them by proposing constraints, +// and then proposing them to TaikoL1 contract. +func (p *Proposer) proposeOp(ctx context.Context, allowEmpty bool) error { + if p.CustomProposeOpHook != nil { + return p.CustomProposeOpHook() + } + + // Wait until L2 execution engine is synced at first. + if err := p.rpc.WaitTillL2ExecutionEngineSynced(ctx); err != nil { + return fmt.Errorf("failed to wait until L2 execution engine synced: %w", err) + } + + log.Info("Start fetching L2 execution engine's transaction pool content") + + txLists, err := p.getTxLists(allowEmpty) + if err != nil { + return err + } + if len(txLists) == 0 { return errNoNewTxs } @@ -341,18 +354,6 @@ func (p *Proposer) ProposeTxList( return nil } -// ProposeEmptyBlockOp performs a proposing one empty block operation. -func (p *Proposer) ProposeEmptyBlockOp(ctx context.Context) error { - emptyTxListBytes, err := rlp.EncodeToBytes(types.Transactions{}) - if err != nil { - return err - } - if err = p.ProposeTxList(ctx, emptyTxListBytes, 0); err != nil { - return err - } - return nil -} - // updateProposingTicker updates the internal proposing timer. func (p *Proposer) updateProposingTicker() { if p.proposingTimer != nil { diff --git a/proposer/proposer_test.go b/proposer/proposer_test.go index e4e94500c..9be02b8ab 100644 --- a/proposer/proposer_test.go +++ b/proposer/proposer_test.go @@ -2,21 +2,24 @@ package proposer import ( "context" - "math/big" "os" "testing" "time" "github.com/ethereum-optimism/optimism/op-service/txmgr" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/rlp" "github.com/stretchr/testify/suite" "github.com/taikoxyz/taiko-client/bindings" + "github.com/taikoxyz/taiko-client/driver/chain_syncer/beaconsync" + "github.com/taikoxyz/taiko-client/driver/chain_syncer/calldata" + "github.com/taikoxyz/taiko-client/driver/state" txlistfetcher "github.com/taikoxyz/taiko-client/driver/txlist_fetcher" "github.com/taikoxyz/taiko-client/internal/testutils" "github.com/taikoxyz/taiko-client/internal/utils" @@ -26,6 +29,7 @@ import ( type ProposerTestSuite struct { testutils.ClientTestSuite + s *calldata.Syncer p *Proposer cancel context.CancelFunc } @@ -33,6 +37,19 @@ type ProposerTestSuite struct { func (s *ProposerTestSuite) SetupTest() { s.ClientTestSuite.SetupTest() + state2, err := state.New(context.Background(), s.RPCClient) + s.Nil(err) + + syncer, err := calldata.NewSyncer( + context.Background(), + s.RPCClient, + state2, + beaconsync.NewSyncProgressTracker(s.RPCClient.L2, 1*time.Hour), + 0, + ) + s.Nil(err) + s.s = syncer + l1ProposerPrivKey, err := crypto.ToECDSA(common.FromHex(os.Getenv("L1_PROPOSER_PRIVATE_KEY"))) s.Nil(err) @@ -57,6 +74,7 @@ func (s *ProposerTestSuite) SetupTest() { AssignmentHookAddress: common.HexToAddress(os.Getenv("ASSIGNMENT_HOOK_ADDRESS")), L1ProposerPrivKey: l1ProposerPrivKey, L2SuggestedFeeRecipient: common.HexToAddress(os.Getenv("L2_SUGGESTED_FEE_RECIPIENT")), + MinProposingInternal: 0, ProposeInterval: 1024 * time.Hour, MaxProposedTxListsPerEpoch: 1, WaitReceiptTimeout: 12 * time.Second, @@ -120,102 +138,93 @@ func parseTxs(client *rpc.Client, event *bindings.TaikoL1ClientBlockProposed) (t } func (s *ProposerTestSuite) getLatestProposedTxs( - start uint64, n int, timeout time.Duration, -) ([]types.Transactions, error) { +) (<-chan []types.Transactions, error) { sink := make(chan *bindings.TaikoL1ClientBlockProposed) - - sub, err := s.p.rpc.TaikoL1.WatchBlockProposed(&bind.WatchOpts{ - Start: &start, - }, sink, nil, nil) + sub, err := s.p.rpc.TaikoL1.WatchBlockProposed(nil, sink, nil, nil) if err != nil { return nil, err } - defer sub.Unsubscribe() - - var txLst = make([]types.Transactions, 0, n) - tick := time.After(timeout) - for len(txLst) < cap(txLst) { - select { - case event := <-sink: - txs, err := parseTxs(s.RPCClient, event) - if err != nil { - return nil, err + + var resCh = make(chan []types.Transactions, 1) + go func() { + defer sub.Unsubscribe() + + txLst := make([]types.Transactions, 0, n) + tick := time.After(timeout) + for len(txLst) < cap(txLst) { + select { + case event := <-sink: + txs, err := parseTxs(s.RPCClient, event) + if err != nil { + log.Error("failed to parse txs", "err", err) + } + txLst = append(txLst, txs) + case <-tick: + return } - txLst = append(txLst, txs) - case <-tick: - break } - } + resCh <- txLst + }() - return txLst, nil + return resCh, nil } -func (s *ProposerTestSuite) TestEmptyBlock() { - s.p.FroceProposingInternal = 3 * time.Second - s.p.BlockMinGasLimit = math.MaxUint64 - s.p.BlockMinTxListBytes = math.MaxUint64 - s.p.ProposeInterval = time.Second +func (s *ProposerTestSuite) TestProposeOpEmptyBlock() { + // mint blocks + defer s.Nil(s.s.ProcessL1Blocks(context.Background())) + + p := s.p - number, err := s.RPCClient.L1.BlockNumber(context.Background()) + txsCh, err := s.getLatestProposedTxs(1, time.Minute) s.Nil(err) - // start proposer - s.Nil(s.p.Start()) - defer s.p.Close() + // Start proposer + p.LocalAddressesOnly = false + p.MinGasUsed = math.MaxUint64 + p.MinTxListBytes = math.MaxUint64 + p.MinProposingInternal = 0 + s.Nil(p.ProposeOp(context.Background())) - txs, err := s.getLatestProposedTxs(number, 1, time.Second*30) + // wait result. + txs := <-txsCh s.Nil(err) - s.Equal(true, len(txs) == 1 && len(txs[0]) == 0) + s.Equal(true, len(txs) == 1 && txs[0].Len() == 0) } func (s *ProposerTestSuite) TestProposeOpNoEmptyBlock() { - p := s.p - - head, err := s.RPCClient.L1.HeaderByNumber(context.Background(), nil) - s.Nil(err) - - auth, err := bind.NewKeyedTransactorWithChainID(p.L1ProposerPrivKey, s.RPCClient.L2.ChainID) - s.Nil(err) + defer s.Nil(s.s.ProcessL1Blocks(context.Background())) - nonce, err := s.RPCClient.L2.PendingNonceAt(context.Background(), auth.From) - s.Nil(err) - - gasTipCap, err := s.RPCClient.L2.SuggestGasTipCap(context.Background()) - s.Nil(err) - gasFeeCap := new(big.Int).Add( - gasTipCap, - new(big.Int).Mul(head.BaseFee, big.NewInt(2)), - ) + p := s.p batchSize := 100 + + var err error for i := 0; i < batchSize; i++ { to := common.BytesToAddress(testutils.RandomBytes(32)) - baseTx := types.NewTx(&types.DynamicFeeTx{ - ChainID: s.RPCClient.L2.ChainID, - To: &to, - Nonce: nonce + uint64(i), - GasTipCap: gasTipCap, - GasFeeCap: gasFeeCap, - Gas: 2100000, - }) - tx, err := auth.Signer(auth.From, baseTx) + _, err = testutils.MakeDynamicTx(s.RPCClient.L2, s.TestAddrPrivKey, &to, nil, nil) s.Nil(err) - s.Nil(s.RPCClient.L2.SendTransaction(context.Background(), tx)) } - preBuiltTxList, err := s.RPCClient.GetPoolContent( - context.Background(), - p.proposerAddress, - p.protocolConfigs.BlockMaxGasLimit, - rpc.BlockMaxTxListBytes, - p.LocalAddresses, - p.MaxProposedTxListsPerEpoch, - ) + var preBuiltTxList []*miner.PreBuiltTxList + for i := 0; i < 3 && len(preBuiltTxList) == 0; i++ { + preBuiltTxList, err = s.RPCClient.GetPoolContent( + context.Background(), + p.proposerAddress, + p.protocolConfigs.BlockMaxGasLimit, + rpc.BlockMaxTxListBytes, + p.LocalAddresses, + p.MaxProposedTxListsPerEpoch, + ) + time.Sleep(time.Second) + } s.Nil(err) s.Equal(true, len(preBuiltTxList) > 0) + txsCh, err := s.getLatestProposedTxs(len(preBuiltTxList), time.Minute) + s.Nil(err) + var ( blockMinGasLimit uint64 = math.MaxUint64 blockMinTxListBytes uint64 = math.MaxUint64 @@ -237,21 +246,22 @@ func (s *ProposerTestSuite) TestProposeOpNoEmptyBlock() { // Start proposer p.LocalAddressesOnly = false - p.BlockMinGasLimit = blockMinGasLimit - p.BlockMinTxListBytes = blockMinTxListBytes + p.MinGasUsed = blockMinGasLimit + p.MinTxListBytes = blockMinTxListBytes p.ProposeInterval = time.Second - s.Nil(p.Start()) - defer p.Close() - - txs, err := s.getLatestProposedTxs(head.Number.Uint64(), len(txLists), time.Minute) - s.Nil(err) + p.MinProposingInternal = time.Minute + s.Nil(p.ProposeOp(context.Background())) + txs := <-txsCh for i := 0; i < len(txLists); i++ { s.Equal(txLists[i].Len(), txs[i].Len()) } } func (s *ProposerTestSuite) TestProposeOp() { + // mint blocks + defer s.Nil(s.s.ProcessL1Blocks(context.Background())) + // Propose txs in L2 execution engine's mempool sink := make(chan *bindings.TaikoL1ClientBlockProposed) @@ -262,30 +272,10 @@ func (s *ProposerTestSuite) TestProposeOp() { close(sink) }() - nonce, err := s.p.rpc.L2.PendingNonceAt(context.Background(), s.TestAddr) + to := common.BytesToAddress(testutils.RandomBytes(20)) + _, err = testutils.MakeDynamicTx(s.RPCClient.L2, s.TestAddrPrivKey, &to, nil, nil) s.Nil(err) - parent, err := s.p.rpc.L2.BlockByNumber(context.Background(), nil) - s.Nil(err) - - baseFeeInfo, err := s.p.rpc.TaikoL2.GetBasefee(nil, 1, uint32(parent.GasUsed())) - s.Nil(err) - - to := common.BytesToAddress(testutils.RandomBytes(32)) - tx := types.NewTx(&types.DynamicFeeTx{ - ChainID: s.RPCClient.L2.ChainID, - Nonce: nonce, - GasTipCap: common.Big0, - GasFeeCap: new(big.Int).SetUint64(baseFeeInfo.Basefee.Uint64() * 2), - Gas: 21000, - To: &to, - Value: common.Big1, - }) - - signedTx, err := types.SignTx(tx, types.LatestSignerForChainID(s.p.rpc.L2.ChainID), s.TestAddrPrivKey) - s.Nil(err) - s.Nil(s.p.rpc.L2.SendTransaction(context.Background(), signedTx)) - s.Nil(s.p.ProposeOp(context.Background())) event := <-sink @@ -315,13 +305,10 @@ func (s *ProposerTestSuite) TestProposeOpLocalsOnly() { close(sink) }() + s.p.MinProposingInternal = 1 * time.Hour s.Error(errNoNewTxs, s.p.ProposeOp(context.Background())) } -func (s *ProposerTestSuite) TestProposeEmptyBlockOp() { - s.Nil(s.p.ProposeEmptyBlockOp(context.Background())) -} - func (s *ProposerTestSuite) TestCustomProposeOpHook() { flag := false