diff --git a/cmd/flags/prover.go b/cmd/flags/prover.go index 2df28ed24..709929861 100644 --- a/cmd/flags/prover.go +++ b/cmd/flags/prover.go @@ -172,6 +172,13 @@ var ( Usage: "Version or tag or the L2 Node Version used as an L2 RPC Url by this guardian prover", Category: proverCategory, } + // Confirmations specific flag + BlockConfirmations = &cli.Uint64Flag{ + Name: "prover.blockConfirmations", + Usage: "Confirmations to the latest l1 block before submitting a proof for a l2 block", + Value: 6, + Category: proverCategory, + } ) // ProverFlags All prover flags. @@ -207,4 +214,5 @@ var ProverFlags = MergeFlags(CommonFlags, []cli.Flag{ Allowance, L1NodeVersion, L2NodeVersion, + BlockConfirmations, }) diff --git a/pkg/chain_iterator/block_batch_iterator.go b/pkg/chain_iterator/block_batch_iterator.go index 69ceefca2..87376de34 100644 --- a/pkg/chain_iterator/block_batch_iterator.go +++ b/pkg/chain_iterator/block_batch_iterator.go @@ -19,6 +19,7 @@ import ( const ( DefaultBlocksReadPerEpoch = 1000 DefaultRetryInterval = 12 * time.Second + DefaultBlockConfirmations = 0 ) var ( @@ -54,6 +55,7 @@ type BlockBatchIterator struct { isEnd bool reorgRewindDepth uint64 retryInterval time.Duration + blockConfirmations *uint64 } // BlockBatchIteratorConfig represents the configs of a block batch iterator. @@ -65,6 +67,7 @@ type BlockBatchIteratorConfig struct { OnBlocks OnBlocksFunc ReorgRewindDepth *uint64 RetryInterval time.Duration + BlockConfirmations *uint64 } // NewBlockBatchIterator creates a new block batch iterator instance. @@ -95,12 +98,13 @@ func NewBlockBatchIterator(ctx context.Context, cfg *BlockBatchIteratorConfig) ( } iterator := &BlockBatchIterator{ - ctx: ctx, - client: cfg.Client, - chainID: cfg.Client.ChainID, - startHeight: cfg.StartHeight.Uint64(), - onBlocks: cfg.OnBlocks, - current: startHeader, + ctx: ctx, + client: cfg.Client, + chainID: cfg.Client.ChainID, + startHeight: cfg.StartHeight.Uint64(), + onBlocks: cfg.OnBlocks, + current: startHeader, + blockConfirmations: cfg.BlockConfirmations, } if cfg.MaxBlocksReadPerEpoch != nil { @@ -165,18 +169,31 @@ func (i *BlockBatchIterator) iter() (err error) { } var ( - endHeight uint64 - endHeader *types.Header - destHeight uint64 - isLastEpoch bool + endHeight uint64 + endHeader *types.Header + destHeight uint64 + isLastEpoch bool + blockConfirmations uint64 ) + if i.blockConfirmations == nil { + blockConfirmations = DefaultBlockConfirmations + } else { + blockConfirmations = *i.blockConfirmations + } + if i.endHeight != nil { destHeight = *i.endHeight } else { - if destHeight, err = i.client.BlockNumber(i.ctx); err != nil { + destHeight, err = i.client.BlockNumber(i.ctx) + if err != nil { return err } + if destHeight > blockConfirmations { + destHeight -= blockConfirmations + } else { + destHeight = 0 + } } if i.current.Number.Uint64() >= destHeight { diff --git a/pkg/chain_iterator/block_batch_iterator_test.go b/pkg/chain_iterator/block_batch_iterator_test.go index 9aa5b63f7..5a7760edf 100644 --- a/pkg/chain_iterator/block_batch_iterator_test.go +++ b/pkg/chain_iterator/block_batch_iterator_test.go @@ -2,6 +2,7 @@ package chainiterator import ( "context" + "io" "math/big" "testing" "time" @@ -48,6 +49,71 @@ func (s *BlockBatchIteratorTestSuite) TestIter() { s.Equal(headHeight, lastEnd.Uint64()) } +func (s *BlockBatchIteratorTestSuite) TestIterWithoutSpecifiedEndHeight() { + var maxBlocksReadPerEpoch uint64 = 2 + var blockConfirmations uint64 = 6 + + headHeight, err := s.RPCClient.L1.BlockNumber(context.Background()) + s.Nil(err) + s.Greater(headHeight, uint64(0)) + + lastEnd := common.Big0 + + iter, err := NewBlockBatchIterator(context.Background(), &BlockBatchIteratorConfig{ + Client: s.RPCClient.L1, + MaxBlocksReadPerEpoch: &maxBlocksReadPerEpoch, + StartHeight: common.Big0, + BlockConfirmations: &blockConfirmations, + OnBlocks: func( + _ context.Context, + start, end *types.Header, + _ UpdateCurrentFunc, + _ EndIterFunc, + ) error { + s.Equal(lastEnd.Uint64(), start.Number.Uint64()) + lastEnd = end.Number + return nil + }, + }) + + s.Nil(err) + s.Nil(iter.Iter()) + s.Equal(headHeight-blockConfirmations, lastEnd.Uint64()) +} + +func (s *BlockBatchIteratorTestSuite) TestIterWithLessThanConfirmations() { + var maxBlocksReadPerEpoch uint64 = 2 + + headHeight, err := s.RPCClient.L1.BlockNumber(context.Background()) + s.Nil(err) + s.Greater(headHeight, uint64(0)) + + lastEnd := headHeight + + var blockConfirmations = headHeight + 3 + + iter, err := NewBlockBatchIterator(context.Background(), &BlockBatchIteratorConfig{ + Client: s.RPCClient.L1, + MaxBlocksReadPerEpoch: &maxBlocksReadPerEpoch, + StartHeight: new(big.Int).SetUint64(headHeight), + BlockConfirmations: &blockConfirmations, + OnBlocks: func( + _ context.Context, + start, end *types.Header, + _ UpdateCurrentFunc, + _ EndIterFunc, + ) error { + s.Equal(lastEnd, start.Number.Uint64()) + lastEnd = end.Number.Uint64() + return nil + }, + }) + + s.Nil(err) + s.Equal(io.EOF, iter.iter()) + s.Equal(headHeight, lastEnd) +} + func (s *BlockBatchIteratorTestSuite) TestIterEndFunc() { var maxBlocksReadPerEpoch uint64 = 2 diff --git a/pkg/chain_iterator/event_iterator/block_proposed_iterator.go b/pkg/chain_iterator/event_iterator/block_proposed_iterator.go index 7e654182e..12ff6b82f 100644 --- a/pkg/chain_iterator/event_iterator/block_proposed_iterator.go +++ b/pkg/chain_iterator/event_iterator/block_proposed_iterator.go @@ -43,6 +43,7 @@ type BlockProposedIteratorConfig struct { EndHeight *big.Int FilterQuery []*big.Int OnBlockProposedEvent OnBlockProposedEvent + BlockConfirmations *uint64 } // NewBlockProposedIterator creates a new instance of BlockProposed event iterator. @@ -63,6 +64,7 @@ func NewBlockProposedIterator(ctx context.Context, cfg *BlockProposedIteratorCon MaxBlocksReadPerEpoch: cfg.MaxBlocksReadPerEpoch, StartHeight: cfg.StartHeight, EndHeight: cfg.EndHeight, + BlockConfirmations: cfg.BlockConfirmations, OnBlocks: assembleBlockProposedIteratorCallback( cfg.Client, cfg.TaikoL1, diff --git a/pkg/chain_iterator/event_iterator/transition_proven_iterator.go b/pkg/chain_iterator/event_iterator/transition_proven_iterator.go deleted file mode 100644 index 61103b4a2..000000000 --- a/pkg/chain_iterator/event_iterator/transition_proven_iterator.go +++ /dev/null @@ -1,144 +0,0 @@ -package eventiterator - -import ( - "context" - "errors" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/core/types" - - "github.com/taikoxyz/taiko-client/bindings" - chainIterator "github.com/taikoxyz/taiko-client/pkg/chain_iterator" - "github.com/taikoxyz/taiko-client/pkg/rpc" -) - -// EndTransitionProvedEventIterFunc ends the current iteration. -type EndTransitionProvedEventIterFunc func() - -// OnTransitionProved represents the callback function which will be called when a TaikoL1.TransitionProved event is -// iterated. -type OnTransitionProved func( - context.Context, - *bindings.TaikoL1ClientTransitionProved, - EndTransitionProvedEventIterFunc, -) error - -// TransitionProvedIterator iterates the emitted TaikoL1.TransitionProved events in the chain, -// with the awareness of reorganization. -type TransitionProvedIterator struct { - ctx context.Context - taikoL1 *bindings.TaikoL1Client - blockBatchIterator *chainIterator.BlockBatchIterator - filterQuery []*big.Int - isEnd bool -} - -// TransitionProvenIteratorConfig represents the configs of a TransitionProved event iterator. -type TransitionProvenIteratorConfig struct { - Client *rpc.EthClient - TaikoL1 *bindings.TaikoL1Client - MaxBlocksReadPerEpoch *uint64 - StartHeight *big.Int - EndHeight *big.Int - FilterQuery []*big.Int - OnTransitionProved OnTransitionProved -} - -// NewTransitionProvedIterator creates a new instance of TransitionProved event iterator. -func NewTransitionProvedIterator( - ctx context.Context, - cfg *TransitionProvenIteratorConfig, -) (*TransitionProvedIterator, error) { - if cfg.OnTransitionProved == nil { - return nil, errors.New("invalid callback") - } - - iterator := &TransitionProvedIterator{ - ctx: ctx, - taikoL1: cfg.TaikoL1, - filterQuery: cfg.FilterQuery, - } - - // Initialize the inner block iterator. - blockIterator, err := chainIterator.NewBlockBatchIterator(ctx, &chainIterator.BlockBatchIteratorConfig{ - Client: cfg.Client, - MaxBlocksReadPerEpoch: cfg.MaxBlocksReadPerEpoch, - StartHeight: cfg.StartHeight, - EndHeight: cfg.EndHeight, - OnBlocks: assembleTransitionProvedIteratorCallback( - cfg.Client, - cfg.TaikoL1, - cfg.FilterQuery, - cfg.OnTransitionProved, - iterator, - ), - }) - if err != nil { - return nil, err - } - - iterator.blockBatchIterator = blockIterator - - return iterator, nil -} - -// Iter iterates the given chain between the given start and end heights, -// will call the callback when a TransitionProved event is iterated. -func (i *TransitionProvedIterator) Iter() error { - return i.blockBatchIterator.Iter() -} - -// end ends the current iteration. -func (i *TransitionProvedIterator) end() { - i.isEnd = true -} - -// assembleTransitionProvedIteratorCallback assembles the callback which will be used -// by a event iterator's inner block iterator. -func assembleTransitionProvedIteratorCallback( - client *rpc.EthClient, - taikoL1Client *bindings.TaikoL1Client, - filterQuery []*big.Int, - callback OnTransitionProved, - eventIter *TransitionProvedIterator, -) chainIterator.OnBlocksFunc { - return func( - ctx context.Context, - start, end *types.Header, - updateCurrentFunc chainIterator.UpdateCurrentFunc, - endFunc chainIterator.EndIterFunc, - ) error { - endHeight := end.Number.Uint64() - iter, err := taikoL1Client.FilterTransitionProved( - &bind.FilterOpts{Start: start.Number.Uint64(), End: &endHeight, Context: ctx}, - filterQuery, - ) - if err != nil { - return err - } - defer iter.Close() - - for iter.Next() { - event := iter.Event - - if err := callback(ctx, event, eventIter.end); err != nil { - return err - } - - if eventIter.isEnd { - endFunc() - return nil - } - - current, err := client.HeaderByHash(ctx, event.Raw.BlockHash) - if err != nil { - return err - } - - updateCurrentFunc(current) - } - - return nil - } -} diff --git a/prover/config.go b/prover/config.go index 6e76d2603..5c3dd524f 100644 --- a/prover/config.go +++ b/prover/config.go @@ -56,6 +56,7 @@ type Config struct { RaikoHostEndpoint string L1NodeVersion string L2NodeVersion string + BlockConfirmations uint64 } // NewConfigFromCliContext creates a new config instance from command line flags. @@ -176,5 +177,6 @@ func NewConfigFromCliContext(c *cli.Context) (*Config, error) { Allowance: allowance, L1NodeVersion: c.String(flags.L1NodeVersion.Name), L2NodeVersion: c.String(flags.L2NodeVersion.Name), + BlockConfirmations: c.Uint64(flags.BlockConfirmations.Name), }, nil } diff --git a/prover/prover.go b/prover/prover.go index dd472357f..c88245727 100644 --- a/prover/prover.go +++ b/prover/prover.go @@ -339,6 +339,7 @@ func (p *Prover) proveOp() error { TaikoL1: p.rpc.TaikoL1, StartHeight: new(big.Int).SetUint64(p.sharedState.GetL1Current().Number.Uint64()), OnBlockProposedEvent: p.blockProposedHandler.Handle, + BlockConfirmations: &p.cfg.BlockConfirmations, }) if err != nil { log.Error("Failed to start event iterator", "event", "BlockProposed", "error", err)