From ff7641ce4fcc94f012cfecaaa97cdbf2439a07ad Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 31 Oct 2024 17:42:15 +0100 Subject: [PATCH 01/27] feat: Epoch Notifier --- agglayer/client.go | 30 +- agglayer/client_test.go | 67 ++++ agglayer/mock_agglayer_client.go | 32 +- agglayer/types.go | 11 + aggsender/aggsender.go | 24 +- aggsender/aggsender_test.go | 32 +- aggsender/block_notifier_polling.go | 195 ++++++++++ aggsender/block_notifier_polling_test.go | 121 ++++++ aggsender/config.go | 21 +- aggsender/epoch_notifier_per_block.go | 184 +++++++++ aggsender/epoch_notifier_per_block_test.go | 201 ++++++++++ aggsender/generic_subscriber_impl.go | 33 ++ aggsender/mocks/agg_sender_storage.go | 354 +++++++++++++++++ aggsender/mocks/block_notifier.go | 128 +++++++ aggsender/mocks/epoch_notifier.go | 128 +++++++ aggsender/mocks/eth_client.go | 154 ++++++++ aggsender/mocks/generic_subscriber.go | 113 ++++++ aggsender/mocks/l1_info_tree_syncer.go | 217 +++++++++++ aggsender/mocks/l2_bridge_syncer.go | 423 +++++++++++++++++++++ aggsender/mocks/logger.go | 376 ++++++++++++++++++ aggsender/types/block_notifier.go | 14 + aggsender/types/epoch_notifier.go | 25 ++ aggsender/types/generic_subscriber.go | 6 + aggsender/types/types.go | 2 + cmd/run.go | 31 +- config/default.go | 3 + crates/cdk/versions.json | 2 +- test/Makefile | 9 +- 28 files changed, 2887 insertions(+), 49 deletions(-) create mode 100644 agglayer/client_test.go create mode 100644 aggsender/block_notifier_polling.go create mode 100644 aggsender/block_notifier_polling_test.go create mode 100644 aggsender/epoch_notifier_per_block.go create mode 100644 aggsender/epoch_notifier_per_block_test.go create mode 100644 aggsender/generic_subscriber_impl.go create mode 100644 aggsender/mocks/agg_sender_storage.go create mode 100644 aggsender/mocks/block_notifier.go create mode 100644 aggsender/mocks/epoch_notifier.go create mode 100644 aggsender/mocks/eth_client.go create mode 100644 aggsender/mocks/generic_subscriber.go create mode 100644 aggsender/mocks/l1_info_tree_syncer.go create mode 100644 aggsender/mocks/l2_bridge_syncer.go create mode 100644 aggsender/mocks/logger.go create mode 100644 aggsender/types/block_notifier.go create mode 100644 aggsender/types/epoch_notifier.go create mode 100644 aggsender/types/generic_subscriber.go diff --git a/agglayer/client.go b/agglayer/client.go index e60c1c7c9..92938c4f3 100644 --- a/agglayer/client.go +++ b/agglayer/client.go @@ -15,7 +15,14 @@ import ( const errCodeAgglayerRateLimitExceeded int = -10007 -var ErrAgglayerRateLimitExceeded = fmt.Errorf("agglayer rate limit exceeded") +var ( + ErrAgglayerRateLimitExceeded = fmt.Errorf("agglayer rate limit exceeded") + jSONRPCCall = rpc.JSONRPCCall +) + +type AggLayerClientGetClockConfiguration interface { + GetClockConfiguration() (*ClockConfiguration, error) +} // AgglayerClientInterface is the interface that defines the methods that the AggLayerClient will implement type AgglayerClientInterface interface { @@ -23,6 +30,7 @@ type AgglayerClientInterface interface { WaitTxToBeMined(hash common.Hash, ctx context.Context) error SendCertificate(certificate *SignedCertificate) (common.Hash, error) GetCertificateHeader(certificateHash common.Hash) (*CertificateHeader, error) + AggLayerClientGetClockConfiguration } // AggLayerClient is the client that will be used to interact with the AggLayer @@ -130,3 +138,23 @@ func (c *AggLayerClient) GetCertificateHeader(certificateHash common.Hash) (*Cer return result, nil } + +// GetClockConfiguration returns the clock configuration of AggLayer +func (c *AggLayerClient) GetClockConfiguration() (*ClockConfiguration, error) { + response, err := jSONRPCCall(c.url, "interop_getClockConfiguration") + if err != nil { + return nil, err + } + + if response.Error != nil { + return nil, fmt.Errorf("GetClockConfiguration code=%d msg=%s", response.Error.Code, response.Error.Message) + } + + var result *ClockConfiguration + err = json.Unmarshal(response.Result, &result) + if err != nil { + return nil, err + } + + return result, nil +} diff --git a/agglayer/client_test.go b/agglayer/client_test.go new file mode 100644 index 000000000..5418b7433 --- /dev/null +++ b/agglayer/client_test.go @@ -0,0 +1,67 @@ +package agglayer + +import ( + "fmt" + "testing" + + "github.com/0xPolygon/cdk-rpc/rpc" + "github.com/stretchr/testify/require" +) + +const ( + testURL = "http://localhost:8080" +) + +func TestGetClockConfigurationResponseWithError(t *testing.T) { + sut := NewAggLayerClient(testURL) + response := rpc.Response{ + Error: &rpc.ErrorObject{}, + } + jSONRPCCall = func(url, method string, params ...interface{}) (rpc.Response, error) { + return response, nil + } + clockConfig, err := sut.GetClockConfiguration() + require.Nil(t, clockConfig) + require.Error(t, err) +} + +func TestGetClockConfigurationResponseBadJson(t *testing.T) { + sut := NewAggLayerClient(testURL) + response := rpc.Response{ + Result: []byte(`{`), + } + jSONRPCCall = func(url, method string, params ...interface{}) (rpc.Response, error) { + return response, nil + } + clockConfig, err := sut.GetClockConfiguration() + require.Nil(t, clockConfig) + require.Error(t, err) +} + +func TestGetClockConfigurationErrorResponse(t *testing.T) { + sut := NewAggLayerClient(testURL) + + jSONRPCCall = func(url, method string, params ...interface{}) (rpc.Response, error) { + return rpc.Response{}, fmt.Errorf("unittest error") + } + clockConfig, err := sut.GetClockConfiguration() + require.Nil(t, clockConfig) + require.Error(t, err) +} + +func TestGetClockConfigurationOkResponse(t *testing.T) { + sut := NewAggLayerClient(testURL) + response := rpc.Response{ + Result: []byte(`{"epoch_duration": 1, "genesis_block": 1}`), + } + jSONRPCCall = func(url, method string, params ...interface{}) (rpc.Response, error) { + return response, nil + } + clockConfig, err := sut.GetClockConfiguration() + require.NotNil(t, clockConfig) + require.NoError(t, err) + require.Equal(t, ClockConfiguration{ + EpochDuration: 1, + GenesisBlock: 1, + }, *clockConfig) +} diff --git a/agglayer/mock_agglayer_client.go b/agglayer/mock_agglayer_client.go index 43100a2ed..a6eae49ea 100644 --- a/agglayer/mock_agglayer_client.go +++ b/agglayer/mock_agglayer_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.45.0. DO NOT EDIT. +// Code generated by mockery v2.39.0. DO NOT EDIT. package agglayer @@ -45,6 +45,36 @@ func (_m *AgglayerClientMock) GetCertificateHeader(certificateHash common.Hash) return r0, r1 } +// GetClockConfiguration provides a mock function with given fields: +func (_m *AgglayerClientMock) GetClockConfiguration() (*ClockConfiguration, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetClockConfiguration") + } + + var r0 *ClockConfiguration + var r1 error + if rf, ok := ret.Get(0).(func() (*ClockConfiguration, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() *ClockConfiguration); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*ClockConfiguration) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // SendCertificate provides a mock function with given fields: certificate func (_m *AgglayerClientMock) SendCertificate(certificate *SignedCertificate) (common.Hash, error) { ret := _m.Called(certificate) diff --git a/agglayer/types.go b/agglayer/types.go index 9350e7919..4cc88b320 100644 --- a/agglayer/types.go +++ b/agglayer/types.go @@ -531,3 +531,14 @@ func (c CertificateHeader) String() string { return fmt.Sprintf("Height: %d, CertificateID: %s, NewLocalExitRoot: %s", c.Height, c.CertificateID.String(), c.NewLocalExitRoot.String()) } + +// ClockConfiguration represents the configuration of the epoch clock +// returned by the interop_getClockConfiguration RPC call +type ClockConfiguration struct { + EpochDuration uint64 `json:"epoch_duration"` + GenesisBlock uint64 `json:"genesis_block"` +} + +func (c ClockConfiguration) String() string { + return fmt.Sprintf("EpochDuration: %d, GenesisBlock: %d", c.EpochDuration, c.GenesisBlock) +} diff --git a/aggsender/aggsender.go b/aggsender/aggsender.go index e3242bdf2..ec0f6bb08 100644 --- a/aggsender/aggsender.go +++ b/aggsender/aggsender.go @@ -12,7 +12,7 @@ import ( "github.com/0xPolygon/cdk/agglayer" "github.com/0xPolygon/cdk/aggsender/db" - aggsendertypes "github.com/0xPolygon/cdk/aggsender/types" + "github.com/0xPolygon/cdk/aggsender/types" "github.com/0xPolygon/cdk/bridgesync" cdkcommon "github.com/0xPolygon/cdk/common" "github.com/0xPolygon/cdk/l1infotreesync" @@ -33,10 +33,11 @@ var ( // AggSender is a component that will send certificates to the aggLayer type AggSender struct { - log aggsendertypes.Logger + log types.Logger - l2Syncer aggsendertypes.L2BridgeSyncer - l1infoTreeSyncer aggsendertypes.L1InfoTreeSyncer + l2Syncer types.L2BridgeSyncer + l1infoTreeSyncer types.L1InfoTreeSyncer + epochNotifier types.EpochNotifier storage db.AggSenderStorage aggLayerClient agglayer.AgglayerClientInterface @@ -53,7 +54,8 @@ func New( cfg Config, aggLayerClient agglayer.AgglayerClientInterface, l1InfoTreeSyncer *l1infotreesync.L1InfoTreeSync, - l2Syncer *bridgesync.BridgeSync) (*AggSender, error) { + l2Syncer *bridgesync.BridgeSync, + epochNotifier types.EpochNotifier) (*AggSender, error) { storage, err := db.NewAggSenderSQLStorage(logger, cfg.StoragePath) if err != nil { return nil, err @@ -74,6 +76,7 @@ func New( aggLayerClient: aggLayerClient, l1infoTreeSyncer: l1InfoTreeSyncer, sequencerKey: sequencerPrivateKey, + epochNotifier: epochNotifier, }, nil } @@ -85,12 +88,12 @@ func (a *AggSender) Start(ctx context.Context) { // sendCertificates sends certificates to the aggLayer func (a *AggSender) sendCertificates(ctx context.Context) { - ticker := time.NewTicker(a.cfg.BlockGetInterval.Duration) - + chEpoch := a.epochNotifier.Subscribe("aggsender") for { select { - case <-ticker.C: - if _, err := a.sendCertificate(ctx); err != nil { + case epoch := <-chEpoch: + a.log.Infof("Epoch %d received", epoch.Epoch) + if err := a.sendCertificate(ctx); err != nil { log.Error(err) } case <-ctx.Done(): @@ -247,8 +250,7 @@ func (a *AggSender) getNextHeightAndPreviousLER( func (a *AggSender) buildCertificate(ctx context.Context, bridges []bridgesync.Bridge, claims []bridgesync.Claim, - lastSentCertificateInfo aggsendertypes.CertificateInfo, - toBlock uint64) (*agglayer.Certificate, error) { + lastSentCertificateInfo types.CertificateInfo) (*agglayer.Certificate, error) { if len(bridges) == 0 && len(claims) == 0 { return nil, errNoBridgesAndClaims } diff --git a/aggsender/aggsender_test.go b/aggsender/aggsender_test.go index e55422e05..9a73c7ae8 100644 --- a/aggsender/aggsender_test.go +++ b/aggsender/aggsender_test.go @@ -27,12 +27,19 @@ import ( func TestExploratoryGetCertificateHeader(t *testing.T) { t.Skip("This test is exploratory and should be skipped") - aggLayerClient := agglayer.NewAggLayerClient("http://localhost:32795") + aggLayerClient := agglayer.NewAggLayerClient("http://localhost:32796") certificateID := common.HexToHash("0xf153e75e24591432ac5deafaeaafba3fec0fd851261c86051b9c0d540b38c369") certificateHeader, err := aggLayerClient.GetCertificateHeader(certificateID) require.NoError(t, err) fmt.Print(certificateHeader) } +func TestExploratoryGetClockConfiguration(t *testing.T) { + t.Skip("This test is exploratory and should be skipped") + aggLayerClient := agglayer.NewAggLayerClient("http://localhost:32796") + clockConfig, err := aggLayerClient.GetClockConfiguration() + require.NoError(t, err) + fmt.Print(clockConfig) +} func TestConfigString(t *testing.T) { config := Config{ @@ -274,7 +281,8 @@ func TestGetImportedBridgeExits(t *testing.T) { t.Parallel() mockProof := generateTestProof(t) - mockL1InfoTreeSyncer := mocks.NewL1InfoTreeSyncerMock(t) + + mockL1InfoTreeSyncer := mocks.NewL1InfoTreeSyncer(t) mockL1InfoTreeSyncer.On("GetInfoByGlobalExitRoot", mock.Anything).Return(&l1infotreesync.L1InfoTreeLeaf{ L1InfoTreeIndex: 1, Timestamp: 123456789, @@ -507,8 +515,8 @@ func TestGetImportedBridgeExits(t *testing.T) { } func TestBuildCertificate(t *testing.T) { - mockL2BridgeSyncer := mocks.NewL2BridgeSyncerMock(t) - mockL1InfoTreeSyncer := mocks.NewL1InfoTreeSyncerMock(t) + mockL2BridgeSyncer := mocks.NewL2BridgeSyncer(t) + mockL1InfoTreeSyncer := mocks.NewL1InfoTreeSyncer(t) mockProof := generateTestProof(t) tests := []struct { @@ -822,7 +830,7 @@ func TestCheckIfCertificatesAreSettled(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - mockStorage := mocks.NewAggSenderStorageMock(t) + mockStorage := mocks.NewAggSenderStorage(t) mockAggLayerClient := agglayer.NewAgglayerClientMock(t) mockLogger := log.WithFields("test", "unittest") @@ -885,18 +893,18 @@ func TestSendCertificate(t *testing.T) { expectedError string } - setupTest := func(cfg testCfg) (*AggSender, *mocks.AggSenderStorageMock, *mocks.L2BridgeSyncerMock, - *agglayer.AgglayerClientMock, *mocks.L1InfoTreeSyncerMock) { + setupTest := func(cfg testCfg) (*AggSender, *mocks.AggSenderStorage, *mocks.L2BridgeSyncer, + *agglayer.AgglayerClientMock, *mocks.L1InfoTreeSyncer) { var ( aggsender = &AggSender{ log: log.WithFields("aggsender", 1), cfg: Config{}, sequencerKey: cfg.sequencerKey, } - mockStorage *mocks.AggSenderStorageMock - mockL2Syncer *mocks.L2BridgeSyncerMock + mockStorage *mocks.AggSenderStorage + mockL2Syncer *mocks.L2BridgeSyncer mockAggLayerClient *agglayer.AgglayerClientMock - mockL1InfoTreeSyncer *mocks.L1InfoTreeSyncerMock + mockL1InfoTreeSyncer *mocks.L1InfoTreeSyncer ) if cfg.shouldSendCertificate != nil || cfg.getLastSentCertificate != nil || @@ -918,7 +926,7 @@ func TestSendCertificate(t *testing.T) { if cfg.lastL2BlockProcessed != nil || cfg.originNetwork != nil || cfg.getBridges != nil || cfg.getClaims != nil || cfg.getInfoByGlobalExitRoot != nil { - mockL2Syncer = mocks.NewL2BridgeSyncerMock(t) + mockL2Syncer = mocks.NewL2BridgeSyncer(t) mockL2Syncer.On("GetLastProcessedBlock", mock.Anything).Return(cfg.lastL2BlockProcessed...).Once() @@ -950,7 +958,7 @@ func TestSendCertificate(t *testing.T) { if cfg.getInfoByGlobalExitRoot != nil || cfg.getL1InfoTreeRootByIndex != nil || cfg.getL1InfoTreeMerkleProofFromIndexToRoot != nil { - mockL1InfoTreeSyncer = mocks.NewL1InfoTreeSyncerMock(t) + mockL1InfoTreeSyncer = mocks.NewL1InfoTreeSyncer(t) mockL1InfoTreeSyncer.On("GetInfoByGlobalExitRoot", mock.Anything).Return(cfg.getInfoByGlobalExitRoot...).Once() if cfg.getL1InfoTreeRootByIndex != nil { diff --git a/aggsender/block_notifier_polling.go b/aggsender/block_notifier_polling.go new file mode 100644 index 000000000..47618d543 --- /dev/null +++ b/aggsender/block_notifier_polling.go @@ -0,0 +1,195 @@ +package aggsender + +import ( + "context" + "fmt" + "math/big" + "sync" + "time" + + "github.com/0xPolygon/cdk/aggsender/types" + "github.com/0xPolygon/cdk/etherman" +) + +var ( + timeNowFunc = time.Now +) + +const ( + AutomaticBlockInterval = time.Second * 0 + // minBlockInterval is the minimum interval at which the AggSender will check for new blocks + minBlockInterval = time.Second + // maxBlockInterval is the maximum interval at which the AggSender will check for new blocks + maxBlockInterval = time.Minute +) + +type ConfigBlockNotifierPolling struct { + // BlockFinalityType is the finality of the block to be notified + BlockFinalityType etherman.BlockNumberFinality + // CheckNewBlockInterval is the interval at which the AggSender will check for new blocks + // if is 0 it will be calculated automatically + CheckNewBlockInterval time.Duration +} + +type BlockNotifierPolling struct { + ethClient types.EthClient + blockFinality *big.Int + logger types.Logger + config ConfigBlockNotifierPolling + mu sync.Mutex + lastStatus *blockNotifierPollingInternalStatus + types.GenericSubscriber[types.EventNewBlock] +} + +// NewBlockNotifierPolling creates a new BlockNotifierPolling. +// if param `subscriber` is nil a new GenericSubscriberImpl[types.EventNewBlock] will be created. +// To use this class you need to subscribe and each time that a new block appear the subscriber +// +// will be notified through the channel. (check unit tests TestExploratoryBlockNotifierPolling +// +// for more information) +func NewBlockNotifierPolling(ethClient types.EthClient, + config ConfigBlockNotifierPolling, + logger types.Logger, + subscriber types.GenericSubscriber[types.EventNewBlock]) (*BlockNotifierPolling, error) { + if subscriber == nil { + subscriber = NewGenericSubscriberImpl[types.EventNewBlock]() + } + finality, err := config.BlockFinalityType.ToBlockNum() + if err != nil { + return nil, fmt.Errorf("failed to convert block finality type to block number: %w", err) + } + + return &BlockNotifierPolling{ + ethClient: ethClient, + blockFinality: finality, + logger: logger, + config: config, + GenericSubscriber: subscriber, + }, nil +} + +func (b *BlockNotifierPolling) String() string { + status := b.getGlobalStatus() + res := fmt.Sprintf("BlockNotifierPolling: finality=%s", b.config.BlockFinalityType) + if status != nil { + res += fmt.Sprintf(" lastBlockSeen=%d", status.lastBlockSeen) + } else { + res += " lastBlockSeen=none" + } + return res +} + +// StartAsync starts the BlockNotifierPolling in a new goroutine +func (b *BlockNotifierPolling) StartAsync(ctx context.Context) { + go b.Start(ctx) +} + +// Start starts the BlockNotifierPolling blocking the current goroutine +func (b *BlockNotifierPolling) Start(ctx context.Context) { + ticker := time.NewTimer(b.config.CheckNewBlockInterval) + defer ticker.Stop() + + var status *blockNotifierPollingInternalStatus = nil + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + delay, newStatus := b.step(ctx, status) + status = newStatus + b.setGlobalStatus(status) + b.logger.Debugf("Next block request in %s", delay) + ticker.Reset(delay) + } + } +} + +func (b *BlockNotifierPolling) setGlobalStatus(status *blockNotifierPollingInternalStatus) { + b.mu.Lock() + defer b.mu.Unlock() + b.lastStatus = status +} + +func (b *BlockNotifierPolling) getGlobalStatus() *blockNotifierPollingInternalStatus { + b.mu.Lock() + defer b.mu.Unlock() + if b.lastStatus == nil { + return nil + } + copyStatus := *b.lastStatus + return ©Status +} + +func (b *BlockNotifierPolling) step(ctx context.Context, + status *blockNotifierPollingInternalStatus) (time.Duration, *blockNotifierPollingInternalStatus) { + currentBlock, err := b.ethClient.HeaderByNumber(ctx, b.blockFinality) + if err != nil || currentBlock == nil { + b.logger.Errorf("Failed to get block number: %v", err) + return b.nextBlockRequestDelay(status, err), status + } + b.logger.Debugf("Current block [finality:%s]: %d", b.config.BlockFinalityType, currentBlock.Number.Uint64()) + if status == nil { + status = &blockNotifierPollingInternalStatus{ + lastBlockSeen: currentBlock.Number.Uint64(), + lastBlockTime: timeNowFunc(), + } + return b.nextBlockRequestDelay(status, nil), status + } + + if currentBlock.Number.Uint64() != status.lastBlockSeen { + b.logger.Debugf("New block seen [finality:%s]: %d", b.config.BlockFinalityType, currentBlock.Number.Uint64()) + b.Publish(types.EventNewBlock{ + BlockNumber: currentBlock.Number.Uint64(), + BlockFinalityType: b.config.BlockFinalityType, + }) + if currentBlock.Number.Uint64()-status.lastBlockSeen != 1 { + b.logger.Warnf("Missed block(s) [finality:%s]: %d -> %d", + b.config.BlockFinalityType, status.lastBlockSeen, currentBlock.Number.Uint64()) + status.previousBlockTime = nil + return b.nextBlockRequestDelay(status, nil), status + } + status.lastBlockSeen = currentBlock.Number.Uint64() + now := timeNowFunc() + timePreviousBlock := now.Sub(status.lastBlockTime) + status.previousBlockTime = &timePreviousBlock + status.lastBlockTime = now + b.logger.Debugf("New block seen [finality:%s]: %d. blockRate:%s", + b.config.BlockFinalityType, currentBlock.Number.Uint64(), status.previousBlockTime) + } + return b.nextBlockRequestDelay(status, nil), status +} + +func (b *BlockNotifierPolling) nextBlockRequestDelay(status *blockNotifierPollingInternalStatus, + err error) time.Duration { + if b.config.CheckNewBlockInterval == AutomaticBlockInterval { + if status == nil { + return minBlockInterval + } + if status.previousBlockTime == nil { + // First interation is done with maximum precision + return minBlockInterval + } + if status.previousBlockTime != nil { + now := timeNowFunc() + expectedTimeNextBlock := status.lastBlockTime.Add(*status.previousBlockTime) + distanceToNextBlock := expectedTimeNextBlock.Sub(now) + interval := distanceToNextBlock * 4 / 5 //nolint:mnd // 80% of for reach the next block + b.logger.Debugf("Next block request delay: %s. distanceToNextBlock=%s", interval, distanceToNextBlock) + return max(minBlockInterval, min(maxBlockInterval, interval)) + } + } + if err == nil { + return b.config.CheckNewBlockInterval + } + // If error we wait twice the interval + return b.config.CheckNewBlockInterval * 2 //nolint:mnd // 2 times the interval +} + +type blockNotifierPollingInternalStatus struct { + lastBlockSeen uint64 + lastBlockTime time.Time // first appear of block lastBlockSeen + previousBlockTime *time.Duration // time of the previous block to appear + +} diff --git a/aggsender/block_notifier_polling_test.go b/aggsender/block_notifier_polling_test.go new file mode 100644 index 000000000..233ba5782 --- /dev/null +++ b/aggsender/block_notifier_polling_test.go @@ -0,0 +1,121 @@ +package aggsender + +import ( + "context" + "fmt" + "math/big" + "os" + "testing" + "time" + + "github.com/0xPolygon/cdk/aggsender/mocks" + "github.com/0xPolygon/cdk/etherman" + "github.com/0xPolygon/cdk/log" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func TestExploratoryBlockNotifierPolling(t *testing.T) { + t.Skip() + urlRPCL1 := os.Getenv("L1URL") + fmt.Println("URL=", urlRPCL1) + ethClient, err := ethclient.Dial(urlRPCL1) + require.NoError(t, err) + + sut, errSut := NewBlockNotifierPolling(ethClient, + ConfigBlockNotifierPolling{ + BlockFinalityType: etherman.LatestBlock, + }, log.WithFields("test", "test"), nil) + require.NoError(t, errSut) + sut.StartAsync(context.Background()) + ch := sut.Subscribe("test") + for { + select { + case block := <-ch: + fmt.Println(block) + } + } +} +func TestDelayNoPreviousBLock(t *testing.T) { + testData := newBlockNotifierPollingTestData(t, nil) + status := blockNotifierPollingInternalStatus{ + lastBlockSeen: 100, + } + delay := testData.sut.nextBlockRequestDelay(&status, nil) + require.Equal(t, minBlockInterval, delay) +} + +func TestDelayBLock(t *testing.T) { + testData := newBlockNotifierPollingTestData(t, nil) + pt := time.Second * 10 + status := blockNotifierPollingInternalStatus{ + lastBlockSeen: 100, + previousBlockTime: &pt, + } + delay := testData.sut.nextBlockRequestDelay(&status, nil) + require.Equal(t, minBlockInterval, delay) +} + +func TestNewBlockNotifierPolling(t *testing.T) { + testData := newBlockNotifierPollingTestData(t, nil) + require.NotNil(t, testData.sut) + _, err := NewBlockNotifierPolling(testData.ethClientMock, ConfigBlockNotifierPolling{ + BlockFinalityType: etherman.BlockNumberFinality("invalid"), + }, log.WithFields("test", "test"), nil) + require.Error(t, err) +} + +func TestBlockNotifierPollingString(t *testing.T) { + testData := newBlockNotifierPollingTestData(t, nil) + require.NotEmpty(t, testData.sut.String()) + testData.sut.lastStatus = &blockNotifierPollingInternalStatus{ + lastBlockSeen: 100, + } + require.NotEmpty(t, testData.sut.String()) +} + +func TestBlockNotifierPollingStart(t *testing.T) { + testData := newBlockNotifierPollingTestData(t, nil) + ch := testData.sut.Subscribe("test") + hdr1 := &types.Header{ + Number: big.NewInt(100), + } + testData.ethClientMock.EXPECT().HeaderByNumber(mock.Anything, mock.Anything).Return(hdr1, nil).Once() + hdr2 := &types.Header{ + Number: big.NewInt(101), + } + testData.ethClientMock.EXPECT().HeaderByNumber(mock.Anything, mock.Anything).Return(hdr2, nil).Once() + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go testData.sut.Start(ctx) + block := <-ch + require.NotNil(t, block) + require.Equal(t, uint64(101), block.BlockNumber) +} + +type blockNotifierPollingTestData struct { + sut *BlockNotifierPolling + ethClientMock *mocks.EthClient + ctx context.Context +} + +func newBlockNotifierPollingTestData(t *testing.T, config *ConfigBlockNotifierPolling) blockNotifierPollingTestData { + t.Helper() + if config == nil { + config = &ConfigBlockNotifierPolling{ + BlockFinalityType: etherman.LatestBlock, + CheckNewBlockInterval: time.Second, + } + } + EthClientMock := mocks.NewEthClient(t) + logger := log.WithFields("test", "BlockNotifierPolling") + sut, err := NewBlockNotifierPolling(EthClientMock, *config, logger, nil) + require.NoError(t, err) + return blockNotifierPollingTestData{ + sut: sut, + ethClientMock: EthClientMock, + ctx: context.TODO(), + } +} diff --git a/aggsender/config.go b/aggsender/config.go index 4ff78f96b..ec2c92b02 100644 --- a/aggsender/config.go +++ b/aggsender/config.go @@ -18,18 +18,11 @@ type Config struct { AggsenderPrivateKey types.KeystoreFileConfig `mapstructure:"AggsenderPrivateKey"` // URLRPCL2 is the URL of the L2 RPC node URLRPCL2 string `mapstructure:"URLRPCL2"` - // SaveCertificatesToFilesPath if != "" tells the AggSender to save the certificates to a file in this path - SaveCertificatesToFilesPath string `mapstructure:"SaveCertificatesToFilesPath"` -} - -// String returns a string representation of the Config -func (c Config) String() string { - return "StoragePath: " + c.StoragePath + "\n" + - "AggLayerURL: " + c.AggLayerURL + "\n" + - "BlockGetInterval: " + c.BlockGetInterval.String() + "\n" + - "CheckSettledInterval: " + c.CheckSettledInterval.String() + "\n" + - "AggsenderPrivateKeyPath: " + c.AggsenderPrivateKey.Path + "\n" + - "AggsenderPrivateKeyPassword: " + c.AggsenderPrivateKey.Password + "\n" + - "URLRPCL2: " + c.URLRPCL2 + "\n" + - "SaveCertificatesToFilesPath: " + c.SaveCertificatesToFilesPath + "\n" + // BlockFinality indicates which finality follows AggLayer + BlockFinality string `jsonschema:"enum=LatestBlock, enum=SafeBlock, enum=PendingBlock, enum=FinalizedBlock, enum=EarliestBlock" mapstructure:"BlockFinality"` //nolint:lll + // BlocksBeforeEpochEnding indicates how many blocks before the epoch ending + // the AggSender should send the certificate + BlocksBeforeEpochEnding uint `mapstructure:"BlocksBeforeEpochEnding"` + // SaveCertificatesToFiles is a flag which tells the AggSender to save the certificates to a file + SaveCertificatesToFiles bool `mapstructure:"SaveCertificatesToFiles"` } diff --git a/aggsender/epoch_notifier_per_block.go b/aggsender/epoch_notifier_per_block.go new file mode 100644 index 000000000..f145003b9 --- /dev/null +++ b/aggsender/epoch_notifier_per_block.go @@ -0,0 +1,184 @@ +package aggsender + +import ( + "context" + "fmt" + + "github.com/0xPolygon/cdk/agglayer" + "github.com/0xPolygon/cdk/aggsender/types" +) + +type ExtraInfoEventEpoch struct { + PendingBlocks int +} + +func (e *ExtraInfoEventEpoch) String() string { + return fmt.Sprintf("ExtraInfoEventEpoch: pendingBlocks=%d", e.PendingBlocks) +} + +type ConfigEpochNotifierPerBlock struct { + StartingEpochBlock uint64 + NumBlockPerEpoch uint + + // Num blocks before the end of the epoch to notify it + NotifyPendingBlocksBeforeEndEpoch uint +} + +func NewConfigEpochNotifierPerBlock(aggLayer agglayer.AggLayerClientGetClockConfiguration, + notifyPendingBlocksBeforeEndEpoch uint) (*ConfigEpochNotifierPerBlock, error) { + if aggLayer == nil { + return nil, fmt.Errorf("newConfigEpochNotifierPerBlock: aggLayerClient is required") + } + clockConfig, err := aggLayer.GetClockConfiguration() + if err != nil { + return nil, fmt.Errorf("newConfigEpochNotifierPerBlock: error getting clock configuration from AggLayer: %w", err) + } + return &ConfigEpochNotifierPerBlock{ + StartingEpochBlock: clockConfig.GenesisBlock, + NumBlockPerEpoch: uint(clockConfig.EpochDuration), + NotifyPendingBlocksBeforeEndEpoch: notifyPendingBlocksBeforeEndEpoch, + }, nil +} + +func (c *ConfigEpochNotifierPerBlock) Validate() error { + if c.NumBlockPerEpoch == 0 { + return fmt.Errorf("numBlockPerEpoch: num block per epoch is required > 0 ") + } + if c.NumBlockPerEpoch-c.NotifyPendingBlocksBeforeEndEpoch == 0 { + return fmt.Errorf("notifyPendingBlocksBeforeEndEpoch: Notify before num blocks end of epoch is required > 0") + } + return nil +} + +type EpochNotifierPerBlock struct { + blockNotifier types.BlockNotifier + logger types.Logger + + lastStartingEpochBlock uint64 + + Config ConfigEpochNotifierPerBlock + types.GenericSubscriber[types.EpochEvent] +} + +func NewEpochNotifierPerBlock(blockNotifier types.BlockNotifier, + logger types.Logger, + config ConfigEpochNotifierPerBlock, + subscriber types.GenericSubscriber[types.EpochEvent]) (*EpochNotifierPerBlock, error) { + if subscriber == nil { + subscriber = NewGenericSubscriberImpl[types.EpochEvent]() + } + + err := config.Validate() + if err != nil { + return nil, fmt.Errorf("invalid config: %w", err) + } + return &EpochNotifierPerBlock{ + blockNotifier: blockNotifier, + logger: logger, + lastStartingEpochBlock: config.StartingEpochBlock, + Config: config, + GenericSubscriber: subscriber, + }, nil +} + +func (e *EpochNotifierPerBlock) String() string { + return fmt.Sprintf("EpochNotifierPerBlock: startingEpochBlock=%d, numBlockPerEpoch=%d,"+ + " notifyPendingBlocksBeforeEndEpoch=%d", + e.Config.StartingEpochBlock, e.Config.NumBlockPerEpoch, e.Config.NotifyPendingBlocksBeforeEndEpoch) +} + +// StartAsync starts the notifier in a goroutine +func (e *EpochNotifierPerBlock) StartAsync(ctx context.Context) { + eventNewBlockChannel := e.blockNotifier.Subscribe("EpochNotifierPerBlock") + go e.startInternal(ctx, eventNewBlockChannel) +} + +// Start starts the notifier synchronously +func (e *EpochNotifierPerBlock) Start(ctx context.Context) { + eventNewBlockChannel := e.blockNotifier.Subscribe("EpochNotifierPerBlock") + e.startInternal(ctx, eventNewBlockChannel) +} + +func (e *EpochNotifierPerBlock) startInternal(ctx context.Context, eventNewBlockChannel <-chan types.EventNewBlock) { + status := internalStatus{ + lastBlockSeen: e.Config.StartingEpochBlock, + waitingForEpoch: e.epochNumber(e.Config.StartingEpochBlock), + } + for { + select { + case <-ctx.Done(): + return + case newBlock := <-eventNewBlockChannel: + var event *types.EpochEvent + status, event = e.step(status, newBlock) + if event != nil { + e.logger.Infof("new Epoch Event: %s", event.String()) + e.GenericSubscriber.Publish(*event) + } + } + } +} + +type internalStatus struct { + lastBlockSeen uint64 + waitingForEpoch uint64 +} + +func (e *EpochNotifierPerBlock) step(status internalStatus, + newBlock types.EventNewBlock) (internalStatus, *types.EpochEvent) { + currentBlock := newBlock.BlockNumber + if currentBlock < e.Config.StartingEpochBlock { + // This is a bit strange, the first epoch is in the future + e.logger.Warnf("Block number %d is before the starting first epoch block %d."+ + " Please check your config", currentBlock, e.Config.StartingEpochBlock) + return status, nil + } + // No new block + if currentBlock <= status.lastBlockSeen { + return status, nil + } + status.lastBlockSeen = currentBlock + + needNotify, closingEpoch := e.isClosingEpochBlock(currentBlock, status.waitingForEpoch) + if needNotify { + // Notify the epoch has started + info := e.infoEpoch(currentBlock, closingEpoch) + if status.waitingForEpoch == 0 && info.PendingBlocks > int(e.Config.NotifyPendingBlocksBeforeEndEpoch) { + // We are in the first epoch, but we are not near the end of the epoch + return status, nil + } + status.waitingForEpoch = closingEpoch + 1 + return status, &types.EpochEvent{ + Epoch: closingEpoch, + ExtraInfo: info, + } + } + return status, nil +} + +func (e *EpochNotifierPerBlock) infoEpoch(currentBlock, newEpochNotified uint64) *ExtraInfoEventEpoch { + nextBlockStartingEpoch := e.endBlockEpoch(newEpochNotified) + return &ExtraInfoEventEpoch{ + PendingBlocks: int(nextBlockStartingEpoch - currentBlock), + } +} +func (e *EpochNotifierPerBlock) isClosingEpochBlock(currentBlock, lastEpochNotified uint64) (bool, uint64) { + nextEpoch := e.epochNumber(currentBlock + uint64(e.Config.NotifyPendingBlocksBeforeEndEpoch)) + return nextEpoch > lastEpochNotified, e.epochNumber(currentBlock) +} +func (e *EpochNotifierPerBlock) startingBlockEpoch(epoch uint64) uint64 { + if epoch == 0 { + return e.Config.StartingEpochBlock - 1 + } + return e.Config.StartingEpochBlock + ((epoch - 1) * uint64(e.Config.NumBlockPerEpoch)) +} + +func (e *EpochNotifierPerBlock) endBlockEpoch(epoch uint64) uint64 { + return e.startingBlockEpoch(epoch + 1) +} +func (e *EpochNotifierPerBlock) epochNumber(currentBlock uint64) uint64 { + if currentBlock < e.Config.StartingEpochBlock { + return 0 + } + return 1 + ((currentBlock - e.Config.StartingEpochBlock) / uint64(e.Config.NumBlockPerEpoch)) +} diff --git a/aggsender/epoch_notifier_per_block_test.go b/aggsender/epoch_notifier_per_block_test.go new file mode 100644 index 000000000..ef28c6659 --- /dev/null +++ b/aggsender/epoch_notifier_per_block_test.go @@ -0,0 +1,201 @@ +package aggsender + +import ( + "context" + "fmt" + "testing" + + "github.com/0xPolygon/cdk/agglayer" + "github.com/0xPolygon/cdk/aggsender/mocks" + "github.com/0xPolygon/cdk/aggsender/types" + "github.com/0xPolygon/cdk/etherman" + "github.com/0xPolygon/cdk/log" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func TestStartingBlockEpoch(t *testing.T) { + testData := newNotifierPerBlockTestData(t, &ConfigEpochNotifierPerBlock{ + StartingEpochBlock: 9, + NumBlockPerEpoch: 10, + NotifyPendingBlocksBeforeEndEpoch: 1, + }) + // EPOCH: ---0 ----+----1 -----+----2 ----+----3 ----+----4 ----+----5 ----+---- + // BLOCK: 9 19 29 39 49 + require.Equal(t, uint64(8), testData.sut.startingBlockEpoch(0)) + require.Equal(t, uint64(9), testData.sut.startingBlockEpoch(1)) + require.Equal(t, uint64(19), testData.sut.startingBlockEpoch(2)) +} + +func TestEpochStep(t *testing.T) { + testData := newNotifierPerBlockTestData(t, &ConfigEpochNotifierPerBlock{ + StartingEpochBlock: 9, + NumBlockPerEpoch: 10, + NotifyPendingBlocksBeforeEndEpoch: 1, + }) + // EPOCH: ---0 ----+----1 -----+----2 ----+----3 ----+----4 ----+----5 ----+---- + // BLOCK: 9 19 29 39 49 + // start EPOCH#1 -> 9 + // end EPOCH#1 -> 19 + // start EPOCH#2 -> 19 + + tests := []struct { + name string + initialStatus internalStatus + blockNumber uint64 + expectedEvent bool + expectedEventEpoch uint64 + expectedEventPendingBlocks int + }{ + { + name: "First block of epoch, no notification until close to end", + initialStatus: internalStatus{lastBlockSeen: 8, waitingForEpoch: 0}, + blockNumber: 9, + expectedEvent: false, + expectedEventEpoch: 1, + expectedEventPendingBlocks: 0, + }, + { + name: "epoch#1 close to end, notify it!", + initialStatus: internalStatus{lastBlockSeen: 17, waitingForEpoch: 0}, + blockNumber: 18, + expectedEvent: true, + expectedEventEpoch: 1, // Finishing epoch 0 + expectedEventPendingBlocks: 1, // 19 - 18 + }, + { + name: "epoch#1 close to end, but already notified", + initialStatus: internalStatus{lastBlockSeen: 17, waitingForEpoch: 2}, + blockNumber: 18, + expectedEvent: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, event := testData.sut.step(tt.initialStatus, types.EventNewBlock{BlockNumber: tt.blockNumber, BlockFinalityType: etherman.LatestBlock}) + require.Equal(t, tt.expectedEvent, event != nil) + if event != nil { + require.Equal(t, tt.expectedEventEpoch, event.Epoch, "Epoch") + extraInfo, ok := event.ExtraInfo.(*ExtraInfoEventEpoch) + require.True(t, ok, "ExtraInfo") + require.Equal(t, tt.expectedEventPendingBlocks, extraInfo.PendingBlocks, "PendingBlocks") + } + }) + } +} + +func TestNewConfigEpochNotifierPerBlock(t *testing.T) { + _, err := NewConfigEpochNotifierPerBlock(nil, 1) + require.Error(t, err) + aggLayerMock := agglayer.NewAgglayerClientMock(t) + aggLayerMock.On("GetClockConfiguration").Return(nil, fmt.Errorf("error")).Once() + _, err = NewConfigEpochNotifierPerBlock(aggLayerMock, 1) + require.Error(t, err) + cfgAggLayer := &agglayer.ClockConfiguration{ + GenesisBlock: 123, + EpochDuration: 456, + } + aggLayerMock.On("GetClockConfiguration").Return(cfgAggLayer, nil).Once() + cfg, err := NewConfigEpochNotifierPerBlock(aggLayerMock, 1) + require.NoError(t, err) + require.Equal(t, uint64(123), cfg.StartingEpochBlock) + require.Equal(t, uint(456), cfg.NumBlockPerEpoch) +} + +func TestNotifyEpoch(t *testing.T) { + testData := newNotifierPerBlockTestData(t, nil) + ch := testData.sut.Subscribe("test") + chBlocks := make(chan types.EventNewBlock) + testData.blockNotifierMock.EXPECT().Subscribe(mock.Anything).Return(chBlocks) + testData.sut.StartAsync(testData.ctx) + chBlocks <- types.EventNewBlock{BlockNumber: 109, BlockFinalityType: etherman.LatestBlock} + epochEvent := <-ch + require.Equal(t, uint64(11), epochEvent.Epoch) + testData.ctx.Done() +} + +func TestStepSameEpoch(t *testing.T) { + testData := newNotifierPerBlockTestData(t, nil) + status := internalStatus{ + lastBlockSeen: 100, + waitingForEpoch: testData.sut.epochNumber(100), + } + newStatus, _ := testData.sut.step(status, types.EventNewBlock{BlockNumber: 103, BlockFinalityType: etherman.LatestBlock}) + require.Equal(t, uint64(103), newStatus.lastBlockSeen) + require.Equal(t, status.waitingForEpoch, newStatus.waitingForEpoch) +} + +func TestStepNotifyEpoch(t *testing.T) { + testData := newNotifierPerBlockTestData(t, nil) + status := internalStatus{ + lastBlockSeen: 100, + waitingForEpoch: testData.sut.epochNumber(100), + } + status, _ = testData.sut.step(status, types.EventNewBlock{BlockNumber: 109, BlockFinalityType: etherman.LatestBlock}) + require.Equal(t, uint64(109), status.lastBlockSeen) + require.Equal(t, uint64(12), status.waitingForEpoch) +} + +func TestBlockEpochNumber(t *testing.T) { + testData := newNotifierPerBlockTestData(t, &ConfigEpochNotifierPerBlock{ + StartingEpochBlock: 105, + NumBlockPerEpoch: 10, + NotifyPendingBlocksBeforeEndEpoch: 1, + }) + require.Equal(t, uint64(0), testData.sut.epochNumber(0)) + require.Equal(t, uint64(0), testData.sut.epochNumber(104)) + require.Equal(t, uint64(1), testData.sut.epochNumber(105)) + require.Equal(t, uint64(1), testData.sut.epochNumber(114)) + require.Equal(t, uint64(2), testData.sut.epochNumber(115)) + require.Equal(t, uint64(2), testData.sut.epochNumber(116)) + require.Equal(t, uint64(2), testData.sut.epochNumber(124)) + require.Equal(t, uint64(3), testData.sut.epochNumber(125)) +} + +func TestBlockBeforeEpoch(t *testing.T) { + testData := newNotifierPerBlockTestData(t, &ConfigEpochNotifierPerBlock{ + StartingEpochBlock: 105, + NumBlockPerEpoch: 10, + NotifyPendingBlocksBeforeEndEpoch: 1, + }) + status := internalStatus{ + lastBlockSeen: 104, + waitingForEpoch: testData.sut.epochNumber(104), + } + newStatus, _ := testData.sut.step(status, types.EventNewBlock{BlockNumber: 104, BlockFinalityType: etherman.LatestBlock}) + // We are previous block of first epoch, so we should do nothing + require.Equal(t, status, newStatus) + status = newStatus + // First block of first epoch + newStatus, _ = testData.sut.step(status, types.EventNewBlock{BlockNumber: 105, BlockFinalityType: etherman.LatestBlock}) + require.Equal(t, uint64(105), newStatus.lastBlockSeen) + // Near end first epoch + newStatus, _ = testData.sut.step(status, types.EventNewBlock{BlockNumber: 114, BlockFinalityType: etherman.LatestBlock}) + require.Equal(t, uint64(114), newStatus.lastBlockSeen) +} + +type notifierPerBlockTestData struct { + sut *EpochNotifierPerBlock + blockNotifierMock *mocks.BlockNotifier + ctx context.Context +} + +func newNotifierPerBlockTestData(t *testing.T, config *ConfigEpochNotifierPerBlock) notifierPerBlockTestData { + t.Helper() + if config == nil { + config = &ConfigEpochNotifierPerBlock{ + StartingEpochBlock: 0, + NumBlockPerEpoch: 10, + NotifyPendingBlocksBeforeEndEpoch: 1, + } + } + blockNotifierMock := mocks.NewBlockNotifier(t) + logger := log.WithFields("test", "EpochNotifierPerBlock") + sut, err := NewEpochNotifierPerBlock(blockNotifierMock, logger, *config, nil) + require.NoError(t, err) + return notifierPerBlockTestData{ + sut: sut, + blockNotifierMock: blockNotifierMock, + ctx: context.TODO(), + } +} diff --git a/aggsender/generic_subscriber_impl.go b/aggsender/generic_subscriber_impl.go new file mode 100644 index 000000000..e4251449d --- /dev/null +++ b/aggsender/generic_subscriber_impl.go @@ -0,0 +1,33 @@ +package aggsender + +import "sync" + +type GenericSubscriberImpl[T any] struct { + // map of subscribers with names + subs map[chan T]string + mu sync.RWMutex +} + +func NewGenericSubscriberImpl[T any]() *GenericSubscriberImpl[T] { + return &GenericSubscriberImpl[T]{ + subs: make(map[chan T]string), + } +} + +func (g *GenericSubscriberImpl[T]) Subscribe(subscriberName string) <-chan T { + ch := make(chan T) + g.mu.Lock() + defer g.mu.Unlock() + g.subs[ch] = subscriberName + return ch +} + +func (g *GenericSubscriberImpl[T]) Publish(data T) { + g.mu.RLock() + defer g.mu.RUnlock() + for ch := range g.subs { + go func(ch chan T) { + ch <- data + }(ch) + } +} diff --git a/aggsender/mocks/agg_sender_storage.go b/aggsender/mocks/agg_sender_storage.go new file mode 100644 index 000000000..2f9a9e8ea --- /dev/null +++ b/aggsender/mocks/agg_sender_storage.go @@ -0,0 +1,354 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + agglayer "github.com/0xPolygon/cdk/agglayer" + common "github.com/ethereum/go-ethereum/common" + + context "context" + + mock "github.com/stretchr/testify/mock" + + types "github.com/0xPolygon/cdk/aggsender/types" +) + +// AggSenderStorage is an autogenerated mock type for the AggSenderStorage type +type AggSenderStorage struct { + mock.Mock +} + +type AggSenderStorage_Expecter struct { + mock *mock.Mock +} + +func (_m *AggSenderStorage) EXPECT() *AggSenderStorage_Expecter { + return &AggSenderStorage_Expecter{mock: &_m.Mock} +} + +// DeleteCertificate provides a mock function with given fields: ctx, certificateID +func (_m *AggSenderStorage) DeleteCertificate(ctx context.Context, certificateID common.Hash) error { + ret := _m.Called(ctx, certificateID) + + if len(ret) == 0 { + panic("no return value specified for DeleteCertificate") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, common.Hash) error); ok { + r0 = rf(ctx, certificateID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// AggSenderStorage_DeleteCertificate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteCertificate' +type AggSenderStorage_DeleteCertificate_Call struct { + *mock.Call +} + +// DeleteCertificate is a helper method to define mock.On call +// - ctx context.Context +// - certificateID common.Hash +func (_e *AggSenderStorage_Expecter) DeleteCertificate(ctx interface{}, certificateID interface{}) *AggSenderStorage_DeleteCertificate_Call { + return &AggSenderStorage_DeleteCertificate_Call{Call: _e.mock.On("DeleteCertificate", ctx, certificateID)} +} + +func (_c *AggSenderStorage_DeleteCertificate_Call) Run(run func(ctx context.Context, certificateID common.Hash)) *AggSenderStorage_DeleteCertificate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(common.Hash)) + }) + return _c +} + +func (_c *AggSenderStorage_DeleteCertificate_Call) Return(_a0 error) *AggSenderStorage_DeleteCertificate_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *AggSenderStorage_DeleteCertificate_Call) RunAndReturn(run func(context.Context, common.Hash) error) *AggSenderStorage_DeleteCertificate_Call { + _c.Call.Return(run) + return _c +} + +// GetCertificateByHeight provides a mock function with given fields: ctx, height +func (_m *AggSenderStorage) GetCertificateByHeight(ctx context.Context, height uint64) (types.CertificateInfo, error) { + ret := _m.Called(ctx, height) + + if len(ret) == 0 { + panic("no return value specified for GetCertificateByHeight") + } + + var r0 types.CertificateInfo + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64) (types.CertificateInfo, error)); ok { + return rf(ctx, height) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64) types.CertificateInfo); ok { + r0 = rf(ctx, height) + } else { + r0 = ret.Get(0).(types.CertificateInfo) + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64) error); ok { + r1 = rf(ctx, height) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AggSenderStorage_GetCertificateByHeight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCertificateByHeight' +type AggSenderStorage_GetCertificateByHeight_Call struct { + *mock.Call +} + +// GetCertificateByHeight is a helper method to define mock.On call +// - ctx context.Context +// - height uint64 +func (_e *AggSenderStorage_Expecter) GetCertificateByHeight(ctx interface{}, height interface{}) *AggSenderStorage_GetCertificateByHeight_Call { + return &AggSenderStorage_GetCertificateByHeight_Call{Call: _e.mock.On("GetCertificateByHeight", ctx, height)} +} + +func (_c *AggSenderStorage_GetCertificateByHeight_Call) Run(run func(ctx context.Context, height uint64)) *AggSenderStorage_GetCertificateByHeight_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64)) + }) + return _c +} + +func (_c *AggSenderStorage_GetCertificateByHeight_Call) Return(_a0 types.CertificateInfo, _a1 error) *AggSenderStorage_GetCertificateByHeight_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AggSenderStorage_GetCertificateByHeight_Call) RunAndReturn(run func(context.Context, uint64) (types.CertificateInfo, error)) *AggSenderStorage_GetCertificateByHeight_Call { + _c.Call.Return(run) + return _c +} + +// GetCertificatesByStatus provides a mock function with given fields: ctx, status +func (_m *AggSenderStorage) GetCertificatesByStatus(ctx context.Context, status []agglayer.CertificateStatus) ([]*types.CertificateInfo, error) { + ret := _m.Called(ctx, status) + + if len(ret) == 0 { + panic("no return value specified for GetCertificatesByStatus") + } + + var r0 []*types.CertificateInfo + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, []agglayer.CertificateStatus) ([]*types.CertificateInfo, error)); ok { + return rf(ctx, status) + } + if rf, ok := ret.Get(0).(func(context.Context, []agglayer.CertificateStatus) []*types.CertificateInfo); ok { + r0 = rf(ctx, status) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*types.CertificateInfo) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, []agglayer.CertificateStatus) error); ok { + r1 = rf(ctx, status) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AggSenderStorage_GetCertificatesByStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCertificatesByStatus' +type AggSenderStorage_GetCertificatesByStatus_Call struct { + *mock.Call +} + +// GetCertificatesByStatus is a helper method to define mock.On call +// - ctx context.Context +// - status []agglayer.CertificateStatus +func (_e *AggSenderStorage_Expecter) GetCertificatesByStatus(ctx interface{}, status interface{}) *AggSenderStorage_GetCertificatesByStatus_Call { + return &AggSenderStorage_GetCertificatesByStatus_Call{Call: _e.mock.On("GetCertificatesByStatus", ctx, status)} +} + +func (_c *AggSenderStorage_GetCertificatesByStatus_Call) Run(run func(ctx context.Context, status []agglayer.CertificateStatus)) *AggSenderStorage_GetCertificatesByStatus_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].([]agglayer.CertificateStatus)) + }) + return _c +} + +func (_c *AggSenderStorage_GetCertificatesByStatus_Call) Return(_a0 []*types.CertificateInfo, _a1 error) *AggSenderStorage_GetCertificatesByStatus_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AggSenderStorage_GetCertificatesByStatus_Call) RunAndReturn(run func(context.Context, []agglayer.CertificateStatus) ([]*types.CertificateInfo, error)) *AggSenderStorage_GetCertificatesByStatus_Call { + _c.Call.Return(run) + return _c +} + +// GetLastSentCertificate provides a mock function with given fields: ctx +func (_m *AggSenderStorage) GetLastSentCertificate(ctx context.Context) (types.CertificateInfo, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetLastSentCertificate") + } + + var r0 types.CertificateInfo + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (types.CertificateInfo, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) types.CertificateInfo); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(types.CertificateInfo) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AggSenderStorage_GetLastSentCertificate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLastSentCertificate' +type AggSenderStorage_GetLastSentCertificate_Call struct { + *mock.Call +} + +// GetLastSentCertificate is a helper method to define mock.On call +// - ctx context.Context +func (_e *AggSenderStorage_Expecter) GetLastSentCertificate(ctx interface{}) *AggSenderStorage_GetLastSentCertificate_Call { + return &AggSenderStorage_GetLastSentCertificate_Call{Call: _e.mock.On("GetLastSentCertificate", ctx)} +} + +func (_c *AggSenderStorage_GetLastSentCertificate_Call) Run(run func(ctx context.Context)) *AggSenderStorage_GetLastSentCertificate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *AggSenderStorage_GetLastSentCertificate_Call) Return(_a0 types.CertificateInfo, _a1 error) *AggSenderStorage_GetLastSentCertificate_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AggSenderStorage_GetLastSentCertificate_Call) RunAndReturn(run func(context.Context) (types.CertificateInfo, error)) *AggSenderStorage_GetLastSentCertificate_Call { + _c.Call.Return(run) + return _c +} + +// SaveLastSentCertificate provides a mock function with given fields: ctx, certificate +func (_m *AggSenderStorage) SaveLastSentCertificate(ctx context.Context, certificate types.CertificateInfo) error { + ret := _m.Called(ctx, certificate) + + if len(ret) == 0 { + panic("no return value specified for SaveLastSentCertificate") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, types.CertificateInfo) error); ok { + r0 = rf(ctx, certificate) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// AggSenderStorage_SaveLastSentCertificate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SaveLastSentCertificate' +type AggSenderStorage_SaveLastSentCertificate_Call struct { + *mock.Call +} + +// SaveLastSentCertificate is a helper method to define mock.On call +// - ctx context.Context +// - certificate types.CertificateInfo +func (_e *AggSenderStorage_Expecter) SaveLastSentCertificate(ctx interface{}, certificate interface{}) *AggSenderStorage_SaveLastSentCertificate_Call { + return &AggSenderStorage_SaveLastSentCertificate_Call{Call: _e.mock.On("SaveLastSentCertificate", ctx, certificate)} +} + +func (_c *AggSenderStorage_SaveLastSentCertificate_Call) Run(run func(ctx context.Context, certificate types.CertificateInfo)) *AggSenderStorage_SaveLastSentCertificate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(types.CertificateInfo)) + }) + return _c +} + +func (_c *AggSenderStorage_SaveLastSentCertificate_Call) Return(_a0 error) *AggSenderStorage_SaveLastSentCertificate_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *AggSenderStorage_SaveLastSentCertificate_Call) RunAndReturn(run func(context.Context, types.CertificateInfo) error) *AggSenderStorage_SaveLastSentCertificate_Call { + _c.Call.Return(run) + return _c +} + +// UpdateCertificateStatus provides a mock function with given fields: ctx, certificate +func (_m *AggSenderStorage) UpdateCertificateStatus(ctx context.Context, certificate types.CertificateInfo) error { + ret := _m.Called(ctx, certificate) + + if len(ret) == 0 { + panic("no return value specified for UpdateCertificateStatus") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, types.CertificateInfo) error); ok { + r0 = rf(ctx, certificate) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// AggSenderStorage_UpdateCertificateStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateCertificateStatus' +type AggSenderStorage_UpdateCertificateStatus_Call struct { + *mock.Call +} + +// UpdateCertificateStatus is a helper method to define mock.On call +// - ctx context.Context +// - certificate types.CertificateInfo +func (_e *AggSenderStorage_Expecter) UpdateCertificateStatus(ctx interface{}, certificate interface{}) *AggSenderStorage_UpdateCertificateStatus_Call { + return &AggSenderStorage_UpdateCertificateStatus_Call{Call: _e.mock.On("UpdateCertificateStatus", ctx, certificate)} +} + +func (_c *AggSenderStorage_UpdateCertificateStatus_Call) Run(run func(ctx context.Context, certificate types.CertificateInfo)) *AggSenderStorage_UpdateCertificateStatus_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(types.CertificateInfo)) + }) + return _c +} + +func (_c *AggSenderStorage_UpdateCertificateStatus_Call) Return(_a0 error) *AggSenderStorage_UpdateCertificateStatus_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *AggSenderStorage_UpdateCertificateStatus_Call) RunAndReturn(run func(context.Context, types.CertificateInfo) error) *AggSenderStorage_UpdateCertificateStatus_Call { + _c.Call.Return(run) + return _c +} + +// NewAggSenderStorage creates a new instance of AggSenderStorage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewAggSenderStorage(t interface { + mock.TestingT + Cleanup(func()) +}) *AggSenderStorage { + mock := &AggSenderStorage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/aggsender/mocks/block_notifier.go b/aggsender/mocks/block_notifier.go new file mode 100644 index 000000000..f8fc556df --- /dev/null +++ b/aggsender/mocks/block_notifier.go @@ -0,0 +1,128 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + types "github.com/0xPolygon/cdk/aggsender/types" + mock "github.com/stretchr/testify/mock" +) + +// BlockNotifier is an autogenerated mock type for the BlockNotifier type +type BlockNotifier struct { + mock.Mock +} + +type BlockNotifier_Expecter struct { + mock *mock.Mock +} + +func (_m *BlockNotifier) EXPECT() *BlockNotifier_Expecter { + return &BlockNotifier_Expecter{mock: &_m.Mock} +} + +// String provides a mock function with given fields: +func (_m *BlockNotifier) String() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for String") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// BlockNotifier_String_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'String' +type BlockNotifier_String_Call struct { + *mock.Call +} + +// String is a helper method to define mock.On call +func (_e *BlockNotifier_Expecter) String() *BlockNotifier_String_Call { + return &BlockNotifier_String_Call{Call: _e.mock.On("String")} +} + +func (_c *BlockNotifier_String_Call) Run(run func()) *BlockNotifier_String_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *BlockNotifier_String_Call) Return(_a0 string) *BlockNotifier_String_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *BlockNotifier_String_Call) RunAndReturn(run func() string) *BlockNotifier_String_Call { + _c.Call.Return(run) + return _c +} + +// Subscribe provides a mock function with given fields: id +func (_m *BlockNotifier) Subscribe(id string) <-chan types.EventNewBlock { + ret := _m.Called(id) + + if len(ret) == 0 { + panic("no return value specified for Subscribe") + } + + var r0 <-chan types.EventNewBlock + if rf, ok := ret.Get(0).(func(string) <-chan types.EventNewBlock); ok { + r0 = rf(id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(<-chan types.EventNewBlock) + } + } + + return r0 +} + +// BlockNotifier_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe' +type BlockNotifier_Subscribe_Call struct { + *mock.Call +} + +// Subscribe is a helper method to define mock.On call +// - id string +func (_e *BlockNotifier_Expecter) Subscribe(id interface{}) *BlockNotifier_Subscribe_Call { + return &BlockNotifier_Subscribe_Call{Call: _e.mock.On("Subscribe", id)} +} + +func (_c *BlockNotifier_Subscribe_Call) Run(run func(id string)) *BlockNotifier_Subscribe_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *BlockNotifier_Subscribe_Call) Return(_a0 <-chan types.EventNewBlock) *BlockNotifier_Subscribe_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *BlockNotifier_Subscribe_Call) RunAndReturn(run func(string) <-chan types.EventNewBlock) *BlockNotifier_Subscribe_Call { + _c.Call.Return(run) + return _c +} + +// NewBlockNotifier creates a new instance of BlockNotifier. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewBlockNotifier(t interface { + mock.TestingT + Cleanup(func()) +}) *BlockNotifier { + mock := &BlockNotifier{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/aggsender/mocks/epoch_notifier.go b/aggsender/mocks/epoch_notifier.go new file mode 100644 index 000000000..bff8094f5 --- /dev/null +++ b/aggsender/mocks/epoch_notifier.go @@ -0,0 +1,128 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + types "github.com/0xPolygon/cdk/aggsender/types" + mock "github.com/stretchr/testify/mock" +) + +// EpochNotifier is an autogenerated mock type for the EpochNotifier type +type EpochNotifier struct { + mock.Mock +} + +type EpochNotifier_Expecter struct { + mock *mock.Mock +} + +func (_m *EpochNotifier) EXPECT() *EpochNotifier_Expecter { + return &EpochNotifier_Expecter{mock: &_m.Mock} +} + +// String provides a mock function with given fields: +func (_m *EpochNotifier) String() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for String") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// EpochNotifier_String_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'String' +type EpochNotifier_String_Call struct { + *mock.Call +} + +// String is a helper method to define mock.On call +func (_e *EpochNotifier_Expecter) String() *EpochNotifier_String_Call { + return &EpochNotifier_String_Call{Call: _e.mock.On("String")} +} + +func (_c *EpochNotifier_String_Call) Run(run func()) *EpochNotifier_String_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EpochNotifier_String_Call) Return(_a0 string) *EpochNotifier_String_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EpochNotifier_String_Call) RunAndReturn(run func() string) *EpochNotifier_String_Call { + _c.Call.Return(run) + return _c +} + +// Subscribe provides a mock function with given fields: id +func (_m *EpochNotifier) Subscribe(id string) <-chan types.EpochEvent { + ret := _m.Called(id) + + if len(ret) == 0 { + panic("no return value specified for Subscribe") + } + + var r0 <-chan types.EpochEvent + if rf, ok := ret.Get(0).(func(string) <-chan types.EpochEvent); ok { + r0 = rf(id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(<-chan types.EpochEvent) + } + } + + return r0 +} + +// EpochNotifier_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe' +type EpochNotifier_Subscribe_Call struct { + *mock.Call +} + +// Subscribe is a helper method to define mock.On call +// - id string +func (_e *EpochNotifier_Expecter) Subscribe(id interface{}) *EpochNotifier_Subscribe_Call { + return &EpochNotifier_Subscribe_Call{Call: _e.mock.On("Subscribe", id)} +} + +func (_c *EpochNotifier_Subscribe_Call) Run(run func(id string)) *EpochNotifier_Subscribe_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *EpochNotifier_Subscribe_Call) Return(_a0 <-chan types.EpochEvent) *EpochNotifier_Subscribe_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EpochNotifier_Subscribe_Call) RunAndReturn(run func(string) <-chan types.EpochEvent) *EpochNotifier_Subscribe_Call { + _c.Call.Return(run) + return _c +} + +// NewEpochNotifier creates a new instance of EpochNotifier. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewEpochNotifier(t interface { + mock.TestingT + Cleanup(func()) +}) *EpochNotifier { + mock := &EpochNotifier{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/aggsender/mocks/eth_client.go b/aggsender/mocks/eth_client.go new file mode 100644 index 000000000..6a68de414 --- /dev/null +++ b/aggsender/mocks/eth_client.go @@ -0,0 +1,154 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + context "context" + big "math/big" + + coretypes "github.com/ethereum/go-ethereum/core/types" + + mock "github.com/stretchr/testify/mock" +) + +// EthClient is an autogenerated mock type for the EthClient type +type EthClient struct { + mock.Mock +} + +type EthClient_Expecter struct { + mock *mock.Mock +} + +func (_m *EthClient) EXPECT() *EthClient_Expecter { + return &EthClient_Expecter{mock: &_m.Mock} +} + +// BlockNumber provides a mock function with given fields: ctx +func (_m *EthClient) BlockNumber(ctx context.Context) (uint64, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for BlockNumber") + } + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (uint64, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) uint64); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClient_BlockNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BlockNumber' +type EthClient_BlockNumber_Call struct { + *mock.Call +} + +// BlockNumber is a helper method to define mock.On call +// - ctx context.Context +func (_e *EthClient_Expecter) BlockNumber(ctx interface{}) *EthClient_BlockNumber_Call { + return &EthClient_BlockNumber_Call{Call: _e.mock.On("BlockNumber", ctx)} +} + +func (_c *EthClient_BlockNumber_Call) Run(run func(ctx context.Context)) *EthClient_BlockNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *EthClient_BlockNumber_Call) Return(_a0 uint64, _a1 error) *EthClient_BlockNumber_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClient_BlockNumber_Call) RunAndReturn(run func(context.Context) (uint64, error)) *EthClient_BlockNumber_Call { + _c.Call.Return(run) + return _c +} + +// HeaderByNumber provides a mock function with given fields: ctx, number +func (_m *EthClient) HeaderByNumber(ctx context.Context, number *big.Int) (*coretypes.Header, error) { + ret := _m.Called(ctx, number) + + if len(ret) == 0 { + panic("no return value specified for HeaderByNumber") + } + + var r0 *coretypes.Header + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (*coretypes.Header, error)); ok { + return rf(ctx, number) + } + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) *coretypes.Header); ok { + r0 = rf(ctx, number) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*coretypes.Header) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { + r1 = rf(ctx, number) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClient_HeaderByNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HeaderByNumber' +type EthClient_HeaderByNumber_Call struct { + *mock.Call +} + +// HeaderByNumber is a helper method to define mock.On call +// - ctx context.Context +// - number *big.Int +func (_e *EthClient_Expecter) HeaderByNumber(ctx interface{}, number interface{}) *EthClient_HeaderByNumber_Call { + return &EthClient_HeaderByNumber_Call{Call: _e.mock.On("HeaderByNumber", ctx, number)} +} + +func (_c *EthClient_HeaderByNumber_Call) Run(run func(ctx context.Context, number *big.Int)) *EthClient_HeaderByNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*big.Int)) + }) + return _c +} + +func (_c *EthClient_HeaderByNumber_Call) Return(_a0 *coretypes.Header, _a1 error) *EthClient_HeaderByNumber_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClient_HeaderByNumber_Call) RunAndReturn(run func(context.Context, *big.Int) (*coretypes.Header, error)) *EthClient_HeaderByNumber_Call { + _c.Call.Return(run) + return _c +} + +// NewEthClient creates a new instance of EthClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewEthClient(t interface { + mock.TestingT + Cleanup(func()) +}) *EthClient { + mock := &EthClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/aggsender/mocks/generic_subscriber.go b/aggsender/mocks/generic_subscriber.go new file mode 100644 index 000000000..b4bee4b46 --- /dev/null +++ b/aggsender/mocks/generic_subscriber.go @@ -0,0 +1,113 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// GenericSubscriber is an autogenerated mock type for the GenericSubscriber type +type GenericSubscriber[T interface{}] struct { + mock.Mock +} + +type GenericSubscriber_Expecter[T interface{}] struct { + mock *mock.Mock +} + +func (_m *GenericSubscriber[T]) EXPECT() *GenericSubscriber_Expecter[T] { + return &GenericSubscriber_Expecter[T]{mock: &_m.Mock} +} + +// Publish provides a mock function with given fields: data +func (_m *GenericSubscriber[T]) Publish(data T) { + _m.Called(data) +} + +// GenericSubscriber_Publish_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Publish' +type GenericSubscriber_Publish_Call[T interface{}] struct { + *mock.Call +} + +// Publish is a helper method to define mock.On call +// - data T +func (_e *GenericSubscriber_Expecter[T]) Publish(data interface{}) *GenericSubscriber_Publish_Call[T] { + return &GenericSubscriber_Publish_Call[T]{Call: _e.mock.On("Publish", data)} +} + +func (_c *GenericSubscriber_Publish_Call[T]) Run(run func(data T)) *GenericSubscriber_Publish_Call[T] { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(T)) + }) + return _c +} + +func (_c *GenericSubscriber_Publish_Call[T]) Return() *GenericSubscriber_Publish_Call[T] { + _c.Call.Return() + return _c +} + +func (_c *GenericSubscriber_Publish_Call[T]) RunAndReturn(run func(T)) *GenericSubscriber_Publish_Call[T] { + _c.Call.Return(run) + return _c +} + +// Subscribe provides a mock function with given fields: subscriberName +func (_m *GenericSubscriber[T]) Subscribe(subscriberName string) <-chan T { + ret := _m.Called(subscriberName) + + if len(ret) == 0 { + panic("no return value specified for Subscribe") + } + + var r0 <-chan T + if rf, ok := ret.Get(0).(func(string) <-chan T); ok { + r0 = rf(subscriberName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(<-chan T) + } + } + + return r0 +} + +// GenericSubscriber_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe' +type GenericSubscriber_Subscribe_Call[T interface{}] struct { + *mock.Call +} + +// Subscribe is a helper method to define mock.On call +// - subscriberName string +func (_e *GenericSubscriber_Expecter[T]) Subscribe(subscriberName interface{}) *GenericSubscriber_Subscribe_Call[T] { + return &GenericSubscriber_Subscribe_Call[T]{Call: _e.mock.On("Subscribe", subscriberName)} +} + +func (_c *GenericSubscriber_Subscribe_Call[T]) Run(run func(subscriberName string)) *GenericSubscriber_Subscribe_Call[T] { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *GenericSubscriber_Subscribe_Call[T]) Return(_a0 <-chan T) *GenericSubscriber_Subscribe_Call[T] { + _c.Call.Return(_a0) + return _c +} + +func (_c *GenericSubscriber_Subscribe_Call[T]) RunAndReturn(run func(string) <-chan T) *GenericSubscriber_Subscribe_Call[T] { + _c.Call.Return(run) + return _c +} + +// NewGenericSubscriber creates a new instance of GenericSubscriber. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewGenericSubscriber[T interface{}](t interface { + mock.TestingT + Cleanup(func()) +}) *GenericSubscriber[T] { + mock := &GenericSubscriber[T]{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/aggsender/mocks/l1_info_tree_syncer.go b/aggsender/mocks/l1_info_tree_syncer.go new file mode 100644 index 000000000..70ac97de9 --- /dev/null +++ b/aggsender/mocks/l1_info_tree_syncer.go @@ -0,0 +1,217 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + context "context" + + common "github.com/ethereum/go-ethereum/common" + + l1infotreesync "github.com/0xPolygon/cdk/l1infotreesync" + + mock "github.com/stretchr/testify/mock" + + treetypes "github.com/0xPolygon/cdk/tree/types" +) + +// L1InfoTreeSyncer is an autogenerated mock type for the L1InfoTreeSyncer type +type L1InfoTreeSyncer struct { + mock.Mock +} + +type L1InfoTreeSyncer_Expecter struct { + mock *mock.Mock +} + +func (_m *L1InfoTreeSyncer) EXPECT() *L1InfoTreeSyncer_Expecter { + return &L1InfoTreeSyncer_Expecter{mock: &_m.Mock} +} + +// GetInfoByGlobalExitRoot provides a mock function with given fields: globalExitRoot +func (_m *L1InfoTreeSyncer) GetInfoByGlobalExitRoot(globalExitRoot common.Hash) (*l1infotreesync.L1InfoTreeLeaf, error) { + ret := _m.Called(globalExitRoot) + + if len(ret) == 0 { + panic("no return value specified for GetInfoByGlobalExitRoot") + } + + var r0 *l1infotreesync.L1InfoTreeLeaf + var r1 error + if rf, ok := ret.Get(0).(func(common.Hash) (*l1infotreesync.L1InfoTreeLeaf, error)); ok { + return rf(globalExitRoot) + } + if rf, ok := ret.Get(0).(func(common.Hash) *l1infotreesync.L1InfoTreeLeaf); ok { + r0 = rf(globalExitRoot) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*l1infotreesync.L1InfoTreeLeaf) + } + } + + if rf, ok := ret.Get(1).(func(common.Hash) error); ok { + r1 = rf(globalExitRoot) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// L1InfoTreeSyncer_GetInfoByGlobalExitRoot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetInfoByGlobalExitRoot' +type L1InfoTreeSyncer_GetInfoByGlobalExitRoot_Call struct { + *mock.Call +} + +// GetInfoByGlobalExitRoot is a helper method to define mock.On call +// - globalExitRoot common.Hash +func (_e *L1InfoTreeSyncer_Expecter) GetInfoByGlobalExitRoot(globalExitRoot interface{}) *L1InfoTreeSyncer_GetInfoByGlobalExitRoot_Call { + return &L1InfoTreeSyncer_GetInfoByGlobalExitRoot_Call{Call: _e.mock.On("GetInfoByGlobalExitRoot", globalExitRoot)} +} + +func (_c *L1InfoTreeSyncer_GetInfoByGlobalExitRoot_Call) Run(run func(globalExitRoot common.Hash)) *L1InfoTreeSyncer_GetInfoByGlobalExitRoot_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(common.Hash)) + }) + return _c +} + +func (_c *L1InfoTreeSyncer_GetInfoByGlobalExitRoot_Call) Return(_a0 *l1infotreesync.L1InfoTreeLeaf, _a1 error) *L1InfoTreeSyncer_GetInfoByGlobalExitRoot_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *L1InfoTreeSyncer_GetInfoByGlobalExitRoot_Call) RunAndReturn(run func(common.Hash) (*l1infotreesync.L1InfoTreeLeaf, error)) *L1InfoTreeSyncer_GetInfoByGlobalExitRoot_Call { + _c.Call.Return(run) + return _c +} + +// GetL1InfoTreeMerkleProofFromIndexToRoot provides a mock function with given fields: ctx, index, root +func (_m *L1InfoTreeSyncer) GetL1InfoTreeMerkleProofFromIndexToRoot(ctx context.Context, index uint32, root common.Hash) (treetypes.Proof, error) { + ret := _m.Called(ctx, index, root) + + if len(ret) == 0 { + panic("no return value specified for GetL1InfoTreeMerkleProofFromIndexToRoot") + } + + var r0 treetypes.Proof + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint32, common.Hash) (treetypes.Proof, error)); ok { + return rf(ctx, index, root) + } + if rf, ok := ret.Get(0).(func(context.Context, uint32, common.Hash) treetypes.Proof); ok { + r0 = rf(ctx, index, root) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(treetypes.Proof) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint32, common.Hash) error); ok { + r1 = rf(ctx, index, root) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// L1InfoTreeSyncer_GetL1InfoTreeMerkleProofFromIndexToRoot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetL1InfoTreeMerkleProofFromIndexToRoot' +type L1InfoTreeSyncer_GetL1InfoTreeMerkleProofFromIndexToRoot_Call struct { + *mock.Call +} + +// GetL1InfoTreeMerkleProofFromIndexToRoot is a helper method to define mock.On call +// - ctx context.Context +// - index uint32 +// - root common.Hash +func (_e *L1InfoTreeSyncer_Expecter) GetL1InfoTreeMerkleProofFromIndexToRoot(ctx interface{}, index interface{}, root interface{}) *L1InfoTreeSyncer_GetL1InfoTreeMerkleProofFromIndexToRoot_Call { + return &L1InfoTreeSyncer_GetL1InfoTreeMerkleProofFromIndexToRoot_Call{Call: _e.mock.On("GetL1InfoTreeMerkleProofFromIndexToRoot", ctx, index, root)} +} + +func (_c *L1InfoTreeSyncer_GetL1InfoTreeMerkleProofFromIndexToRoot_Call) Run(run func(ctx context.Context, index uint32, root common.Hash)) *L1InfoTreeSyncer_GetL1InfoTreeMerkleProofFromIndexToRoot_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint32), args[2].(common.Hash)) + }) + return _c +} + +func (_c *L1InfoTreeSyncer_GetL1InfoTreeMerkleProofFromIndexToRoot_Call) Return(_a0 treetypes.Proof, _a1 error) *L1InfoTreeSyncer_GetL1InfoTreeMerkleProofFromIndexToRoot_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *L1InfoTreeSyncer_GetL1InfoTreeMerkleProofFromIndexToRoot_Call) RunAndReturn(run func(context.Context, uint32, common.Hash) (treetypes.Proof, error)) *L1InfoTreeSyncer_GetL1InfoTreeMerkleProofFromIndexToRoot_Call { + _c.Call.Return(run) + return _c +} + +// GetL1InfoTreeRootByIndex provides a mock function with given fields: ctx, index +func (_m *L1InfoTreeSyncer) GetL1InfoTreeRootByIndex(ctx context.Context, index uint32) (treetypes.Root, error) { + ret := _m.Called(ctx, index) + + if len(ret) == 0 { + panic("no return value specified for GetL1InfoTreeRootByIndex") + } + + var r0 treetypes.Root + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint32) (treetypes.Root, error)); ok { + return rf(ctx, index) + } + if rf, ok := ret.Get(0).(func(context.Context, uint32) treetypes.Root); ok { + r0 = rf(ctx, index) + } else { + r0 = ret.Get(0).(treetypes.Root) + } + + if rf, ok := ret.Get(1).(func(context.Context, uint32) error); ok { + r1 = rf(ctx, index) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// L1InfoTreeSyncer_GetL1InfoTreeRootByIndex_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetL1InfoTreeRootByIndex' +type L1InfoTreeSyncer_GetL1InfoTreeRootByIndex_Call struct { + *mock.Call +} + +// GetL1InfoTreeRootByIndex is a helper method to define mock.On call +// - ctx context.Context +// - index uint32 +func (_e *L1InfoTreeSyncer_Expecter) GetL1InfoTreeRootByIndex(ctx interface{}, index interface{}) *L1InfoTreeSyncer_GetL1InfoTreeRootByIndex_Call { + return &L1InfoTreeSyncer_GetL1InfoTreeRootByIndex_Call{Call: _e.mock.On("GetL1InfoTreeRootByIndex", ctx, index)} +} + +func (_c *L1InfoTreeSyncer_GetL1InfoTreeRootByIndex_Call) Run(run func(ctx context.Context, index uint32)) *L1InfoTreeSyncer_GetL1InfoTreeRootByIndex_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint32)) + }) + return _c +} + +func (_c *L1InfoTreeSyncer_GetL1InfoTreeRootByIndex_Call) Return(_a0 treetypes.Root, _a1 error) *L1InfoTreeSyncer_GetL1InfoTreeRootByIndex_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *L1InfoTreeSyncer_GetL1InfoTreeRootByIndex_Call) RunAndReturn(run func(context.Context, uint32) (treetypes.Root, error)) *L1InfoTreeSyncer_GetL1InfoTreeRootByIndex_Call { + _c.Call.Return(run) + return _c +} + +// NewL1InfoTreeSyncer creates a new instance of L1InfoTreeSyncer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewL1InfoTreeSyncer(t interface { + mock.TestingT + Cleanup(func()) +}) *L1InfoTreeSyncer { + mock := &L1InfoTreeSyncer{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/aggsender/mocks/l2_bridge_syncer.go b/aggsender/mocks/l2_bridge_syncer.go new file mode 100644 index 000000000..800007ffe --- /dev/null +++ b/aggsender/mocks/l2_bridge_syncer.go @@ -0,0 +1,423 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + bridgesync "github.com/0xPolygon/cdk/bridgesync" + common "github.com/ethereum/go-ethereum/common" + + context "context" + + etherman "github.com/0xPolygon/cdk/etherman" + + mock "github.com/stretchr/testify/mock" + + treetypes "github.com/0xPolygon/cdk/tree/types" +) + +// L2BridgeSyncer is an autogenerated mock type for the L2BridgeSyncer type +type L2BridgeSyncer struct { + mock.Mock +} + +type L2BridgeSyncer_Expecter struct { + mock *mock.Mock +} + +func (_m *L2BridgeSyncer) EXPECT() *L2BridgeSyncer_Expecter { + return &L2BridgeSyncer_Expecter{mock: &_m.Mock} +} + +// BlockFinality provides a mock function with given fields: +func (_m *L2BridgeSyncer) BlockFinality() etherman.BlockNumberFinality { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for BlockFinality") + } + + var r0 etherman.BlockNumberFinality + if rf, ok := ret.Get(0).(func() etherman.BlockNumberFinality); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(etherman.BlockNumberFinality) + } + + return r0 +} + +// L2BridgeSyncer_BlockFinality_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BlockFinality' +type L2BridgeSyncer_BlockFinality_Call struct { + *mock.Call +} + +// BlockFinality is a helper method to define mock.On call +func (_e *L2BridgeSyncer_Expecter) BlockFinality() *L2BridgeSyncer_BlockFinality_Call { + return &L2BridgeSyncer_BlockFinality_Call{Call: _e.mock.On("BlockFinality")} +} + +func (_c *L2BridgeSyncer_BlockFinality_Call) Run(run func()) *L2BridgeSyncer_BlockFinality_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *L2BridgeSyncer_BlockFinality_Call) Return(_a0 etherman.BlockNumberFinality) *L2BridgeSyncer_BlockFinality_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *L2BridgeSyncer_BlockFinality_Call) RunAndReturn(run func() etherman.BlockNumberFinality) *L2BridgeSyncer_BlockFinality_Call { + _c.Call.Return(run) + return _c +} + +// GetBlockByLER provides a mock function with given fields: ctx, ler +func (_m *L2BridgeSyncer) GetBlockByLER(ctx context.Context, ler common.Hash) (uint64, error) { + ret := _m.Called(ctx, ler) + + if len(ret) == 0 { + panic("no return value specified for GetBlockByLER") + } + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (uint64, error)); ok { + return rf(ctx, ler) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Hash) uint64); ok { + r0 = rf(ctx, ler) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(context.Context, common.Hash) error); ok { + r1 = rf(ctx, ler) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// L2BridgeSyncer_GetBlockByLER_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBlockByLER' +type L2BridgeSyncer_GetBlockByLER_Call struct { + *mock.Call +} + +// GetBlockByLER is a helper method to define mock.On call +// - ctx context.Context +// - ler common.Hash +func (_e *L2BridgeSyncer_Expecter) GetBlockByLER(ctx interface{}, ler interface{}) *L2BridgeSyncer_GetBlockByLER_Call { + return &L2BridgeSyncer_GetBlockByLER_Call{Call: _e.mock.On("GetBlockByLER", ctx, ler)} +} + +func (_c *L2BridgeSyncer_GetBlockByLER_Call) Run(run func(ctx context.Context, ler common.Hash)) *L2BridgeSyncer_GetBlockByLER_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(common.Hash)) + }) + return _c +} + +func (_c *L2BridgeSyncer_GetBlockByLER_Call) Return(_a0 uint64, _a1 error) *L2BridgeSyncer_GetBlockByLER_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *L2BridgeSyncer_GetBlockByLER_Call) RunAndReturn(run func(context.Context, common.Hash) (uint64, error)) *L2BridgeSyncer_GetBlockByLER_Call { + _c.Call.Return(run) + return _c +} + +// GetBridgesPublished provides a mock function with given fields: ctx, fromBlock, toBlock +func (_m *L2BridgeSyncer) GetBridgesPublished(ctx context.Context, fromBlock uint64, toBlock uint64) ([]bridgesync.Bridge, error) { + ret := _m.Called(ctx, fromBlock, toBlock) + + if len(ret) == 0 { + panic("no return value specified for GetBridgesPublished") + } + + var r0 []bridgesync.Bridge + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64) ([]bridgesync.Bridge, error)); ok { + return rf(ctx, fromBlock, toBlock) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64) []bridgesync.Bridge); ok { + r0 = rf(ctx, fromBlock, toBlock) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]bridgesync.Bridge) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64, uint64) error); ok { + r1 = rf(ctx, fromBlock, toBlock) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// L2BridgeSyncer_GetBridgesPublished_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBridgesPublished' +type L2BridgeSyncer_GetBridgesPublished_Call struct { + *mock.Call +} + +// GetBridgesPublished is a helper method to define mock.On call +// - ctx context.Context +// - fromBlock uint64 +// - toBlock uint64 +func (_e *L2BridgeSyncer_Expecter) GetBridgesPublished(ctx interface{}, fromBlock interface{}, toBlock interface{}) *L2BridgeSyncer_GetBridgesPublished_Call { + return &L2BridgeSyncer_GetBridgesPublished_Call{Call: _e.mock.On("GetBridgesPublished", ctx, fromBlock, toBlock)} +} + +func (_c *L2BridgeSyncer_GetBridgesPublished_Call) Run(run func(ctx context.Context, fromBlock uint64, toBlock uint64)) *L2BridgeSyncer_GetBridgesPublished_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(uint64)) + }) + return _c +} + +func (_c *L2BridgeSyncer_GetBridgesPublished_Call) Return(_a0 []bridgesync.Bridge, _a1 error) *L2BridgeSyncer_GetBridgesPublished_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *L2BridgeSyncer_GetBridgesPublished_Call) RunAndReturn(run func(context.Context, uint64, uint64) ([]bridgesync.Bridge, error)) *L2BridgeSyncer_GetBridgesPublished_Call { + _c.Call.Return(run) + return _c +} + +// GetClaims provides a mock function with given fields: ctx, fromBlock, toBlock +func (_m *L2BridgeSyncer) GetClaims(ctx context.Context, fromBlock uint64, toBlock uint64) ([]bridgesync.Claim, error) { + ret := _m.Called(ctx, fromBlock, toBlock) + + if len(ret) == 0 { + panic("no return value specified for GetClaims") + } + + var r0 []bridgesync.Claim + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64) ([]bridgesync.Claim, error)); ok { + return rf(ctx, fromBlock, toBlock) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64) []bridgesync.Claim); ok { + r0 = rf(ctx, fromBlock, toBlock) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]bridgesync.Claim) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64, uint64) error); ok { + r1 = rf(ctx, fromBlock, toBlock) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// L2BridgeSyncer_GetClaims_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetClaims' +type L2BridgeSyncer_GetClaims_Call struct { + *mock.Call +} + +// GetClaims is a helper method to define mock.On call +// - ctx context.Context +// - fromBlock uint64 +// - toBlock uint64 +func (_e *L2BridgeSyncer_Expecter) GetClaims(ctx interface{}, fromBlock interface{}, toBlock interface{}) *L2BridgeSyncer_GetClaims_Call { + return &L2BridgeSyncer_GetClaims_Call{Call: _e.mock.On("GetClaims", ctx, fromBlock, toBlock)} +} + +func (_c *L2BridgeSyncer_GetClaims_Call) Run(run func(ctx context.Context, fromBlock uint64, toBlock uint64)) *L2BridgeSyncer_GetClaims_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(uint64)) + }) + return _c +} + +func (_c *L2BridgeSyncer_GetClaims_Call) Return(_a0 []bridgesync.Claim, _a1 error) *L2BridgeSyncer_GetClaims_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *L2BridgeSyncer_GetClaims_Call) RunAndReturn(run func(context.Context, uint64, uint64) ([]bridgesync.Claim, error)) *L2BridgeSyncer_GetClaims_Call { + _c.Call.Return(run) + return _c +} + +// GetExitRootByIndex provides a mock function with given fields: ctx, index +func (_m *L2BridgeSyncer) GetExitRootByIndex(ctx context.Context, index uint32) (treetypes.Root, error) { + ret := _m.Called(ctx, index) + + if len(ret) == 0 { + panic("no return value specified for GetExitRootByIndex") + } + + var r0 treetypes.Root + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint32) (treetypes.Root, error)); ok { + return rf(ctx, index) + } + if rf, ok := ret.Get(0).(func(context.Context, uint32) treetypes.Root); ok { + r0 = rf(ctx, index) + } else { + r0 = ret.Get(0).(treetypes.Root) + } + + if rf, ok := ret.Get(1).(func(context.Context, uint32) error); ok { + r1 = rf(ctx, index) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// L2BridgeSyncer_GetExitRootByIndex_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetExitRootByIndex' +type L2BridgeSyncer_GetExitRootByIndex_Call struct { + *mock.Call +} + +// GetExitRootByIndex is a helper method to define mock.On call +// - ctx context.Context +// - index uint32 +func (_e *L2BridgeSyncer_Expecter) GetExitRootByIndex(ctx interface{}, index interface{}) *L2BridgeSyncer_GetExitRootByIndex_Call { + return &L2BridgeSyncer_GetExitRootByIndex_Call{Call: _e.mock.On("GetExitRootByIndex", ctx, index)} +} + +func (_c *L2BridgeSyncer_GetExitRootByIndex_Call) Run(run func(ctx context.Context, index uint32)) *L2BridgeSyncer_GetExitRootByIndex_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint32)) + }) + return _c +} + +func (_c *L2BridgeSyncer_GetExitRootByIndex_Call) Return(_a0 treetypes.Root, _a1 error) *L2BridgeSyncer_GetExitRootByIndex_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *L2BridgeSyncer_GetExitRootByIndex_Call) RunAndReturn(run func(context.Context, uint32) (treetypes.Root, error)) *L2BridgeSyncer_GetExitRootByIndex_Call { + _c.Call.Return(run) + return _c +} + +// GetLastProcessedBlock provides a mock function with given fields: ctx +func (_m *L2BridgeSyncer) GetLastProcessedBlock(ctx context.Context) (uint64, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetLastProcessedBlock") + } + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (uint64, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) uint64); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// L2BridgeSyncer_GetLastProcessedBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLastProcessedBlock' +type L2BridgeSyncer_GetLastProcessedBlock_Call struct { + *mock.Call +} + +// GetLastProcessedBlock is a helper method to define mock.On call +// - ctx context.Context +func (_e *L2BridgeSyncer_Expecter) GetLastProcessedBlock(ctx interface{}) *L2BridgeSyncer_GetLastProcessedBlock_Call { + return &L2BridgeSyncer_GetLastProcessedBlock_Call{Call: _e.mock.On("GetLastProcessedBlock", ctx)} +} + +func (_c *L2BridgeSyncer_GetLastProcessedBlock_Call) Run(run func(ctx context.Context)) *L2BridgeSyncer_GetLastProcessedBlock_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *L2BridgeSyncer_GetLastProcessedBlock_Call) Return(_a0 uint64, _a1 error) *L2BridgeSyncer_GetLastProcessedBlock_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *L2BridgeSyncer_GetLastProcessedBlock_Call) RunAndReturn(run func(context.Context) (uint64, error)) *L2BridgeSyncer_GetLastProcessedBlock_Call { + _c.Call.Return(run) + return _c +} + +// OriginNetwork provides a mock function with given fields: +func (_m *L2BridgeSyncer) OriginNetwork() uint32 { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for OriginNetwork") + } + + var r0 uint32 + if rf, ok := ret.Get(0).(func() uint32); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(uint32) + } + + return r0 +} + +// L2BridgeSyncer_OriginNetwork_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OriginNetwork' +type L2BridgeSyncer_OriginNetwork_Call struct { + *mock.Call +} + +// OriginNetwork is a helper method to define mock.On call +func (_e *L2BridgeSyncer_Expecter) OriginNetwork() *L2BridgeSyncer_OriginNetwork_Call { + return &L2BridgeSyncer_OriginNetwork_Call{Call: _e.mock.On("OriginNetwork")} +} + +func (_c *L2BridgeSyncer_OriginNetwork_Call) Run(run func()) *L2BridgeSyncer_OriginNetwork_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *L2BridgeSyncer_OriginNetwork_Call) Return(_a0 uint32) *L2BridgeSyncer_OriginNetwork_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *L2BridgeSyncer_OriginNetwork_Call) RunAndReturn(run func() uint32) *L2BridgeSyncer_OriginNetwork_Call { + _c.Call.Return(run) + return _c +} + +// NewL2BridgeSyncer creates a new instance of L2BridgeSyncer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewL2BridgeSyncer(t interface { + mock.TestingT + Cleanup(func()) +}) *L2BridgeSyncer { + mock := &L2BridgeSyncer{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/aggsender/mocks/logger.go b/aggsender/mocks/logger.go new file mode 100644 index 000000000..bb26739e0 --- /dev/null +++ b/aggsender/mocks/logger.go @@ -0,0 +1,376 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// Logger is an autogenerated mock type for the Logger type +type Logger struct { + mock.Mock +} + +type Logger_Expecter struct { + mock *mock.Mock +} + +func (_m *Logger) EXPECT() *Logger_Expecter { + return &Logger_Expecter{mock: &_m.Mock} +} + +// Debug provides a mock function with given fields: args +func (_m *Logger) Debug(args ...interface{}) { + var _ca []interface{} + _ca = append(_ca, args...) + _m.Called(_ca...) +} + +// Logger_Debug_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Debug' +type Logger_Debug_Call struct { + *mock.Call +} + +// Debug is a helper method to define mock.On call +// - args ...interface{} +func (_e *Logger_Expecter) Debug(args ...interface{}) *Logger_Debug_Call { + return &Logger_Debug_Call{Call: _e.mock.On("Debug", + append([]interface{}{}, args...)...)} +} + +func (_c *Logger_Debug_Call) Run(run func(args ...interface{})) *Logger_Debug_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]interface{}, len(args)-0) + for i, a := range args[0:] { + if a != nil { + variadicArgs[i] = a.(interface{}) + } + } + run(variadicArgs...) + }) + return _c +} + +func (_c *Logger_Debug_Call) Return() *Logger_Debug_Call { + _c.Call.Return() + return _c +} + +func (_c *Logger_Debug_Call) RunAndReturn(run func(...interface{})) *Logger_Debug_Call { + _c.Call.Return(run) + return _c +} + +// Debugf provides a mock function with given fields: format, args +func (_m *Logger) Debugf(format string, args ...interface{}) { + var _ca []interface{} + _ca = append(_ca, format) + _ca = append(_ca, args...) + _m.Called(_ca...) +} + +// Logger_Debugf_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Debugf' +type Logger_Debugf_Call struct { + *mock.Call +} + +// Debugf is a helper method to define mock.On call +// - format string +// - args ...interface{} +func (_e *Logger_Expecter) Debugf(format interface{}, args ...interface{}) *Logger_Debugf_Call { + return &Logger_Debugf_Call{Call: _e.mock.On("Debugf", + append([]interface{}{format}, args...)...)} +} + +func (_c *Logger_Debugf_Call) Run(run func(format string, args ...interface{})) *Logger_Debugf_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]interface{}, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(interface{}) + } + } + run(args[0].(string), variadicArgs...) + }) + return _c +} + +func (_c *Logger_Debugf_Call) Return() *Logger_Debugf_Call { + _c.Call.Return() + return _c +} + +func (_c *Logger_Debugf_Call) RunAndReturn(run func(string, ...interface{})) *Logger_Debugf_Call { + _c.Call.Return(run) + return _c +} + +// Error provides a mock function with given fields: args +func (_m *Logger) Error(args ...interface{}) { + var _ca []interface{} + _ca = append(_ca, args...) + _m.Called(_ca...) +} + +// Logger_Error_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Error' +type Logger_Error_Call struct { + *mock.Call +} + +// Error is a helper method to define mock.On call +// - args ...interface{} +func (_e *Logger_Expecter) Error(args ...interface{}) *Logger_Error_Call { + return &Logger_Error_Call{Call: _e.mock.On("Error", + append([]interface{}{}, args...)...)} +} + +func (_c *Logger_Error_Call) Run(run func(args ...interface{})) *Logger_Error_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]interface{}, len(args)-0) + for i, a := range args[0:] { + if a != nil { + variadicArgs[i] = a.(interface{}) + } + } + run(variadicArgs...) + }) + return _c +} + +func (_c *Logger_Error_Call) Return() *Logger_Error_Call { + _c.Call.Return() + return _c +} + +func (_c *Logger_Error_Call) RunAndReturn(run func(...interface{})) *Logger_Error_Call { + _c.Call.Return(run) + return _c +} + +// Errorf provides a mock function with given fields: format, args +func (_m *Logger) Errorf(format string, args ...interface{}) { + var _ca []interface{} + _ca = append(_ca, format) + _ca = append(_ca, args...) + _m.Called(_ca...) +} + +// Logger_Errorf_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Errorf' +type Logger_Errorf_Call struct { + *mock.Call +} + +// Errorf is a helper method to define mock.On call +// - format string +// - args ...interface{} +func (_e *Logger_Expecter) Errorf(format interface{}, args ...interface{}) *Logger_Errorf_Call { + return &Logger_Errorf_Call{Call: _e.mock.On("Errorf", + append([]interface{}{format}, args...)...)} +} + +func (_c *Logger_Errorf_Call) Run(run func(format string, args ...interface{})) *Logger_Errorf_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]interface{}, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(interface{}) + } + } + run(args[0].(string), variadicArgs...) + }) + return _c +} + +func (_c *Logger_Errorf_Call) Return() *Logger_Errorf_Call { + _c.Call.Return() + return _c +} + +func (_c *Logger_Errorf_Call) RunAndReturn(run func(string, ...interface{})) *Logger_Errorf_Call { + _c.Call.Return(run) + return _c +} + +// Info provides a mock function with given fields: args +func (_m *Logger) Info(args ...interface{}) { + var _ca []interface{} + _ca = append(_ca, args...) + _m.Called(_ca...) +} + +// Logger_Info_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Info' +type Logger_Info_Call struct { + *mock.Call +} + +// Info is a helper method to define mock.On call +// - args ...interface{} +func (_e *Logger_Expecter) Info(args ...interface{}) *Logger_Info_Call { + return &Logger_Info_Call{Call: _e.mock.On("Info", + append([]interface{}{}, args...)...)} +} + +func (_c *Logger_Info_Call) Run(run func(args ...interface{})) *Logger_Info_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]interface{}, len(args)-0) + for i, a := range args[0:] { + if a != nil { + variadicArgs[i] = a.(interface{}) + } + } + run(variadicArgs...) + }) + return _c +} + +func (_c *Logger_Info_Call) Return() *Logger_Info_Call { + _c.Call.Return() + return _c +} + +func (_c *Logger_Info_Call) RunAndReturn(run func(...interface{})) *Logger_Info_Call { + _c.Call.Return(run) + return _c +} + +// Infof provides a mock function with given fields: format, args +func (_m *Logger) Infof(format string, args ...interface{}) { + var _ca []interface{} + _ca = append(_ca, format) + _ca = append(_ca, args...) + _m.Called(_ca...) +} + +// Logger_Infof_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Infof' +type Logger_Infof_Call struct { + *mock.Call +} + +// Infof is a helper method to define mock.On call +// - format string +// - args ...interface{} +func (_e *Logger_Expecter) Infof(format interface{}, args ...interface{}) *Logger_Infof_Call { + return &Logger_Infof_Call{Call: _e.mock.On("Infof", + append([]interface{}{format}, args...)...)} +} + +func (_c *Logger_Infof_Call) Run(run func(format string, args ...interface{})) *Logger_Infof_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]interface{}, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(interface{}) + } + } + run(args[0].(string), variadicArgs...) + }) + return _c +} + +func (_c *Logger_Infof_Call) Return() *Logger_Infof_Call { + _c.Call.Return() + return _c +} + +func (_c *Logger_Infof_Call) RunAndReturn(run func(string, ...interface{})) *Logger_Infof_Call { + _c.Call.Return(run) + return _c +} + +// Warn provides a mock function with given fields: args +func (_m *Logger) Warn(args ...interface{}) { + var _ca []interface{} + _ca = append(_ca, args...) + _m.Called(_ca...) +} + +// Logger_Warn_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Warn' +type Logger_Warn_Call struct { + *mock.Call +} + +// Warn is a helper method to define mock.On call +// - args ...interface{} +func (_e *Logger_Expecter) Warn(args ...interface{}) *Logger_Warn_Call { + return &Logger_Warn_Call{Call: _e.mock.On("Warn", + append([]interface{}{}, args...)...)} +} + +func (_c *Logger_Warn_Call) Run(run func(args ...interface{})) *Logger_Warn_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]interface{}, len(args)-0) + for i, a := range args[0:] { + if a != nil { + variadicArgs[i] = a.(interface{}) + } + } + run(variadicArgs...) + }) + return _c +} + +func (_c *Logger_Warn_Call) Return() *Logger_Warn_Call { + _c.Call.Return() + return _c +} + +func (_c *Logger_Warn_Call) RunAndReturn(run func(...interface{})) *Logger_Warn_Call { + _c.Call.Return(run) + return _c +} + +// Warnf provides a mock function with given fields: format, args +func (_m *Logger) Warnf(format string, args ...interface{}) { + var _ca []interface{} + _ca = append(_ca, format) + _ca = append(_ca, args...) + _m.Called(_ca...) +} + +// Logger_Warnf_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Warnf' +type Logger_Warnf_Call struct { + *mock.Call +} + +// Warnf is a helper method to define mock.On call +// - format string +// - args ...interface{} +func (_e *Logger_Expecter) Warnf(format interface{}, args ...interface{}) *Logger_Warnf_Call { + return &Logger_Warnf_Call{Call: _e.mock.On("Warnf", + append([]interface{}{format}, args...)...)} +} + +func (_c *Logger_Warnf_Call) Run(run func(format string, args ...interface{})) *Logger_Warnf_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]interface{}, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(interface{}) + } + } + run(args[0].(string), variadicArgs...) + }) + return _c +} + +func (_c *Logger_Warnf_Call) Return() *Logger_Warnf_Call { + _c.Call.Return() + return _c +} + +func (_c *Logger_Warnf_Call) RunAndReturn(run func(string, ...interface{})) *Logger_Warnf_Call { + _c.Call.Return(run) + return _c +} + +// NewLogger creates a new instance of Logger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewLogger(t interface { + mock.TestingT + Cleanup(func()) +}) *Logger { + mock := &Logger{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/aggsender/types/block_notifier.go b/aggsender/types/block_notifier.go new file mode 100644 index 000000000..c19e60698 --- /dev/null +++ b/aggsender/types/block_notifier.go @@ -0,0 +1,14 @@ +package types + +import "github.com/0xPolygon/cdk/etherman" + +type EventNewBlock struct { + BlockNumber uint64 + BlockFinalityType etherman.BlockNumberFinality +} + +type BlockNotifier interface { + // NotifyEpochStarted notifies the epoch has started. + Subscribe(id string) <-chan EventNewBlock + String() string +} diff --git a/aggsender/types/epoch_notifier.go b/aggsender/types/epoch_notifier.go new file mode 100644 index 000000000..426ad3622 --- /dev/null +++ b/aggsender/types/epoch_notifier.go @@ -0,0 +1,25 @@ +package types + +import ( + "context" + "fmt" +) + +// EpochEvent is the event that notifies the neear end epoch +type EpochEvent struct { + Epoch uint64 + // ExtraInfo if a detailed information about the epoch that depends on implementation + ExtraInfo fmt.Stringer +} + +func (e EpochEvent) String() string { + return fmt.Sprintf("EpochEvent: epoch=%d extra=%s", e.Epoch, e.ExtraInfo) +} + +type EpochNotifier interface { + // NotifyEpochStarted notifies the epoch is close to end. + Subscribe(id string) <-chan EpochEvent + // Start starts the notifier synchronously + Start(ctx context.Context) + String() string +} diff --git a/aggsender/types/generic_subscriber.go b/aggsender/types/generic_subscriber.go new file mode 100644 index 000000000..67038c5ce --- /dev/null +++ b/aggsender/types/generic_subscriber.go @@ -0,0 +1,6 @@ +package types + +type GenericSubscriber[T any] interface { + Subscribe(subscriberName string) <-chan T + Publish(data T) +} diff --git a/aggsender/types/types.go b/aggsender/types/types.go index 46d311769..d9e0b2e7e 100644 --- a/aggsender/types/types.go +++ b/aggsender/types/types.go @@ -47,6 +47,8 @@ type Logger interface { Infof(format string, args ...interface{}) Error(args ...interface{}) Errorf(format string, args ...interface{}) + Warn(args ...interface{}) + Warnf(format string, args ...interface{}) Debug(args ...interface{}) Debugf(format string, args ...interface{}) } diff --git a/cmd/run.go b/cmd/run.go index c30da7391..4d8d15a2e 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -125,6 +125,7 @@ func start(cliCtx *cli.Context) error { aggsender, err := createAggSender( cliCtx.Context, c.AggSender, + l1Client, l1InfoTreeSync, l2BridgeSync, ) @@ -132,7 +133,7 @@ func start(cliCtx *cli.Context) error { log.Fatal(err) } - go aggsender.Start(cliCtx.Context) + aggsender.Start(cliCtx.Context) } } @@ -144,13 +145,35 @@ func start(cliCtx *cli.Context) error { func createAggSender( ctx context.Context, cfg aggsender.Config, + l1EthClient *ethclient.Client, l1InfoTreeSync *l1infotreesync.L1InfoTreeSync, - l2Syncer *bridgesync.BridgeSync, -) (*aggsender.AggSender, error) { + l2Syncer *bridgesync.BridgeSync) (*aggsender.AggSender, error) { logger := log.WithFields("module", cdkcommon.AGGSENDER) agglayerClient := agglayer.NewAggLayerClient(cfg.AggLayerURL) + blockNotifier, err := aggsender.NewBlockNotifierPolling(l1EthClient, aggsender.ConfigBlockNotifierPolling{ + BlockFinalityType: etherman.BlockNumberFinality(cfg.BlockFinality), + CheckNewBlockInterval: aggsender.AutomaticBlockInterval, + }, logger, nil) + if err != nil { + return nil, err + } - return aggsender.New(ctx, logger, cfg, agglayerClient, l1InfoTreeSync, l2Syncer) + notifierCfg, err := aggsender.NewConfigEpochNotifierPerBlock(agglayerClient, cfg.BlocksBeforeEpochEnding) + if err != nil { + return nil, fmt.Errorf("cant generate config for Epoch Notifier because: %w", err) + } + epochNotifier, err := aggsender.NewEpochNotifierPerBlock( + blockNotifier, + logger, + *notifierCfg, nil) + if err != nil { + return nil, err + } + log.Infof("Starting blockNotifier: %s", blockNotifier.String()) + go blockNotifier.Start(ctx) + log.Infof("Starting epochNotifier: %s", epochNotifier.String()) + go epochNotifier.Start(ctx) + return aggsender.New(ctx, logger, cfg, agglayerClient, l1InfoTreeSync, l2Syncer, epochNotifier) } func createAggregator(ctx context.Context, c config.Config, runMigrations bool) *aggregator.Aggregator { diff --git a/config/default.go b/config/default.go index bbf4d2e08..a2318881f 100644 --- a/config/default.go +++ b/config/default.go @@ -7,6 +7,7 @@ L1URL = "http://localhost:8545" L2URL = "http://localhost:8123" AggLayerURL = "https://agglayer-dev.polygon.technology" + ForkId = 9 ContractVersions = "elderberry" IsValidiumMode = false @@ -340,5 +341,7 @@ AggsenderPrivateKey = {Path = "{{SequencerPrivateKeyPath}}", Password = "{{Seque BlockGetInterval = "2s" URLRPCL2="{{L2URL}}" CheckSettledInterval = "2s" +BlockFinality = "LatestBlock" +BlocksBeforeEpochEnding = 2 SaveCertificatesToFiles = false ` diff --git a/crates/cdk/versions.json b/crates/cdk/versions.json index bafbd00be..0d7f3daf9 100644 --- a/crates/cdk/versions.json +++ b/crates/cdk/versions.json @@ -5,7 +5,7 @@ "cdk_validium_node_image": "0xpolygon/cdk-validium-node:0.7.0-cdk", "zkevm_bridge_proxy_image": "haproxy:3.0-bookworm", "zkevm_bridge_service_image": "hermeznetwork/zkevm-bridge-service:v0.6.0-RC1", - "zkevm_bridge_ui_image": "leovct/zkevm-bridge-ui:multi-network-2", + "zkevm_bridge_ui_image": "leovct/zkevm-bridge-ui:multi-network", "zkevm_contracts_image": "leovct/zkevm-contracts:v8.0.0-rc.4-fork.12", "zkevm_da_image": "0xpolygon/cdk-data-availability:0.0.10", "zkevm_node_image": "hermeznetwork/zkevm-node:v0.7.3", diff --git a/test/Makefile b/test/Makefile index 51a475edd..2435730cb 100644 --- a/test/Makefile +++ b/test/Makefile @@ -3,6 +3,8 @@ generate-mocks: generate-mocks-bridgesync generate-mocks-reorgdetector generate- generate-mocks-da generate-mocks-l1infotreesync generate-mocks-helpers \ generate-mocks-sync generate-mocks-l1infotreesync generate-mocks-aggregator \ generate-mocks-aggsender generate-mocks-agglayer generate-mocks-bridgesync + generate-mocks-sync generate-mocks-l1infotreesync generate-mocks-aggregator \ + generate-mocks-aggsender generate-mocks-agglayer generate-mocks-bridgesync .PHONY: generate-mocks-bridgesync generate-mocks-bridgesync: ## Generates mocks for bridgesync, using mockery tool @@ -61,11 +63,8 @@ generate-mocks-aggregator: ## Generates mocks for aggregator, using mockery tool .PHONY: generate-mocks-aggsender generate-mocks-aggsender: ## Generates mocks for aggsender, using mockery tool - export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=L1InfoTreeSyncer --dir=../aggsender/types --output=../aggsender/mocks --outpkg=mocks --structname=L1InfoTreeSyncerMock --filename=mock_l1infotree_syncer.go ${COMMON_MOCKERY_PARAMS} - export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=L2BridgeSyncer --dir=../aggsender/types --output=../aggsender/mocks --outpkg=mocks --structname=L2BridgeSyncerMock --filename=mock_l2bridge_syncer.go ${COMMON_MOCKERY_PARAMS} - export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=Logger --dir=../aggsender/types --output=../aggsender/mocks --outpkg=mocks --structname=LoggerMock --filename=mock_logger.go ${COMMON_MOCKERY_PARAMS} - export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=AggSenderStorage --dir=../aggsender/db --output=../aggsender/mocks --outpkg=mocks --structname=AggSenderStorageMock --filename=mock_aggsender_storage.go ${COMMON_MOCKERY_PARAMS} - export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=EthClient --dir=../aggsender/types --output=../aggsender/mocks --outpkg=mocks --structname=EthClientMock --filename=mock_eth_client.go ${COMMON_MOCKERY_PARAMS} + rm -Rf ../aggsender/mocks + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --all --case snake --dir ../aggsender --output ../aggsender/mocks --outpkg mocks ${COMMON_MOCKERY_PARAMS} .PHONY: generate-mocks-agglayer generate-mocks-agglayer: ## Generates mocks for agglayer, using mockery tool From 691962858a52f944f6d52c6e54d90711f5e704ef Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 31 Oct 2024 18:37:05 +0100 Subject: [PATCH 02/27] fix: epoch, rebase error --- aggsender/aggsender.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aggsender/aggsender.go b/aggsender/aggsender.go index ec0f6bb08..869734b2c 100644 --- a/aggsender/aggsender.go +++ b/aggsender/aggsender.go @@ -250,7 +250,8 @@ func (a *AggSender) getNextHeightAndPreviousLER( func (a *AggSender) buildCertificate(ctx context.Context, bridges []bridgesync.Bridge, claims []bridgesync.Claim, - lastSentCertificateInfo types.CertificateInfo) (*agglayer.Certificate, error) { + lastSentCertificateInfo types.CertificateInfo, + toBlock uint64) (*agglayer.Certificate, error) { if len(bridges) == 0 && len(claims) == 0 { return nil, errNoBridgesAndClaims } From 497488d9edfae3255635da42202aded644011081 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 7 Nov 2024 12:16:33 +0100 Subject: [PATCH 03/27] feat: rename ClockConfiguration to EpochConfiguration that is the final name on AggLayer --- agglayer/client.go | 14 ++++++------ agglayer/client_test.go | 26 +++++++++++++++------- agglayer/mock_agglayer_client.go | 6 ++--- agglayer/types.go | 2 +- aggsender/aggsender_test.go | 4 ++-- aggsender/epoch_notifier_per_block.go | 4 ++-- aggsender/epoch_notifier_per_block_test.go | 4 ++-- 7 files changed, 35 insertions(+), 25 deletions(-) diff --git a/agglayer/client.go b/agglayer/client.go index 92938c4f3..8396fc9e3 100644 --- a/agglayer/client.go +++ b/agglayer/client.go @@ -20,8 +20,8 @@ var ( jSONRPCCall = rpc.JSONRPCCall ) -type AggLayerClientGetClockConfiguration interface { - GetClockConfiguration() (*ClockConfiguration, error) +type AggLayerClientGetEpochConfiguration interface { + GetEpochConfiguration() (*ClockConfiguration, error) } // AgglayerClientInterface is the interface that defines the methods that the AggLayerClient will implement @@ -30,7 +30,7 @@ type AgglayerClientInterface interface { WaitTxToBeMined(hash common.Hash, ctx context.Context) error SendCertificate(certificate *SignedCertificate) (common.Hash, error) GetCertificateHeader(certificateHash common.Hash) (*CertificateHeader, error) - AggLayerClientGetClockConfiguration + AggLayerClientGetEpochConfiguration } // AggLayerClient is the client that will be used to interact with the AggLayer @@ -139,15 +139,15 @@ func (c *AggLayerClient) GetCertificateHeader(certificateHash common.Hash) (*Cer return result, nil } -// GetClockConfiguration returns the clock configuration of AggLayer -func (c *AggLayerClient) GetClockConfiguration() (*ClockConfiguration, error) { - response, err := jSONRPCCall(c.url, "interop_getClockConfiguration") +// GetEpochConfiguration returns the clock configuration of AggLayer +func (c *AggLayerClient) GetEpochConfiguration() (*ClockConfiguration, error) { + response, err := jSONRPCCall(c.url, "interop_getEpochConfiguration") if err != nil { return nil, err } if response.Error != nil { - return nil, fmt.Errorf("GetClockConfiguration code=%d msg=%s", response.Error.Code, response.Error.Message) + return nil, fmt.Errorf("GetEpochConfiguration code=%d msg=%s", response.Error.Code, response.Error.Message) } var result *ClockConfiguration diff --git a/agglayer/client_test.go b/agglayer/client_test.go index 5418b7433..68d5ddb41 100644 --- a/agglayer/client_test.go +++ b/agglayer/client_test.go @@ -12,7 +12,17 @@ const ( testURL = "http://localhost:8080" ) -func TestGetClockConfigurationResponseWithError(t *testing.T) { +func TestExploratoryClient(t *testing.T) { + t.Skip("This test is for exploratory purposes only") + sut := NewAggLayerClient("http://127.0.0.1:32853") + config, err := sut.GetEpochConfiguration() + require.NoError(t, err) + require.NotNil(t, config) + fmt.Printf("Config: %s", config.String()) + +} + +func TestGetEpochConfigurationResponseWithError(t *testing.T) { sut := NewAggLayerClient(testURL) response := rpc.Response{ Error: &rpc.ErrorObject{}, @@ -20,12 +30,12 @@ func TestGetClockConfigurationResponseWithError(t *testing.T) { jSONRPCCall = func(url, method string, params ...interface{}) (rpc.Response, error) { return response, nil } - clockConfig, err := sut.GetClockConfiguration() + clockConfig, err := sut.GetEpochConfiguration() require.Nil(t, clockConfig) require.Error(t, err) } -func TestGetClockConfigurationResponseBadJson(t *testing.T) { +func TestGetEpochConfigurationResponseBadJson(t *testing.T) { sut := NewAggLayerClient(testURL) response := rpc.Response{ Result: []byte(`{`), @@ -33,23 +43,23 @@ func TestGetClockConfigurationResponseBadJson(t *testing.T) { jSONRPCCall = func(url, method string, params ...interface{}) (rpc.Response, error) { return response, nil } - clockConfig, err := sut.GetClockConfiguration() + clockConfig, err := sut.GetEpochConfiguration() require.Nil(t, clockConfig) require.Error(t, err) } -func TestGetClockConfigurationErrorResponse(t *testing.T) { +func TestGetEpochConfigurationErrorResponse(t *testing.T) { sut := NewAggLayerClient(testURL) jSONRPCCall = func(url, method string, params ...interface{}) (rpc.Response, error) { return rpc.Response{}, fmt.Errorf("unittest error") } - clockConfig, err := sut.GetClockConfiguration() + clockConfig, err := sut.GetEpochConfiguration() require.Nil(t, clockConfig) require.Error(t, err) } -func TestGetClockConfigurationOkResponse(t *testing.T) { +func TestGetEpochConfigurationOkResponse(t *testing.T) { sut := NewAggLayerClient(testURL) response := rpc.Response{ Result: []byte(`{"epoch_duration": 1, "genesis_block": 1}`), @@ -57,7 +67,7 @@ func TestGetClockConfigurationOkResponse(t *testing.T) { jSONRPCCall = func(url, method string, params ...interface{}) (rpc.Response, error) { return response, nil } - clockConfig, err := sut.GetClockConfiguration() + clockConfig, err := sut.GetEpochConfiguration() require.NotNil(t, clockConfig) require.NoError(t, err) require.Equal(t, ClockConfiguration{ diff --git a/agglayer/mock_agglayer_client.go b/agglayer/mock_agglayer_client.go index a6eae49ea..1b7567130 100644 --- a/agglayer/mock_agglayer_client.go +++ b/agglayer/mock_agglayer_client.go @@ -45,12 +45,12 @@ func (_m *AgglayerClientMock) GetCertificateHeader(certificateHash common.Hash) return r0, r1 } -// GetClockConfiguration provides a mock function with given fields: -func (_m *AgglayerClientMock) GetClockConfiguration() (*ClockConfiguration, error) { +// GetEpochConfiguration provides a mock function with given fields: +func (_m *AgglayerClientMock) GetEpochConfiguration() (*ClockConfiguration, error) { ret := _m.Called() if len(ret) == 0 { - panic("no return value specified for GetClockConfiguration") + panic("no return value specified for GetEpochConfiguration") } var r0 *ClockConfiguration diff --git a/agglayer/types.go b/agglayer/types.go index 4cc88b320..64f3e0a57 100644 --- a/agglayer/types.go +++ b/agglayer/types.go @@ -533,7 +533,7 @@ func (c CertificateHeader) String() string { } // ClockConfiguration represents the configuration of the epoch clock -// returned by the interop_getClockConfiguration RPC call +// returned by the interop_GetEpochConfiguration RPC call type ClockConfiguration struct { EpochDuration uint64 `json:"epoch_duration"` GenesisBlock uint64 `json:"genesis_block"` diff --git a/aggsender/aggsender_test.go b/aggsender/aggsender_test.go index 9a73c7ae8..e19de2958 100644 --- a/aggsender/aggsender_test.go +++ b/aggsender/aggsender_test.go @@ -33,10 +33,10 @@ func TestExploratoryGetCertificateHeader(t *testing.T) { require.NoError(t, err) fmt.Print(certificateHeader) } -func TestExploratoryGetClockConfiguration(t *testing.T) { +func TestExploratoryGetEpochConfiguration(t *testing.T) { t.Skip("This test is exploratory and should be skipped") aggLayerClient := agglayer.NewAggLayerClient("http://localhost:32796") - clockConfig, err := aggLayerClient.GetClockConfiguration() + clockConfig, err := aggLayerClient.GetEpochConfiguration() require.NoError(t, err) fmt.Print(clockConfig) } diff --git a/aggsender/epoch_notifier_per_block.go b/aggsender/epoch_notifier_per_block.go index f145003b9..c9b138890 100644 --- a/aggsender/epoch_notifier_per_block.go +++ b/aggsender/epoch_notifier_per_block.go @@ -24,12 +24,12 @@ type ConfigEpochNotifierPerBlock struct { NotifyPendingBlocksBeforeEndEpoch uint } -func NewConfigEpochNotifierPerBlock(aggLayer agglayer.AggLayerClientGetClockConfiguration, +func NewConfigEpochNotifierPerBlock(aggLayer agglayer.AggLayerClientGetEpochConfiguration, notifyPendingBlocksBeforeEndEpoch uint) (*ConfigEpochNotifierPerBlock, error) { if aggLayer == nil { return nil, fmt.Errorf("newConfigEpochNotifierPerBlock: aggLayerClient is required") } - clockConfig, err := aggLayer.GetClockConfiguration() + clockConfig, err := aggLayer.GetEpochConfiguration() if err != nil { return nil, fmt.Errorf("newConfigEpochNotifierPerBlock: error getting clock configuration from AggLayer: %w", err) } diff --git a/aggsender/epoch_notifier_per_block_test.go b/aggsender/epoch_notifier_per_block_test.go index ef28c6659..9e84fb6a4 100644 --- a/aggsender/epoch_notifier_per_block_test.go +++ b/aggsender/epoch_notifier_per_block_test.go @@ -88,14 +88,14 @@ func TestNewConfigEpochNotifierPerBlock(t *testing.T) { _, err := NewConfigEpochNotifierPerBlock(nil, 1) require.Error(t, err) aggLayerMock := agglayer.NewAgglayerClientMock(t) - aggLayerMock.On("GetClockConfiguration").Return(nil, fmt.Errorf("error")).Once() + aggLayerMock.On("GetEpochConfiguration").Return(nil, fmt.Errorf("error")).Once() _, err = NewConfigEpochNotifierPerBlock(aggLayerMock, 1) require.Error(t, err) cfgAggLayer := &agglayer.ClockConfiguration{ GenesisBlock: 123, EpochDuration: 456, } - aggLayerMock.On("GetClockConfiguration").Return(cfgAggLayer, nil).Once() + aggLayerMock.On("GetEpochConfiguration").Return(cfgAggLayer, nil).Once() cfg, err := NewConfigEpochNotifierPerBlock(aggLayerMock, 1) require.NoError(t, err) require.Equal(t, uint64(123), cfg.StartingEpochBlock) From 0b8ba050002e6d5be59557824ff08189f3c0617b Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 7 Nov 2024 12:31:00 +0100 Subject: [PATCH 04/27] fix: lint --- agglayer/client_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/agglayer/client_test.go b/agglayer/client_test.go index 68d5ddb41..82baea85e 100644 --- a/agglayer/client_test.go +++ b/agglayer/client_test.go @@ -19,7 +19,6 @@ func TestExploratoryClient(t *testing.T) { require.NoError(t, err) require.NotNil(t, config) fmt.Printf("Config: %s", config.String()) - } func TestGetEpochConfigurationResponseWithError(t *testing.T) { From 0fe7463a165719647537b56dd05515058ef6aef1 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Fri, 8 Nov 2024 21:31:48 +0100 Subject: [PATCH 05/27] fix: adapt to rebase --- aggsender/aggsender.go | 6 +- aggsender/aggsender_test.go | 12 +- aggsender/config.go | 20 +- aggsender/mocks/agg_sender_storage.go | 87 +++-- aggsender/mocks/epoch_notifier.go | 35 ++ aggsender/mocks/mock_aggsender_storage.go | 351 ------------------ aggsender/mocks/mock_eth_client.go | 154 -------- aggsender/mocks/mock_l1infotree_syncer.go | 217 ----------- aggsender/mocks/mock_l2bridge_syncer.go | 423 ---------------------- aggsender/mocks/mock_logger.go | 290 --------------- cmd/run.go | 2 +- crates/cdk/versions.json | 2 +- 12 files changed, 108 insertions(+), 1491 deletions(-) delete mode 100644 aggsender/mocks/mock_aggsender_storage.go delete mode 100644 aggsender/mocks/mock_eth_client.go delete mode 100644 aggsender/mocks/mock_l1infotree_syncer.go delete mode 100644 aggsender/mocks/mock_l2bridge_syncer.go delete mode 100644 aggsender/mocks/mock_logger.go diff --git a/aggsender/aggsender.go b/aggsender/aggsender.go index 869734b2c..263f98e85 100644 --- a/aggsender/aggsender.go +++ b/aggsender/aggsender.go @@ -93,7 +93,7 @@ func (a *AggSender) sendCertificates(ctx context.Context) { select { case epoch := <-chEpoch: a.log.Infof("Epoch %d received", epoch.Epoch) - if err := a.sendCertificate(ctx); err != nil { + if _, err := a.sendCertificate(ctx); err != nil { log.Error(err) } case <-ctx.Done(): @@ -186,7 +186,7 @@ func (a *AggSender) sendCertificate(ctx context.Context) (*agglayer.SignedCertif } createdTime := time.Now().UTC().UnixMilli() - certInfo := aggsendertypes.CertificateInfo{ + certInfo := types.CertificateInfo{ Height: certificate.Height, CertificateID: certificateHash, NewLocalExitRoot: certificate.NewLocalExitRoot, @@ -227,7 +227,7 @@ func (a *AggSender) saveCertificateToFile(signedCertificate *agglayer.SignedCert // getNextHeightAndPreviousLER returns the height and previous LER for the new certificate func (a *AggSender) getNextHeightAndPreviousLER( - lastSentCertificateInfo *aggsendertypes.CertificateInfo) (uint64, common.Hash) { + lastSentCertificateInfo *types.CertificateInfo) (uint64, common.Hash) { height := lastSentCertificateInfo.Height + 1 if lastSentCertificateInfo.Status == agglayer.InError { // previous certificate was in error, so we need to resend it diff --git a/aggsender/aggsender_test.go b/aggsender/aggsender_test.go index e19de2958..5e01aa45b 100644 --- a/aggsender/aggsender_test.go +++ b/aggsender/aggsender_test.go @@ -49,6 +49,8 @@ func TestConfigString(t *testing.T) { CheckSettledInterval: types.Duration{Duration: 20 * time.Second}, AggsenderPrivateKey: types.KeystoreFileConfig{Path: "/path/to/key", Password: "password"}, URLRPCL2: "http://l2.rpc.url", + BlockFinality: "latestBlock", + BlocksBeforeEpochEnding: 10, SaveCertificatesToFilesPath: "/path/to/certificates", } @@ -59,6 +61,8 @@ func TestConfigString(t *testing.T) { "AggsenderPrivateKeyPath: /path/to/key\n" + "AggsenderPrivateKeyPassword: password\n" + "URLRPCL2: http://l2.rpc.url\n" + + "BlockFinality: latestBlock\n" + + "BlocksBeforeEpochEnding: 10\n" + "SaveCertificatesToFilesPath: /path/to/certificates\n" require.Equal(t, expected, config.String()) @@ -909,7 +913,7 @@ func TestSendCertificate(t *testing.T) { if cfg.shouldSendCertificate != nil || cfg.getLastSentCertificate != nil || cfg.saveLastSentCertificate != nil { - mockStorage = mocks.NewAggSenderStorageMock(t) + mockStorage = mocks.NewAggSenderStorage(t) mockStorage.On("GetCertificatesByStatus", nonSettledStatuses). Return(cfg.shouldSendCertificate...).Once() @@ -1489,10 +1493,10 @@ func TestSendCertificate_NoClaims(t *testing.T) { require.NoError(t, err) ctx := context.Background() - mockStorage := mocks.NewAggSenderStorageMock(t) - mockL2Syncer := mocks.NewL2BridgeSyncerMock(t) + mockStorage := mocks.NewAggSenderStorage(t) + mockL2Syncer := mocks.NewL2BridgeSyncer(t) mockAggLayerClient := agglayer.NewAgglayerClientMock(t) - mockL1InfoTreeSyncer := mocks.NewL1InfoTreeSyncerMock(t) + mockL1InfoTreeSyncer := mocks.NewL1InfoTreeSyncer(t) aggSender := &AggSender{ log: log.WithFields("aggsender-test", "no claims test"), diff --git a/aggsender/config.go b/aggsender/config.go index ec2c92b02..686945897 100644 --- a/aggsender/config.go +++ b/aggsender/config.go @@ -1,6 +1,8 @@ package aggsender import ( + "fmt" + "github.com/0xPolygon/cdk/config/types" ) @@ -23,6 +25,20 @@ type Config struct { // BlocksBeforeEpochEnding indicates how many blocks before the epoch ending // the AggSender should send the certificate BlocksBeforeEpochEnding uint `mapstructure:"BlocksBeforeEpochEnding"` - // SaveCertificatesToFiles is a flag which tells the AggSender to save the certificates to a file - SaveCertificatesToFiles bool `mapstructure:"SaveCertificatesToFiles"` + // SaveCertificatesToFilesPath if != "" tells the AggSender to save the certificates to a file in this path + SaveCertificatesToFilesPath string `mapstructure:"SaveCertificatesToFilesPath"` +} + +// String returns a string representation of the Config +func (c Config) String() string { + return "StoragePath: " + c.StoragePath + "\n" + + "AggLayerURL: " + c.AggLayerURL + "\n" + + "BlockGetInterval: " + c.BlockGetInterval.String() + "\n" + + "CheckSettledInterval: " + c.CheckSettledInterval.String() + "\n" + + "AggsenderPrivateKeyPath: " + c.AggsenderPrivateKey.Path + "\n" + + "AggsenderPrivateKeyPassword: " + c.AggsenderPrivateKey.Password + "\n" + + "URLRPCL2: " + c.URLRPCL2 + "\n" + + "BlockFinality: " + c.BlockFinality + "\n" + + "BlocksBeforeEpochEnding: " + fmt.Sprintf("%d", c.BlocksBeforeEpochEnding) + "\n" + + "SaveCertificatesToFilesPath: " + c.SaveCertificatesToFilesPath + "\n" } diff --git a/aggsender/mocks/agg_sender_storage.go b/aggsender/mocks/agg_sender_storage.go index 2f9a9e8ea..1816d4a37 100644 --- a/aggsender/mocks/agg_sender_storage.go +++ b/aggsender/mocks/agg_sender_storage.go @@ -73,9 +73,9 @@ func (_c *AggSenderStorage_DeleteCertificate_Call) RunAndReturn(run func(context return _c } -// GetCertificateByHeight provides a mock function with given fields: ctx, height -func (_m *AggSenderStorage) GetCertificateByHeight(ctx context.Context, height uint64) (types.CertificateInfo, error) { - ret := _m.Called(ctx, height) +// GetCertificateByHeight provides a mock function with given fields: height +func (_m *AggSenderStorage) GetCertificateByHeight(height uint64) (types.CertificateInfo, error) { + ret := _m.Called(height) if len(ret) == 0 { panic("no return value specified for GetCertificateByHeight") @@ -83,17 +83,17 @@ func (_m *AggSenderStorage) GetCertificateByHeight(ctx context.Context, height u var r0 types.CertificateInfo var r1 error - if rf, ok := ret.Get(0).(func(context.Context, uint64) (types.CertificateInfo, error)); ok { - return rf(ctx, height) + if rf, ok := ret.Get(0).(func(uint64) (types.CertificateInfo, error)); ok { + return rf(height) } - if rf, ok := ret.Get(0).(func(context.Context, uint64) types.CertificateInfo); ok { - r0 = rf(ctx, height) + if rf, ok := ret.Get(0).(func(uint64) types.CertificateInfo); ok { + r0 = rf(height) } else { r0 = ret.Get(0).(types.CertificateInfo) } - if rf, ok := ret.Get(1).(func(context.Context, uint64) error); ok { - r1 = rf(ctx, height) + if rf, ok := ret.Get(1).(func(uint64) error); ok { + r1 = rf(height) } else { r1 = ret.Error(1) } @@ -107,15 +107,14 @@ type AggSenderStorage_GetCertificateByHeight_Call struct { } // GetCertificateByHeight is a helper method to define mock.On call -// - ctx context.Context // - height uint64 -func (_e *AggSenderStorage_Expecter) GetCertificateByHeight(ctx interface{}, height interface{}) *AggSenderStorage_GetCertificateByHeight_Call { - return &AggSenderStorage_GetCertificateByHeight_Call{Call: _e.mock.On("GetCertificateByHeight", ctx, height)} +func (_e *AggSenderStorage_Expecter) GetCertificateByHeight(height interface{}) *AggSenderStorage_GetCertificateByHeight_Call { + return &AggSenderStorage_GetCertificateByHeight_Call{Call: _e.mock.On("GetCertificateByHeight", height)} } -func (_c *AggSenderStorage_GetCertificateByHeight_Call) Run(run func(ctx context.Context, height uint64)) *AggSenderStorage_GetCertificateByHeight_Call { +func (_c *AggSenderStorage_GetCertificateByHeight_Call) Run(run func(height uint64)) *AggSenderStorage_GetCertificateByHeight_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(uint64)) + run(args[0].(uint64)) }) return _c } @@ -125,14 +124,14 @@ func (_c *AggSenderStorage_GetCertificateByHeight_Call) Return(_a0 types.Certifi return _c } -func (_c *AggSenderStorage_GetCertificateByHeight_Call) RunAndReturn(run func(context.Context, uint64) (types.CertificateInfo, error)) *AggSenderStorage_GetCertificateByHeight_Call { +func (_c *AggSenderStorage_GetCertificateByHeight_Call) RunAndReturn(run func(uint64) (types.CertificateInfo, error)) *AggSenderStorage_GetCertificateByHeight_Call { _c.Call.Return(run) return _c } -// GetCertificatesByStatus provides a mock function with given fields: ctx, status -func (_m *AggSenderStorage) GetCertificatesByStatus(ctx context.Context, status []agglayer.CertificateStatus) ([]*types.CertificateInfo, error) { - ret := _m.Called(ctx, status) +// GetCertificatesByStatus provides a mock function with given fields: status +func (_m *AggSenderStorage) GetCertificatesByStatus(status []agglayer.CertificateStatus) ([]*types.CertificateInfo, error) { + ret := _m.Called(status) if len(ret) == 0 { panic("no return value specified for GetCertificatesByStatus") @@ -140,19 +139,19 @@ func (_m *AggSenderStorage) GetCertificatesByStatus(ctx context.Context, status var r0 []*types.CertificateInfo var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []agglayer.CertificateStatus) ([]*types.CertificateInfo, error)); ok { - return rf(ctx, status) + if rf, ok := ret.Get(0).(func([]agglayer.CertificateStatus) ([]*types.CertificateInfo, error)); ok { + return rf(status) } - if rf, ok := ret.Get(0).(func(context.Context, []agglayer.CertificateStatus) []*types.CertificateInfo); ok { - r0 = rf(ctx, status) + if rf, ok := ret.Get(0).(func([]agglayer.CertificateStatus) []*types.CertificateInfo); ok { + r0 = rf(status) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*types.CertificateInfo) } } - if rf, ok := ret.Get(1).(func(context.Context, []agglayer.CertificateStatus) error); ok { - r1 = rf(ctx, status) + if rf, ok := ret.Get(1).(func([]agglayer.CertificateStatus) error); ok { + r1 = rf(status) } else { r1 = ret.Error(1) } @@ -166,15 +165,14 @@ type AggSenderStorage_GetCertificatesByStatus_Call struct { } // GetCertificatesByStatus is a helper method to define mock.On call -// - ctx context.Context // - status []agglayer.CertificateStatus -func (_e *AggSenderStorage_Expecter) GetCertificatesByStatus(ctx interface{}, status interface{}) *AggSenderStorage_GetCertificatesByStatus_Call { - return &AggSenderStorage_GetCertificatesByStatus_Call{Call: _e.mock.On("GetCertificatesByStatus", ctx, status)} +func (_e *AggSenderStorage_Expecter) GetCertificatesByStatus(status interface{}) *AggSenderStorage_GetCertificatesByStatus_Call { + return &AggSenderStorage_GetCertificatesByStatus_Call{Call: _e.mock.On("GetCertificatesByStatus", status)} } -func (_c *AggSenderStorage_GetCertificatesByStatus_Call) Run(run func(ctx context.Context, status []agglayer.CertificateStatus)) *AggSenderStorage_GetCertificatesByStatus_Call { +func (_c *AggSenderStorage_GetCertificatesByStatus_Call) Run(run func(status []agglayer.CertificateStatus)) *AggSenderStorage_GetCertificatesByStatus_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].([]agglayer.CertificateStatus)) + run(args[0].([]agglayer.CertificateStatus)) }) return _c } @@ -184,14 +182,14 @@ func (_c *AggSenderStorage_GetCertificatesByStatus_Call) Return(_a0 []*types.Cer return _c } -func (_c *AggSenderStorage_GetCertificatesByStatus_Call) RunAndReturn(run func(context.Context, []agglayer.CertificateStatus) ([]*types.CertificateInfo, error)) *AggSenderStorage_GetCertificatesByStatus_Call { +func (_c *AggSenderStorage_GetCertificatesByStatus_Call) RunAndReturn(run func([]agglayer.CertificateStatus) ([]*types.CertificateInfo, error)) *AggSenderStorage_GetCertificatesByStatus_Call { _c.Call.Return(run) return _c } -// GetLastSentCertificate provides a mock function with given fields: ctx -func (_m *AggSenderStorage) GetLastSentCertificate(ctx context.Context) (types.CertificateInfo, error) { - ret := _m.Called(ctx) +// GetLastSentCertificate provides a mock function with given fields: +func (_m *AggSenderStorage) GetLastSentCertificate() (types.CertificateInfo, error) { + ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetLastSentCertificate") @@ -199,17 +197,17 @@ func (_m *AggSenderStorage) GetLastSentCertificate(ctx context.Context) (types.C var r0 types.CertificateInfo var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (types.CertificateInfo, error)); ok { - return rf(ctx) + if rf, ok := ret.Get(0).(func() (types.CertificateInfo, error)); ok { + return rf() } - if rf, ok := ret.Get(0).(func(context.Context) types.CertificateInfo); ok { - r0 = rf(ctx) + if rf, ok := ret.Get(0).(func() types.CertificateInfo); ok { + r0 = rf() } else { r0 = ret.Get(0).(types.CertificateInfo) } - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() } else { r1 = ret.Error(1) } @@ -223,14 +221,13 @@ type AggSenderStorage_GetLastSentCertificate_Call struct { } // GetLastSentCertificate is a helper method to define mock.On call -// - ctx context.Context -func (_e *AggSenderStorage_Expecter) GetLastSentCertificate(ctx interface{}) *AggSenderStorage_GetLastSentCertificate_Call { - return &AggSenderStorage_GetLastSentCertificate_Call{Call: _e.mock.On("GetLastSentCertificate", ctx)} +func (_e *AggSenderStorage_Expecter) GetLastSentCertificate() *AggSenderStorage_GetLastSentCertificate_Call { + return &AggSenderStorage_GetLastSentCertificate_Call{Call: _e.mock.On("GetLastSentCertificate")} } -func (_c *AggSenderStorage_GetLastSentCertificate_Call) Run(run func(ctx context.Context)) *AggSenderStorage_GetLastSentCertificate_Call { +func (_c *AggSenderStorage_GetLastSentCertificate_Call) Run(run func()) *AggSenderStorage_GetLastSentCertificate_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context)) + run() }) return _c } @@ -240,7 +237,7 @@ func (_c *AggSenderStorage_GetLastSentCertificate_Call) Return(_a0 types.Certifi return _c } -func (_c *AggSenderStorage_GetLastSentCertificate_Call) RunAndReturn(run func(context.Context) (types.CertificateInfo, error)) *AggSenderStorage_GetLastSentCertificate_Call { +func (_c *AggSenderStorage_GetLastSentCertificate_Call) RunAndReturn(run func() (types.CertificateInfo, error)) *AggSenderStorage_GetLastSentCertificate_Call { _c.Call.Return(run) return _c } diff --git a/aggsender/mocks/epoch_notifier.go b/aggsender/mocks/epoch_notifier.go index bff8094f5..fb8bf35f5 100644 --- a/aggsender/mocks/epoch_notifier.go +++ b/aggsender/mocks/epoch_notifier.go @@ -3,6 +3,8 @@ package mocks import ( + context "context" + types "github.com/0xPolygon/cdk/aggsender/types" mock "github.com/stretchr/testify/mock" ) @@ -20,6 +22,39 @@ func (_m *EpochNotifier) EXPECT() *EpochNotifier_Expecter { return &EpochNotifier_Expecter{mock: &_m.Mock} } +// Start provides a mock function with given fields: ctx +func (_m *EpochNotifier) Start(ctx context.Context) { + _m.Called(ctx) +} + +// EpochNotifier_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start' +type EpochNotifier_Start_Call struct { + *mock.Call +} + +// Start is a helper method to define mock.On call +// - ctx context.Context +func (_e *EpochNotifier_Expecter) Start(ctx interface{}) *EpochNotifier_Start_Call { + return &EpochNotifier_Start_Call{Call: _e.mock.On("Start", ctx)} +} + +func (_c *EpochNotifier_Start_Call) Run(run func(ctx context.Context)) *EpochNotifier_Start_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *EpochNotifier_Start_Call) Return() *EpochNotifier_Start_Call { + _c.Call.Return() + return _c +} + +func (_c *EpochNotifier_Start_Call) RunAndReturn(run func(context.Context)) *EpochNotifier_Start_Call { + _c.Call.Return(run) + return _c +} + // String provides a mock function with given fields: func (_m *EpochNotifier) String() string { ret := _m.Called() diff --git a/aggsender/mocks/mock_aggsender_storage.go b/aggsender/mocks/mock_aggsender_storage.go deleted file mode 100644 index 17f8d2272..000000000 --- a/aggsender/mocks/mock_aggsender_storage.go +++ /dev/null @@ -1,351 +0,0 @@ -// Code generated by mockery. DO NOT EDIT. - -package mocks - -import ( - agglayer "github.com/0xPolygon/cdk/agglayer" - common "github.com/ethereum/go-ethereum/common" - - context "context" - - mock "github.com/stretchr/testify/mock" - - types "github.com/0xPolygon/cdk/aggsender/types" -) - -// AggSenderStorageMock is an autogenerated mock type for the AggSenderStorage type -type AggSenderStorageMock struct { - mock.Mock -} - -type AggSenderStorageMock_Expecter struct { - mock *mock.Mock -} - -func (_m *AggSenderStorageMock) EXPECT() *AggSenderStorageMock_Expecter { - return &AggSenderStorageMock_Expecter{mock: &_m.Mock} -} - -// DeleteCertificate provides a mock function with given fields: ctx, certificateID -func (_m *AggSenderStorageMock) DeleteCertificate(ctx context.Context, certificateID common.Hash) error { - ret := _m.Called(ctx, certificateID) - - if len(ret) == 0 { - panic("no return value specified for DeleteCertificate") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, common.Hash) error); ok { - r0 = rf(ctx, certificateID) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// AggSenderStorageMock_DeleteCertificate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteCertificate' -type AggSenderStorageMock_DeleteCertificate_Call struct { - *mock.Call -} - -// DeleteCertificate is a helper method to define mock.On call -// - ctx context.Context -// - certificateID common.Hash -func (_e *AggSenderStorageMock_Expecter) DeleteCertificate(ctx interface{}, certificateID interface{}) *AggSenderStorageMock_DeleteCertificate_Call { - return &AggSenderStorageMock_DeleteCertificate_Call{Call: _e.mock.On("DeleteCertificate", ctx, certificateID)} -} - -func (_c *AggSenderStorageMock_DeleteCertificate_Call) Run(run func(ctx context.Context, certificateID common.Hash)) *AggSenderStorageMock_DeleteCertificate_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(common.Hash)) - }) - return _c -} - -func (_c *AggSenderStorageMock_DeleteCertificate_Call) Return(_a0 error) *AggSenderStorageMock_DeleteCertificate_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *AggSenderStorageMock_DeleteCertificate_Call) RunAndReturn(run func(context.Context, common.Hash) error) *AggSenderStorageMock_DeleteCertificate_Call { - _c.Call.Return(run) - return _c -} - -// GetCertificateByHeight provides a mock function with given fields: height -func (_m *AggSenderStorageMock) GetCertificateByHeight(height uint64) (types.CertificateInfo, error) { - ret := _m.Called(height) - - if len(ret) == 0 { - panic("no return value specified for GetCertificateByHeight") - } - - var r0 types.CertificateInfo - var r1 error - if rf, ok := ret.Get(0).(func(uint64) (types.CertificateInfo, error)); ok { - return rf(height) - } - if rf, ok := ret.Get(0).(func(uint64) types.CertificateInfo); ok { - r0 = rf(height) - } else { - r0 = ret.Get(0).(types.CertificateInfo) - } - - if rf, ok := ret.Get(1).(func(uint64) error); ok { - r1 = rf(height) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AggSenderStorageMock_GetCertificateByHeight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCertificateByHeight' -type AggSenderStorageMock_GetCertificateByHeight_Call struct { - *mock.Call -} - -// GetCertificateByHeight is a helper method to define mock.On call -// - height uint64 -func (_e *AggSenderStorageMock_Expecter) GetCertificateByHeight(height interface{}) *AggSenderStorageMock_GetCertificateByHeight_Call { - return &AggSenderStorageMock_GetCertificateByHeight_Call{Call: _e.mock.On("GetCertificateByHeight", height)} -} - -func (_c *AggSenderStorageMock_GetCertificateByHeight_Call) Run(run func(height uint64)) *AggSenderStorageMock_GetCertificateByHeight_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(uint64)) - }) - return _c -} - -func (_c *AggSenderStorageMock_GetCertificateByHeight_Call) Return(_a0 types.CertificateInfo, _a1 error) *AggSenderStorageMock_GetCertificateByHeight_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AggSenderStorageMock_GetCertificateByHeight_Call) RunAndReturn(run func(uint64) (types.CertificateInfo, error)) *AggSenderStorageMock_GetCertificateByHeight_Call { - _c.Call.Return(run) - return _c -} - -// GetCertificatesByStatus provides a mock function with given fields: status -func (_m *AggSenderStorageMock) GetCertificatesByStatus(status []agglayer.CertificateStatus) ([]*types.CertificateInfo, error) { - ret := _m.Called(status) - - if len(ret) == 0 { - panic("no return value specified for GetCertificatesByStatus") - } - - var r0 []*types.CertificateInfo - var r1 error - if rf, ok := ret.Get(0).(func([]agglayer.CertificateStatus) ([]*types.CertificateInfo, error)); ok { - return rf(status) - } - if rf, ok := ret.Get(0).(func([]agglayer.CertificateStatus) []*types.CertificateInfo); ok { - r0 = rf(status) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*types.CertificateInfo) - } - } - - if rf, ok := ret.Get(1).(func([]agglayer.CertificateStatus) error); ok { - r1 = rf(status) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AggSenderStorageMock_GetCertificatesByStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCertificatesByStatus' -type AggSenderStorageMock_GetCertificatesByStatus_Call struct { - *mock.Call -} - -// GetCertificatesByStatus is a helper method to define mock.On call -// - status []agglayer.CertificateStatus -func (_e *AggSenderStorageMock_Expecter) GetCertificatesByStatus(status interface{}) *AggSenderStorageMock_GetCertificatesByStatus_Call { - return &AggSenderStorageMock_GetCertificatesByStatus_Call{Call: _e.mock.On("GetCertificatesByStatus", status)} -} - -func (_c *AggSenderStorageMock_GetCertificatesByStatus_Call) Run(run func(status []agglayer.CertificateStatus)) *AggSenderStorageMock_GetCertificatesByStatus_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].([]agglayer.CertificateStatus)) - }) - return _c -} - -func (_c *AggSenderStorageMock_GetCertificatesByStatus_Call) Return(_a0 []*types.CertificateInfo, _a1 error) *AggSenderStorageMock_GetCertificatesByStatus_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AggSenderStorageMock_GetCertificatesByStatus_Call) RunAndReturn(run func([]agglayer.CertificateStatus) ([]*types.CertificateInfo, error)) *AggSenderStorageMock_GetCertificatesByStatus_Call { - _c.Call.Return(run) - return _c -} - -// GetLastSentCertificate provides a mock function with given fields: -func (_m *AggSenderStorageMock) GetLastSentCertificate() (types.CertificateInfo, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetLastSentCertificate") - } - - var r0 types.CertificateInfo - var r1 error - if rf, ok := ret.Get(0).(func() (types.CertificateInfo, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() types.CertificateInfo); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(types.CertificateInfo) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AggSenderStorageMock_GetLastSentCertificate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLastSentCertificate' -type AggSenderStorageMock_GetLastSentCertificate_Call struct { - *mock.Call -} - -// GetLastSentCertificate is a helper method to define mock.On call -func (_e *AggSenderStorageMock_Expecter) GetLastSentCertificate() *AggSenderStorageMock_GetLastSentCertificate_Call { - return &AggSenderStorageMock_GetLastSentCertificate_Call{Call: _e.mock.On("GetLastSentCertificate")} -} - -func (_c *AggSenderStorageMock_GetLastSentCertificate_Call) Run(run func()) *AggSenderStorageMock_GetLastSentCertificate_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *AggSenderStorageMock_GetLastSentCertificate_Call) Return(_a0 types.CertificateInfo, _a1 error) *AggSenderStorageMock_GetLastSentCertificate_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AggSenderStorageMock_GetLastSentCertificate_Call) RunAndReturn(run func() (types.CertificateInfo, error)) *AggSenderStorageMock_GetLastSentCertificate_Call { - _c.Call.Return(run) - return _c -} - -// SaveLastSentCertificate provides a mock function with given fields: ctx, certificate -func (_m *AggSenderStorageMock) SaveLastSentCertificate(ctx context.Context, certificate types.CertificateInfo) error { - ret := _m.Called(ctx, certificate) - - if len(ret) == 0 { - panic("no return value specified for SaveLastSentCertificate") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, types.CertificateInfo) error); ok { - r0 = rf(ctx, certificate) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// AggSenderStorageMock_SaveLastSentCertificate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SaveLastSentCertificate' -type AggSenderStorageMock_SaveLastSentCertificate_Call struct { - *mock.Call -} - -// SaveLastSentCertificate is a helper method to define mock.On call -// - ctx context.Context -// - certificate types.CertificateInfo -func (_e *AggSenderStorageMock_Expecter) SaveLastSentCertificate(ctx interface{}, certificate interface{}) *AggSenderStorageMock_SaveLastSentCertificate_Call { - return &AggSenderStorageMock_SaveLastSentCertificate_Call{Call: _e.mock.On("SaveLastSentCertificate", ctx, certificate)} -} - -func (_c *AggSenderStorageMock_SaveLastSentCertificate_Call) Run(run func(ctx context.Context, certificate types.CertificateInfo)) *AggSenderStorageMock_SaveLastSentCertificate_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(types.CertificateInfo)) - }) - return _c -} - -func (_c *AggSenderStorageMock_SaveLastSentCertificate_Call) Return(_a0 error) *AggSenderStorageMock_SaveLastSentCertificate_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *AggSenderStorageMock_SaveLastSentCertificate_Call) RunAndReturn(run func(context.Context, types.CertificateInfo) error) *AggSenderStorageMock_SaveLastSentCertificate_Call { - _c.Call.Return(run) - return _c -} - -// UpdateCertificateStatus provides a mock function with given fields: ctx, certificate -func (_m *AggSenderStorageMock) UpdateCertificateStatus(ctx context.Context, certificate types.CertificateInfo) error { - ret := _m.Called(ctx, certificate) - - if len(ret) == 0 { - panic("no return value specified for UpdateCertificateStatus") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, types.CertificateInfo) error); ok { - r0 = rf(ctx, certificate) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// AggSenderStorageMock_UpdateCertificateStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateCertificateStatus' -type AggSenderStorageMock_UpdateCertificateStatus_Call struct { - *mock.Call -} - -// UpdateCertificateStatus is a helper method to define mock.On call -// - ctx context.Context -// - certificate types.CertificateInfo -func (_e *AggSenderStorageMock_Expecter) UpdateCertificateStatus(ctx interface{}, certificate interface{}) *AggSenderStorageMock_UpdateCertificateStatus_Call { - return &AggSenderStorageMock_UpdateCertificateStatus_Call{Call: _e.mock.On("UpdateCertificateStatus", ctx, certificate)} -} - -func (_c *AggSenderStorageMock_UpdateCertificateStatus_Call) Run(run func(ctx context.Context, certificate types.CertificateInfo)) *AggSenderStorageMock_UpdateCertificateStatus_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(types.CertificateInfo)) - }) - return _c -} - -func (_c *AggSenderStorageMock_UpdateCertificateStatus_Call) Return(_a0 error) *AggSenderStorageMock_UpdateCertificateStatus_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *AggSenderStorageMock_UpdateCertificateStatus_Call) RunAndReturn(run func(context.Context, types.CertificateInfo) error) *AggSenderStorageMock_UpdateCertificateStatus_Call { - _c.Call.Return(run) - return _c -} - -// NewAggSenderStorageMock creates a new instance of AggSenderStorageMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewAggSenderStorageMock(t interface { - mock.TestingT - Cleanup(func()) -}) *AggSenderStorageMock { - mock := &AggSenderStorageMock{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/aggsender/mocks/mock_eth_client.go b/aggsender/mocks/mock_eth_client.go deleted file mode 100644 index ebf618bf3..000000000 --- a/aggsender/mocks/mock_eth_client.go +++ /dev/null @@ -1,154 +0,0 @@ -// Code generated by mockery. DO NOT EDIT. - -package mocks - -import ( - context "context" - big "math/big" - - coretypes "github.com/ethereum/go-ethereum/core/types" - - mock "github.com/stretchr/testify/mock" -) - -// EthClientMock is an autogenerated mock type for the EthClient type -type EthClientMock struct { - mock.Mock -} - -type EthClientMock_Expecter struct { - mock *mock.Mock -} - -func (_m *EthClientMock) EXPECT() *EthClientMock_Expecter { - return &EthClientMock_Expecter{mock: &_m.Mock} -} - -// BlockNumber provides a mock function with given fields: ctx -func (_m *EthClientMock) BlockNumber(ctx context.Context) (uint64, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for BlockNumber") - } - - var r0 uint64 - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (uint64, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) uint64); ok { - r0 = rf(ctx) - } else { - r0 = ret.Get(0).(uint64) - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// EthClientMock_BlockNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BlockNumber' -type EthClientMock_BlockNumber_Call struct { - *mock.Call -} - -// BlockNumber is a helper method to define mock.On call -// - ctx context.Context -func (_e *EthClientMock_Expecter) BlockNumber(ctx interface{}) *EthClientMock_BlockNumber_Call { - return &EthClientMock_BlockNumber_Call{Call: _e.mock.On("BlockNumber", ctx)} -} - -func (_c *EthClientMock_BlockNumber_Call) Run(run func(ctx context.Context)) *EthClientMock_BlockNumber_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context)) - }) - return _c -} - -func (_c *EthClientMock_BlockNumber_Call) Return(_a0 uint64, _a1 error) *EthClientMock_BlockNumber_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *EthClientMock_BlockNumber_Call) RunAndReturn(run func(context.Context) (uint64, error)) *EthClientMock_BlockNumber_Call { - _c.Call.Return(run) - return _c -} - -// HeaderByNumber provides a mock function with given fields: ctx, number -func (_m *EthClientMock) HeaderByNumber(ctx context.Context, number *big.Int) (*coretypes.Header, error) { - ret := _m.Called(ctx, number) - - if len(ret) == 0 { - panic("no return value specified for HeaderByNumber") - } - - var r0 *coretypes.Header - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (*coretypes.Header, error)); ok { - return rf(ctx, number) - } - if rf, ok := ret.Get(0).(func(context.Context, *big.Int) *coretypes.Header); ok { - r0 = rf(ctx, number) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*coretypes.Header) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { - r1 = rf(ctx, number) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// EthClientMock_HeaderByNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HeaderByNumber' -type EthClientMock_HeaderByNumber_Call struct { - *mock.Call -} - -// HeaderByNumber is a helper method to define mock.On call -// - ctx context.Context -// - number *big.Int -func (_e *EthClientMock_Expecter) HeaderByNumber(ctx interface{}, number interface{}) *EthClientMock_HeaderByNumber_Call { - return &EthClientMock_HeaderByNumber_Call{Call: _e.mock.On("HeaderByNumber", ctx, number)} -} - -func (_c *EthClientMock_HeaderByNumber_Call) Run(run func(ctx context.Context, number *big.Int)) *EthClientMock_HeaderByNumber_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*big.Int)) - }) - return _c -} - -func (_c *EthClientMock_HeaderByNumber_Call) Return(_a0 *coretypes.Header, _a1 error) *EthClientMock_HeaderByNumber_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *EthClientMock_HeaderByNumber_Call) RunAndReturn(run func(context.Context, *big.Int) (*coretypes.Header, error)) *EthClientMock_HeaderByNumber_Call { - _c.Call.Return(run) - return _c -} - -// NewEthClientMock creates a new instance of EthClientMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewEthClientMock(t interface { - mock.TestingT - Cleanup(func()) -}) *EthClientMock { - mock := &EthClientMock{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/aggsender/mocks/mock_l1infotree_syncer.go b/aggsender/mocks/mock_l1infotree_syncer.go deleted file mode 100644 index e113d4ed6..000000000 --- a/aggsender/mocks/mock_l1infotree_syncer.go +++ /dev/null @@ -1,217 +0,0 @@ -// Code generated by mockery. DO NOT EDIT. - -package mocks - -import ( - context "context" - - common "github.com/ethereum/go-ethereum/common" - - l1infotreesync "github.com/0xPolygon/cdk/l1infotreesync" - - mock "github.com/stretchr/testify/mock" - - treetypes "github.com/0xPolygon/cdk/tree/types" -) - -// L1InfoTreeSyncerMock is an autogenerated mock type for the L1InfoTreeSyncer type -type L1InfoTreeSyncerMock struct { - mock.Mock -} - -type L1InfoTreeSyncerMock_Expecter struct { - mock *mock.Mock -} - -func (_m *L1InfoTreeSyncerMock) EXPECT() *L1InfoTreeSyncerMock_Expecter { - return &L1InfoTreeSyncerMock_Expecter{mock: &_m.Mock} -} - -// GetInfoByGlobalExitRoot provides a mock function with given fields: globalExitRoot -func (_m *L1InfoTreeSyncerMock) GetInfoByGlobalExitRoot(globalExitRoot common.Hash) (*l1infotreesync.L1InfoTreeLeaf, error) { - ret := _m.Called(globalExitRoot) - - if len(ret) == 0 { - panic("no return value specified for GetInfoByGlobalExitRoot") - } - - var r0 *l1infotreesync.L1InfoTreeLeaf - var r1 error - if rf, ok := ret.Get(0).(func(common.Hash) (*l1infotreesync.L1InfoTreeLeaf, error)); ok { - return rf(globalExitRoot) - } - if rf, ok := ret.Get(0).(func(common.Hash) *l1infotreesync.L1InfoTreeLeaf); ok { - r0 = rf(globalExitRoot) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*l1infotreesync.L1InfoTreeLeaf) - } - } - - if rf, ok := ret.Get(1).(func(common.Hash) error); ok { - r1 = rf(globalExitRoot) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// L1InfoTreeSyncerMock_GetInfoByGlobalExitRoot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetInfoByGlobalExitRoot' -type L1InfoTreeSyncerMock_GetInfoByGlobalExitRoot_Call struct { - *mock.Call -} - -// GetInfoByGlobalExitRoot is a helper method to define mock.On call -// - globalExitRoot common.Hash -func (_e *L1InfoTreeSyncerMock_Expecter) GetInfoByGlobalExitRoot(globalExitRoot interface{}) *L1InfoTreeSyncerMock_GetInfoByGlobalExitRoot_Call { - return &L1InfoTreeSyncerMock_GetInfoByGlobalExitRoot_Call{Call: _e.mock.On("GetInfoByGlobalExitRoot", globalExitRoot)} -} - -func (_c *L1InfoTreeSyncerMock_GetInfoByGlobalExitRoot_Call) Run(run func(globalExitRoot common.Hash)) *L1InfoTreeSyncerMock_GetInfoByGlobalExitRoot_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(common.Hash)) - }) - return _c -} - -func (_c *L1InfoTreeSyncerMock_GetInfoByGlobalExitRoot_Call) Return(_a0 *l1infotreesync.L1InfoTreeLeaf, _a1 error) *L1InfoTreeSyncerMock_GetInfoByGlobalExitRoot_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *L1InfoTreeSyncerMock_GetInfoByGlobalExitRoot_Call) RunAndReturn(run func(common.Hash) (*l1infotreesync.L1InfoTreeLeaf, error)) *L1InfoTreeSyncerMock_GetInfoByGlobalExitRoot_Call { - _c.Call.Return(run) - return _c -} - -// GetL1InfoTreeMerkleProofFromIndexToRoot provides a mock function with given fields: ctx, index, root -func (_m *L1InfoTreeSyncerMock) GetL1InfoTreeMerkleProofFromIndexToRoot(ctx context.Context, index uint32, root common.Hash) (treetypes.Proof, error) { - ret := _m.Called(ctx, index, root) - - if len(ret) == 0 { - panic("no return value specified for GetL1InfoTreeMerkleProofFromIndexToRoot") - } - - var r0 treetypes.Proof - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, uint32, common.Hash) (treetypes.Proof, error)); ok { - return rf(ctx, index, root) - } - if rf, ok := ret.Get(0).(func(context.Context, uint32, common.Hash) treetypes.Proof); ok { - r0 = rf(ctx, index, root) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(treetypes.Proof) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, uint32, common.Hash) error); ok { - r1 = rf(ctx, index, root) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// L1InfoTreeSyncerMock_GetL1InfoTreeMerkleProofFromIndexToRoot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetL1InfoTreeMerkleProofFromIndexToRoot' -type L1InfoTreeSyncerMock_GetL1InfoTreeMerkleProofFromIndexToRoot_Call struct { - *mock.Call -} - -// GetL1InfoTreeMerkleProofFromIndexToRoot is a helper method to define mock.On call -// - ctx context.Context -// - index uint32 -// - root common.Hash -func (_e *L1InfoTreeSyncerMock_Expecter) GetL1InfoTreeMerkleProofFromIndexToRoot(ctx interface{}, index interface{}, root interface{}) *L1InfoTreeSyncerMock_GetL1InfoTreeMerkleProofFromIndexToRoot_Call { - return &L1InfoTreeSyncerMock_GetL1InfoTreeMerkleProofFromIndexToRoot_Call{Call: _e.mock.On("GetL1InfoTreeMerkleProofFromIndexToRoot", ctx, index, root)} -} - -func (_c *L1InfoTreeSyncerMock_GetL1InfoTreeMerkleProofFromIndexToRoot_Call) Run(run func(ctx context.Context, index uint32, root common.Hash)) *L1InfoTreeSyncerMock_GetL1InfoTreeMerkleProofFromIndexToRoot_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(uint32), args[2].(common.Hash)) - }) - return _c -} - -func (_c *L1InfoTreeSyncerMock_GetL1InfoTreeMerkleProofFromIndexToRoot_Call) Return(_a0 treetypes.Proof, _a1 error) *L1InfoTreeSyncerMock_GetL1InfoTreeMerkleProofFromIndexToRoot_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *L1InfoTreeSyncerMock_GetL1InfoTreeMerkleProofFromIndexToRoot_Call) RunAndReturn(run func(context.Context, uint32, common.Hash) (treetypes.Proof, error)) *L1InfoTreeSyncerMock_GetL1InfoTreeMerkleProofFromIndexToRoot_Call { - _c.Call.Return(run) - return _c -} - -// GetL1InfoTreeRootByIndex provides a mock function with given fields: ctx, index -func (_m *L1InfoTreeSyncerMock) GetL1InfoTreeRootByIndex(ctx context.Context, index uint32) (treetypes.Root, error) { - ret := _m.Called(ctx, index) - - if len(ret) == 0 { - panic("no return value specified for GetL1InfoTreeRootByIndex") - } - - var r0 treetypes.Root - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, uint32) (treetypes.Root, error)); ok { - return rf(ctx, index) - } - if rf, ok := ret.Get(0).(func(context.Context, uint32) treetypes.Root); ok { - r0 = rf(ctx, index) - } else { - r0 = ret.Get(0).(treetypes.Root) - } - - if rf, ok := ret.Get(1).(func(context.Context, uint32) error); ok { - r1 = rf(ctx, index) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// L1InfoTreeSyncerMock_GetL1InfoTreeRootByIndex_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetL1InfoTreeRootByIndex' -type L1InfoTreeSyncerMock_GetL1InfoTreeRootByIndex_Call struct { - *mock.Call -} - -// GetL1InfoTreeRootByIndex is a helper method to define mock.On call -// - ctx context.Context -// - index uint32 -func (_e *L1InfoTreeSyncerMock_Expecter) GetL1InfoTreeRootByIndex(ctx interface{}, index interface{}) *L1InfoTreeSyncerMock_GetL1InfoTreeRootByIndex_Call { - return &L1InfoTreeSyncerMock_GetL1InfoTreeRootByIndex_Call{Call: _e.mock.On("GetL1InfoTreeRootByIndex", ctx, index)} -} - -func (_c *L1InfoTreeSyncerMock_GetL1InfoTreeRootByIndex_Call) Run(run func(ctx context.Context, index uint32)) *L1InfoTreeSyncerMock_GetL1InfoTreeRootByIndex_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(uint32)) - }) - return _c -} - -func (_c *L1InfoTreeSyncerMock_GetL1InfoTreeRootByIndex_Call) Return(_a0 treetypes.Root, _a1 error) *L1InfoTreeSyncerMock_GetL1InfoTreeRootByIndex_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *L1InfoTreeSyncerMock_GetL1InfoTreeRootByIndex_Call) RunAndReturn(run func(context.Context, uint32) (treetypes.Root, error)) *L1InfoTreeSyncerMock_GetL1InfoTreeRootByIndex_Call { - _c.Call.Return(run) - return _c -} - -// NewL1InfoTreeSyncerMock creates a new instance of L1InfoTreeSyncerMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewL1InfoTreeSyncerMock(t interface { - mock.TestingT - Cleanup(func()) -}) *L1InfoTreeSyncerMock { - mock := &L1InfoTreeSyncerMock{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/aggsender/mocks/mock_l2bridge_syncer.go b/aggsender/mocks/mock_l2bridge_syncer.go deleted file mode 100644 index 725184c31..000000000 --- a/aggsender/mocks/mock_l2bridge_syncer.go +++ /dev/null @@ -1,423 +0,0 @@ -// Code generated by mockery. DO NOT EDIT. - -package mocks - -import ( - bridgesync "github.com/0xPolygon/cdk/bridgesync" - common "github.com/ethereum/go-ethereum/common" - - context "context" - - etherman "github.com/0xPolygon/cdk/etherman" - - mock "github.com/stretchr/testify/mock" - - treetypes "github.com/0xPolygon/cdk/tree/types" -) - -// L2BridgeSyncerMock is an autogenerated mock type for the L2BridgeSyncer type -type L2BridgeSyncerMock struct { - mock.Mock -} - -type L2BridgeSyncerMock_Expecter struct { - mock *mock.Mock -} - -func (_m *L2BridgeSyncerMock) EXPECT() *L2BridgeSyncerMock_Expecter { - return &L2BridgeSyncerMock_Expecter{mock: &_m.Mock} -} - -// BlockFinality provides a mock function with given fields: -func (_m *L2BridgeSyncerMock) BlockFinality() etherman.BlockNumberFinality { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for BlockFinality") - } - - var r0 etherman.BlockNumberFinality - if rf, ok := ret.Get(0).(func() etherman.BlockNumberFinality); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(etherman.BlockNumberFinality) - } - - return r0 -} - -// L2BridgeSyncerMock_BlockFinality_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BlockFinality' -type L2BridgeSyncerMock_BlockFinality_Call struct { - *mock.Call -} - -// BlockFinality is a helper method to define mock.On call -func (_e *L2BridgeSyncerMock_Expecter) BlockFinality() *L2BridgeSyncerMock_BlockFinality_Call { - return &L2BridgeSyncerMock_BlockFinality_Call{Call: _e.mock.On("BlockFinality")} -} - -func (_c *L2BridgeSyncerMock_BlockFinality_Call) Run(run func()) *L2BridgeSyncerMock_BlockFinality_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *L2BridgeSyncerMock_BlockFinality_Call) Return(_a0 etherman.BlockNumberFinality) *L2BridgeSyncerMock_BlockFinality_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *L2BridgeSyncerMock_BlockFinality_Call) RunAndReturn(run func() etherman.BlockNumberFinality) *L2BridgeSyncerMock_BlockFinality_Call { - _c.Call.Return(run) - return _c -} - -// GetBlockByLER provides a mock function with given fields: ctx, ler -func (_m *L2BridgeSyncerMock) GetBlockByLER(ctx context.Context, ler common.Hash) (uint64, error) { - ret := _m.Called(ctx, ler) - - if len(ret) == 0 { - panic("no return value specified for GetBlockByLER") - } - - var r0 uint64 - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (uint64, error)); ok { - return rf(ctx, ler) - } - if rf, ok := ret.Get(0).(func(context.Context, common.Hash) uint64); ok { - r0 = rf(ctx, ler) - } else { - r0 = ret.Get(0).(uint64) - } - - if rf, ok := ret.Get(1).(func(context.Context, common.Hash) error); ok { - r1 = rf(ctx, ler) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// L2BridgeSyncerMock_GetBlockByLER_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBlockByLER' -type L2BridgeSyncerMock_GetBlockByLER_Call struct { - *mock.Call -} - -// GetBlockByLER is a helper method to define mock.On call -// - ctx context.Context -// - ler common.Hash -func (_e *L2BridgeSyncerMock_Expecter) GetBlockByLER(ctx interface{}, ler interface{}) *L2BridgeSyncerMock_GetBlockByLER_Call { - return &L2BridgeSyncerMock_GetBlockByLER_Call{Call: _e.mock.On("GetBlockByLER", ctx, ler)} -} - -func (_c *L2BridgeSyncerMock_GetBlockByLER_Call) Run(run func(ctx context.Context, ler common.Hash)) *L2BridgeSyncerMock_GetBlockByLER_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(common.Hash)) - }) - return _c -} - -func (_c *L2BridgeSyncerMock_GetBlockByLER_Call) Return(_a0 uint64, _a1 error) *L2BridgeSyncerMock_GetBlockByLER_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *L2BridgeSyncerMock_GetBlockByLER_Call) RunAndReturn(run func(context.Context, common.Hash) (uint64, error)) *L2BridgeSyncerMock_GetBlockByLER_Call { - _c.Call.Return(run) - return _c -} - -// GetBridgesPublished provides a mock function with given fields: ctx, fromBlock, toBlock -func (_m *L2BridgeSyncerMock) GetBridgesPublished(ctx context.Context, fromBlock uint64, toBlock uint64) ([]bridgesync.Bridge, error) { - ret := _m.Called(ctx, fromBlock, toBlock) - - if len(ret) == 0 { - panic("no return value specified for GetBridgesPublished") - } - - var r0 []bridgesync.Bridge - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64) ([]bridgesync.Bridge, error)); ok { - return rf(ctx, fromBlock, toBlock) - } - if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64) []bridgesync.Bridge); ok { - r0 = rf(ctx, fromBlock, toBlock) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]bridgesync.Bridge) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, uint64, uint64) error); ok { - r1 = rf(ctx, fromBlock, toBlock) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// L2BridgeSyncerMock_GetBridgesPublished_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBridgesPublished' -type L2BridgeSyncerMock_GetBridgesPublished_Call struct { - *mock.Call -} - -// GetBridgesPublished is a helper method to define mock.On call -// - ctx context.Context -// - fromBlock uint64 -// - toBlock uint64 -func (_e *L2BridgeSyncerMock_Expecter) GetBridgesPublished(ctx interface{}, fromBlock interface{}, toBlock interface{}) *L2BridgeSyncerMock_GetBridgesPublished_Call { - return &L2BridgeSyncerMock_GetBridgesPublished_Call{Call: _e.mock.On("GetBridgesPublished", ctx, fromBlock, toBlock)} -} - -func (_c *L2BridgeSyncerMock_GetBridgesPublished_Call) Run(run func(ctx context.Context, fromBlock uint64, toBlock uint64)) *L2BridgeSyncerMock_GetBridgesPublished_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(uint64), args[2].(uint64)) - }) - return _c -} - -func (_c *L2BridgeSyncerMock_GetBridgesPublished_Call) Return(_a0 []bridgesync.Bridge, _a1 error) *L2BridgeSyncerMock_GetBridgesPublished_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *L2BridgeSyncerMock_GetBridgesPublished_Call) RunAndReturn(run func(context.Context, uint64, uint64) ([]bridgesync.Bridge, error)) *L2BridgeSyncerMock_GetBridgesPublished_Call { - _c.Call.Return(run) - return _c -} - -// GetClaims provides a mock function with given fields: ctx, fromBlock, toBlock -func (_m *L2BridgeSyncerMock) GetClaims(ctx context.Context, fromBlock uint64, toBlock uint64) ([]bridgesync.Claim, error) { - ret := _m.Called(ctx, fromBlock, toBlock) - - if len(ret) == 0 { - panic("no return value specified for GetClaims") - } - - var r0 []bridgesync.Claim - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64) ([]bridgesync.Claim, error)); ok { - return rf(ctx, fromBlock, toBlock) - } - if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64) []bridgesync.Claim); ok { - r0 = rf(ctx, fromBlock, toBlock) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]bridgesync.Claim) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, uint64, uint64) error); ok { - r1 = rf(ctx, fromBlock, toBlock) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// L2BridgeSyncerMock_GetClaims_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetClaims' -type L2BridgeSyncerMock_GetClaims_Call struct { - *mock.Call -} - -// GetClaims is a helper method to define mock.On call -// - ctx context.Context -// - fromBlock uint64 -// - toBlock uint64 -func (_e *L2BridgeSyncerMock_Expecter) GetClaims(ctx interface{}, fromBlock interface{}, toBlock interface{}) *L2BridgeSyncerMock_GetClaims_Call { - return &L2BridgeSyncerMock_GetClaims_Call{Call: _e.mock.On("GetClaims", ctx, fromBlock, toBlock)} -} - -func (_c *L2BridgeSyncerMock_GetClaims_Call) Run(run func(ctx context.Context, fromBlock uint64, toBlock uint64)) *L2BridgeSyncerMock_GetClaims_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(uint64), args[2].(uint64)) - }) - return _c -} - -func (_c *L2BridgeSyncerMock_GetClaims_Call) Return(_a0 []bridgesync.Claim, _a1 error) *L2BridgeSyncerMock_GetClaims_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *L2BridgeSyncerMock_GetClaims_Call) RunAndReturn(run func(context.Context, uint64, uint64) ([]bridgesync.Claim, error)) *L2BridgeSyncerMock_GetClaims_Call { - _c.Call.Return(run) - return _c -} - -// GetExitRootByIndex provides a mock function with given fields: ctx, index -func (_m *L2BridgeSyncerMock) GetExitRootByIndex(ctx context.Context, index uint32) (treetypes.Root, error) { - ret := _m.Called(ctx, index) - - if len(ret) == 0 { - panic("no return value specified for GetExitRootByIndex") - } - - var r0 treetypes.Root - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, uint32) (treetypes.Root, error)); ok { - return rf(ctx, index) - } - if rf, ok := ret.Get(0).(func(context.Context, uint32) treetypes.Root); ok { - r0 = rf(ctx, index) - } else { - r0 = ret.Get(0).(treetypes.Root) - } - - if rf, ok := ret.Get(1).(func(context.Context, uint32) error); ok { - r1 = rf(ctx, index) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// L2BridgeSyncerMock_GetExitRootByIndex_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetExitRootByIndex' -type L2BridgeSyncerMock_GetExitRootByIndex_Call struct { - *mock.Call -} - -// GetExitRootByIndex is a helper method to define mock.On call -// - ctx context.Context -// - index uint32 -func (_e *L2BridgeSyncerMock_Expecter) GetExitRootByIndex(ctx interface{}, index interface{}) *L2BridgeSyncerMock_GetExitRootByIndex_Call { - return &L2BridgeSyncerMock_GetExitRootByIndex_Call{Call: _e.mock.On("GetExitRootByIndex", ctx, index)} -} - -func (_c *L2BridgeSyncerMock_GetExitRootByIndex_Call) Run(run func(ctx context.Context, index uint32)) *L2BridgeSyncerMock_GetExitRootByIndex_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(uint32)) - }) - return _c -} - -func (_c *L2BridgeSyncerMock_GetExitRootByIndex_Call) Return(_a0 treetypes.Root, _a1 error) *L2BridgeSyncerMock_GetExitRootByIndex_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *L2BridgeSyncerMock_GetExitRootByIndex_Call) RunAndReturn(run func(context.Context, uint32) (treetypes.Root, error)) *L2BridgeSyncerMock_GetExitRootByIndex_Call { - _c.Call.Return(run) - return _c -} - -// GetLastProcessedBlock provides a mock function with given fields: ctx -func (_m *L2BridgeSyncerMock) GetLastProcessedBlock(ctx context.Context) (uint64, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for GetLastProcessedBlock") - } - - var r0 uint64 - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (uint64, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) uint64); ok { - r0 = rf(ctx) - } else { - r0 = ret.Get(0).(uint64) - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// L2BridgeSyncerMock_GetLastProcessedBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLastProcessedBlock' -type L2BridgeSyncerMock_GetLastProcessedBlock_Call struct { - *mock.Call -} - -// GetLastProcessedBlock is a helper method to define mock.On call -// - ctx context.Context -func (_e *L2BridgeSyncerMock_Expecter) GetLastProcessedBlock(ctx interface{}) *L2BridgeSyncerMock_GetLastProcessedBlock_Call { - return &L2BridgeSyncerMock_GetLastProcessedBlock_Call{Call: _e.mock.On("GetLastProcessedBlock", ctx)} -} - -func (_c *L2BridgeSyncerMock_GetLastProcessedBlock_Call) Run(run func(ctx context.Context)) *L2BridgeSyncerMock_GetLastProcessedBlock_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context)) - }) - return _c -} - -func (_c *L2BridgeSyncerMock_GetLastProcessedBlock_Call) Return(_a0 uint64, _a1 error) *L2BridgeSyncerMock_GetLastProcessedBlock_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *L2BridgeSyncerMock_GetLastProcessedBlock_Call) RunAndReturn(run func(context.Context) (uint64, error)) *L2BridgeSyncerMock_GetLastProcessedBlock_Call { - _c.Call.Return(run) - return _c -} - -// OriginNetwork provides a mock function with given fields: -func (_m *L2BridgeSyncerMock) OriginNetwork() uint32 { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for OriginNetwork") - } - - var r0 uint32 - if rf, ok := ret.Get(0).(func() uint32); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint32) - } - - return r0 -} - -// L2BridgeSyncerMock_OriginNetwork_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OriginNetwork' -type L2BridgeSyncerMock_OriginNetwork_Call struct { - *mock.Call -} - -// OriginNetwork is a helper method to define mock.On call -func (_e *L2BridgeSyncerMock_Expecter) OriginNetwork() *L2BridgeSyncerMock_OriginNetwork_Call { - return &L2BridgeSyncerMock_OriginNetwork_Call{Call: _e.mock.On("OriginNetwork")} -} - -func (_c *L2BridgeSyncerMock_OriginNetwork_Call) Run(run func()) *L2BridgeSyncerMock_OriginNetwork_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *L2BridgeSyncerMock_OriginNetwork_Call) Return(_a0 uint32) *L2BridgeSyncerMock_OriginNetwork_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *L2BridgeSyncerMock_OriginNetwork_Call) RunAndReturn(run func() uint32) *L2BridgeSyncerMock_OriginNetwork_Call { - _c.Call.Return(run) - return _c -} - -// NewL2BridgeSyncerMock creates a new instance of L2BridgeSyncerMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewL2BridgeSyncerMock(t interface { - mock.TestingT - Cleanup(func()) -}) *L2BridgeSyncerMock { - mock := &L2BridgeSyncerMock{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/aggsender/mocks/mock_logger.go b/aggsender/mocks/mock_logger.go deleted file mode 100644 index 5b0eb4e99..000000000 --- a/aggsender/mocks/mock_logger.go +++ /dev/null @@ -1,290 +0,0 @@ -// Code generated by mockery. DO NOT EDIT. - -package mocks - -import mock "github.com/stretchr/testify/mock" - -// LoggerMock is an autogenerated mock type for the Logger type -type LoggerMock struct { - mock.Mock -} - -type LoggerMock_Expecter struct { - mock *mock.Mock -} - -func (_m *LoggerMock) EXPECT() *LoggerMock_Expecter { - return &LoggerMock_Expecter{mock: &_m.Mock} -} - -// Debug provides a mock function with given fields: args -func (_m *LoggerMock) Debug(args ...interface{}) { - var _ca []interface{} - _ca = append(_ca, args...) - _m.Called(_ca...) -} - -// LoggerMock_Debug_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Debug' -type LoggerMock_Debug_Call struct { - *mock.Call -} - -// Debug is a helper method to define mock.On call -// - args ...interface{} -func (_e *LoggerMock_Expecter) Debug(args ...interface{}) *LoggerMock_Debug_Call { - return &LoggerMock_Debug_Call{Call: _e.mock.On("Debug", - append([]interface{}{}, args...)...)} -} - -func (_c *LoggerMock_Debug_Call) Run(run func(args ...interface{})) *LoggerMock_Debug_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]interface{}, len(args)-0) - for i, a := range args[0:] { - if a != nil { - variadicArgs[i] = a.(interface{}) - } - } - run(variadicArgs...) - }) - return _c -} - -func (_c *LoggerMock_Debug_Call) Return() *LoggerMock_Debug_Call { - _c.Call.Return() - return _c -} - -func (_c *LoggerMock_Debug_Call) RunAndReturn(run func(...interface{})) *LoggerMock_Debug_Call { - _c.Call.Return(run) - return _c -} - -// Debugf provides a mock function with given fields: format, args -func (_m *LoggerMock) Debugf(format string, args ...interface{}) { - var _ca []interface{} - _ca = append(_ca, format) - _ca = append(_ca, args...) - _m.Called(_ca...) -} - -// LoggerMock_Debugf_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Debugf' -type LoggerMock_Debugf_Call struct { - *mock.Call -} - -// Debugf is a helper method to define mock.On call -// - format string -// - args ...interface{} -func (_e *LoggerMock_Expecter) Debugf(format interface{}, args ...interface{}) *LoggerMock_Debugf_Call { - return &LoggerMock_Debugf_Call{Call: _e.mock.On("Debugf", - append([]interface{}{format}, args...)...)} -} - -func (_c *LoggerMock_Debugf_Call) Run(run func(format string, args ...interface{})) *LoggerMock_Debugf_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]interface{}, len(args)-1) - for i, a := range args[1:] { - if a != nil { - variadicArgs[i] = a.(interface{}) - } - } - run(args[0].(string), variadicArgs...) - }) - return _c -} - -func (_c *LoggerMock_Debugf_Call) Return() *LoggerMock_Debugf_Call { - _c.Call.Return() - return _c -} - -func (_c *LoggerMock_Debugf_Call) RunAndReturn(run func(string, ...interface{})) *LoggerMock_Debugf_Call { - _c.Call.Return(run) - return _c -} - -// Error provides a mock function with given fields: args -func (_m *LoggerMock) Error(args ...interface{}) { - var _ca []interface{} - _ca = append(_ca, args...) - _m.Called(_ca...) -} - -// LoggerMock_Error_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Error' -type LoggerMock_Error_Call struct { - *mock.Call -} - -// Error is a helper method to define mock.On call -// - args ...interface{} -func (_e *LoggerMock_Expecter) Error(args ...interface{}) *LoggerMock_Error_Call { - return &LoggerMock_Error_Call{Call: _e.mock.On("Error", - append([]interface{}{}, args...)...)} -} - -func (_c *LoggerMock_Error_Call) Run(run func(args ...interface{})) *LoggerMock_Error_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]interface{}, len(args)-0) - for i, a := range args[0:] { - if a != nil { - variadicArgs[i] = a.(interface{}) - } - } - run(variadicArgs...) - }) - return _c -} - -func (_c *LoggerMock_Error_Call) Return() *LoggerMock_Error_Call { - _c.Call.Return() - return _c -} - -func (_c *LoggerMock_Error_Call) RunAndReturn(run func(...interface{})) *LoggerMock_Error_Call { - _c.Call.Return(run) - return _c -} - -// Errorf provides a mock function with given fields: format, args -func (_m *LoggerMock) Errorf(format string, args ...interface{}) { - var _ca []interface{} - _ca = append(_ca, format) - _ca = append(_ca, args...) - _m.Called(_ca...) -} - -// LoggerMock_Errorf_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Errorf' -type LoggerMock_Errorf_Call struct { - *mock.Call -} - -// Errorf is a helper method to define mock.On call -// - format string -// - args ...interface{} -func (_e *LoggerMock_Expecter) Errorf(format interface{}, args ...interface{}) *LoggerMock_Errorf_Call { - return &LoggerMock_Errorf_Call{Call: _e.mock.On("Errorf", - append([]interface{}{format}, args...)...)} -} - -func (_c *LoggerMock_Errorf_Call) Run(run func(format string, args ...interface{})) *LoggerMock_Errorf_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]interface{}, len(args)-1) - for i, a := range args[1:] { - if a != nil { - variadicArgs[i] = a.(interface{}) - } - } - run(args[0].(string), variadicArgs...) - }) - return _c -} - -func (_c *LoggerMock_Errorf_Call) Return() *LoggerMock_Errorf_Call { - _c.Call.Return() - return _c -} - -func (_c *LoggerMock_Errorf_Call) RunAndReturn(run func(string, ...interface{})) *LoggerMock_Errorf_Call { - _c.Call.Return(run) - return _c -} - -// Info provides a mock function with given fields: args -func (_m *LoggerMock) Info(args ...interface{}) { - var _ca []interface{} - _ca = append(_ca, args...) - _m.Called(_ca...) -} - -// LoggerMock_Info_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Info' -type LoggerMock_Info_Call struct { - *mock.Call -} - -// Info is a helper method to define mock.On call -// - args ...interface{} -func (_e *LoggerMock_Expecter) Info(args ...interface{}) *LoggerMock_Info_Call { - return &LoggerMock_Info_Call{Call: _e.mock.On("Info", - append([]interface{}{}, args...)...)} -} - -func (_c *LoggerMock_Info_Call) Run(run func(args ...interface{})) *LoggerMock_Info_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]interface{}, len(args)-0) - for i, a := range args[0:] { - if a != nil { - variadicArgs[i] = a.(interface{}) - } - } - run(variadicArgs...) - }) - return _c -} - -func (_c *LoggerMock_Info_Call) Return() *LoggerMock_Info_Call { - _c.Call.Return() - return _c -} - -func (_c *LoggerMock_Info_Call) RunAndReturn(run func(...interface{})) *LoggerMock_Info_Call { - _c.Call.Return(run) - return _c -} - -// Infof provides a mock function with given fields: format, args -func (_m *LoggerMock) Infof(format string, args ...interface{}) { - var _ca []interface{} - _ca = append(_ca, format) - _ca = append(_ca, args...) - _m.Called(_ca...) -} - -// LoggerMock_Infof_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Infof' -type LoggerMock_Infof_Call struct { - *mock.Call -} - -// Infof is a helper method to define mock.On call -// - format string -// - args ...interface{} -func (_e *LoggerMock_Expecter) Infof(format interface{}, args ...interface{}) *LoggerMock_Infof_Call { - return &LoggerMock_Infof_Call{Call: _e.mock.On("Infof", - append([]interface{}{format}, args...)...)} -} - -func (_c *LoggerMock_Infof_Call) Run(run func(format string, args ...interface{})) *LoggerMock_Infof_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]interface{}, len(args)-1) - for i, a := range args[1:] { - if a != nil { - variadicArgs[i] = a.(interface{}) - } - } - run(args[0].(string), variadicArgs...) - }) - return _c -} - -func (_c *LoggerMock_Infof_Call) Return() *LoggerMock_Infof_Call { - _c.Call.Return() - return _c -} - -func (_c *LoggerMock_Infof_Call) RunAndReturn(run func(string, ...interface{})) *LoggerMock_Infof_Call { - _c.Call.Return(run) - return _c -} - -// NewLoggerMock creates a new instance of LoggerMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewLoggerMock(t interface { - mock.TestingT - Cleanup(func()) -}) *LoggerMock { - mock := &LoggerMock{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/cmd/run.go b/cmd/run.go index 4d8d15a2e..070ff4622 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -133,7 +133,7 @@ func start(cliCtx *cli.Context) error { log.Fatal(err) } - aggsender.Start(cliCtx.Context) + go aggsender.Start(cliCtx.Context) } } diff --git a/crates/cdk/versions.json b/crates/cdk/versions.json index 0d7f3daf9..bafbd00be 100644 --- a/crates/cdk/versions.json +++ b/crates/cdk/versions.json @@ -5,7 +5,7 @@ "cdk_validium_node_image": "0xpolygon/cdk-validium-node:0.7.0-cdk", "zkevm_bridge_proxy_image": "haproxy:3.0-bookworm", "zkevm_bridge_service_image": "hermeznetwork/zkevm-bridge-service:v0.6.0-RC1", - "zkevm_bridge_ui_image": "leovct/zkevm-bridge-ui:multi-network", + "zkevm_bridge_ui_image": "leovct/zkevm-bridge-ui:multi-network-2", "zkevm_contracts_image": "leovct/zkevm-contracts:v8.0.0-rc.4-fork.12", "zkevm_da_image": "0xpolygon/cdk-data-availability:0.0.10", "zkevm_node_image": "hermeznetwork/zkevm-node:v0.7.3", From 321dec504f6c4ab6d3aa72d0655276b7e0299f5d Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:22:38 +0100 Subject: [PATCH 06/27] fix: add a new bridge test ETH L1 -> L2 -> L1 --- test/bridge-e2e.bats | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/bridge-e2e.bats b/test/bridge-e2e.bats index ed599c7da..b2e7b4892 100644 --- a/test/bridge-e2e.bats +++ b/test/bridge-e2e.bats @@ -155,3 +155,30 @@ setup() { fi assert_success } + +@test "transfer ETH L1 to L2 to L1" { + + destination_addr=$sender_addr + destination_net=1 + echo " bridgeAsset (ETH->WETH) L1 to L2 dest: $destination_addr eth:$ether_value" >&3 + run bridgeAsset "0x0000000000000000000000000000000000000000" "$l1_rpc_url" + assert_success + + echo "*** Claim in L2" >&3 + timeout="120" + claim_frequency="30" + run wait_for_claim "$timeout" "$claim_frequency" "$l2_rpc_url" + assert_success + + echo " bridgeAsset (WETH->ETH) L2 to L1" >&3 + destination_addr=$sender_addr + destination_net=0 + run bridgeAsset "$weth_token_addr" "$l2_rpc_url" + assert_success + + echo " Claim in L1" >&3 + timeout="360" + claim_frequency="60" + run wait_for_claim "$timeout" "$claim_frequency" "$l1_rpc_url" + assert_success +} From 692c305c321ac1c037ee67328372924753c42c65 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:23:48 +0100 Subject: [PATCH 07/27] feat: remove second go-routine. The check of previous certificate is done before try to send a new cert --- aggsender/aggsender.go | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/aggsender/aggsender.go b/aggsender/aggsender.go index 263f98e85..73439a0b2 100644 --- a/aggsender/aggsender.go +++ b/aggsender/aggsender.go @@ -82,8 +82,7 @@ func New( // Start starts the AggSender func (a *AggSender) Start(ctx context.Context) { - go a.sendCertificates(ctx) - go a.checkIfCertificatesAreSettled(ctx) + a.sendCertificates(ctx) } // sendCertificates sends certificates to the aggLayer @@ -92,7 +91,8 @@ func (a *AggSender) sendCertificates(ctx context.Context) { for { select { case epoch := <-chEpoch: - a.log.Infof("Epoch %d received", epoch.Epoch) + a.log.Infof("Epoch received: %s", epoch.String()) + a.checkPendingCertificatesStatus(ctx) if _, err := a.sendCertificate(ctx); err != nil { log.Error(err) } @@ -478,19 +478,6 @@ func (a *AggSender) signCertificate(certificate *agglayer.Certificate) (*agglaye }, nil } -// checkIfCertificatesAreSettled checks if certificates are settled -func (a *AggSender) checkIfCertificatesAreSettled(ctx context.Context) { - ticker := time.NewTicker(a.cfg.CheckSettledInterval.Duration) - for { - select { - case <-ticker.C: - a.checkPendingCertificatesStatus(ctx) - case <-ctx.Done(): - return - } - } -} - // checkPendingCertificatesStatus checks the status of pending certificates // and updates in the storage if it changed on agglayer func (a *AggSender) checkPendingCertificatesStatus(ctx context.Context) { From 053b649e8e2f7e80426246eb2ec0049f93491ead Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:24:14 +0100 Subject: [PATCH 08/27] feat: remove logs --- aggsender/block_notifier_polling.go | 48 +++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/aggsender/block_notifier_polling.go b/aggsender/block_notifier_polling.go index 47618d543..9603cad89 100644 --- a/aggsender/block_notifier_polling.go +++ b/aggsender/block_notifier_polling.go @@ -100,7 +100,6 @@ func (b *BlockNotifierPolling) Start(ctx context.Context) { delay, newStatus := b.step(ctx, status) status = newStatus b.setGlobalStatus(status) - b.logger.Debugf("Next block request in %s", delay) ticker.Reset(delay) } } @@ -127,34 +126,33 @@ func (b *BlockNotifierPolling) step(ctx context.Context, currentBlock, err := b.ethClient.HeaderByNumber(ctx, b.blockFinality) if err != nil || currentBlock == nil { b.logger.Errorf("Failed to get block number: %v", err) - return b.nextBlockRequestDelay(status, err), status + return b.nextBlockRequestDelay(status, err), status.clear() } - b.logger.Debugf("Current block [finality:%s]: %d", b.config.BlockFinalityType, currentBlock.Number.Uint64()) if status == nil { - status = &blockNotifierPollingInternalStatus{ - lastBlockSeen: currentBlock.Number.Uint64(), - lastBlockTime: timeNowFunc(), - } + status = status.intialBlock(currentBlock.Number.Uint64()) return b.nextBlockRequestDelay(status, nil), status } if currentBlock.Number.Uint64() != status.lastBlockSeen { - b.logger.Debugf("New block seen [finality:%s]: %d", b.config.BlockFinalityType, currentBlock.Number.Uint64()) b.Publish(types.EventNewBlock{ BlockNumber: currentBlock.Number.Uint64(), BlockFinalityType: b.config.BlockFinalityType, }) + now := timeNowFunc() + timePreviousBlock := now.Sub(status.lastBlockTime) + status.previousBlockTime = &timePreviousBlock + status.lastBlockTime = now + if currentBlock.Number.Uint64()-status.lastBlockSeen != 1 { b.logger.Warnf("Missed block(s) [finality:%s]: %d -> %d", b.config.BlockFinalityType, status.lastBlockSeen, currentBlock.Number.Uint64()) status.previousBlockTime = nil + status.lastBlockSeen = currentBlock.Number.Uint64() return b.nextBlockRequestDelay(status, nil), status } + status.lastBlockSeen = currentBlock.Number.Uint64() - now := timeNowFunc() - timePreviousBlock := now.Sub(status.lastBlockTime) - status.previousBlockTime = &timePreviousBlock - status.lastBlockTime = now + b.logger.Debugf("New block seen [finality:%s]: %d. blockRate:%s", b.config.BlockFinalityType, currentBlock.Number.Uint64(), status.previousBlockTime) } @@ -176,7 +174,6 @@ func (b *BlockNotifierPolling) nextBlockRequestDelay(status *blockNotifierPollin expectedTimeNextBlock := status.lastBlockTime.Add(*status.previousBlockTime) distanceToNextBlock := expectedTimeNextBlock.Sub(now) interval := distanceToNextBlock * 4 / 5 //nolint:mnd // 80% of for reach the next block - b.logger.Debugf("Next block request delay: %s. distanceToNextBlock=%s", interval, distanceToNextBlock) return max(minBlockInterval, min(maxBlockInterval, interval)) } } @@ -191,5 +188,30 @@ type blockNotifierPollingInternalStatus struct { lastBlockSeen uint64 lastBlockTime time.Time // first appear of block lastBlockSeen previousBlockTime *time.Duration // time of the previous block to appear +} + +func (s *blockNotifierPollingInternalStatus) String() string { + if s == nil { + return "nil" + } + return fmt.Sprintf("lastBlockSeen=%d lastBlockTime=%s previousBlockTime=%s", + s.lastBlockSeen, s.lastBlockTime, s.previousBlockTime) +} +func (s *blockNotifierPollingInternalStatus) clear() *blockNotifierPollingInternalStatus { + return &blockNotifierPollingInternalStatus{} +} + +func (s *blockNotifierPollingInternalStatus) intialBlock(block uint64) *blockNotifierPollingInternalStatus { + return &blockNotifierPollingInternalStatus{ + lastBlockSeen: block, + lastBlockTime: timeNowFunc(), + } +} + +func (s *blockNotifierPollingInternalStatus) incommingBlock(block uint64) *blockNotifierPollingInternalStatus { + return &blockNotifierPollingInternalStatus{ + lastBlockSeen: block, + lastBlockTime: timeNowFunc(), + } } From 438371f9e5ac5dc9ec376d20b8e46bcbcdea9388 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:24:32 +0100 Subject: [PATCH 09/27] feat: remove logs --- aggsender/epoch_notifier_per_block.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aggsender/epoch_notifier_per_block.go b/aggsender/epoch_notifier_per_block.go index c9b138890..d1309a226 100644 --- a/aggsender/epoch_notifier_per_block.go +++ b/aggsender/epoch_notifier_per_block.go @@ -112,7 +112,7 @@ func (e *EpochNotifierPerBlock) startInternal(ctx context.Context, eventNewBlock var event *types.EpochEvent status, event = e.step(status, newBlock) if event != nil { - e.logger.Infof("new Epoch Event: %s", event.String()) + e.logger.Debugf("new Epoch Event: %s", event.String()) e.GenericSubscriber.Publish(*event) } } From 3e4025b92aafb09769f3104d3636207e7f106ab0 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:25:06 +0100 Subject: [PATCH 10/27] feat: set for L1InfoTreeSync SyncBlockChunkSize=100 --- config/default.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/default.go b/config/default.go index a2318881f..f54aa82e9 100644 --- a/config/default.go +++ b/config/default.go @@ -216,7 +216,7 @@ DBPath = "{{PathRWData}}/reorgdetectorl2.sqlite" DBPath = "{{PathRWData}}/L1InfoTreeSync.sqlite" GlobalExitRootAddr="{{NetworkConfig.L1.GlobalExitRootManagerAddr}}" RollupManagerAddr = "{{NetworkConfig.L1.RollupManagerAddr}}" -SyncBlockChunkSize=10 +SyncBlockChunkSize=100 BlockFinality="LatestBlock" URLRPCL1="{{L1URL}}" WaitForNewBlocksPeriod="100ms" From b49fc8ea55fb354731eef893c71a34037fdac40e Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:25:33 +0100 Subject: [PATCH 11/27] fix: output of local_config script --- scripts/local_config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/local_config b/scripts/local_config index 09e0167a3..5830b6e67 100755 --- a/scripts/local_config +++ b/scripts/local_config @@ -447,4 +447,4 @@ EOF echo " -----------------------------------------------------------" echo " " echo " - rembember to clean previous execution data: " -echo " rm -Rf ${path_rw_data}/*" +echo " rm -Rf ${zkevm_path_rw_data}/*" From aaf9254f853bdb47d559fb519fceb64c537cf008 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:46:22 +0100 Subject: [PATCH 12/27] fix: unittest --- aggsender/aggsender_test.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/aggsender/aggsender_test.go b/aggsender/aggsender_test.go index 5e01aa45b..1ea46f5ce 100644 --- a/aggsender/aggsender_test.go +++ b/aggsender/aggsender_test.go @@ -859,13 +859,8 @@ func TestCheckIfCertificatesAreSettled(t *testing.T) { }, } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - go aggSender.checkIfCertificatesAreSettled(ctx) - - time.Sleep(2 * time.Second) - cancel() + ctx := context.TODO() + aggSender.checkPendingCertificatesStatus(ctx) mockAggLayerClient.AssertExpectations(t) mockStorage.AssertExpectations(t) From 8b382e3265008960b3bfef217db7b7d7a5498b89 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 12:06:42 +0100 Subject: [PATCH 13/27] fix: unittest --- aggsender/block_notifier_polling.go | 120 ++++++++++++----------- aggsender/block_notifier_polling_test.go | 94 +++++++++++++++++- 2 files changed, 155 insertions(+), 59 deletions(-) diff --git a/aggsender/block_notifier_polling.go b/aggsender/block_notifier_polling.go index 9603cad89..f79459d33 100644 --- a/aggsender/block_notifier_polling.go +++ b/aggsender/block_notifier_polling.go @@ -80,11 +80,6 @@ func (b *BlockNotifierPolling) String() string { return res } -// StartAsync starts the BlockNotifierPolling in a new goroutine -func (b *BlockNotifierPolling) StartAsync(ctx context.Context) { - go b.Start(ctx) -} - // Start starts the BlockNotifierPolling blocking the current goroutine func (b *BlockNotifierPolling) Start(ctx context.Context) { ticker := time.NewTimer(b.config.CheckNewBlockInterval) @@ -97,9 +92,12 @@ func (b *BlockNotifierPolling) Start(ctx context.Context) { case <-ctx.Done(): return case <-ticker.C: - delay, newStatus := b.step(ctx, status) + delay, newStatus, event := b.step(ctx, status) status = newStatus b.setGlobalStatus(status) + if event != nil { + b.Publish(*event) + } ticker.Reset(delay) } } @@ -121,67 +119,70 @@ func (b *BlockNotifierPolling) getGlobalStatus() *blockNotifierPollingInternalSt return ©Status } +// step is the main function of the BlockNotifierPolling, it checks if there is a new block +// it returns: +// - the delay for the next check +// - the new status +// - the new even to emit or nil func (b *BlockNotifierPolling) step(ctx context.Context, - status *blockNotifierPollingInternalStatus) (time.Duration, *blockNotifierPollingInternalStatus) { + previousState *blockNotifierPollingInternalStatus) (time.Duration, + *blockNotifierPollingInternalStatus, *types.EventNewBlock) { currentBlock, err := b.ethClient.HeaderByNumber(ctx, b.blockFinality) - if err != nil || currentBlock == nil { + if err == nil && currentBlock == nil { + err = fmt.Errorf("failed to get block number: return a nil block") + } + if err != nil { b.logger.Errorf("Failed to get block number: %v", err) - return b.nextBlockRequestDelay(status, err), status.clear() - } - if status == nil { - status = status.intialBlock(currentBlock.Number.Uint64()) - return b.nextBlockRequestDelay(status, nil), status - } - - if currentBlock.Number.Uint64() != status.lastBlockSeen { - b.Publish(types.EventNewBlock{ - BlockNumber: currentBlock.Number.Uint64(), - BlockFinalityType: b.config.BlockFinalityType, - }) - now := timeNowFunc() - timePreviousBlock := now.Sub(status.lastBlockTime) - status.previousBlockTime = &timePreviousBlock - status.lastBlockTime = now - - if currentBlock.Number.Uint64()-status.lastBlockSeen != 1 { - b.logger.Warnf("Missed block(s) [finality:%s]: %d -> %d", - b.config.BlockFinalityType, status.lastBlockSeen, currentBlock.Number.Uint64()) - status.previousBlockTime = nil - status.lastBlockSeen = currentBlock.Number.Uint64() - return b.nextBlockRequestDelay(status, nil), status - } - - status.lastBlockSeen = currentBlock.Number.Uint64() + newState := previousState.clear() + return b.nextBlockRequestDelay(nil, err), newState, nil + } + if previousState == nil { + newState := previousState.intialBlock(currentBlock.Number.Uint64()) + return b.nextBlockRequestDelay(previousState, nil), newState, nil + } + if currentBlock.Number.Uint64() == previousState.lastBlockSeen { + // No new block, so no changes on state + return b.nextBlockRequestDelay(previousState, nil), previousState, nil + } + // New blockNumber! + eventToEmit := &types.EventNewBlock{ + BlockNumber: currentBlock.Number.Uint64(), + BlockFinalityType: b.config.BlockFinalityType, + } - b.logger.Debugf("New block seen [finality:%s]: %d. blockRate:%s", - b.config.BlockFinalityType, currentBlock.Number.Uint64(), status.previousBlockTime) + if currentBlock.Number.Uint64()-previousState.lastBlockSeen != 1 { + b.logger.Warnf("Missed block(s) [finality:%s]: %d -> %d", + b.config.BlockFinalityType, previousState.lastBlockSeen, currentBlock.Number.Uint64()) + // It start from scratch because something fails in calculation of block period + newState := previousState.clear() + return b.nextBlockRequestDelay(nil, nil), newState, eventToEmit } - return b.nextBlockRequestDelay(status, nil), status + newState := previousState.incommingNewBlock(currentBlock.Number.Uint64()) + b.logger.Debugf("New block seen [finality:%s]: %d. blockRate:%s", + b.config.BlockFinalityType, currentBlock.Number.Uint64(), newState.previousBlockTime) + + return b.nextBlockRequestDelay(newState, nil), newState, eventToEmit } func (b *BlockNotifierPolling) nextBlockRequestDelay(status *blockNotifierPollingInternalStatus, err error) time.Duration { if b.config.CheckNewBlockInterval == AutomaticBlockInterval { - if status == nil { - return minBlockInterval - } - if status.previousBlockTime == nil { - // First interation is done with maximum precision - return minBlockInterval - } - if status.previousBlockTime != nil { - now := timeNowFunc() - expectedTimeNextBlock := status.lastBlockTime.Add(*status.previousBlockTime) - distanceToNextBlock := expectedTimeNextBlock.Sub(now) - interval := distanceToNextBlock * 4 / 5 //nolint:mnd // 80% of for reach the next block - return max(minBlockInterval, min(maxBlockInterval, interval)) - } - } - if err == nil { return b.config.CheckNewBlockInterval } - // If error we wait twice the interval - return b.config.CheckNewBlockInterval * 2 //nolint:mnd // 2 times the interval + // Initial stages wait the minimum interval to increas accuracy + if status == nil || status.previousBlockTime == nil { + return minBlockInterval + } + if err != nil { + // If error we wait twice the min interval + return minBlockInterval * 2 //nolint:mnd // 2 times the interval + } + // we have a previous block time so we can calculate the interval + now := timeNowFunc() + expectedTimeNextBlock := status.lastBlockTime.Add(*status.previousBlockTime) + distanceToNextBlock := expectedTimeNextBlock.Sub(now) + interval := distanceToNextBlock * 4 / 5 //nolint:mnd // 80% of for reach the next block + return max(minBlockInterval, min(maxBlockInterval, interval)) } type blockNotifierPollingInternalStatus struct { @@ -209,9 +210,12 @@ func (s *blockNotifierPollingInternalStatus) intialBlock(block uint64) *blockNot } } -func (s *blockNotifierPollingInternalStatus) incommingBlock(block uint64) *blockNotifierPollingInternalStatus { +func (s *blockNotifierPollingInternalStatus) incommingNewBlock(block uint64) *blockNotifierPollingInternalStatus { + now := timeNowFunc() + timePreviousBlock := now.Sub(s.lastBlockTime) return &blockNotifierPollingInternalStatus{ - lastBlockSeen: block, - lastBlockTime: timeNowFunc(), + lastBlockSeen: block, + lastBlockTime: now, + previousBlockTime: &timePreviousBlock, } } diff --git a/aggsender/block_notifier_polling_test.go b/aggsender/block_notifier_polling_test.go index 233ba5782..c226af213 100644 --- a/aggsender/block_notifier_polling_test.go +++ b/aggsender/block_notifier_polling_test.go @@ -9,6 +9,7 @@ import ( "time" "github.com/0xPolygon/cdk/aggsender/mocks" + aggsendertypes "github.com/0xPolygon/cdk/aggsender/types" "github.com/0xPolygon/cdk/etherman" "github.com/0xPolygon/cdk/log" "github.com/ethereum/go-ethereum/core/types" @@ -29,7 +30,7 @@ func TestExploratoryBlockNotifierPolling(t *testing.T) { BlockFinalityType: etherman.LatestBlock, }, log.WithFields("test", "test"), nil) require.NoError(t, errSut) - sut.StartAsync(context.Background()) + go sut.Start(context.Background()) ch := sut.Subscribe("test") for { select { @@ -38,6 +39,97 @@ func TestExploratoryBlockNotifierPolling(t *testing.T) { } } } + +func TestBlockNotifierPollingStep(t *testing.T) { + time0 := time.Unix(1731322117, 0) + period0 := time.Second * 10 + period0_80percent := time.Second * 8 + time1 := time0.Add(period0) + tests := []struct { + name string + previousStatus *blockNotifierPollingInternalStatus + HeaderByNumberError bool + HeaderByNumberErrorNumber uint64 + forcedTime time.Time + expectedStatus *blockNotifierPollingInternalStatus + expectedDelay time.Duration + expectedEvent *aggsendertypes.EventNewBlock + }{ + { + name: "initial->receive block", + previousStatus: nil, + HeaderByNumberError: false, + HeaderByNumberErrorNumber: 100, + forcedTime: time0, + expectedStatus: &blockNotifierPollingInternalStatus{ + lastBlockSeen: 100, + lastBlockTime: time0, + }, + expectedDelay: minBlockInterval, + expectedEvent: nil, + }, + { + name: "received block->error", + previousStatus: nil, + HeaderByNumberError: true, + forcedTime: time0, + expectedStatus: &blockNotifierPollingInternalStatus{}, + expectedDelay: minBlockInterval, + expectedEvent: nil, + }, + + { + name: "have block period->receive new block", + previousStatus: &blockNotifierPollingInternalStatus{ + lastBlockSeen: 100, + lastBlockTime: time0, + previousBlockTime: &period0, + }, + HeaderByNumberError: false, + HeaderByNumberErrorNumber: 101, + forcedTime: time1, + expectedStatus: &blockNotifierPollingInternalStatus{ + lastBlockSeen: 101, + lastBlockTime: time1, + previousBlockTime: &period0, + }, + expectedDelay: period0_80percent, + expectedEvent: &aggsendertypes.EventNewBlock{ + BlockNumber: 101, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + //t.Parallel() + testData := newBlockNotifierPollingTestData(t, nil) + + timeNowFunc = func() time.Time { + return tt.forcedTime + } + + if tt.HeaderByNumberError == false { + hdr1 := &types.Header{ + Number: big.NewInt(int64(tt.HeaderByNumberErrorNumber)), + } + testData.ethClientMock.EXPECT().HeaderByNumber(mock.Anything, mock.Anything).Return(hdr1, nil).Once() + } else { + testData.ethClientMock.EXPECT().HeaderByNumber(mock.Anything, mock.Anything).Return(nil, fmt.Errorf("error")).Once() + } + delay, newStatus, event := testData.sut.step(context.TODO(), tt.previousStatus) + require.Equal(t, tt.expectedDelay, delay, "delay") + require.Equal(t, tt.expectedStatus, newStatus, "new_status") + if tt.expectedEvent == nil { + require.Nil(t, event, "send_event") + } else { + require.Equal(t, tt.expectedEvent.BlockNumber, event.BlockNumber, "send_event") + } + }) + } + +} + func TestDelayNoPreviousBLock(t *testing.T) { testData := newBlockNotifierPollingTestData(t, nil) status := blockNotifierPollingInternalStatus{ From ad267dfd375456ccb1150c94cabfec34a2d60b00 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 13:08:51 +0100 Subject: [PATCH 14/27] fix: wip --- aggsender/block_notifier_polling.go | 2 +- aggsender/block_notifier_polling_test.go | 3 +-- test/config/kurtosis-cdk-node-config.toml.template | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/aggsender/block_notifier_polling.go b/aggsender/block_notifier_polling.go index f79459d33..70ef6fedb 100644 --- a/aggsender/block_notifier_polling.go +++ b/aggsender/block_notifier_polling.go @@ -154,7 +154,7 @@ func (b *BlockNotifierPolling) step(ctx context.Context, b.logger.Warnf("Missed block(s) [finality:%s]: %d -> %d", b.config.BlockFinalityType, previousState.lastBlockSeen, currentBlock.Number.Uint64()) // It start from scratch because something fails in calculation of block period - newState := previousState.clear() + newState := previousState.intialBlock(currentBlock.Number.Uint64()) return b.nextBlockRequestDelay(nil, nil), newState, eventToEmit } newState := previousState.incommingNewBlock(currentBlock.Number.Uint64()) diff --git a/aggsender/block_notifier_polling_test.go b/aggsender/block_notifier_polling_test.go index c226af213..59ef17567 100644 --- a/aggsender/block_notifier_polling_test.go +++ b/aggsender/block_notifier_polling_test.go @@ -102,7 +102,7 @@ func TestBlockNotifierPollingStep(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - //t.Parallel() + t.Parallel() testData := newBlockNotifierPollingTestData(t, nil) timeNowFunc = func() time.Time { @@ -127,7 +127,6 @@ func TestBlockNotifierPollingStep(t *testing.T) { } }) } - } func TestDelayNoPreviousBLock(t *testing.T) { diff --git a/test/config/kurtosis-cdk-node-config.toml.template b/test/config/kurtosis-cdk-node-config.toml.template index 508c1286e..4069b3506 100644 --- a/test/config/kurtosis-cdk-node-config.toml.template +++ b/test/config/kurtosis-cdk-node-config.toml.template @@ -25,8 +25,6 @@ AggregatorPrivateKeyPassword = "{{.zkevm_l2_keystore_password}}" SenderProofToL1Addr = "{{.zkevm_l2_agglayer_address}}" polygonBridgeAddr = "{{.zkevm_bridge_address}}" - -RPCURL = "http://{{.l2_rpc_name}}{{.deployment_suffix}}:{{.zkevm_rpc_http_port}}" WitnessURL = "http://{{.l2_rpc_name}}{{.deployment_suffix}}:{{.zkevm_rpc_http_port}}" From 8f5cd474b8eb5551ec7605b9f98420c97d15d5ad Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 13:53:48 +0100 Subject: [PATCH 15/27] fix: wip --- aggsender/block_notifier_polling_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/aggsender/block_notifier_polling_test.go b/aggsender/block_notifier_polling_test.go index 59ef17567..83b3b6436 100644 --- a/aggsender/block_notifier_polling_test.go +++ b/aggsender/block_notifier_polling_test.go @@ -102,7 +102,6 @@ func TestBlockNotifierPollingStep(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - t.Parallel() testData := newBlockNotifierPollingTestData(t, nil) timeNowFunc = func() time.Time { From a1524fed17da4bca6f5ecb8464cff6816677f101 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 15:49:14 +0100 Subject: [PATCH 16/27] feat: merge 'transfer ETH L1 to L2 to L1' test with 'Native gas token deposit to WETH' --- test/bridge-e2e.bats | 37 ++++++++----------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/test/bridge-e2e.bats b/test/bridge-e2e.bats index b2e7b4892..d73e8ed1b 100644 --- a/test/bridge-e2e.bats +++ b/test/bridge-e2e.bats @@ -51,11 +51,11 @@ setup() { local initial_receiver_balance=$(cast call --rpc-url "$l2_rpc_url" "$weth_token_addr" "$balance_of_fn_sig" "$destination_addr" | awk '{print $1}') echo "Initial receiver balance of native token on L2 $initial_receiver_balance" >&3 - echo "Running LxLy deposit" >&3 + echo "Running LxLy deposit on L1" >&3 run bridgeAsset "$native_token_addr" "$l1_rpc_url" assert_success - echo "Running LxLy claim" >&3 + echo "Running LxLy claim on L2" >&3 timeout="120" claim_frequency="10" run wait_for_claim "$timeout" "$claim_frequency" "$l2_rpc_url" @@ -66,6 +66,12 @@ setup() { break fi assert_success + + echo "Claim in L1" >&3 + timeout="400" + claim_frequency="60" + run wait_for_claim "$timeout" "$claim_frequency" "$l1_rpc_url" + assert_success } @test "Custom gas token deposit" { @@ -155,30 +161,3 @@ setup() { fi assert_success } - -@test "transfer ETH L1 to L2 to L1" { - - destination_addr=$sender_addr - destination_net=1 - echo " bridgeAsset (ETH->WETH) L1 to L2 dest: $destination_addr eth:$ether_value" >&3 - run bridgeAsset "0x0000000000000000000000000000000000000000" "$l1_rpc_url" - assert_success - - echo "*** Claim in L2" >&3 - timeout="120" - claim_frequency="30" - run wait_for_claim "$timeout" "$claim_frequency" "$l2_rpc_url" - assert_success - - echo " bridgeAsset (WETH->ETH) L2 to L1" >&3 - destination_addr=$sender_addr - destination_net=0 - run bridgeAsset "$weth_token_addr" "$l2_rpc_url" - assert_success - - echo " Claim in L1" >&3 - timeout="360" - claim_frequency="60" - run wait_for_claim "$timeout" "$claim_frequency" "$l1_rpc_url" - assert_success -} From 223a93b92693d6d01550c849618d75255bc04169 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 18:03:45 +0100 Subject: [PATCH 17/27] fix: e2e --- test/bridge-e2e.bats | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/bridge-e2e.bats b/test/bridge-e2e.bats index d73e8ed1b..00a524fb7 100644 --- a/test/bridge-e2e.bats +++ b/test/bridge-e2e.bats @@ -65,6 +65,12 @@ setup() { if [ $status -eq 0 ]; then break fi + assert_success + + echo "bridgeAsset L2 WETH to L1 ETH" >&3 + destination_addr=$sender_addr + destination_net=0 + run bridgeAsset "$weth_token_addr" "$l2_rpc_url" assert_success echo "Claim in L1" >&3 From f68087308a34ed8d3cb9a7a5d5fd9d4fb4fbcfa1 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 18:32:55 +0100 Subject: [PATCH 18/27] fix: PR comments --- aggsender/block_notifier_polling.go | 4 +--- aggsender/types/block_notifier.go | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/aggsender/block_notifier_polling.go b/aggsender/block_notifier_polling.go index 70ef6fedb..17dafefa1 100644 --- a/aggsender/block_notifier_polling.go +++ b/aggsender/block_notifier_polling.go @@ -44,9 +44,7 @@ type BlockNotifierPolling struct { // NewBlockNotifierPolling creates a new BlockNotifierPolling. // if param `subscriber` is nil a new GenericSubscriberImpl[types.EventNewBlock] will be created. // To use this class you need to subscribe and each time that a new block appear the subscriber -// -// will be notified through the channel. (check unit tests TestExploratoryBlockNotifierPolling -// +// will be notified through the channel. (check unit tests TestExploratoryBlockNotifierPolling // for more information) func NewBlockNotifierPolling(ethClient types.EthClient, config ConfigBlockNotifierPolling, diff --git a/aggsender/types/block_notifier.go b/aggsender/types/block_notifier.go index c19e60698..475abc1bf 100644 --- a/aggsender/types/block_notifier.go +++ b/aggsender/types/block_notifier.go @@ -7,6 +7,7 @@ type EventNewBlock struct { BlockFinalityType etherman.BlockNumberFinality } +// BlockNotifier is the interface that wraps the basic methods to notify a new block. type BlockNotifier interface { // NotifyEpochStarted notifies the epoch has started. Subscribe(id string) <-chan EventNewBlock From 1ebcc5a8c5cfc0a0e1eb5fc70412de0242645b55 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 18:57:16 +0100 Subject: [PATCH 19/27] fix: e2e --- test/bridge-e2e.bats | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/bridge-e2e.bats b/test/bridge-e2e.bats index 00a524fb7..892e371b9 100644 --- a/test/bridge-e2e.bats +++ b/test/bridge-e2e.bats @@ -68,12 +68,11 @@ setup() { assert_success echo "bridgeAsset L2 WETH to L1 ETH" >&3 - destination_addr=$sender_addr destination_net=0 run bridgeAsset "$weth_token_addr" "$l2_rpc_url" assert_success - echo "Claim in L1" >&3 + echo "Claim in L1 ETH" >&3 timeout="400" claim_frequency="60" run wait_for_claim "$timeout" "$claim_frequency" "$l1_rpc_url" From 705d5ccbc67323418c0d6cbd06b6a09ebc557272 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 19:26:46 +0100 Subject: [PATCH 20/27] fix: e2e --- test/bridge-e2e.bats | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/bridge-e2e.bats b/test/bridge-e2e.bats index 892e371b9..9f1310e3d 100644 --- a/test/bridge-e2e.bats +++ b/test/bridge-e2e.bats @@ -62,9 +62,6 @@ setup() { assert_success run verify_balance "$l2_rpc_url" "$weth_token_addr" "$destination_addr" "$initial_receiver_balance" "$ether_value" - if [ $status -eq 0 ]; then - break - fi assert_success echo "bridgeAsset L2 WETH to L1 ETH" >&3 From 5047239f427927e9a60168ab9d2d247b9a3324c7 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 20:28:43 +0100 Subject: [PATCH 21/27] fix: e2e --- test/bridge-e2e.bats | 1 + 1 file changed, 1 insertion(+) diff --git a/test/bridge-e2e.bats b/test/bridge-e2e.bats index 9f1310e3d..3254652dd 100644 --- a/test/bridge-e2e.bats +++ b/test/bridge-e2e.bats @@ -52,6 +52,7 @@ setup() { echo "Initial receiver balance of native token on L2 $initial_receiver_balance" >&3 echo "Running LxLy deposit on L1" >&3 + destination_addr=$sender_addr run bridgeAsset "$native_token_addr" "$l1_rpc_url" assert_success From 251cb708632355406e01b637ec8be4d4451554be Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 21:09:24 +0100 Subject: [PATCH 22/27] fix: e2e --- test/bridge-e2e.bats | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/bridge-e2e.bats b/test/bridge-e2e.bats index 3254652dd..9a0d2529b 100644 --- a/test/bridge-e2e.bats +++ b/test/bridge-e2e.bats @@ -51,8 +51,9 @@ setup() { local initial_receiver_balance=$(cast call --rpc-url "$l2_rpc_url" "$weth_token_addr" "$balance_of_fn_sig" "$destination_addr" | awk '{print $1}') echo "Initial receiver balance of native token on L2 $initial_receiver_balance" >&3 - echo "Running LxLy deposit on L1" >&3 + echo "Running LxLy deposit on L1 to network: $l2_rpc_network_id native_token: $native_token_addr" >&3 destination_addr=$sender_addr + destination_net=$l2_rpc_network_id run bridgeAsset "$native_token_addr" "$l1_rpc_url" assert_success @@ -65,7 +66,8 @@ setup() { run verify_balance "$l2_rpc_url" "$weth_token_addr" "$destination_addr" "$initial_receiver_balance" "$ether_value" assert_success - echo "bridgeAsset L2 WETH to L1 ETH" >&3 + echo "bridgeAsset L2 WETH to L1 ETH" >&3 + destination_addr=$sender_addr destination_net=0 run bridgeAsset "$weth_token_addr" "$l2_rpc_url" assert_success From 12ddfe66fae6428fc619bc700136779f1d7ae719 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 21:28:26 +0100 Subject: [PATCH 23/27] fix: e2e --- test/bridge-e2e.bats | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/bridge-e2e.bats b/test/bridge-e2e.bats index 9a0d2529b..e44a0f8fc 100644 --- a/test/bridge-e2e.bats +++ b/test/bridge-e2e.bats @@ -51,13 +51,13 @@ setup() { local initial_receiver_balance=$(cast call --rpc-url "$l2_rpc_url" "$weth_token_addr" "$balance_of_fn_sig" "$destination_addr" | awk '{print $1}') echo "Initial receiver balance of native token on L2 $initial_receiver_balance" >&3 - echo "Running LxLy deposit on L1 to network: $l2_rpc_network_id native_token: $native_token_addr" >&3 + echo "=== Running LxLy deposit on L1 to network: $l2_rpc_network_id native_token: $native_token_addr" >&3 destination_addr=$sender_addr destination_net=$l2_rpc_network_id run bridgeAsset "$native_token_addr" "$l1_rpc_url" assert_success - echo "Running LxLy claim on L2" >&3 + echo "=== Running LxLy claim on L2" >&3 timeout="120" claim_frequency="10" run wait_for_claim "$timeout" "$claim_frequency" "$l2_rpc_url" @@ -66,13 +66,13 @@ setup() { run verify_balance "$l2_rpc_url" "$weth_token_addr" "$destination_addr" "$initial_receiver_balance" "$ether_value" assert_success - echo "bridgeAsset L2 WETH to L1 ETH" >&3 + echo "=== bridgeAsset L2 WETH: $weth_token_addr to L1 ETH" >&3 destination_addr=$sender_addr destination_net=0 run bridgeAsset "$weth_token_addr" "$l2_rpc_url" assert_success - echo "Claim in L1 ETH" >&3 + echo "=== Claim in L1 ETH" >&3 timeout="400" claim_frequency="60" run wait_for_claim "$timeout" "$claim_frequency" "$l1_rpc_url" From 06c121a1e17f62aa0a123084e0eb890f7cef3413 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 11 Nov 2024 21:29:26 +0100 Subject: [PATCH 24/27] fix: e2e --- test/bridge-e2e.bats | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/bridge-e2e.bats b/test/bridge-e2e.bats index e44a0f8fc..e754ef701 100644 --- a/test/bridge-e2e.bats +++ b/test/bridge-e2e.bats @@ -48,11 +48,12 @@ setup() { } @test "Native gas token deposit to WETH" { + destination_addr=$sender_addr local initial_receiver_balance=$(cast call --rpc-url "$l2_rpc_url" "$weth_token_addr" "$balance_of_fn_sig" "$destination_addr" | awk '{print $1}') echo "Initial receiver balance of native token on L2 $initial_receiver_balance" >&3 echo "=== Running LxLy deposit on L1 to network: $l2_rpc_network_id native_token: $native_token_addr" >&3 - destination_addr=$sender_addr + destination_net=$l2_rpc_network_id run bridgeAsset "$native_token_addr" "$l1_rpc_url" assert_success From 41378a77452730b02cc2dafa366e30eb06ea8c82 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 12 Nov 2024 10:15:19 +0100 Subject: [PATCH 25/27] feat: notify epoch is a percentage of epoch --- aggsender/aggsender_test.go | 4 +- aggsender/config.go | 8 ++-- aggsender/epoch_notifier_per_block.go | 46 ++++++++++++++-------- aggsender/epoch_notifier_per_block_test.go | 30 +++++++------- cmd/run.go | 2 +- config/default.go | 2 +- test/helpers/lxly-bridge-test.bash | 1 + 7 files changed, 54 insertions(+), 39 deletions(-) diff --git a/aggsender/aggsender_test.go b/aggsender/aggsender_test.go index 1ea46f5ce..8f1aea36c 100644 --- a/aggsender/aggsender_test.go +++ b/aggsender/aggsender_test.go @@ -50,7 +50,7 @@ func TestConfigString(t *testing.T) { AggsenderPrivateKey: types.KeystoreFileConfig{Path: "/path/to/key", Password: "password"}, URLRPCL2: "http://l2.rpc.url", BlockFinality: "latestBlock", - BlocksBeforeEpochEnding: 10, + EpochNotificationPercentage: 50, SaveCertificatesToFilesPath: "/path/to/certificates", } @@ -62,7 +62,7 @@ func TestConfigString(t *testing.T) { "AggsenderPrivateKeyPassword: password\n" + "URLRPCL2: http://l2.rpc.url\n" + "BlockFinality: latestBlock\n" + - "BlocksBeforeEpochEnding: 10\n" + + "EpochNotificationPercentage: 50\n" + "SaveCertificatesToFilesPath: /path/to/certificates\n" require.Equal(t, expected, config.String()) diff --git a/aggsender/config.go b/aggsender/config.go index 686945897..a7efdd378 100644 --- a/aggsender/config.go +++ b/aggsender/config.go @@ -22,9 +22,11 @@ type Config struct { URLRPCL2 string `mapstructure:"URLRPCL2"` // BlockFinality indicates which finality follows AggLayer BlockFinality string `jsonschema:"enum=LatestBlock, enum=SafeBlock, enum=PendingBlock, enum=FinalizedBlock, enum=EarliestBlock" mapstructure:"BlockFinality"` //nolint:lll - // BlocksBeforeEpochEnding indicates how many blocks before the epoch ending + // EpochNotificationPercentage indicates the percentage of the epoch // the AggSender should send the certificate - BlocksBeforeEpochEnding uint `mapstructure:"BlocksBeforeEpochEnding"` + // 0 -> Begining + // 50 -> Middle + EpochNotificationPercentage uint `mapstructure:"EpochNotificationPercentage"` // SaveCertificatesToFilesPath if != "" tells the AggSender to save the certificates to a file in this path SaveCertificatesToFilesPath string `mapstructure:"SaveCertificatesToFilesPath"` } @@ -39,6 +41,6 @@ func (c Config) String() string { "AggsenderPrivateKeyPassword: " + c.AggsenderPrivateKey.Password + "\n" + "URLRPCL2: " + c.URLRPCL2 + "\n" + "BlockFinality: " + c.BlockFinality + "\n" + - "BlocksBeforeEpochEnding: " + fmt.Sprintf("%d", c.BlocksBeforeEpochEnding) + "\n" + + "EpochNotificationPercentage: " + fmt.Sprintf("%d", c.EpochNotificationPercentage) + "\n" + "SaveCertificatesToFilesPath: " + c.SaveCertificatesToFilesPath + "\n" } diff --git a/aggsender/epoch_notifier_per_block.go b/aggsender/epoch_notifier_per_block.go index d1309a226..5fc4bcec9 100644 --- a/aggsender/epoch_notifier_per_block.go +++ b/aggsender/epoch_notifier_per_block.go @@ -20,12 +20,15 @@ type ConfigEpochNotifierPerBlock struct { StartingEpochBlock uint64 NumBlockPerEpoch uint - // Num blocks before the end of the epoch to notify it - NotifyPendingBlocksBeforeEndEpoch uint + // EpochNotificationPercentage + // 0 -> begining new Epoch + // 50 -> middle of epoch + // 100 -> end of epoch (same as 0) + EpochNotificationPercentage uint } func NewConfigEpochNotifierPerBlock(aggLayer agglayer.AggLayerClientGetEpochConfiguration, - notifyPendingBlocksBeforeEndEpoch uint) (*ConfigEpochNotifierPerBlock, error) { + epochNotificationPercentage uint) (*ConfigEpochNotifierPerBlock, error) { if aggLayer == nil { return nil, fmt.Errorf("newConfigEpochNotifierPerBlock: aggLayerClient is required") } @@ -34,9 +37,9 @@ func NewConfigEpochNotifierPerBlock(aggLayer agglayer.AggLayerClientGetEpochConf return nil, fmt.Errorf("newConfigEpochNotifierPerBlock: error getting clock configuration from AggLayer: %w", err) } return &ConfigEpochNotifierPerBlock{ - StartingEpochBlock: clockConfig.GenesisBlock, - NumBlockPerEpoch: uint(clockConfig.EpochDuration), - NotifyPendingBlocksBeforeEndEpoch: notifyPendingBlocksBeforeEndEpoch, + StartingEpochBlock: clockConfig.GenesisBlock, + NumBlockPerEpoch: uint(clockConfig.EpochDuration), + EpochNotificationPercentage: epochNotificationPercentage, }, nil } @@ -44,8 +47,8 @@ func (c *ConfigEpochNotifierPerBlock) Validate() error { if c.NumBlockPerEpoch == 0 { return fmt.Errorf("numBlockPerEpoch: num block per epoch is required > 0 ") } - if c.NumBlockPerEpoch-c.NotifyPendingBlocksBeforeEndEpoch == 0 { - return fmt.Errorf("notifyPendingBlocksBeforeEndEpoch: Notify before num blocks end of epoch is required > 0") + if c.EpochNotificationPercentage >= 100 { + return fmt.Errorf("epochNotificationPercentage: must be between 0 and 99") } return nil } @@ -83,8 +86,8 @@ func NewEpochNotifierPerBlock(blockNotifier types.BlockNotifier, func (e *EpochNotifierPerBlock) String() string { return fmt.Sprintf("EpochNotifierPerBlock: startingEpochBlock=%d, numBlockPerEpoch=%d,"+ - " notifyPendingBlocksBeforeEndEpoch=%d", - e.Config.StartingEpochBlock, e.Config.NumBlockPerEpoch, e.Config.NotifyPendingBlocksBeforeEndEpoch) + " EpochNotificationPercentage=%d", + e.Config.StartingEpochBlock, e.Config.NumBlockPerEpoch, e.Config.EpochNotificationPercentage) } // StartAsync starts the notifier in a goroutine @@ -139,14 +142,10 @@ func (e *EpochNotifierPerBlock) step(status internalStatus, } status.lastBlockSeen = currentBlock - needNotify, closingEpoch := e.isClosingEpochBlock(currentBlock, status.waitingForEpoch) + needNotify, closingEpoch := e.isNotificationRequired(currentBlock, status.waitingForEpoch) if needNotify { // Notify the epoch has started info := e.infoEpoch(currentBlock, closingEpoch) - if status.waitingForEpoch == 0 && info.PendingBlocks > int(e.Config.NotifyPendingBlocksBeforeEndEpoch) { - // We are in the first epoch, but we are not near the end of the epoch - return status, nil - } status.waitingForEpoch = closingEpoch + 1 return status, &types.EpochEvent{ Epoch: closingEpoch, @@ -162,10 +161,23 @@ func (e *EpochNotifierPerBlock) infoEpoch(currentBlock, newEpochNotified uint64) PendingBlocks: int(nextBlockStartingEpoch - currentBlock), } } -func (e *EpochNotifierPerBlock) isClosingEpochBlock(currentBlock, lastEpochNotified uint64) (bool, uint64) { - nextEpoch := e.epochNumber(currentBlock + uint64(e.Config.NotifyPendingBlocksBeforeEndEpoch)) +func (e *EpochNotifierPerBlock) percentEpoch(currentBlock uint64) float64 { + epoch := e.epochNumber(currentBlock) + startingBlock := e.startingBlockEpoch(epoch) + elapsedBlocks := currentBlock - startingBlock + return float64(elapsedBlocks) / float64(e.Config.NumBlockPerEpoch) +} +func (e *EpochNotifierPerBlock) isNotificationRequired(currentBlock, lastEpochNotified uint64) (bool, uint64) { + percentEpoch := e.percentEpoch(currentBlock) + thresholdPercent := float64(e.Config.EpochNotificationPercentage) / 100.0 + if percentEpoch < thresholdPercent { + e.logger.Debugf("Block %d is at %f%% of the epoch no notify", currentBlock, percentEpoch*100) + return false, e.epochNumber(currentBlock) + } + nextEpoch := e.epochNumber(currentBlock) + 1 return nextEpoch > lastEpochNotified, e.epochNumber(currentBlock) } + func (e *EpochNotifierPerBlock) startingBlockEpoch(epoch uint64) uint64 { if epoch == 0 { return e.Config.StartingEpochBlock - 1 diff --git a/aggsender/epoch_notifier_per_block_test.go b/aggsender/epoch_notifier_per_block_test.go index 9e84fb6a4..99119f5eb 100644 --- a/aggsender/epoch_notifier_per_block_test.go +++ b/aggsender/epoch_notifier_per_block_test.go @@ -16,9 +16,9 @@ import ( func TestStartingBlockEpoch(t *testing.T) { testData := newNotifierPerBlockTestData(t, &ConfigEpochNotifierPerBlock{ - StartingEpochBlock: 9, - NumBlockPerEpoch: 10, - NotifyPendingBlocksBeforeEndEpoch: 1, + StartingEpochBlock: 9, + NumBlockPerEpoch: 10, + EpochNotificationPercentage: 80, }) // EPOCH: ---0 ----+----1 -----+----2 ----+----3 ----+----4 ----+----5 ----+---- // BLOCK: 9 19 29 39 49 @@ -29,9 +29,9 @@ func TestStartingBlockEpoch(t *testing.T) { func TestEpochStep(t *testing.T) { testData := newNotifierPerBlockTestData(t, &ConfigEpochNotifierPerBlock{ - StartingEpochBlock: 9, - NumBlockPerEpoch: 10, - NotifyPendingBlocksBeforeEndEpoch: 1, + StartingEpochBlock: 9, + NumBlockPerEpoch: 10, + EpochNotificationPercentage: 50, }) // EPOCH: ---0 ----+----1 -----+----2 ----+----3 ----+----4 ----+----5 ----+---- // BLOCK: 9 19 29 39 49 @@ -138,9 +138,9 @@ func TestStepNotifyEpoch(t *testing.T) { func TestBlockEpochNumber(t *testing.T) { testData := newNotifierPerBlockTestData(t, &ConfigEpochNotifierPerBlock{ - StartingEpochBlock: 105, - NumBlockPerEpoch: 10, - NotifyPendingBlocksBeforeEndEpoch: 1, + StartingEpochBlock: 105, + NumBlockPerEpoch: 10, + EpochNotificationPercentage: 1, }) require.Equal(t, uint64(0), testData.sut.epochNumber(0)) require.Equal(t, uint64(0), testData.sut.epochNumber(104)) @@ -154,9 +154,9 @@ func TestBlockEpochNumber(t *testing.T) { func TestBlockBeforeEpoch(t *testing.T) { testData := newNotifierPerBlockTestData(t, &ConfigEpochNotifierPerBlock{ - StartingEpochBlock: 105, - NumBlockPerEpoch: 10, - NotifyPendingBlocksBeforeEndEpoch: 1, + StartingEpochBlock: 105, + NumBlockPerEpoch: 10, + EpochNotificationPercentage: 1, }) status := internalStatus{ lastBlockSeen: 104, @@ -184,9 +184,9 @@ func newNotifierPerBlockTestData(t *testing.T, config *ConfigEpochNotifierPerBlo t.Helper() if config == nil { config = &ConfigEpochNotifierPerBlock{ - StartingEpochBlock: 0, - NumBlockPerEpoch: 10, - NotifyPendingBlocksBeforeEndEpoch: 1, + StartingEpochBlock: 0, + NumBlockPerEpoch: 10, + EpochNotificationPercentage: 50, } } blockNotifierMock := mocks.NewBlockNotifier(t) diff --git a/cmd/run.go b/cmd/run.go index 070ff4622..6042e935a 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -158,7 +158,7 @@ func createAggSender( return nil, err } - notifierCfg, err := aggsender.NewConfigEpochNotifierPerBlock(agglayerClient, cfg.BlocksBeforeEpochEnding) + notifierCfg, err := aggsender.NewConfigEpochNotifierPerBlock(agglayerClient, cfg.EpochNotificationPercentage) if err != nil { return nil, fmt.Errorf("cant generate config for Epoch Notifier because: %w", err) } diff --git a/config/default.go b/config/default.go index f54aa82e9..d7188e433 100644 --- a/config/default.go +++ b/config/default.go @@ -342,6 +342,6 @@ BlockGetInterval = "2s" URLRPCL2="{{L2URL}}" CheckSettledInterval = "2s" BlockFinality = "LatestBlock" -BlocksBeforeEpochEnding = 2 +EpochNotificationPercentage = 50 SaveCertificatesToFiles = false ` diff --git a/test/helpers/lxly-bridge-test.bash b/test/helpers/lxly-bridge-test.bash index 7b3cb0086..ad5ab9430 100644 --- a/test/helpers/lxly-bridge-test.bash +++ b/test/helpers/lxly-bridge-test.bash @@ -36,6 +36,7 @@ function claim() { readonly bridge_deposit_file=$(mktemp) readonly claimable_deposit_file=$(mktemp) echo "Getting full list of deposits" >&3 + echo " curl -s \"$bridge_api_url/bridges/$destination_addr?limit=100&offset=0\"" >&3 curl -s "$bridge_api_url/bridges/$destination_addr?limit=100&offset=0" | jq '.' | tee $bridge_deposit_file echo "Looking for claimable deposits" >&3 From 3cab2b3b08f74e68d83333e251e77d1ff7242e1e Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 12 Nov 2024 10:24:57 +0100 Subject: [PATCH 26/27] feat: edge case of 99% --- aggsender/epoch_notifier_per_block.go | 4 ++++ aggsender/epoch_notifier_per_block_test.go | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/aggsender/epoch_notifier_per_block.go b/aggsender/epoch_notifier_per_block.go index 5fc4bcec9..7fd079879 100644 --- a/aggsender/epoch_notifier_per_block.go +++ b/aggsender/epoch_notifier_per_block.go @@ -170,6 +170,10 @@ func (e *EpochNotifierPerBlock) percentEpoch(currentBlock uint64) float64 { func (e *EpochNotifierPerBlock) isNotificationRequired(currentBlock, lastEpochNotified uint64) (bool, uint64) { percentEpoch := e.percentEpoch(currentBlock) thresholdPercent := float64(e.Config.EpochNotificationPercentage) / 100.0 + maxTresholdPercent := float64(e.Config.NumBlockPerEpoch-1) / float64(e.Config.NumBlockPerEpoch) + if thresholdPercent > maxTresholdPercent { + thresholdPercent = maxTresholdPercent + } if percentEpoch < thresholdPercent { e.logger.Debugf("Block %d is at %f%% of the epoch no notify", currentBlock, percentEpoch*100) return false, e.epochNumber(currentBlock) diff --git a/aggsender/epoch_notifier_per_block_test.go b/aggsender/epoch_notifier_per_block_test.go index 99119f5eb..203116d01 100644 --- a/aggsender/epoch_notifier_per_block_test.go +++ b/aggsender/epoch_notifier_per_block_test.go @@ -27,6 +27,24 @@ func TestStartingBlockEpoch(t *testing.T) { require.Equal(t, uint64(19), testData.sut.startingBlockEpoch(2)) } +func TestEpochNotifyPercentageEdgeCase0(t *testing.T) { + testData := newNotifierPerBlockTestData(t, nil) + testData.sut.Config.EpochNotificationPercentage = 0 + notify, epoch := testData.sut.isNotificationRequired(9, 0) + require.True(t, notify) + require.Equal(t, uint64(1), epoch) +} + +// if percent is 99 means at end of epoch, so in a config 0, epoch-size=10, +// 99% means last block of epoch +func TestEpochNotifyPercentageEdgeCase99(t *testing.T) { + testData := newNotifierPerBlockTestData(t, nil) + testData.sut.Config.EpochNotificationPercentage = 99 + notify, epoch := testData.sut.isNotificationRequired(9, 0) + require.True(t, notify) + require.Equal(t, uint64(1), epoch) +} + func TestEpochStep(t *testing.T) { testData := newNotifierPerBlockTestData(t, &ConfigEpochNotifierPerBlock{ StartingEpochBlock: 9, From bb7e5d4aee790e77d64e06a6ada7956010b72143 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 12 Nov 2024 11:31:24 +0100 Subject: [PATCH 27/27] feat: PR comment, checkPendingCertificatesStatus returns bool and error --- aggsender/aggsender.go | 39 +++++++++++++++++++-------- aggsender/aggsender_test.go | 33 +++++++++++++---------- aggsender/config.go | 2 +- aggsender/epoch_notifier_per_block.go | 12 ++++++--- go.mod | 4 +-- go.sum | 7 +++++ 6 files changed, 65 insertions(+), 32 deletions(-) diff --git a/aggsender/aggsender.go b/aggsender/aggsender.go index 73439a0b2..dcbbc2687 100644 --- a/aggsender/aggsender.go +++ b/aggsender/aggsender.go @@ -8,6 +8,7 @@ import ( "fmt" "math/big" "os" + "slices" "time" "github.com/0xPolygon/cdk/agglayer" @@ -92,9 +93,14 @@ func (a *AggSender) sendCertificates(ctx context.Context) { select { case epoch := <-chEpoch: a.log.Infof("Epoch received: %s", epoch.String()) - a.checkPendingCertificatesStatus(ctx) - if _, err := a.sendCertificate(ctx); err != nil { - log.Error(err) + thereArePendingCerts, err := a.checkPendingCertificatesStatus(ctx) + if err == nil && !thereArePendingCerts { + if _, err := a.sendCertificate(ctx); err != nil { + log.Error(err) + } + } else { + log.Warnf("Skipping epoch %s because there are pending certificates %v or error: %w", + epoch.String(), thereArePendingCerts, err) } case <-ctx.Done(): a.log.Info("AggSender stopped") @@ -480,19 +486,28 @@ func (a *AggSender) signCertificate(certificate *agglayer.Certificate) (*agglaye // checkPendingCertificatesStatus checks the status of pending certificates // and updates in the storage if it changed on agglayer -func (a *AggSender) checkPendingCertificatesStatus(ctx context.Context) { +// It returns: +// bool -> if there are pending certificates +// error -> if there was an error +func (a *AggSender) checkPendingCertificatesStatus(ctx context.Context) (bool, error) { pendingCertificates, err := a.storage.GetCertificatesByStatus(nonSettledStatuses) if err != nil { - a.log.Errorf("error getting pending certificates: %w", err) - return + err = fmt.Errorf("error getting pending certificates: %w", err) + a.log.Error(err) + return true, err } + thereArePendingCertificates := false a.log.Debugf("checkPendingCertificatesStatus num of pendingCertificates: %d", len(pendingCertificates)) for _, certificate := range pendingCertificates { certificateHeader, err := a.aggLayerClient.GetCertificateHeader(certificate.CertificateID) if err != nil { - a.log.Errorf("error getting certificate header of %s from agglayer: %w", - certificate.String(), err) - continue + err = fmt.Errorf("error getting certificate header of %d/%s from agglayer: %w", + certificate.Height, certificate.String(), err) + a.log.Error(err) + return true, err + } + if slices.Contains(nonSettledStatuses, certificateHeader.Status) { + thereArePendingCertificates = true } a.log.Debugf("aggLayerClient.GetCertificateHeader status [%s] of certificate %s ", certificateHeader.Status, @@ -506,11 +521,13 @@ func (a *AggSender) checkPendingCertificatesStatus(ctx context.Context) { certificate.UpdatedAt = time.Now().UTC().UnixMilli() if err := a.storage.UpdateCertificateStatus(ctx, *certificate); err != nil { - a.log.Errorf("error updating certificate %s status in storage: %w", certificateHeader.String(), err) - continue + err = fmt.Errorf("error updating certificate %s status in storage: %w", certificateHeader.String(), err) + a.log.Error(err) + return true, err } } } + return thereArePendingCertificates, nil } // shouldSendCertificate checks if a certificate should be sent at given time diff --git a/aggsender/aggsender_test.go b/aggsender/aggsender_test.go index 8f1aea36c..0d071e768 100644 --- a/aggsender/aggsender_test.go +++ b/aggsender/aggsender_test.go @@ -750,17 +750,17 @@ func generateTestProof(t *testing.T) treeTypes.Proof { } func TestCheckIfCertificatesAreSettled(t *testing.T) { - t.Parallel() - tests := []struct { - name string - pendingCertificates []*aggsendertypes.CertificateInfo - certificateHeaders map[common.Hash]*agglayer.CertificateHeader - getFromDBError error - clientError error - updateDBError error - expectedErrorLogMessages []string - expectedInfoMessages []string + name string + pendingCertificates []*aggsendertypes.CertificateInfo + certificateHeaders map[common.Hash]*agglayer.CertificateHeader + getFromDBError error + clientError error + updateDBError error + expectedErrorLogMessages []string + expectedInfoMessages []string + expectedThereArePendingCerts bool + expectedError bool }{ { name: "All certificates settled - update successful", @@ -796,6 +796,8 @@ func TestCheckIfCertificatesAreSettled(t *testing.T) { expectedErrorLogMessages: []string{ "error getting pending certificates: %w", }, + expectedThereArePendingCerts: true, + expectedError: true, }, { name: "Error getting certificate header", @@ -809,6 +811,8 @@ func TestCheckIfCertificatesAreSettled(t *testing.T) { expectedErrorLogMessages: []string{ "error getting header of certificate %s with height: %d from agglayer: %w", }, + expectedThereArePendingCerts: true, + expectedError: true, }, { name: "Error updating certificate status", @@ -825,6 +829,8 @@ func TestCheckIfCertificatesAreSettled(t *testing.T) { expectedInfoMessages: []string{ "certificate %s changed status to %s", }, + expectedThereArePendingCerts: true, + expectedError: true, }, } @@ -832,8 +838,6 @@ func TestCheckIfCertificatesAreSettled(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { - t.Parallel() - mockStorage := mocks.NewAggSenderStorage(t) mockAggLayerClient := agglayer.NewAgglayerClientMock(t) mockLogger := log.WithFields("test", "unittest") @@ -860,8 +864,9 @@ func TestCheckIfCertificatesAreSettled(t *testing.T) { } ctx := context.TODO() - aggSender.checkPendingCertificatesStatus(ctx) - + thereArePendingCerts, err := aggSender.checkPendingCertificatesStatus(ctx) + require.Equal(t, tt.expectedThereArePendingCerts, thereArePendingCerts) + require.Equal(t, tt.expectedError, err != nil) mockAggLayerClient.AssertExpectations(t) mockStorage.AssertExpectations(t) }) diff --git a/aggsender/config.go b/aggsender/config.go index a7efdd378..8ae0b759b 100644 --- a/aggsender/config.go +++ b/aggsender/config.go @@ -24,7 +24,7 @@ type Config struct { BlockFinality string `jsonschema:"enum=LatestBlock, enum=SafeBlock, enum=PendingBlock, enum=FinalizedBlock, enum=EarliestBlock" mapstructure:"BlockFinality"` //nolint:lll // EpochNotificationPercentage indicates the percentage of the epoch // the AggSender should send the certificate - // 0 -> Begining + // 0 -> Begin // 50 -> Middle EpochNotificationPercentage uint `mapstructure:"EpochNotificationPercentage"` // SaveCertificatesToFilesPath if != "" tells the AggSender to save the certificates to a file in this path diff --git a/aggsender/epoch_notifier_per_block.go b/aggsender/epoch_notifier_per_block.go index 7fd079879..3b5607317 100644 --- a/aggsender/epoch_notifier_per_block.go +++ b/aggsender/epoch_notifier_per_block.go @@ -8,6 +8,10 @@ import ( "github.com/0xPolygon/cdk/aggsender/types" ) +const ( + maxPercent = 100.0 +) + type ExtraInfoEventEpoch struct { PendingBlocks int } @@ -21,7 +25,7 @@ type ConfigEpochNotifierPerBlock struct { NumBlockPerEpoch uint // EpochNotificationPercentage - // 0 -> begining new Epoch + // 0 -> begin new Epoch // 50 -> middle of epoch // 100 -> end of epoch (same as 0) EpochNotificationPercentage uint @@ -47,7 +51,7 @@ func (c *ConfigEpochNotifierPerBlock) Validate() error { if c.NumBlockPerEpoch == 0 { return fmt.Errorf("numBlockPerEpoch: num block per epoch is required > 0 ") } - if c.EpochNotificationPercentage >= 100 { + if c.EpochNotificationPercentage >= maxPercent { return fmt.Errorf("epochNotificationPercentage: must be between 0 and 99") } return nil @@ -169,13 +173,13 @@ func (e *EpochNotifierPerBlock) percentEpoch(currentBlock uint64) float64 { } func (e *EpochNotifierPerBlock) isNotificationRequired(currentBlock, lastEpochNotified uint64) (bool, uint64) { percentEpoch := e.percentEpoch(currentBlock) - thresholdPercent := float64(e.Config.EpochNotificationPercentage) / 100.0 + thresholdPercent := float64(e.Config.EpochNotificationPercentage) / maxPercent maxTresholdPercent := float64(e.Config.NumBlockPerEpoch-1) / float64(e.Config.NumBlockPerEpoch) if thresholdPercent > maxTresholdPercent { thresholdPercent = maxTresholdPercent } if percentEpoch < thresholdPercent { - e.logger.Debugf("Block %d is at %f%% of the epoch no notify", currentBlock, percentEpoch*100) + e.logger.Debugf("Block %d is at %f%% of the epoch no notify", currentBlock, percentEpoch*maxPercent) return false, e.epochNumber(currentBlock) } nextEpoch := e.epochNumber(currentBlock) + 1 diff --git a/go.mod b/go.mod index 0061c72fc..430e83261 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( go.uber.org/zap v1.27.0 golang.org/x/crypto v0.27.0 golang.org/x/net v0.29.0 - golang.org/x/sync v0.8.0 + golang.org/x/sync v0.9.0 google.golang.org/grpc v1.64.0 google.golang.org/protobuf v1.34.2 modernc.org/sqlite v1.32.0 @@ -151,7 +151,7 @@ require ( github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect go.uber.org/multierr v1.10.0 // indirect - golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect + golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.5.0 // indirect diff --git a/go.sum b/go.sum index ceb905ac3..3ad80938a 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,7 @@ github.com/0xPolygon/cdk-rpc v0.0.0-20241004114257-6c3cb6eebfb6 h1:FXL/rcO7/GtZ3 github.com/0xPolygon/cdk-rpc v0.0.0-20241004114257-6c3cb6eebfb6/go.mod h1:2scWqMMufrQXu7TikDgQ3BsyaKoX8qP26D6E262vSOg= github.com/0xPolygon/zkevm-ethtx-manager v0.2.1 h1:2Yb+KdJFMpVrS9LIkd658XiWuN+MCTs7SgeWaopXScg= github.com/0xPolygon/zkevm-ethtx-manager v0.2.1/go.mod h1:lqQmzSo2OXEZItD0R4Cd+lqKFxphXEWgqHefVcGDZZc= +github.com/0xPolygonHermez/zkevm-data-streamer v0.2.7/go.mod h1:7nM7Ihk+fTG1TQPwdZoGOYd3wprqqyIyjtS514uHzWE= github.com/0xPolygonHermez/zkevm-synchronizer-l1 v1.0.5 h1:YmnhuCl349MoNASN0fMeGKU1o9HqJhiZkfMsA/1cTRA= github.com/0xPolygonHermez/zkevm-synchronizer-l1 v1.0.5/go.mod h1:X4Su/M/+hSISqdl9yomKlRsbTyuZHsRohporyHsP8gg= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -482,6 +483,8 @@ golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= +golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= +golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= @@ -489,6 +492,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -510,6 +514,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -571,6 +577,7 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=