diff --git a/aggsender/aggsender.go b/aggsender/aggsender.go index ff17fe94a..35f6a281c 100644 --- a/aggsender/aggsender.go +++ b/aggsender/aggsender.go @@ -53,7 +53,7 @@ type AggSender struct { cfg config.Config status *types.AggsenderStatus - flow types.AggsenderFlow + flow types.AggsenderBuilderFlow l2OriginNetwork uint32 } @@ -92,7 +92,7 @@ func New( return nil, err } - flowManager, err := flows.NewFlow( + flowManager, err := flows.NewBuilderFlow( ctx, cfg, logger, @@ -132,12 +132,22 @@ func New( aggLayerClient, ) + verifierFlow, err := flows.NewLocalVerifier( + ctx, + cfg, + l1Client, + flowManager, + ) + if err != nil { + return nil, fmt.Errorf("error creating verifier flow: %w", err) + } + localValidator := validator.NewLocalValidator( logger, storage, validator.NewAggsenderValidator( logger, - flowManager, + verifierFlow, query.NewL1InfoTreeDataQuerier(l1Client, l1InfoTreeSyncer), certQuerier, query.NewLERDataQuerier(cfg.RollupCreationBlockL1, rollupDataQuerier), diff --git a/aggsender/aggsender_test.go b/aggsender/aggsender_test.go index 9a05f4f32..264e7cda4 100644 --- a/aggsender/aggsender_test.go +++ b/aggsender/aggsender_test.go @@ -228,7 +228,7 @@ func TestSendCertificate_NoClaims(t *testing.T) { cfg: config.Config{}, validatorPoller: mockValidatorPoller, localValidator: mockLocalValidator, - flow: flows.NewPPFlow(logger, + flow: flows.NewPPBuilderFlow(logger, flows.NewBaseFlow(logger, mockL2BridgeQuerier, mockStorage, mockL1Querier, mockLERQuerier, flows.NewBaseFlowConfigDefault()), mockStorage, mockL1Querier, mockL2BridgeQuerier, signer, true, 0), @@ -281,14 +281,14 @@ func TestSendCertificate(t *testing.T) { testCases := []struct { name string - mockFn func(*mocks.AggSenderStorage, *mocks.AggsenderFlow, *agglayermocks.AgglayerClientMock) + mockFn func(*mocks.AggSenderStorage, *mocks.AggsenderBuilderFlow, *agglayermocks.AgglayerClientMock) mockValidatorFn func() (*mocks.ValidatorPoller, *mocks.CertificateValidateAndSigner) expectedError string }{ { name: "error getting certificate build params", mockFn: func(mockStorage *mocks.AggSenderStorage, - mockFlow *mocks.AggsenderFlow, + mockFlow *mocks.AggsenderBuilderFlow, mockAgglayerClient *agglayermocks.AgglayerClientMock) { mockFlow.EXPECT().GetCertificateBuildParams(mock.Anything).Return(nil, errors.New("some error")).Once() }, @@ -297,7 +297,7 @@ func TestSendCertificate(t *testing.T) { { name: "no new blocks consumed", mockFn: func(mockStorage *mocks.AggSenderStorage, - mockFlow *mocks.AggsenderFlow, + mockFlow *mocks.AggsenderBuilderFlow, mockAgglayerClient *agglayermocks.AgglayerClientMock) { mockFlow.EXPECT().GetCertificateBuildParams(mock.Anything).Return(nil, nil).Once() }, @@ -305,7 +305,7 @@ func TestSendCertificate(t *testing.T) { { name: "error building certificate", mockFn: func(mockStorage *mocks.AggSenderStorage, - mockFlow *mocks.AggsenderFlow, + mockFlow *mocks.AggsenderBuilderFlow, mockAgglayerClient *agglayermocks.AgglayerClientMock) { mockFlow.EXPECT().GetCertificateBuildParams(mock.Anything).Return(&aggsendertypes.CertificateBuildParams{ Bridges: []bridgesync.Bridge{{}}, @@ -317,7 +317,7 @@ func TestSendCertificate(t *testing.T) { { name: "error sending certificate", mockFn: func(mockStorage *mocks.AggSenderStorage, - mockFlow *mocks.AggsenderFlow, + mockFlow *mocks.AggsenderBuilderFlow, mockAgglayerClient *agglayermocks.AgglayerClientMock) { mockFlow.EXPECT().GetCertificateBuildParams(mock.Anything).Return(&aggsendertypes.CertificateBuildParams{ Bridges: []bridgesync.Bridge{{}}, @@ -347,7 +347,7 @@ func TestSendCertificate(t *testing.T) { { name: "error saving certificate to storage", mockFn: func(mockStorage *mocks.AggSenderStorage, - mockFlow *mocks.AggsenderFlow, + mockFlow *mocks.AggsenderBuilderFlow, mockAgglayerClient *agglayermocks.AgglayerClientMock) { mockFlow.EXPECT().GetCertificateBuildParams(mock.Anything).Return(&aggsendertypes.CertificateBuildParams{ Bridges: []bridgesync.Bridge{{}}, @@ -377,7 +377,7 @@ func TestSendCertificate(t *testing.T) { { name: "error getting validator signature", mockFn: func(mockStorage *mocks.AggSenderStorage, - mockFlow *mocks.AggsenderFlow, + mockFlow *mocks.AggsenderBuilderFlow, mockAgglayerClient *agglayermocks.AgglayerClientMock) { mockFlow.EXPECT().GetCertificateBuildParams(mock.Anything).Return(&aggsendertypes.CertificateBuildParams{ Bridges: []bridgesync.Bridge{{}}, @@ -403,7 +403,7 @@ func TestSendCertificate(t *testing.T) { { name: "successful validation and sending of a certificate", mockFn: func(mockStorage *mocks.AggSenderStorage, - mockFlow *mocks.AggsenderFlow, + mockFlow *mocks.AggsenderBuilderFlow, mockAgglayerClient *agglayermocks.AgglayerClientMock) { mockFlow.EXPECT().GetCertificateBuildParams(mock.Anything).Return(&aggsendertypes.CertificateBuildParams{ Bridges: []bridgesync.Bridge{{}}, @@ -432,7 +432,7 @@ func TestSendCertificate(t *testing.T) { { name: "successful sending and saving of a certificate", mockFn: func(mockStorage *mocks.AggSenderStorage, - mockFlow *mocks.AggsenderFlow, + mockFlow *mocks.AggsenderBuilderFlow, mockAgglayerClient *agglayermocks.AgglayerClientMock) { mockFlow.EXPECT().GetCertificateBuildParams(mock.Anything).Return(&aggsendertypes.CertificateBuildParams{ Bridges: []bridgesync.Bridge{{}}, @@ -465,7 +465,7 @@ func TestSendCertificate(t *testing.T) { t.Parallel() mockStorage := mocks.NewAggSenderStorage(t) - mockAggsenderFlow := mocks.NewAggsenderFlow(t) + mockAggsenderFlow := mocks.NewAggsenderBuilderFlow(t) mockAgglayerClient := agglayermocks.NewAgglayerClientMock(t) mockEpochNotifier := mocks.NewEpochNotifier(t) tt.mockFn(mockStorage, mockAggsenderFlow, mockAgglayerClient) @@ -560,7 +560,7 @@ func TestSendCertificatesRetry(t *testing.T) { mockCertStatusChecker := mocks.NewCertificateStatusChecker(t) mockEpochNotifier := mocks.NewEpochNotifier(t) mockStorage := mocks.NewAggSenderStorage(t) - mockFlow := mocks.NewAggsenderFlow(t) + mockFlow := mocks.NewAggsenderBuilderFlow(t) logger := log.WithFields("aggsender-test", "TestSendCertificatesRetry") aggSender := &AggSender{ @@ -612,20 +612,20 @@ func TestSendCertificates(t *testing.T) { tests := []struct { name string - mockFn func(*mocks.CertificateStatusChecker, *mocks.EpochNotifier, *mocks.AggSenderStorage, *mocks.AggsenderFlow) + mockFn func(*mocks.CertificateStatusChecker, *mocks.EpochNotifier, *mocks.AggSenderStorage, *mocks.AggsenderBuilderFlow) returnAfterNIterations int certStatusCheckInterval time.Duration }{ { name: "context canceled", - mockFn: func(mockCertStatusChecker *mocks.CertificateStatusChecker, mockEpochNotifier *mocks.EpochNotifier, mockStorage *mocks.AggSenderStorage, mockFlow *mocks.AggsenderFlow) { + mockFn: func(mockCertStatusChecker *mocks.CertificateStatusChecker, mockEpochNotifier *mocks.EpochNotifier, mockStorage *mocks.AggSenderStorage, mockFlow *mocks.AggsenderBuilderFlow) { mockEpochNotifier.EXPECT().Subscribe("aggsender").Return(make(chan aggsendertypes.EpochEvent)).Once() }, returnAfterNIterations: 0, }, { name: "retry certificate after in-error", - mockFn: func(mockCertStatusChecker *mocks.CertificateStatusChecker, mockEpochNotifier *mocks.EpochNotifier, mockStorage *mocks.AggSenderStorage, mockFlow *mocks.AggsenderFlow) { + mockFn: func(mockCertStatusChecker *mocks.CertificateStatusChecker, mockEpochNotifier *mocks.EpochNotifier, mockStorage *mocks.AggSenderStorage, mockFlow *mocks.AggsenderBuilderFlow) { mockCertStatusChecker.EXPECT().CheckPendingCertificatesStatus(mock.Anything).Return(aggsendertypes.CertStatus{ ExistPendingCerts: false, ExistNewInErrorCert: true, @@ -639,7 +639,7 @@ func TestSendCertificates(t *testing.T) { }, { name: "epoch received with no pending certificates", - mockFn: func(mockCertStatusChecker *mocks.CertificateStatusChecker, mockEpochNotifier *mocks.EpochNotifier, mockStorage *mocks.AggSenderStorage, mockFlow *mocks.AggsenderFlow) { + mockFn: func(mockCertStatusChecker *mocks.CertificateStatusChecker, mockEpochNotifier *mocks.EpochNotifier, mockStorage *mocks.AggSenderStorage, mockFlow *mocks.AggsenderBuilderFlow) { chEpoch := make(chan aggsendertypes.EpochEvent, 1) chEpoch <- aggsendertypes.EpochEvent{Epoch: 1} mockEpochNotifier.EXPECT().Subscribe("aggsender").Return(chEpoch).Once() @@ -653,7 +653,7 @@ func TestSendCertificates(t *testing.T) { }, { name: "epoch received with pending certificates", - mockFn: func(mockCertStatusChecker *mocks.CertificateStatusChecker, mockEpochNotifier *mocks.EpochNotifier, mockStorage *mocks.AggSenderStorage, mockFlow *mocks.AggsenderFlow) { + mockFn: func(mockCertStatusChecker *mocks.CertificateStatusChecker, mockEpochNotifier *mocks.EpochNotifier, mockStorage *mocks.AggSenderStorage, mockFlow *mocks.AggsenderBuilderFlow) { chEpoch := make(chan aggsendertypes.EpochEvent, 1) chEpoch <- aggsendertypes.EpochEvent{Epoch: 1} mockEpochNotifier.EXPECT().Subscribe("aggsender").Return(chEpoch).Once() @@ -674,7 +674,7 @@ func TestSendCertificates(t *testing.T) { mockCertStatusChecker := mocks.NewCertificateStatusChecker(t) mockEpochNotifier := mocks.NewEpochNotifier(t) mockStorage := mocks.NewAggSenderStorage(t) - mockFlow := mocks.NewAggsenderFlow(t) + mockFlow := mocks.NewAggsenderBuilderFlow(t) tt.mockFn(mockCertStatusChecker, mockEpochNotifier, mockStorage, mockFlow) @@ -727,7 +727,7 @@ type aggsenderTestData struct { l2BridgeQuerier *mocks.BridgeQuerier storageMock *mocks.AggSenderStorage epochNotifierMock *mocks.EpochNotifier - flowMock *mocks.AggsenderFlow + flowMock *mocks.AggsenderBuilderFlow compatibilityChekerMock *mocksdb.CompatibilityChecker certStatusCheckerMock *mocks.CertificateStatusChecker sut *AggSender @@ -805,14 +805,14 @@ func newAggsenderTestData(t *testing.T, creationFlags testDataFlags) *aggsenderT DelayBetweenRetries: types.Duration{Duration: time.Millisecond}, }, epochNotifier: epochNotifierMock, - flow: flows.NewPPFlow(logger, + flow: flows.NewPPBuilderFlow(logger, flows.NewBaseFlow(logger, l2BridgeQuerier, storage, l1InfoTreeQuerierMock, lerQuerier, flows.NewBaseFlowConfigDefault()), storage, l1InfoTreeQuerierMock, l2BridgeQuerier, signer, true, 0), } - var flowMock *mocks.AggsenderFlow + var flowMock *mocks.AggsenderBuilderFlow if creationFlags&testDataFlagMockFlow != 0 { - flowMock = mocks.NewAggsenderFlow(t) + flowMock = mocks.NewAggsenderBuilderFlow(t) sut.flow = flowMock } diff --git a/aggsender/aggsender_validator.go b/aggsender/aggsender_validator.go index 3dafe9079..fce0b50df 100644 --- a/aggsender/aggsender_validator.go +++ b/aggsender/aggsender_validator.go @@ -28,10 +28,11 @@ type AggsenderValidator struct { func NewAggsenderValidator(ctx context.Context, logger aggkitcommon.Logger, cfg validator.Config, - flow validator.FlowInterface, + flow types.AggsenderVerifierFlow, l1InfoTreeDataQuerier validator.L1InfoTreeRootByLeafQuerier, aggLayerClient agglayer.AggLayerClientCertificateIDQuerier, certQuerier types.CertificateQuerier, + aggchainFEPQuerier types.AggchainFEPRollupQuerier, lerQuerier types.LERQuerier, signer signertypes.Signer) (*AggsenderValidator, error) { validatorCert := validator.NewAggsenderValidator( diff --git a/aggsender/flows/flow_aggchain_prover.go b/aggsender/flows/builder_flow_aggchain_prover.go similarity index 92% rename from aggsender/flows/flow_aggchain_prover.go rename to aggsender/flows/builder_flow_aggchain_prover.go index f988c7b8b..8efa43d8c 100644 --- a/aggsender/flows/flow_aggchain_prover.go +++ b/aggsender/flows/builder_flow_aggchain_prover.go @@ -15,10 +15,10 @@ import ( "github.com/ethereum/go-ethereum/common" ) -var _ types.AggsenderFlow = (*AggchainProverFlow)(nil) +var _ types.AggsenderBuilderFlow = (*AggchainProverBuilderFlow)(nil) -// AggchainProverFlow is a struct that holds the logic for the AggchainProver prover type flow -type AggchainProverFlow struct { +// AggchainProverBuilderFlow is a struct that holds the logic for the AggchainProver prover type flow +type AggchainProverBuilderFlow struct { baseFlow types.AggsenderFlowBaser log types.Logger @@ -69,9 +69,9 @@ func NewAggchainProverFlowConfig( } } -// NewAggchainProverFlow returns a new instance of the AggchainProverFlow injecting baseFlow instead of +// NewAggchainProverBuilderFlow returns a new instance of the AggchainProverBuilderFlow injecting baseFlow instead of // creating it -func NewAggchainProverFlow( +func NewAggchainProverBuilderFlow( log types.Logger, aggChainProverConfig AggchainProverFlowConfig, baseFlow types.AggsenderFlowBaser, @@ -82,14 +82,14 @@ func NewAggchainProverFlow( signer signertypes.Signer, optimisticModeQuerier types.OptimisticModeQuerier, aggchainProofQuerier types.AggchainProofQuerier, -) *AggchainProverFlow { +) *AggchainProverBuilderFlow { feature := NewMaxL2BlockNumberLimiter( aggChainProverConfig.maxL2BlockNumber, log, false, // AggchainProverFlow allows to resize retry certs false, // AggchainProverFlow allows to send no bridges certs ) - return &AggchainProverFlow{ + return &AggchainProverBuilderFlow{ log: log, storage: storage, l1InfoTreeDataQuerier: l1InfoTreeQuerier, @@ -105,7 +105,7 @@ func NewAggchainProverFlow( // CheckInitialStatus checks that initial status is correct. // For AggchainProverFlow checks that starting block and last certificate match -func (a *AggchainProverFlow) CheckInitialStatus(ctx context.Context) error { +func (a *AggchainProverBuilderFlow) CheckInitialStatus(ctx context.Context) error { lastSentCertificate, err := a.storage.GetLastSentCertificateHeader() if err != nil { return fmt.Errorf("aggchainProverFlow - error getting last sent certificate: %w", err) @@ -130,7 +130,7 @@ func (a *AggchainProverFlow) CheckInitialStatus(ctx context.Context) error { } // getCertificateTypeToGenerate returns the type of certificate to generate -func (a *AggchainProverFlow) getCertificateTypeToGenerate() (types.CertificateType, error) { +func (a *AggchainProverBuilderFlow) getCertificateTypeToGenerate() (types.CertificateType, error) { // AggchainProverFlow only supports FEP certificates optimisticMode, err := a.optimisticModeQuerier.IsOptimisticModeOn() if err != nil { @@ -145,7 +145,7 @@ func (a *AggchainProverFlow) getCertificateTypeToGenerate() (types.CertificateTy // GeneratePreBuildParams generates the pre-build parameters for the AggchainProverFlow // Only used in aggsender validator -func (a *AggchainProverFlow) GenerateBuildParams(ctx context.Context, +func (a *AggchainProverBuilderFlow) GenerateBuildParams(ctx context.Context, preParams *types.CertificatePreBuildParams) (*types.CertificateBuildParams, error) { if preParams == nil { return nil, fmt.Errorf("aggchainProverFlow - preParams is nil") @@ -169,7 +169,8 @@ func (a *AggchainProverFlow) GenerateBuildParams(ctx context.Context, // What differentiates this function from the regular PP flow is that, // if the last sent certificate is in error, we need to resend the exact same certificate // also, it calls the aggchain prover to get the aggchain proof -func (a *AggchainProverFlow) GetCertificateBuildParams(ctx context.Context) (*types.CertificateBuildParams, error) { +func (a *AggchainProverBuilderFlow) GetCertificateBuildParams( + ctx context.Context) (*types.CertificateBuildParams, error) { lastSentCert, proof, err := a.storage.GetLastSentCertificateHeaderWithProofIfInError(ctx) if err != nil { return nil, fmt.Errorf("aggchainProverFlow - error checking if last sent certificate is InError: %w", err) @@ -269,7 +270,7 @@ func (a *AggchainProverFlow) GetCertificateBuildParams(ctx context.Context) (*ty // verifyBuildParams verifies the certificate build params and returns an error if they are not valid // it also calls the prover to get the aggchain proof -func (a *AggchainProverFlow) verifyBuildParamsAndGenerateProof( +func (a *AggchainProverBuilderFlow) verifyBuildParamsAndGenerateProof( ctx context.Context, buildParams *types.CertificateBuildParams) (*types.CertificateBuildParams, error) { if err := a.baseFlow.VerifyBuildParams(ctx, buildParams); err != nil { return nil, fmt.Errorf("aggchainProverFlow - error verifying build params: %w", err) @@ -304,7 +305,7 @@ func (a *AggchainProverFlow) verifyBuildParamsAndGenerateProof( // BuildCertificate builds a certificate based on the buildParams // this function is the implementation of the FlowManager interface -func (a *AggchainProverFlow) BuildCertificate(ctx context.Context, +func (a *AggchainProverBuilderFlow) BuildCertificate(ctx context.Context, buildParams *types.CertificateBuildParams) (*agglayertypes.Certificate, error) { cert, err := a.baseFlow.BuildCertificate(ctx, buildParams, buildParams.LastSentCertificate, true) if err != nil { @@ -329,7 +330,7 @@ func (a *AggchainProverFlow) BuildCertificate(ctx context.Context, } // UpdateAggchainData updates the AggchainData field in certificate with the multisig if provided. -func (a *AggchainProverFlow) UpdateAggchainData( +func (a *AggchainProverBuilderFlow) UpdateAggchainData( cert *agglayertypes.Certificate, multisig *agglayertypes.Multisig, ) error { @@ -373,7 +374,8 @@ func adjustBlockRange(buildParams *types.CertificateBuildParams, return buildParams, nil } -func (a *AggchainProverFlow) getLastProvenBlock(fromBlock uint64, lastCertificate *types.CertificateHeader) uint64 { +func (a *AggchainProverBuilderFlow) getLastProvenBlock( + fromBlock uint64, lastCertificate *types.CertificateHeader) uint64 { if fromBlock == 0 { // if this is the first certificate, we need to start from the starting L2 block // that we got from the sovereign rollup @@ -398,6 +400,6 @@ func (a *AggchainProverFlow) getLastProvenBlock(fromBlock uint64, lastCertificat } // Signer returns the signer used to sign the certificate -func (a *AggchainProverFlow) Signer() signertypes.Signer { +func (a *AggchainProverBuilderFlow) Signer() signertypes.Signer { return a.certificateSigner } diff --git a/aggsender/flows/flow_aggchain_prover_optimistic_test.go b/aggsender/flows/builder_flow_aggchain_prover_optimistic_test.go similarity index 98% rename from aggsender/flows/flow_aggchain_prover_optimistic_test.go rename to aggsender/flows/builder_flow_aggchain_prover_optimistic_test.go index 2718c0fb8..56311cf6c 100644 --- a/aggsender/flows/flow_aggchain_prover_optimistic_test.go +++ b/aggsender/flows/builder_flow_aggchain_prover_optimistic_test.go @@ -115,7 +115,7 @@ type AggchainProverFlowTestData struct { ctx context.Context - sut *AggchainProverFlow + sut *AggchainProverBuilderFlow } func NewAggchainProverFlowTestData(t *testing.T, cfgBase BaseFlowConfig) *AggchainProverFlowTestData { @@ -135,7 +135,7 @@ func NewAggchainProverFlowTestData(t *testing.T, cfgBase BaseFlowConfig) *Aggcha // Simulate the access to baseFlow variables res.mockFlowBase.EXPECT().StartL2Block().Return(cfgBase.StartL2Block).Maybe() - res.sut = NewAggchainProverFlow( + res.sut = NewAggchainProverBuilderFlow( log.WithFields("flowManager", "AggchainProverFlowTestData"), NewAggchainProverFlowConfigDefault(), res.mockFlowBase, diff --git a/aggsender/flows/flow_aggchain_prover_test.go b/aggsender/flows/builder_flow_aggchain_prover_test.go similarity index 99% rename from aggsender/flows/flow_aggchain_prover_test.go rename to aggsender/flows/builder_flow_aggchain_prover_test.go index 2bc54204f..9465dc3d1 100644 --- a/aggsender/flows/flow_aggchain_prover_test.go +++ b/aggsender/flows/builder_flow_aggchain_prover_test.go @@ -343,7 +343,7 @@ func Test_AggchainProverFlow_GetCertificateBuildParams(t *testing.T) { mockLERQuerier, NewBaseFlowConfigDefault()) flowBase.timeNowFunc = timeNowUTCForTest - aggchainFlow := NewAggchainProverFlow( + aggchainFlow := NewAggchainProverBuilderFlow( logger, NewAggchainProverFlowConfigDefault(), flowBase, @@ -462,7 +462,7 @@ func Test_AggchainProverFlow_getLastProvenBlock(t *testing.T) { nil, // lerQuerier NewBaseFlowConfig(0, tc.startL2Block, false, true), ) - flow := NewAggchainProverFlow( + flow := NewAggchainProverBuilderFlow( logger, NewAggchainProverFlowConfigDefault(), flowBase, @@ -580,7 +580,7 @@ func Test_AggchainProverFlow_BuildCertificate(t *testing.T) { mockLERQuerier, NewBaseFlowConfigDefault(), ) - aggchainFlow := NewAggchainProverFlow( + aggchainFlow := NewAggchainProverBuilderFlow( logger, NewAggchainProverFlowConfigDefault(), flowBase, @@ -756,7 +756,7 @@ func Test_AggchainProverFlow_CheckInitialStatus(t *testing.T) { mockL2BridgeSyncer := mocks.NewBridgeQuerier(t) logger := log.WithFields("flowManager", "Test_AggchainProverFlow_CheckInitialStatus") - flow := &AggchainProverFlow{ + flow := &AggchainProverBuilderFlow{ log: logger, storage: mockStorage, baseFlow: mockBaseFlow, @@ -850,7 +850,7 @@ func Test_AggchainProverFlow_GenerateBuildParams(t *testing.T) { tc.mockFn(mockBaseFlow) } - flow := &AggchainProverFlow{ + flow := &AggchainProverBuilderFlow{ log: logger, baseFlow: mockBaseFlow, } @@ -960,7 +960,7 @@ func Test_AggchainProverFlow_UpdateAggchainData(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Parallel() logger := log.WithFields("flowManager", "Test_AggchainProverFlow_UpdateAggchainData") - flow := &AggchainProverFlow{ + flow := &AggchainProverBuilderFlow{ log: logger, } diff --git a/aggsender/flows/factory.go b/aggsender/flows/builder_flow_factory.go similarity index 97% rename from aggsender/flows/factory.go rename to aggsender/flows/builder_flow_factory.go index 8df2874f1..119e2502a 100644 --- a/aggsender/flows/factory.go +++ b/aggsender/flows/builder_flow_factory.go @@ -25,7 +25,8 @@ var ( l2GERReaderFactory = l2gersync.NewL2EVMGERReader ) -func NewFlow( +// NewBuilderFlow creates a new AggsenderBuilderFlow based on the provided configuration. +func NewBuilderFlow( ctx context.Context, cfg config.Config, logger *log.Logger, @@ -36,7 +37,7 @@ func NewFlow( l2Syncer types.L2BridgeSyncer, rollupDataQuerier types.RollupDataQuerier, committeeQuerier types.MultisigQuerier, -) (types.AggsenderFlow, error) { +) (types.AggsenderBuilderFlow, error) { switch cfg.Mode { case types.PessimisticProofMode: commonFlowComponents, err := CreateCommonFlowComponents( @@ -52,7 +53,7 @@ func NewFlow( return nil, fmt.Errorf("failed to create common flow components: %w", err) } - return NewPPFlow( + return NewPPBuilderFlow( logger, commonFlowComponents.BaseFlow, storage, @@ -112,7 +113,7 @@ func NewFlow( query.NewGERDataQuerier(commonFlowComponents.L1InfoTreeDataQuerier, l2GERReader), ) - return NewAggchainProverFlow( + return NewAggchainProverBuilderFlow( logger, NewAggchainProverFlowConfig(cfg.MaxL2BlockNumber), commonFlowComponents.BaseFlow, diff --git a/aggsender/flows/factory_test.go b/aggsender/flows/builder_flow_factory_test.go similarity index 99% rename from aggsender/flows/factory_test.go rename to aggsender/flows/builder_flow_factory_test.go index ef806d557..bddf24256 100644 --- a/aggsender/flows/factory_test.go +++ b/aggsender/flows/builder_flow_factory_test.go @@ -177,7 +177,7 @@ func TestNewFlow(t *testing.T) { tc.mockFn(mockCommitteeQuerier) } - flow, err := NewFlow( + flow, err := NewBuilderFlow( ctx, tc.cfg, mockLogger, diff --git a/aggsender/flows/flow_pp.go b/aggsender/flows/builder_flow_pp.go similarity index 84% rename from aggsender/flows/flow_pp.go rename to aggsender/flows/builder_flow_pp.go index 229b8f0ab..47b488f9a 100644 --- a/aggsender/flows/flow_pp.go +++ b/aggsender/flows/builder_flow_pp.go @@ -11,10 +11,10 @@ import ( signertypes "github.com/agglayer/go_signer/signer/types" ) -var _ types.AggsenderFlow = (*PPFlow)(nil) +var _ types.AggsenderBuilderFlow = (*PPBuilderFlow)(nil) -// PPFlow is a struct that holds the logic for the regular pessimistic proof flow -type PPFlow struct { +// PPBuilderFlow is a struct that holds the logic for the regular pessimistic proof flow +type PPBuilderFlow struct { baseFlow types.AggsenderFlowBaser certificateSigner signertypes.Signer log types.Logger @@ -24,22 +24,22 @@ type PPFlow struct { maxL2BlockLimiter types.MaxL2BlockNumberLimiterInterface } -// NewPPFlow returns a new instance of the PPFlow -func NewPPFlow(log types.Logger, +// NewPPBuilderFlow returns a new instance of the PPBuilderFlow +func NewPPBuilderFlow(log types.Logger, baseFlow types.AggsenderFlowBaser, storage db.AggSenderStorage, l1InfoTreeQuerier types.L1InfoTreeDataQuerier, l2BridgeQuerier types.BridgeQuerier, signer signertypes.Signer, forceOneBridgeExit bool, - maxL2BlockNumber uint64) *PPFlow { + maxL2BlockNumber uint64) *PPBuilderFlow { feature := NewMaxL2BlockNumberLimiter( maxL2BlockNumber, log, true, forceOneBridgeExit, ) - return &PPFlow{ + return &PPBuilderFlow{ certificateSigner: signer, log: log, l1InfoTreeDataQuerier: l1InfoTreeQuerier, @@ -51,11 +51,11 @@ func NewPPFlow(log types.Logger, // CheckInitialStatus checks that initial status is correct. // For PPFlow there are no special checks to do, so it just returns nil -func (p *PPFlow) CheckInitialStatus(ctx context.Context) error { +func (p *PPBuilderFlow) CheckInitialStatus(ctx context.Context) error { return nil } -func (p *PPFlow) GenerateBuildParams(ctx context.Context, +func (p *PPBuilderFlow) GenerateBuildParams(ctx context.Context, preParams *types.CertificatePreBuildParams) (*types.CertificateBuildParams, error) { if preParams == nil { return nil, fmt.Errorf("ppFlow - preParams is nil") @@ -73,7 +73,7 @@ func (p *PPFlow) GenerateBuildParams(ctx context.Context, // GetCertificateBuildParams returns the parameters to build a certificate // this function is the implementation of the FlowManager interface -func (p *PPFlow) GetCertificateBuildParams(ctx context.Context) (*types.CertificateBuildParams, error) { +func (p *PPBuilderFlow) GetCertificateBuildParams(ctx context.Context) (*types.CertificateBuildParams, error) { buildParams, err := p.baseFlow.GetCertificateBuildParamsInternal(ctx, types.CertificateTypePP) if err != nil { if errors.Is(err, errNoNewBlocks) { @@ -114,7 +114,7 @@ func (p *PPFlow) GetCertificateBuildParams(ctx context.Context) (*types.Certific // BuildCertificate builds a certificate based on the buildParams // this function is the implementation of the FlowManager interface -func (p *PPFlow) BuildCertificate(ctx context.Context, +func (p *PPBuilderFlow) BuildCertificate(ctx context.Context, buildParams *types.CertificateBuildParams) (*agglayertypes.Certificate, error) { certificate, err := p.baseFlow.BuildCertificate(ctx, buildParams, buildParams.LastSentCertificate, false) if err != nil { @@ -125,7 +125,7 @@ func (p *PPFlow) BuildCertificate(ctx context.Context, } // UpdateAggchainData updates the AggchainData field in certificate with the multisig if needed -func (p *PPFlow) UpdateAggchainData( +func (p *PPBuilderFlow) UpdateAggchainData( cert *agglayertypes.Certificate, multisig *agglayertypes.Multisig) error { if multisig == nil { @@ -142,6 +142,6 @@ func (p *PPFlow) UpdateAggchainData( } // Signer returns the signer used to sign the certificate -func (p *PPFlow) Signer() signertypes.Signer { +func (p *PPBuilderFlow) Signer() signertypes.Signer { return p.certificateSigner } diff --git a/aggsender/flows/flow_pp_test.go b/aggsender/flows/builder_flow_pp_test.go similarity index 99% rename from aggsender/flows/flow_pp_test.go rename to aggsender/flows/builder_flow_pp_test.go index 50018be0b..dce87a2da 100644 --- a/aggsender/flows/flow_pp_test.go +++ b/aggsender/flows/builder_flow_pp_test.go @@ -457,7 +457,7 @@ func Test_PPFlow_GetCertificateBuildParams(t *testing.T) { baseFlow := NewBaseFlow(logger, mockL2BridgeQuerier, mockStorage, mockL1InfoTreeQuerier, mockLERQuerier, NewBaseFlowConfigDefault()) baseFlow.timeNowFunc = timeNowUTCForTest - ppFlow := NewPPFlow( + ppFlow := NewPPBuilderFlow( logger, baseFlow, mockStorage, mockL1InfoTreeQuerier, mockL2BridgeQuerier, nil, tc.forceOneBridgeExit, 0) @@ -549,7 +549,7 @@ func TestGetLastSentBlockAndRetryCount(t *testing.T) { } func Test_PPFlow_CheckInitialStatus(t *testing.T) { - sut := &PPFlow{} + sut := &PPBuilderFlow{} require.Nil(t, sut.CheckInitialStatus(context.TODO())) } @@ -592,7 +592,7 @@ func Test_PPFlow_UpdateAggchainData(t *testing.T) { tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() - sut := &PPFlow{} + sut := &PPBuilderFlow{} err := sut.UpdateAggchainData(tc.certificate, tc.multisig) require.NoError(t, err) diff --git a/aggsender/flows/verifier_flow_aggchain_prover.go b/aggsender/flows/verifier_flow_aggchain_prover.go new file mode 100644 index 000000000..747dccf19 --- /dev/null +++ b/aggsender/flows/verifier_flow_aggchain_prover.go @@ -0,0 +1,80 @@ +package flows + +import ( + "context" + "fmt" + + agglayertypes "github.com/agglayer/aggkit/agglayer/types" + "github.com/agglayer/aggkit/aggsender/types" +) + +var _ types.AggsenderVerifierFlow = (*AggchainProverVerifierFlow)(nil) + +// AggchainProverVerifierFlow is a struct that holds the logic for the aggchain prover flow verification +type AggchainProverVerifierFlow struct { + *AggchainProverBuilderFlow + + aggProofPublicValuesQuery types.AggProofPublicValuesQuerier +} + +// NewAggchainProverVerifierFlow creates a new AggchainProverVerifierFlow +func NewAggchainProverVerifierFlow( + builderFlow *AggchainProverBuilderFlow, + aggProofPublicValuesQuery types.AggProofPublicValuesQuerier, +) *AggchainProverVerifierFlow { + return &AggchainProverVerifierFlow{ + AggchainProverBuilderFlow: builderFlow, + aggProofPublicValuesQuery: aggProofPublicValuesQuery, + } +} + +// VerifyCertificate verifies the new certificate +// This function is used in the validator to verify the certificate +func (a *AggchainProverVerifierFlow) VerifyCertificate( + ctx context.Context, + cert *agglayertypes.Certificate, + lastBlockInCert uint64, + lastSettledBlock uint64) error { + if cert.AggchainData == nil { + return fmt.Errorf("aggchainProverFlow: certificate AggchainData is nil") + } + + var aggchainDataProof *agglayertypes.AggchainDataProof + switch v := cert.AggchainData.(type) { + case *agglayertypes.AggchainDataProof: + aggchainDataProof = v + case *agglayertypes.AggchainDataMultisigWithProof: + aggchainDataProof = v.AggchainProof + default: + return fmt.Errorf("aggchainProverFlow: certificate AggchainData is of unknown type %T", cert.AggchainData) + } + + // we need to reconstruct the AggchainParams field using what proposer provided, + // plus, the current data from the L1 and L2 networks (what was last settled) + l1InfoLeaf, err := a.l1InfoTreeDataQuerier.GetInfoByIndex(ctx, cert.L1InfoTreeLeafCount-1) + if err != nil { + return fmt.Errorf("aggchainProverFlow - error getting L1InfoLeaf by index %d: %w", + cert.L1InfoTreeLeafCount-1, err) + } + + expectedAggchainProofPublicValues, err := a.aggProofPublicValuesQuery.GetAggregationProofPublicValuesData( + lastSettledBlock, + lastBlockInCert, + l1InfoLeaf.Hash, + ) + if err != nil { + return fmt.Errorf("aggchainProverFlow - error getting expected aggchain proof public values: %w", err) + } + + expectedAggchainParams, err := expectedAggchainProofPublicValues.Hash() + if err != nil { + return fmt.Errorf("aggchainProverFlow - error calculating expected aggchain params hash: %w", err) + } + + if aggchainDataProof.AggchainParams != expectedAggchainParams { + return fmt.Errorf("aggchainProverFlow - aggchain params do not match: expected %s, got %s", + expectedAggchainParams, aggchainDataProof.AggchainParams) + } + + return nil +} diff --git a/aggsender/flows/verifier_flow_aggchain_prover_test.go b/aggsender/flows/verifier_flow_aggchain_prover_test.go new file mode 100644 index 000000000..e63eba3c1 --- /dev/null +++ b/aggsender/flows/verifier_flow_aggchain_prover_test.go @@ -0,0 +1,188 @@ +package flows + +import ( + "context" + "errors" + "testing" + + agglayertypes "github.com/agglayer/aggkit/agglayer/types" + "github.com/agglayer/aggkit/aggsender/mocks" + "github.com/agglayer/aggkit/aggsender/types" + "github.com/agglayer/aggkit/l1infotreesync" + "github.com/agglayer/aggkit/log" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func Test_AggchainProverFlow_VerifyCertificate(t *testing.T) { + t.Parallel() + + ctx := context.Background() + requestedEndBlock := uint64(100) + lastProvenBlock := uint64(50) + + validL1InfoLeaf := &l1infotreesync.L1InfoTreeLeaf{ + Hash: common.HexToHash("0x123"), + } + + validAggregationProofPublicValues := &types.AggregationProofPublicValues{ + L1Head: common.HexToHash("0x1"), + L2PreRoot: common.HexToHash("0x2"), + ClaimRoot: common.HexToHash("0x3"), + L2BlockNumber: 100, + RollupConfigHash: common.HexToHash("0x4"), + MultiBlockVKey: common.HexToHash("0x5"), + ProverAddress: common.HexToAddress("0x6"), + } + + expectedAggchainParams, err := validAggregationProofPublicValues.Hash() + require.NoError(t, err) + + testCases := []struct { + name string + certificate *agglayertypes.Certificate + mockFn func(*mocks.L1InfoTreeDataQuerier, *mocks.AggProofPublicValuesQuerier) + expectedError string + }{ + { + name: "certificate AggchainData is nil", + certificate: &agglayertypes.Certificate{ + AggchainData: nil, + }, + expectedError: "aggchainProverFlow: certificate AggchainData is nil", + }, + { + name: "certificate AggchainData is of unknown type", + certificate: &agglayertypes.Certificate{ + AggchainData: &agglayertypes.AggchainDataSignature{}, // wrong type + }, + expectedError: "aggchainProverFlow: certificate AggchainData is of unknown type *types.AggchainDataSignature", + }, + { + name: "error getting L1InfoLeaf by index", + certificate: &agglayertypes.Certificate{ + L1InfoTreeLeafCount: 10, + AggchainData: &agglayertypes.AggchainDataProof{ + AggchainParams: expectedAggchainParams, + }, + }, + mockFn: func(mockL1InfoTreeDataQuerier *mocks.L1InfoTreeDataQuerier, mockAggProofPubValuesQuerier *mocks.AggProofPublicValuesQuerier) { + mockL1InfoTreeDataQuerier.EXPECT().GetInfoByIndex(ctx, uint32(9)).Return(nil, errors.New("l1info error")).Once() + }, + expectedError: "aggchainProverFlow - error getting L1InfoLeaf by index 9: l1info error", + }, + { + name: "error getting expected aggchain proof public values", + certificate: &agglayertypes.Certificate{ + L1InfoTreeLeafCount: 10, + AggchainData: &agglayertypes.AggchainDataProof{ + AggchainParams: expectedAggchainParams, + }, + }, + mockFn: func(mockL1InfoTreeDataQuerier *mocks.L1InfoTreeDataQuerier, mockAggProofPubValuesQuerier *mocks.AggProofPublicValuesQuerier) { + mockL1InfoTreeDataQuerier.EXPECT().GetInfoByIndex(ctx, uint32(9)).Return(validL1InfoLeaf, nil).Once() + mockAggProofPubValuesQuerier.EXPECT().GetAggregationProofPublicValuesData( + lastProvenBlock, requestedEndBlock, validL1InfoLeaf.Hash). + Return(nil, errors.New("aggchain error")).Once() + }, + expectedError: "aggchainProverFlow - error getting expected aggchain proof public values: aggchain error", + }, + { + name: "aggchain params do not match", + certificate: &agglayertypes.Certificate{ + L1InfoTreeLeafCount: 10, + AggchainData: &agglayertypes.AggchainDataProof{ + AggchainParams: common.HexToHash("0xwrong"), // different from expected + }, + }, + mockFn: func(mockL1InfoTreeDataQuerier *mocks.L1InfoTreeDataQuerier, mockAggchainFEPQuerier *mocks.AggProofPublicValuesQuerier) { + mockL1InfoTreeDataQuerier.EXPECT().GetInfoByIndex(ctx, uint32(9)).Return(validL1InfoLeaf, nil).Once() + mockAggchainFEPQuerier.EXPECT().GetAggregationProofPublicValuesData( + lastProvenBlock, requestedEndBlock, validL1InfoLeaf.Hash). + Return(validAggregationProofPublicValues, nil).Once() + }, + expectedError: "aggchainProverFlow - aggchain params do not match", + }, + { + name: "successful verification with AggchainDataProof", + certificate: &agglayertypes.Certificate{ + L1InfoTreeLeafCount: 10, + AggchainData: &agglayertypes.AggchainDataProof{ + AggchainParams: expectedAggchainParams, + }, + }, + mockFn: func(mockL1InfoTreeDataQuerier *mocks.L1InfoTreeDataQuerier, mockAggProofPubValuesQuerier *mocks.AggProofPublicValuesQuerier) { + mockL1InfoTreeDataQuerier.EXPECT().GetInfoByIndex(ctx, uint32(9)).Return(validL1InfoLeaf, nil).Once() + mockAggProofPubValuesQuerier.EXPECT().GetAggregationProofPublicValuesData( + lastProvenBlock, requestedEndBlock, validL1InfoLeaf.Hash). + Return(validAggregationProofPublicValues, nil).Once() + }, + }, + { + name: "successful verification with AggchainDataMultisigWithProof", + certificate: &agglayertypes.Certificate{ + L1InfoTreeLeafCount: 10, + AggchainData: &agglayertypes.AggchainDataMultisigWithProof{ + Multisig: &agglayertypes.Multisig{}, + AggchainProof: &agglayertypes.AggchainDataProof{ + AggchainParams: expectedAggchainParams, + }, + }, + }, + mockFn: func(mockL1InfoTreeDataQuerier *mocks.L1InfoTreeDataQuerier, mockAggProofPubValuesQuerier *mocks.AggProofPublicValuesQuerier) { + mockL1InfoTreeDataQuerier.EXPECT().GetInfoByIndex(ctx, uint32(9)).Return(validL1InfoLeaf, nil).Once() + mockAggProofPubValuesQuerier.EXPECT().GetAggregationProofPublicValuesData( + lastProvenBlock, requestedEndBlock, validL1InfoLeaf.Hash). + Return(validAggregationProofPublicValues, nil).Once() + }, + }, + { + name: "successful verification with edge case - L1InfoTreeLeafCount is 1", + certificate: &agglayertypes.Certificate{ + L1InfoTreeLeafCount: 1, + AggchainData: &agglayertypes.AggchainDataProof{ + AggchainParams: expectedAggchainParams, + }, + }, + mockFn: func(mockL1InfoTreeDataQuerier *mocks.L1InfoTreeDataQuerier, mockAggProofPubValuesQuerier *mocks.AggProofPublicValuesQuerier) { + mockL1InfoTreeDataQuerier.EXPECT().GetInfoByIndex(ctx, uint32(0)).Return(validL1InfoLeaf, nil).Once() + mockAggProofPubValuesQuerier.EXPECT().GetAggregationProofPublicValuesData( + lastProvenBlock, requestedEndBlock, validL1InfoLeaf.Hash). + Return(validAggregationProofPublicValues, nil).Once() + }, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + mockL1InfoTreeDataQuerier := mocks.NewL1InfoTreeDataQuerier(t) + mockAggProofPubValuesQuerier := mocks.NewAggProofPublicValuesQuerier(t) + logger := log.WithFields("flowManager", "Test_AggchainProverFlow_VerifyAggchainData") + + flow := &AggchainProverVerifierFlow{ + AggchainProverBuilderFlow: &AggchainProverBuilderFlow{ + log: logger, + l1InfoTreeDataQuerier: mockL1InfoTreeDataQuerier, + }, + aggProofPublicValuesQuery: mockAggProofPubValuesQuerier, + } + + if tc.mockFn != nil { + tc.mockFn(mockL1InfoTreeDataQuerier, mockAggProofPubValuesQuerier) + } + + err := flow.VerifyCertificate(ctx, tc.certificate, requestedEndBlock, lastProvenBlock) + if tc.expectedError != "" { + require.ErrorContains(t, err, tc.expectedError) + } else { + require.NoError(t, err) + } + + mockL1InfoTreeDataQuerier.AssertExpectations(t) + mockAggProofPubValuesQuerier.AssertExpectations(t) + }) + } +} diff --git a/aggsender/flows/verifier_flow_factory.go b/aggsender/flows/verifier_flow_factory.go new file mode 100644 index 000000000..365ae5936 --- /dev/null +++ b/aggsender/flows/verifier_flow_factory.go @@ -0,0 +1,157 @@ +package flows + +import ( + "context" + "fmt" + + "github.com/0xPolygon/cdk-contracts-tooling/contracts/fep/aggchain-ecdsa-multisig/aggchainfep" + "github.com/agglayer/aggkit/aggsender/config" + "github.com/agglayer/aggkit/aggsender/query" + "github.com/agglayer/aggkit/aggsender/types" + "github.com/agglayer/aggkit/aggsender/validator" + aggkitcommon "github.com/agglayer/aggkit/common" + "github.com/agglayer/aggkit/log" + "github.com/agglayer/aggkit/opnode" + aggkittypes "github.com/agglayer/aggkit/types" + "github.com/ethereum/go-ethereum/common" +) + +// NewVerifierFlow creates a new verifier flow based on the provided configuration. +func NewVerifierFlow( + ctx context.Context, + cfg validator.Config, + logger *log.Logger, + l1Client aggkittypes.BaseEthereumClienter, + l1InfoTreeSyncer types.L1InfoTreeSyncer, + l2Syncer types.L2BridgeSyncer, + rollupDataQuerier types.RollupDataQuerier, + committeeQuerier types.MultisigQuerier, +) (types.AggsenderVerifierFlow, *CommonFlowComponents, error) { + switch cfg.Mode { + case types.PessimisticProofMode: + commonFlowComponents, err := CreateCommonFlowComponents( + ctx, logger, + nil, // storage is not used in validator, + l1Client, l1InfoTreeSyncer, l2Syncer, rollupDataQuerier, committeeQuerier, 0, false, + cfg.MaxCertSize, cfg.LerQuerier.RollupCreationBlockL1, cfg.DelayBetweenRetries.Duration, cfg.Signer, + true, // full claims are (eventually) needed in validator mode + cfg.RequireCommitteeMembershipCheck, + ) + if err != nil { + return nil, nil, fmt.Errorf("failed to create common flow components: %w", err) + } + + builderFlow := NewPPBuilderFlow( + logger, + commonFlowComponents.BaseFlow, + nil, // storage is not used in validator + commonFlowComponents.L1InfoTreeDataQuerier, + commonFlowComponents.L2BridgeQuerier, + commonFlowComponents.Signer, + cfg.PPConfig.RequireOneBridgeInPPCertificate, + cfg.MaxL2BlockNumber, + ) + + return NewPPVerifierFlow(builderFlow), commonFlowComponents, nil + case types.AggchainProofMode: + commonFlowComponents, err := CreateCommonFlowComponents( + ctx, logger, + nil, // storage is not used in validator, + l1Client, l1InfoTreeSyncer, l2Syncer, rollupDataQuerier, committeeQuerier, + 0, cfg.FEPConfig.RequireNoBlockGap, + cfg.MaxCertSize, cfg.LerQuerier.RollupCreationBlockL1, + cfg.DelayBetweenRetries.Duration, cfg.Signer, + true, // full claims are (eventually) needed in validator mode + cfg.RequireCommitteeMembershipCheck, + ) + if err != nil { + return nil, nil, fmt.Errorf("failed to create common flow components: %w", err) + } + + aggProofPublicValuesQuery, err := newAggProofPublicValuesQuery( + cfg.FEPConfig.SovereignRollupAddr, + l1Client, + cfg.FEPConfig.OpNodeURL, + ) + if err != nil { + return nil, nil, fmt.Errorf("failed to create AggProofPublicValuesQuery: %w", err) + } + + builderFlow := NewAggchainProverBuilderFlow( + logger, + NewAggchainProverFlowConfig(cfg.MaxL2BlockNumber), + commonFlowComponents.BaseFlow, + nil, // storage is not used in validator + commonFlowComponents.L1InfoTreeDataQuerier, + commonFlowComponents.L2BridgeQuerier, + l1Client, + commonFlowComponents.Signer, + nil, // we don't query optimistic mode in validator + nil, // we don't query the prover in validator mode + ) + + return NewAggchainProverVerifierFlow(builderFlow, aggProofPublicValuesQuery), commonFlowComponents, nil + default: + return nil, nil, fmt.Errorf("unsupported Aggsender Validator mode: %s", cfg.Mode) + } +} + +// NewLocalVerifier creates a new local verifier flow based on the provided configuration. +func NewLocalVerifier( + ctx context.Context, + cfg config.Config, + l1Client aggkittypes.BaseEthereumClienter, + builderFlow types.AggsenderBuilderFlow, +) (types.AggsenderVerifierFlow, error) { + switch cfg.Mode { + case types.PessimisticProofMode: + ppBuilderFlow, ok := builderFlow.(*PPBuilderFlow) + if !ok { + return nil, + fmt.Errorf("expected PPBuilderFlow for PessimisticProofMode mode, got %T", builderFlow) + } + + return NewPPVerifierFlow(ppBuilderFlow), nil + case types.AggchainProofMode: + builderFlow, ok := builderFlow.(*AggchainProverBuilderFlow) + if !ok { + return nil, + fmt.Errorf("expected AggchainProverBuilderFlow for AggchainProofMode mode, got %T", builderFlow) + } + + aggProofPublicValuesQuery, err := newAggProofPublicValuesQuery( + cfg.SovereignRollupAddr, + l1Client, + cfg.OptimisticModeConfig.OpNodeURL, + ) + if err != nil { + return nil, fmt.Errorf("failed to create AggProofPublicValuesQuery: %w", err) + } + + return NewAggchainProverVerifierFlow(builderFlow, aggProofPublicValuesQuery), nil + default: + return nil, fmt.Errorf("unsupported Aggsender Validator mode: %s", cfg.Mode) + } +} + +// newAggProofPublicValuesQuery creates a new instance of AggProofPublicValuesQuery +func newAggProofPublicValuesQuery( + aggchainFEPContractAddr common.Address, + l1Client aggkittypes.BaseEthereumClienter, + opNodeURL string, +) (*query.AggProofPublicValuesQuery, error) { + aggChainFEPContract, err := aggchainfep.NewAggchainfepCaller(aggchainFEPContractAddr, l1Client) + if err != nil { + return nil, fmt.Errorf("aggchainProverFlow - error creating AggchainFEP rollup caller (%s): %w", + aggchainFEPContractAddr.String(), err) + } + + aggProofPublicValuesQuerier := query.NewAggProofPublicValuesQuery( + aggChainFEPContract, + aggchainFEPContractAddr, + opnode.NewOpNodeClient(opNodeURL), + aggkitcommon.ZeroAddress, // prover address will be gotten from the contract in validator mode + ) + + return aggProofPublicValuesQuerier, nil +} diff --git a/aggsender/flows/verifier_flow_factory_test.go b/aggsender/flows/verifier_flow_factory_test.go new file mode 100644 index 000000000..dadae4130 --- /dev/null +++ b/aggsender/flows/verifier_flow_factory_test.go @@ -0,0 +1,253 @@ +package flows + +import ( + "context" + "fmt" + "testing" + + "github.com/agglayer/aggkit/aggsender/config" + "github.com/agglayer/aggkit/aggsender/mocks" + "github.com/agglayer/aggkit/aggsender/optimistic" + "github.com/agglayer/aggkit/aggsender/types" + "github.com/agglayer/aggkit/aggsender/validator" + "github.com/agglayer/aggkit/log" + typesmocks "github.com/agglayer/aggkit/types/mocks" + signertypes "github.com/agglayer/go_signer/signer/types" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func TestNewVerifierFlow(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + cfg validator.Config + mockFn func(*mocks.MultisigQuerier) + expectedError string + }{ + { + name: "success with PessimisticProofMode", + cfg: validator.Config{ + Mode: types.PessimisticProofMode, + Signer: signertypes.SignerConfig{Method: signertypes.MethodNone}, + RequireCommitteeMembershipCheck: true, + }, + mockFn: func(mockCommittee *mocks.MultisigQuerier) { + committee, err := types.NewMultisigCommittee([]*types.SignerInfo{types.NewSignerInfo("", common.Address{})}, 1) + require.NoError(t, err) + + mockCommittee.EXPECT().GetMultisigCommittee(mock.Anything, mock.Anything).Return(committee, nil).Once() + }, + }, + { + name: "error getting multisig committee when RequireCommitteeMembershipCheck is true", + cfg: validator.Config{ + Mode: types.PessimisticProofMode, + Signer: signertypes.SignerConfig{Method: signertypes.MethodNone}, + RequireCommitteeMembershipCheck: true, + }, + mockFn: func(mockCommittee *mocks.MultisigQuerier) { + mockCommittee.EXPECT().GetMultisigCommittee(mock.Anything, mock.Anything).Return(nil, fmt.Errorf("test error")).Once() + }, + expectedError: "error getting multisig committee: test error", + }, + { + name: "success with AggchainProofMode", + cfg: validator.Config{ + Mode: types.AggchainProofMode, + Signer: signertypes.SignerConfig{Method: signertypes.MethodNone}, + FEPConfig: validator.FEPConfig{ + OpNodeURL: "http://localhost:8545", + }, + }, + mockFn: func(mockCommittee *mocks.MultisigQuerier) { + committee, err := types.NewMultisigCommittee([]*types.SignerInfo{types.NewSignerInfo("", common.Address{})}, 1) + require.NoError(t, err) + + mockCommittee.EXPECT().GetMultisigCommittee(mock.Anything, mock.Anything).Return(committee, nil).Once() + }, + }, + { + name: "error getting multisig committee when RequireCommitteeMembershipCheck is true with AggchainProofMode", + cfg: validator.Config{ + Mode: types.AggchainProofMode, + Signer: signertypes.SignerConfig{Method: signertypes.MethodNone}, + RequireCommitteeMembershipCheck: true, + FEPConfig: validator.FEPConfig{ + OpNodeURL: "http://localhost:8545", + }, + }, + mockFn: func(mockCommittee *mocks.MultisigQuerier) { + mockCommittee.EXPECT().GetMultisigCommittee(mock.Anything, mock.Anything).Return(nil, fmt.Errorf("test error")).Once() + }, + expectedError: "error getting multisig committee: test error", + }, + { + name: "unsupported mode", + cfg: validator.Config{ + Mode: "unsupported-mode", + Signer: signertypes.SignerConfig{Method: signertypes.MethodNone}, + }, + expectedError: "unsupported Aggsender Validator mode: unsupported-mode", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + mockLogger := log.WithFields("test", "NewFlow") + + mockL1Client := typesmocks.NewBaseEthereumClienter(t) + mockL1InfoTreeSyncer := mocks.NewL1InfoTreeSyncer(t) + mockL2Syncer := mocks.NewL2BridgeSyncer(t) + mockRollupDataQuerier := mocks.NewRollupDataQuerier(t) + mockCommitteeQuerier := mocks.NewMultisigQuerier(t) + + mockRollupDataQuerier.EXPECT().GetRollupChainID().Return(uint64(1234), nil).Maybe() + mockL2Syncer.EXPECT().OriginNetwork().Return(1).Maybe() + + if tc.mockFn != nil { + tc.mockFn(mockCommitteeQuerier) + } + + verifierFlow, commonComponents, err := NewVerifierFlow( + ctx, + tc.cfg, + mockLogger, + mockL1Client, + mockL1InfoTreeSyncer, + mockL2Syncer, + mockRollupDataQuerier, + mockCommitteeQuerier, + ) + + if tc.expectedError != "" { + require.ErrorContains(t, err, tc.expectedError) + require.Nil(t, verifierFlow) + require.Nil(t, commonComponents) + } else { + require.NoError(t, err) + require.NotNil(t, verifierFlow) + require.NotNil(t, commonComponents) + } + }) + } +} + +func TestNewLocalVerifier(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + mode types.AggsenderMode + builderFlow types.AggsenderBuilderFlow + cfg config.Config + expectedErrorSubstr string + expectedVerifierFlowType string + }{ + { + name: "Pessimistic mode with nil builder flow", + mode: types.PessimisticProofMode, + builderFlow: (types.AggsenderBuilderFlow)(nil), + cfg: config.Config{Mode: types.PessimisticProofMode}, + expectedErrorSubstr: "expected PPBuilderFlow", + }, + { + name: "Pessimistic mode with wrong builder type - AggchainProverBuilderFlow", + mode: types.PessimisticProofMode, + builderFlow: &AggchainProverBuilderFlow{}, + cfg: config.Config{Mode: types.PessimisticProofMode}, + expectedErrorSubstr: "expected PPBuilderFlow", + }, + { + name: "Pessimistic mode with correct PPBuilderFlow", + mode: types.PessimisticProofMode, + builderFlow: &PPBuilderFlow{}, + cfg: config.Config{Mode: types.PessimisticProofMode}, + expectedVerifierFlowType: "*flows.PPVerifierFlow", + }, + { + name: "Aggchain mode with nil builder flow", + mode: types.AggchainProofMode, + builderFlow: (types.AggsenderBuilderFlow)(nil), + cfg: config.Config{Mode: types.AggchainProofMode}, + expectedErrorSubstr: "expected AggchainProverBuilderFlow", + }, + { + name: "Aggchain mode with wrong builder type - PPBuilderFlow", + mode: types.AggchainProofMode, + builderFlow: &PPBuilderFlow{}, + cfg: config.Config{Mode: types.AggchainProofMode}, + expectedErrorSubstr: "expected AggchainProverBuilderFlow", + }, + { + name: "Unsupported mode", + mode: "unsupported-mode", + builderFlow: (types.AggsenderBuilderFlow)(nil), + cfg: config.Config{Mode: "unsupported-mode"}, + expectedErrorSubstr: "unsupported Aggsender Validator mode", + }, + { + name: "Empty mode string", + mode: "", + builderFlow: (types.AggsenderBuilderFlow)(nil), + cfg: config.Config{Mode: ""}, + expectedErrorSubstr: "unsupported Aggsender Validator mode", + }, + { + name: "Invalid mode with special characters", + mode: "invalid@mode#123", + builderFlow: (types.AggsenderBuilderFlow)(nil), + cfg: config.Config{Mode: "invalid@mode#123"}, + expectedErrorSubstr: "unsupported Aggsender Validator mode", + }, + { + name: "Pessimistic mode with invalid config but correct builder flow", + mode: types.PessimisticProofMode, + builderFlow: &PPBuilderFlow{}, + cfg: config.Config{ + Mode: types.PessimisticProofMode, + // No additional config needed for PP mode + }, + expectedVerifierFlowType: "*flows.PPVerifierFlow", + }, + { + name: "Aggchain mode success", + mode: types.AggchainProofMode, + builderFlow: &AggchainProverBuilderFlow{}, + cfg: config.Config{ + Mode: types.AggchainProofMode, + SovereignRollupAddr: common.HexToAddress("0x1"), // Valid address + OptimisticModeConfig: optimistic.Config{OpNodeURL: ""}, + }, + expectedVerifierFlowType: "*flows.AggchainProverVerifierFlow", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + verifierFlow, err := NewLocalVerifier(ctx, tc.cfg, nil, tc.builderFlow) + + if tc.expectedErrorSubstr != "" { + require.ErrorContains(t, err, tc.expectedErrorSubstr) + } else { + require.NoError(t, err) + require.NotNil(t, verifierFlow) + if tc.expectedVerifierFlowType != "" { + actualType := fmt.Sprintf("%T", verifierFlow) + if actualType != tc.expectedVerifierFlowType { + t.Fatalf("expected verifier flow type %s, got %s", tc.expectedVerifierFlowType, actualType) + } + } + } + }) + } +} diff --git a/aggsender/flows/verifier_flow_pp.go b/aggsender/flows/verifier_flow_pp.go new file mode 100644 index 000000000..3d661b447 --- /dev/null +++ b/aggsender/flows/verifier_flow_pp.go @@ -0,0 +1,35 @@ +package flows + +import ( + "context" + + agglayertypes "github.com/agglayer/aggkit/agglayer/types" + "github.com/agglayer/aggkit/aggsender/types" +) + +var _ types.AggsenderVerifierFlow = (*PPVerifierFlow)(nil) + +// PPVerifierFlow is a struct that holds the logic for the regular pessimistic proof flow verification +type PPVerifierFlow struct { + *PPBuilderFlow +} + +// NewPPVerifierFlow returns a new instance of the PPVerifierFlow +func NewPPVerifierFlow(builderFlow *PPBuilderFlow) *PPVerifierFlow { + return &PPVerifierFlow{ + PPBuilderFlow: builderFlow, + } +} + +// VerifyCertificate verifies the new certificate +// This function is used in the validator to verify the certificate +func (p *PPVerifierFlow) VerifyCertificate( + ctx context.Context, + cert *agglayertypes.Certificate, + lastBlockInCert uint64, + lastSettledBlock uint64) error { + // for PP certificates there is nothing to verify specific to PP flow + // signature of the proposer will be added with signatures of other committee members + // in the multisig, so no need to verify anything here + return nil +} diff --git a/aggsender/mocks/mock_agg_proof_public_values_querier.go b/aggsender/mocks/mock_agg_proof_public_values_querier.go new file mode 100644 index 000000000..67eee292c --- /dev/null +++ b/aggsender/mocks/mock_agg_proof_public_values_querier.go @@ -0,0 +1,97 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + common "github.com/ethereum/go-ethereum/common" + mock "github.com/stretchr/testify/mock" + + types "github.com/agglayer/aggkit/aggsender/types" +) + +// AggProofPublicValuesQuerier is an autogenerated mock type for the AggProofPublicValuesQuerier type +type AggProofPublicValuesQuerier struct { + mock.Mock +} + +type AggProofPublicValuesQuerier_Expecter struct { + mock *mock.Mock +} + +func (_m *AggProofPublicValuesQuerier) EXPECT() *AggProofPublicValuesQuerier_Expecter { + return &AggProofPublicValuesQuerier_Expecter{mock: &_m.Mock} +} + +// GetAggregationProofPublicValuesData provides a mock function with given fields: lastProvenBlock, requestedEndBlock, l1InfoTreeLeafHash +func (_m *AggProofPublicValuesQuerier) GetAggregationProofPublicValuesData(lastProvenBlock uint64, requestedEndBlock uint64, l1InfoTreeLeafHash common.Hash) (*types.AggregationProofPublicValues, error) { + ret := _m.Called(lastProvenBlock, requestedEndBlock, l1InfoTreeLeafHash) + + if len(ret) == 0 { + panic("no return value specified for GetAggregationProofPublicValuesData") + } + + var r0 *types.AggregationProofPublicValues + var r1 error + if rf, ok := ret.Get(0).(func(uint64, uint64, common.Hash) (*types.AggregationProofPublicValues, error)); ok { + return rf(lastProvenBlock, requestedEndBlock, l1InfoTreeLeafHash) + } + if rf, ok := ret.Get(0).(func(uint64, uint64, common.Hash) *types.AggregationProofPublicValues); ok { + r0 = rf(lastProvenBlock, requestedEndBlock, l1InfoTreeLeafHash) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.AggregationProofPublicValues) + } + } + + if rf, ok := ret.Get(1).(func(uint64, uint64, common.Hash) error); ok { + r1 = rf(lastProvenBlock, requestedEndBlock, l1InfoTreeLeafHash) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AggProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAggregationProofPublicValuesData' +type AggProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call struct { + *mock.Call +} + +// GetAggregationProofPublicValuesData is a helper method to define mock.On call +// - lastProvenBlock uint64 +// - requestedEndBlock uint64 +// - l1InfoTreeLeafHash common.Hash +func (_e *AggProofPublicValuesQuerier_Expecter) GetAggregationProofPublicValuesData(lastProvenBlock interface{}, requestedEndBlock interface{}, l1InfoTreeLeafHash interface{}) *AggProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call { + return &AggProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call{Call: _e.mock.On("GetAggregationProofPublicValuesData", lastProvenBlock, requestedEndBlock, l1InfoTreeLeafHash)} +} + +func (_c *AggProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call) Run(run func(lastProvenBlock uint64, requestedEndBlock uint64, l1InfoTreeLeafHash common.Hash)) *AggProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(uint64), args[1].(uint64), args[2].(common.Hash)) + }) + return _c +} + +func (_c *AggProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call) Return(_a0 *types.AggregationProofPublicValues, _a1 error) *AggProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AggProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call) RunAndReturn(run func(uint64, uint64, common.Hash) (*types.AggregationProofPublicValues, error)) *AggProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call { + _c.Call.Return(run) + return _c +} + +// NewAggProofPublicValuesQuerier creates a new instance of AggProofPublicValuesQuerier. 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 NewAggProofPublicValuesQuerier(t interface { + mock.TestingT + Cleanup(func()) +}) *AggProofPublicValuesQuerier { + mock := &AggProofPublicValuesQuerier{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/aggsender/mocks/mock_aggsender_builder_flow.go b/aggsender/mocks/mock_aggsender_builder_flow.go new file mode 100644 index 000000000..2963c3653 --- /dev/null +++ b/aggsender/mocks/mock_aggsender_builder_flow.go @@ -0,0 +1,358 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + context "context" + + agglayertypes "github.com/agglayer/aggkit/agglayer/types" + + mock "github.com/stretchr/testify/mock" + + signertypes "github.com/agglayer/go_signer/signer/types" + + types "github.com/agglayer/aggkit/aggsender/types" +) + +// AggsenderBuilderFlow is an autogenerated mock type for the AggsenderBuilderFlow type +type AggsenderBuilderFlow struct { + mock.Mock +} + +type AggsenderBuilderFlow_Expecter struct { + mock *mock.Mock +} + +func (_m *AggsenderBuilderFlow) EXPECT() *AggsenderBuilderFlow_Expecter { + return &AggsenderBuilderFlow_Expecter{mock: &_m.Mock} +} + +// BuildCertificate provides a mock function with given fields: ctx, buildParams +func (_m *AggsenderBuilderFlow) BuildCertificate(ctx context.Context, buildParams *types.CertificateBuildParams) (*agglayertypes.Certificate, error) { + ret := _m.Called(ctx, buildParams) + + if len(ret) == 0 { + panic("no return value specified for BuildCertificate") + } + + var r0 *agglayertypes.Certificate + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.CertificateBuildParams) (*agglayertypes.Certificate, error)); ok { + return rf(ctx, buildParams) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.CertificateBuildParams) *agglayertypes.Certificate); ok { + r0 = rf(ctx, buildParams) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*agglayertypes.Certificate) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.CertificateBuildParams) error); ok { + r1 = rf(ctx, buildParams) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AggsenderBuilderFlow_BuildCertificate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BuildCertificate' +type AggsenderBuilderFlow_BuildCertificate_Call struct { + *mock.Call +} + +// BuildCertificate is a helper method to define mock.On call +// - ctx context.Context +// - buildParams *types.CertificateBuildParams +func (_e *AggsenderBuilderFlow_Expecter) BuildCertificate(ctx interface{}, buildParams interface{}) *AggsenderBuilderFlow_BuildCertificate_Call { + return &AggsenderBuilderFlow_BuildCertificate_Call{Call: _e.mock.On("BuildCertificate", ctx, buildParams)} +} + +func (_c *AggsenderBuilderFlow_BuildCertificate_Call) Run(run func(ctx context.Context, buildParams *types.CertificateBuildParams)) *AggsenderBuilderFlow_BuildCertificate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*types.CertificateBuildParams)) + }) + return _c +} + +func (_c *AggsenderBuilderFlow_BuildCertificate_Call) Return(_a0 *agglayertypes.Certificate, _a1 error) *AggsenderBuilderFlow_BuildCertificate_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AggsenderBuilderFlow_BuildCertificate_Call) RunAndReturn(run func(context.Context, *types.CertificateBuildParams) (*agglayertypes.Certificate, error)) *AggsenderBuilderFlow_BuildCertificate_Call { + _c.Call.Return(run) + return _c +} + +// CheckInitialStatus provides a mock function with given fields: ctx +func (_m *AggsenderBuilderFlow) CheckInitialStatus(ctx context.Context) error { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for CheckInitialStatus") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// AggsenderBuilderFlow_CheckInitialStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckInitialStatus' +type AggsenderBuilderFlow_CheckInitialStatus_Call struct { + *mock.Call +} + +// CheckInitialStatus is a helper method to define mock.On call +// - ctx context.Context +func (_e *AggsenderBuilderFlow_Expecter) CheckInitialStatus(ctx interface{}) *AggsenderBuilderFlow_CheckInitialStatus_Call { + return &AggsenderBuilderFlow_CheckInitialStatus_Call{Call: _e.mock.On("CheckInitialStatus", ctx)} +} + +func (_c *AggsenderBuilderFlow_CheckInitialStatus_Call) Run(run func(ctx context.Context)) *AggsenderBuilderFlow_CheckInitialStatus_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *AggsenderBuilderFlow_CheckInitialStatus_Call) Return(_a0 error) *AggsenderBuilderFlow_CheckInitialStatus_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *AggsenderBuilderFlow_CheckInitialStatus_Call) RunAndReturn(run func(context.Context) error) *AggsenderBuilderFlow_CheckInitialStatus_Call { + _c.Call.Return(run) + return _c +} + +// GenerateBuildParams provides a mock function with given fields: ctx, preParams +func (_m *AggsenderBuilderFlow) GenerateBuildParams(ctx context.Context, preParams *types.CertificatePreBuildParams) (*types.CertificateBuildParams, error) { + ret := _m.Called(ctx, preParams) + + if len(ret) == 0 { + panic("no return value specified for GenerateBuildParams") + } + + var r0 *types.CertificateBuildParams + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.CertificatePreBuildParams) (*types.CertificateBuildParams, error)); ok { + return rf(ctx, preParams) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.CertificatePreBuildParams) *types.CertificateBuildParams); ok { + r0 = rf(ctx, preParams) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.CertificateBuildParams) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.CertificatePreBuildParams) error); ok { + r1 = rf(ctx, preParams) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AggsenderBuilderFlow_GenerateBuildParams_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GenerateBuildParams' +type AggsenderBuilderFlow_GenerateBuildParams_Call struct { + *mock.Call +} + +// GenerateBuildParams is a helper method to define mock.On call +// - ctx context.Context +// - preParams *types.CertificatePreBuildParams +func (_e *AggsenderBuilderFlow_Expecter) GenerateBuildParams(ctx interface{}, preParams interface{}) *AggsenderBuilderFlow_GenerateBuildParams_Call { + return &AggsenderBuilderFlow_GenerateBuildParams_Call{Call: _e.mock.On("GenerateBuildParams", ctx, preParams)} +} + +func (_c *AggsenderBuilderFlow_GenerateBuildParams_Call) Run(run func(ctx context.Context, preParams *types.CertificatePreBuildParams)) *AggsenderBuilderFlow_GenerateBuildParams_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*types.CertificatePreBuildParams)) + }) + return _c +} + +func (_c *AggsenderBuilderFlow_GenerateBuildParams_Call) Return(_a0 *types.CertificateBuildParams, _a1 error) *AggsenderBuilderFlow_GenerateBuildParams_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AggsenderBuilderFlow_GenerateBuildParams_Call) RunAndReturn(run func(context.Context, *types.CertificatePreBuildParams) (*types.CertificateBuildParams, error)) *AggsenderBuilderFlow_GenerateBuildParams_Call { + _c.Call.Return(run) + return _c +} + +// GetCertificateBuildParams provides a mock function with given fields: ctx +func (_m *AggsenderBuilderFlow) GetCertificateBuildParams(ctx context.Context) (*types.CertificateBuildParams, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetCertificateBuildParams") + } + + var r0 *types.CertificateBuildParams + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*types.CertificateBuildParams, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *types.CertificateBuildParams); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.CertificateBuildParams) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AggsenderBuilderFlow_GetCertificateBuildParams_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCertificateBuildParams' +type AggsenderBuilderFlow_GetCertificateBuildParams_Call struct { + *mock.Call +} + +// GetCertificateBuildParams is a helper method to define mock.On call +// - ctx context.Context +func (_e *AggsenderBuilderFlow_Expecter) GetCertificateBuildParams(ctx interface{}) *AggsenderBuilderFlow_GetCertificateBuildParams_Call { + return &AggsenderBuilderFlow_GetCertificateBuildParams_Call{Call: _e.mock.On("GetCertificateBuildParams", ctx)} +} + +func (_c *AggsenderBuilderFlow_GetCertificateBuildParams_Call) Run(run func(ctx context.Context)) *AggsenderBuilderFlow_GetCertificateBuildParams_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *AggsenderBuilderFlow_GetCertificateBuildParams_Call) Return(_a0 *types.CertificateBuildParams, _a1 error) *AggsenderBuilderFlow_GetCertificateBuildParams_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AggsenderBuilderFlow_GetCertificateBuildParams_Call) RunAndReturn(run func(context.Context) (*types.CertificateBuildParams, error)) *AggsenderBuilderFlow_GetCertificateBuildParams_Call { + _c.Call.Return(run) + return _c +} + +// Signer provides a mock function with no fields +func (_m *AggsenderBuilderFlow) Signer() signertypes.Signer { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Signer") + } + + var r0 signertypes.Signer + if rf, ok := ret.Get(0).(func() signertypes.Signer); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(signertypes.Signer) + } + } + + return r0 +} + +// AggsenderBuilderFlow_Signer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Signer' +type AggsenderBuilderFlow_Signer_Call struct { + *mock.Call +} + +// Signer is a helper method to define mock.On call +func (_e *AggsenderBuilderFlow_Expecter) Signer() *AggsenderBuilderFlow_Signer_Call { + return &AggsenderBuilderFlow_Signer_Call{Call: _e.mock.On("Signer")} +} + +func (_c *AggsenderBuilderFlow_Signer_Call) Run(run func()) *AggsenderBuilderFlow_Signer_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *AggsenderBuilderFlow_Signer_Call) Return(_a0 signertypes.Signer) *AggsenderBuilderFlow_Signer_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *AggsenderBuilderFlow_Signer_Call) RunAndReturn(run func() signertypes.Signer) *AggsenderBuilderFlow_Signer_Call { + _c.Call.Return(run) + return _c +} + +// UpdateAggchainData provides a mock function with given fields: cert, multisig +func (_m *AggsenderBuilderFlow) UpdateAggchainData(cert *agglayertypes.Certificate, multisig *agglayertypes.Multisig) error { + ret := _m.Called(cert, multisig) + + if len(ret) == 0 { + panic("no return value specified for UpdateAggchainData") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*agglayertypes.Certificate, *agglayertypes.Multisig) error); ok { + r0 = rf(cert, multisig) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// AggsenderBuilderFlow_UpdateAggchainData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateAggchainData' +type AggsenderBuilderFlow_UpdateAggchainData_Call struct { + *mock.Call +} + +// UpdateAggchainData is a helper method to define mock.On call +// - cert *agglayertypes.Certificate +// - multisig *agglayertypes.Multisig +func (_e *AggsenderBuilderFlow_Expecter) UpdateAggchainData(cert interface{}, multisig interface{}) *AggsenderBuilderFlow_UpdateAggchainData_Call { + return &AggsenderBuilderFlow_UpdateAggchainData_Call{Call: _e.mock.On("UpdateAggchainData", cert, multisig)} +} + +func (_c *AggsenderBuilderFlow_UpdateAggchainData_Call) Run(run func(cert *agglayertypes.Certificate, multisig *agglayertypes.Multisig)) *AggsenderBuilderFlow_UpdateAggchainData_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*agglayertypes.Certificate), args[1].(*agglayertypes.Multisig)) + }) + return _c +} + +func (_c *AggsenderBuilderFlow_UpdateAggchainData_Call) Return(_a0 error) *AggsenderBuilderFlow_UpdateAggchainData_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *AggsenderBuilderFlow_UpdateAggchainData_Call) RunAndReturn(run func(*agglayertypes.Certificate, *agglayertypes.Multisig) error) *AggsenderBuilderFlow_UpdateAggchainData_Call { + _c.Call.Return(run) + return _c +} + +// NewAggsenderBuilderFlow creates a new instance of AggsenderBuilderFlow. 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 NewAggsenderBuilderFlow(t interface { + mock.TestingT + Cleanup(func()) +}) *AggsenderBuilderFlow { + mock := &AggsenderBuilderFlow{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/aggsender/mocks/mock_aggsender_flow.go b/aggsender/mocks/mock_aggsender_flow.go deleted file mode 100644 index 272e3b334..000000000 --- a/aggsender/mocks/mock_aggsender_flow.go +++ /dev/null @@ -1,358 +0,0 @@ -// Code generated by mockery. DO NOT EDIT. - -package mocks - -import ( - context "context" - - agglayertypes "github.com/agglayer/aggkit/agglayer/types" - - mock "github.com/stretchr/testify/mock" - - signertypes "github.com/agglayer/go_signer/signer/types" - - types "github.com/agglayer/aggkit/aggsender/types" -) - -// AggsenderFlow is an autogenerated mock type for the AggsenderFlow type -type AggsenderFlow struct { - mock.Mock -} - -type AggsenderFlow_Expecter struct { - mock *mock.Mock -} - -func (_m *AggsenderFlow) EXPECT() *AggsenderFlow_Expecter { - return &AggsenderFlow_Expecter{mock: &_m.Mock} -} - -// BuildCertificate provides a mock function with given fields: ctx, buildParams -func (_m *AggsenderFlow) BuildCertificate(ctx context.Context, buildParams *types.CertificateBuildParams) (*agglayertypes.Certificate, error) { - ret := _m.Called(ctx, buildParams) - - if len(ret) == 0 { - panic("no return value specified for BuildCertificate") - } - - var r0 *agglayertypes.Certificate - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *types.CertificateBuildParams) (*agglayertypes.Certificate, error)); ok { - return rf(ctx, buildParams) - } - if rf, ok := ret.Get(0).(func(context.Context, *types.CertificateBuildParams) *agglayertypes.Certificate); ok { - r0 = rf(ctx, buildParams) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*agglayertypes.Certificate) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, *types.CertificateBuildParams) error); ok { - r1 = rf(ctx, buildParams) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AggsenderFlow_BuildCertificate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BuildCertificate' -type AggsenderFlow_BuildCertificate_Call struct { - *mock.Call -} - -// BuildCertificate is a helper method to define mock.On call -// - ctx context.Context -// - buildParams *types.CertificateBuildParams -func (_e *AggsenderFlow_Expecter) BuildCertificate(ctx interface{}, buildParams interface{}) *AggsenderFlow_BuildCertificate_Call { - return &AggsenderFlow_BuildCertificate_Call{Call: _e.mock.On("BuildCertificate", ctx, buildParams)} -} - -func (_c *AggsenderFlow_BuildCertificate_Call) Run(run func(ctx context.Context, buildParams *types.CertificateBuildParams)) *AggsenderFlow_BuildCertificate_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*types.CertificateBuildParams)) - }) - return _c -} - -func (_c *AggsenderFlow_BuildCertificate_Call) Return(_a0 *agglayertypes.Certificate, _a1 error) *AggsenderFlow_BuildCertificate_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AggsenderFlow_BuildCertificate_Call) RunAndReturn(run func(context.Context, *types.CertificateBuildParams) (*agglayertypes.Certificate, error)) *AggsenderFlow_BuildCertificate_Call { - _c.Call.Return(run) - return _c -} - -// CheckInitialStatus provides a mock function with given fields: ctx -func (_m *AggsenderFlow) CheckInitialStatus(ctx context.Context) error { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for CheckInitialStatus") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// AggsenderFlow_CheckInitialStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckInitialStatus' -type AggsenderFlow_CheckInitialStatus_Call struct { - *mock.Call -} - -// CheckInitialStatus is a helper method to define mock.On call -// - ctx context.Context -func (_e *AggsenderFlow_Expecter) CheckInitialStatus(ctx interface{}) *AggsenderFlow_CheckInitialStatus_Call { - return &AggsenderFlow_CheckInitialStatus_Call{Call: _e.mock.On("CheckInitialStatus", ctx)} -} - -func (_c *AggsenderFlow_CheckInitialStatus_Call) Run(run func(ctx context.Context)) *AggsenderFlow_CheckInitialStatus_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context)) - }) - return _c -} - -func (_c *AggsenderFlow_CheckInitialStatus_Call) Return(_a0 error) *AggsenderFlow_CheckInitialStatus_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *AggsenderFlow_CheckInitialStatus_Call) RunAndReturn(run func(context.Context) error) *AggsenderFlow_CheckInitialStatus_Call { - _c.Call.Return(run) - return _c -} - -// GenerateBuildParams provides a mock function with given fields: ctx, preParams -func (_m *AggsenderFlow) GenerateBuildParams(ctx context.Context, preParams *types.CertificatePreBuildParams) (*types.CertificateBuildParams, error) { - ret := _m.Called(ctx, preParams) - - if len(ret) == 0 { - panic("no return value specified for GenerateBuildParams") - } - - var r0 *types.CertificateBuildParams - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *types.CertificatePreBuildParams) (*types.CertificateBuildParams, error)); ok { - return rf(ctx, preParams) - } - if rf, ok := ret.Get(0).(func(context.Context, *types.CertificatePreBuildParams) *types.CertificateBuildParams); ok { - r0 = rf(ctx, preParams) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.CertificateBuildParams) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, *types.CertificatePreBuildParams) error); ok { - r1 = rf(ctx, preParams) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AggsenderFlow_GenerateBuildParams_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GenerateBuildParams' -type AggsenderFlow_GenerateBuildParams_Call struct { - *mock.Call -} - -// GenerateBuildParams is a helper method to define mock.On call -// - ctx context.Context -// - preParams *types.CertificatePreBuildParams -func (_e *AggsenderFlow_Expecter) GenerateBuildParams(ctx interface{}, preParams interface{}) *AggsenderFlow_GenerateBuildParams_Call { - return &AggsenderFlow_GenerateBuildParams_Call{Call: _e.mock.On("GenerateBuildParams", ctx, preParams)} -} - -func (_c *AggsenderFlow_GenerateBuildParams_Call) Run(run func(ctx context.Context, preParams *types.CertificatePreBuildParams)) *AggsenderFlow_GenerateBuildParams_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*types.CertificatePreBuildParams)) - }) - return _c -} - -func (_c *AggsenderFlow_GenerateBuildParams_Call) Return(_a0 *types.CertificateBuildParams, _a1 error) *AggsenderFlow_GenerateBuildParams_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AggsenderFlow_GenerateBuildParams_Call) RunAndReturn(run func(context.Context, *types.CertificatePreBuildParams) (*types.CertificateBuildParams, error)) *AggsenderFlow_GenerateBuildParams_Call { - _c.Call.Return(run) - return _c -} - -// GetCertificateBuildParams provides a mock function with given fields: ctx -func (_m *AggsenderFlow) GetCertificateBuildParams(ctx context.Context) (*types.CertificateBuildParams, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for GetCertificateBuildParams") - } - - var r0 *types.CertificateBuildParams - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (*types.CertificateBuildParams, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) *types.CertificateBuildParams); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.CertificateBuildParams) - } - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AggsenderFlow_GetCertificateBuildParams_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCertificateBuildParams' -type AggsenderFlow_GetCertificateBuildParams_Call struct { - *mock.Call -} - -// GetCertificateBuildParams is a helper method to define mock.On call -// - ctx context.Context -func (_e *AggsenderFlow_Expecter) GetCertificateBuildParams(ctx interface{}) *AggsenderFlow_GetCertificateBuildParams_Call { - return &AggsenderFlow_GetCertificateBuildParams_Call{Call: _e.mock.On("GetCertificateBuildParams", ctx)} -} - -func (_c *AggsenderFlow_GetCertificateBuildParams_Call) Run(run func(ctx context.Context)) *AggsenderFlow_GetCertificateBuildParams_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context)) - }) - return _c -} - -func (_c *AggsenderFlow_GetCertificateBuildParams_Call) Return(_a0 *types.CertificateBuildParams, _a1 error) *AggsenderFlow_GetCertificateBuildParams_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AggsenderFlow_GetCertificateBuildParams_Call) RunAndReturn(run func(context.Context) (*types.CertificateBuildParams, error)) *AggsenderFlow_GetCertificateBuildParams_Call { - _c.Call.Return(run) - return _c -} - -// Signer provides a mock function with no fields -func (_m *AggsenderFlow) Signer() signertypes.Signer { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Signer") - } - - var r0 signertypes.Signer - if rf, ok := ret.Get(0).(func() signertypes.Signer); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(signertypes.Signer) - } - } - - return r0 -} - -// AggsenderFlow_Signer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Signer' -type AggsenderFlow_Signer_Call struct { - *mock.Call -} - -// Signer is a helper method to define mock.On call -func (_e *AggsenderFlow_Expecter) Signer() *AggsenderFlow_Signer_Call { - return &AggsenderFlow_Signer_Call{Call: _e.mock.On("Signer")} -} - -func (_c *AggsenderFlow_Signer_Call) Run(run func()) *AggsenderFlow_Signer_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *AggsenderFlow_Signer_Call) Return(_a0 signertypes.Signer) *AggsenderFlow_Signer_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *AggsenderFlow_Signer_Call) RunAndReturn(run func() signertypes.Signer) *AggsenderFlow_Signer_Call { - _c.Call.Return(run) - return _c -} - -// UpdateAggchainData provides a mock function with given fields: cert, multisig -func (_m *AggsenderFlow) UpdateAggchainData(cert *agglayertypes.Certificate, multisig *agglayertypes.Multisig) error { - ret := _m.Called(cert, multisig) - - if len(ret) == 0 { - panic("no return value specified for UpdateAggchainData") - } - - var r0 error - if rf, ok := ret.Get(0).(func(*agglayertypes.Certificate, *agglayertypes.Multisig) error); ok { - r0 = rf(cert, multisig) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// AggsenderFlow_UpdateAggchainData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateAggchainData' -type AggsenderFlow_UpdateAggchainData_Call struct { - *mock.Call -} - -// UpdateAggchainData is a helper method to define mock.On call -// - cert *agglayertypes.Certificate -// - multisig *agglayertypes.Multisig -func (_e *AggsenderFlow_Expecter) UpdateAggchainData(cert interface{}, multisig interface{}) *AggsenderFlow_UpdateAggchainData_Call { - return &AggsenderFlow_UpdateAggchainData_Call{Call: _e.mock.On("UpdateAggchainData", cert, multisig)} -} - -func (_c *AggsenderFlow_UpdateAggchainData_Call) Run(run func(cert *agglayertypes.Certificate, multisig *agglayertypes.Multisig)) *AggsenderFlow_UpdateAggchainData_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*agglayertypes.Certificate), args[1].(*agglayertypes.Multisig)) - }) - return _c -} - -func (_c *AggsenderFlow_UpdateAggchainData_Call) Return(_a0 error) *AggsenderFlow_UpdateAggchainData_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *AggsenderFlow_UpdateAggchainData_Call) RunAndReturn(run func(*agglayertypes.Certificate, *agglayertypes.Multisig) error) *AggsenderFlow_UpdateAggchainData_Call { - _c.Call.Return(run) - return _c -} - -// NewAggsenderFlow creates a new instance of AggsenderFlow. 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 NewAggsenderFlow(t interface { - mock.TestingT - Cleanup(func()) -}) *AggsenderFlow { - mock := &AggsenderFlow{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/aggsender/mocks/mock_aggsender_verifier_flow.go b/aggsender/mocks/mock_aggsender_verifier_flow.go new file mode 100644 index 000000000..31fd954e8 --- /dev/null +++ b/aggsender/mocks/mock_aggsender_verifier_flow.go @@ -0,0 +1,207 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + context "context" + + agglayertypes "github.com/agglayer/aggkit/agglayer/types" + + mock "github.com/stretchr/testify/mock" + + types "github.com/agglayer/aggkit/aggsender/types" +) + +// AggsenderVerifierFlow is an autogenerated mock type for the AggsenderVerifierFlow type +type AggsenderVerifierFlow struct { + mock.Mock +} + +type AggsenderVerifierFlow_Expecter struct { + mock *mock.Mock +} + +func (_m *AggsenderVerifierFlow) EXPECT() *AggsenderVerifierFlow_Expecter { + return &AggsenderVerifierFlow_Expecter{mock: &_m.Mock} +} + +// BuildCertificate provides a mock function with given fields: ctx, buildParams +func (_m *AggsenderVerifierFlow) BuildCertificate(ctx context.Context, buildParams *types.CertificateBuildParams) (*agglayertypes.Certificate, error) { + ret := _m.Called(ctx, buildParams) + + if len(ret) == 0 { + panic("no return value specified for BuildCertificate") + } + + var r0 *agglayertypes.Certificate + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.CertificateBuildParams) (*agglayertypes.Certificate, error)); ok { + return rf(ctx, buildParams) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.CertificateBuildParams) *agglayertypes.Certificate); ok { + r0 = rf(ctx, buildParams) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*agglayertypes.Certificate) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.CertificateBuildParams) error); ok { + r1 = rf(ctx, buildParams) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AggsenderVerifierFlow_BuildCertificate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BuildCertificate' +type AggsenderVerifierFlow_BuildCertificate_Call struct { + *mock.Call +} + +// BuildCertificate is a helper method to define mock.On call +// - ctx context.Context +// - buildParams *types.CertificateBuildParams +func (_e *AggsenderVerifierFlow_Expecter) BuildCertificate(ctx interface{}, buildParams interface{}) *AggsenderVerifierFlow_BuildCertificate_Call { + return &AggsenderVerifierFlow_BuildCertificate_Call{Call: _e.mock.On("BuildCertificate", ctx, buildParams)} +} + +func (_c *AggsenderVerifierFlow_BuildCertificate_Call) Run(run func(ctx context.Context, buildParams *types.CertificateBuildParams)) *AggsenderVerifierFlow_BuildCertificate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*types.CertificateBuildParams)) + }) + return _c +} + +func (_c *AggsenderVerifierFlow_BuildCertificate_Call) Return(_a0 *agglayertypes.Certificate, _a1 error) *AggsenderVerifierFlow_BuildCertificate_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AggsenderVerifierFlow_BuildCertificate_Call) RunAndReturn(run func(context.Context, *types.CertificateBuildParams) (*agglayertypes.Certificate, error)) *AggsenderVerifierFlow_BuildCertificate_Call { + _c.Call.Return(run) + return _c +} + +// GenerateBuildParams provides a mock function with given fields: ctx, preParams +func (_m *AggsenderVerifierFlow) GenerateBuildParams(ctx context.Context, preParams *types.CertificatePreBuildParams) (*types.CertificateBuildParams, error) { + ret := _m.Called(ctx, preParams) + + if len(ret) == 0 { + panic("no return value specified for GenerateBuildParams") + } + + var r0 *types.CertificateBuildParams + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.CertificatePreBuildParams) (*types.CertificateBuildParams, error)); ok { + return rf(ctx, preParams) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.CertificatePreBuildParams) *types.CertificateBuildParams); ok { + r0 = rf(ctx, preParams) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.CertificateBuildParams) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.CertificatePreBuildParams) error); ok { + r1 = rf(ctx, preParams) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AggsenderVerifierFlow_GenerateBuildParams_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GenerateBuildParams' +type AggsenderVerifierFlow_GenerateBuildParams_Call struct { + *mock.Call +} + +// GenerateBuildParams is a helper method to define mock.On call +// - ctx context.Context +// - preParams *types.CertificatePreBuildParams +func (_e *AggsenderVerifierFlow_Expecter) GenerateBuildParams(ctx interface{}, preParams interface{}) *AggsenderVerifierFlow_GenerateBuildParams_Call { + return &AggsenderVerifierFlow_GenerateBuildParams_Call{Call: _e.mock.On("GenerateBuildParams", ctx, preParams)} +} + +func (_c *AggsenderVerifierFlow_GenerateBuildParams_Call) Run(run func(ctx context.Context, preParams *types.CertificatePreBuildParams)) *AggsenderVerifierFlow_GenerateBuildParams_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*types.CertificatePreBuildParams)) + }) + return _c +} + +func (_c *AggsenderVerifierFlow_GenerateBuildParams_Call) Return(_a0 *types.CertificateBuildParams, _a1 error) *AggsenderVerifierFlow_GenerateBuildParams_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AggsenderVerifierFlow_GenerateBuildParams_Call) RunAndReturn(run func(context.Context, *types.CertificatePreBuildParams) (*types.CertificateBuildParams, error)) *AggsenderVerifierFlow_GenerateBuildParams_Call { + _c.Call.Return(run) + return _c +} + +// VerifyCertificate provides a mock function with given fields: ctx, cert, lastBlockInCert, lastSettledBlock +func (_m *AggsenderVerifierFlow) VerifyCertificate(ctx context.Context, cert *agglayertypes.Certificate, lastBlockInCert uint64, lastSettledBlock uint64) error { + ret := _m.Called(ctx, cert, lastBlockInCert, lastSettledBlock) + + if len(ret) == 0 { + panic("no return value specified for VerifyCertificate") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *agglayertypes.Certificate, uint64, uint64) error); ok { + r0 = rf(ctx, cert, lastBlockInCert, lastSettledBlock) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// AggsenderVerifierFlow_VerifyCertificate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VerifyCertificate' +type AggsenderVerifierFlow_VerifyCertificate_Call struct { + *mock.Call +} + +// VerifyCertificate is a helper method to define mock.On call +// - ctx context.Context +// - cert *agglayertypes.Certificate +// - lastBlockInCert uint64 +// - lastSettledBlock uint64 +func (_e *AggsenderVerifierFlow_Expecter) VerifyCertificate(ctx interface{}, cert interface{}, lastBlockInCert interface{}, lastSettledBlock interface{}) *AggsenderVerifierFlow_VerifyCertificate_Call { + return &AggsenderVerifierFlow_VerifyCertificate_Call{Call: _e.mock.On("VerifyCertificate", ctx, cert, lastBlockInCert, lastSettledBlock)} +} + +func (_c *AggsenderVerifierFlow_VerifyCertificate_Call) Run(run func(ctx context.Context, cert *agglayertypes.Certificate, lastBlockInCert uint64, lastSettledBlock uint64)) *AggsenderVerifierFlow_VerifyCertificate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*agglayertypes.Certificate), args[2].(uint64), args[3].(uint64)) + }) + return _c +} + +func (_c *AggsenderVerifierFlow_VerifyCertificate_Call) Return(_a0 error) *AggsenderVerifierFlow_VerifyCertificate_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *AggsenderVerifierFlow_VerifyCertificate_Call) RunAndReturn(run func(context.Context, *agglayertypes.Certificate, uint64, uint64) error) *AggsenderVerifierFlow_VerifyCertificate_Call { + _c.Call.Return(run) + return _c +} + +// NewAggsenderVerifierFlow creates a new instance of AggsenderVerifierFlow. 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 NewAggsenderVerifierFlow(t interface { + mock.TestingT + Cleanup(func()) +}) *AggsenderVerifierFlow { + mock := &AggsenderVerifierFlow{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/aggsender/optimistic/mocks/mock_fep_contract_querier.go b/aggsender/mocks/mock_fep_contract_querier.go similarity index 100% rename from aggsender/optimistic/mocks/mock_fep_contract_querier.go rename to aggsender/mocks/mock_fep_contract_querier.go diff --git a/aggsender/mocks/mock_l1_info_tree_data_querier.go b/aggsender/mocks/mock_l1_info_tree_data_querier.go index 440e1c149..d2fb8843e 100644 --- a/aggsender/mocks/mock_l1_info_tree_data_querier.go +++ b/aggsender/mocks/mock_l1_info_tree_data_querier.go @@ -151,6 +151,65 @@ func (_c *L1InfoTreeDataQuerier_GetFinalizedL1InfoTreeData_Call) RunAndReturn(ru return _c } +// GetInfoByIndex provides a mock function with given fields: ctx, index +func (_m *L1InfoTreeDataQuerier) GetInfoByIndex(ctx context.Context, index uint32) (*l1infotreesync.L1InfoTreeLeaf, error) { + ret := _m.Called(ctx, index) + + if len(ret) == 0 { + panic("no return value specified for GetInfoByIndex") + } + + var r0 *l1infotreesync.L1InfoTreeLeaf + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint32) (*l1infotreesync.L1InfoTreeLeaf, error)); ok { + return rf(ctx, index) + } + if rf, ok := ret.Get(0).(func(context.Context, uint32) *l1infotreesync.L1InfoTreeLeaf); ok { + r0 = rf(ctx, index) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*l1infotreesync.L1InfoTreeLeaf) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint32) error); ok { + r1 = rf(ctx, index) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// L1InfoTreeDataQuerier_GetInfoByIndex_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetInfoByIndex' +type L1InfoTreeDataQuerier_GetInfoByIndex_Call struct { + *mock.Call +} + +// GetInfoByIndex is a helper method to define mock.On call +// - ctx context.Context +// - index uint32 +func (_e *L1InfoTreeDataQuerier_Expecter) GetInfoByIndex(ctx interface{}, index interface{}) *L1InfoTreeDataQuerier_GetInfoByIndex_Call { + return &L1InfoTreeDataQuerier_GetInfoByIndex_Call{Call: _e.mock.On("GetInfoByIndex", ctx, index)} +} + +func (_c *L1InfoTreeDataQuerier_GetInfoByIndex_Call) Run(run func(ctx context.Context, index uint32)) *L1InfoTreeDataQuerier_GetInfoByIndex_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint32)) + }) + return _c +} + +func (_c *L1InfoTreeDataQuerier_GetInfoByIndex_Call) Return(_a0 *l1infotreesync.L1InfoTreeLeaf, _a1 error) *L1InfoTreeDataQuerier_GetInfoByIndex_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *L1InfoTreeDataQuerier_GetInfoByIndex_Call) RunAndReturn(run func(context.Context, uint32) (*l1infotreesync.L1InfoTreeLeaf, error)) *L1InfoTreeDataQuerier_GetInfoByIndex_Call { + _c.Call.Return(run) + return _c +} + // GetL1InfoRootByLeafIndex provides a mock function with given fields: ctx, leafCount func (_m *L1InfoTreeDataQuerier) GetL1InfoRootByLeafIndex(ctx context.Context, leafCount uint32) (*types.Root, error) { ret := _m.Called(ctx, leafCount) diff --git a/aggsender/optimistic/mocks/mock_op_node_clienter.go b/aggsender/mocks/mock_op_node_clienter.go similarity index 100% rename from aggsender/optimistic/mocks/mock_op_node_clienter.go rename to aggsender/mocks/mock_op_node_clienter.go diff --git a/aggsender/optimistic/interfaces.go b/aggsender/optimistic/interfaces.go deleted file mode 100644 index f8a77d1e2..000000000 --- a/aggsender/optimistic/interfaces.go +++ /dev/null @@ -1,35 +0,0 @@ -package optimistic - -import ( - "math/big" - - optimistichash "github.com/agglayer/aggkit/aggsender/optimistic/optimistichash" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" -) - -// OpNodeClienter is an interface that defines the methods for interacting with the OpNode client. -type OpNodeClienter interface { - OutputAtBlockRoot(blockNum uint64) (common.Hash, error) -} - -// FEPContractQuerier is an interface that defines the methods for interacting with the FEP contract. -type FEPContractQuerier interface { - StartingBlockNumber(opts *bind.CallOpts) (*big.Int, error) - LatestBlockNumber(opts *bind.CallOpts) (*big.Int, error) - GetAggchainSigners(opts *bind.CallOpts) ([]common.Address, error) - OptimisticMode(opts *bind.CallOpts) (bool, error) - SelectedOpSuccinctConfigName(opts *bind.CallOpts) ([32]byte, error) - OpSuccinctConfigs(opts *bind.CallOpts, arg0 [32]byte) (struct { - AggregationVkey [32]byte - RangeVkeyCommitment [32]byte - RollupConfigHash [32]byte - }, error) -} - -// OptimisticAggregationProofPublicValuesQuerier defines an interface for -// querying aggregation proof public values in optimistic mode. -type OptimisticAggregationProofPublicValuesQuerier interface { - GetAggregationProofPublicValuesData(lastProvenBlock, requestedEndBlock uint64, - l1InfoTreeLeafHash common.Hash) (*optimistichash.AggregationProofPublicValues, error) -} diff --git a/aggsender/optimistic/mocks/mock_optimistic_aggregation_proof_public_values_querier.go b/aggsender/optimistic/mocks/mock_optimistic_aggregation_proof_public_values_querier.go deleted file mode 100644 index 1ec6a2050..000000000 --- a/aggsender/optimistic/mocks/mock_optimistic_aggregation_proof_public_values_querier.go +++ /dev/null @@ -1,97 +0,0 @@ -// Code generated by mockery. DO NOT EDIT. - -package mocks - -import ( - common "github.com/ethereum/go-ethereum/common" - mock "github.com/stretchr/testify/mock" - - optimistichash "github.com/agglayer/aggkit/aggsender/optimistic/optimistichash" -) - -// OptimisticAggregationProofPublicValuesQuerier is an autogenerated mock type for the OptimisticAggregationProofPublicValuesQuerier type -type OptimisticAggregationProofPublicValuesQuerier struct { - mock.Mock -} - -type OptimisticAggregationProofPublicValuesQuerier_Expecter struct { - mock *mock.Mock -} - -func (_m *OptimisticAggregationProofPublicValuesQuerier) EXPECT() *OptimisticAggregationProofPublicValuesQuerier_Expecter { - return &OptimisticAggregationProofPublicValuesQuerier_Expecter{mock: &_m.Mock} -} - -// GetAggregationProofPublicValuesData provides a mock function with given fields: lastProvenBlock, requestedEndBlock, l1InfoTreeLeafHash -func (_m *OptimisticAggregationProofPublicValuesQuerier) GetAggregationProofPublicValuesData(lastProvenBlock uint64, requestedEndBlock uint64, l1InfoTreeLeafHash common.Hash) (*optimistichash.AggregationProofPublicValues, error) { - ret := _m.Called(lastProvenBlock, requestedEndBlock, l1InfoTreeLeafHash) - - if len(ret) == 0 { - panic("no return value specified for GetAggregationProofPublicValuesData") - } - - var r0 *optimistichash.AggregationProofPublicValues - var r1 error - if rf, ok := ret.Get(0).(func(uint64, uint64, common.Hash) (*optimistichash.AggregationProofPublicValues, error)); ok { - return rf(lastProvenBlock, requestedEndBlock, l1InfoTreeLeafHash) - } - if rf, ok := ret.Get(0).(func(uint64, uint64, common.Hash) *optimistichash.AggregationProofPublicValues); ok { - r0 = rf(lastProvenBlock, requestedEndBlock, l1InfoTreeLeafHash) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*optimistichash.AggregationProofPublicValues) - } - } - - if rf, ok := ret.Get(1).(func(uint64, uint64, common.Hash) error); ok { - r1 = rf(lastProvenBlock, requestedEndBlock, l1InfoTreeLeafHash) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// OptimisticAggregationProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAggregationProofPublicValuesData' -type OptimisticAggregationProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call struct { - *mock.Call -} - -// GetAggregationProofPublicValuesData is a helper method to define mock.On call -// - lastProvenBlock uint64 -// - requestedEndBlock uint64 -// - l1InfoTreeLeafHash common.Hash -func (_e *OptimisticAggregationProofPublicValuesQuerier_Expecter) GetAggregationProofPublicValuesData(lastProvenBlock interface{}, requestedEndBlock interface{}, l1InfoTreeLeafHash interface{}) *OptimisticAggregationProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call { - return &OptimisticAggregationProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call{Call: _e.mock.On("GetAggregationProofPublicValuesData", lastProvenBlock, requestedEndBlock, l1InfoTreeLeafHash)} -} - -func (_c *OptimisticAggregationProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call) Run(run func(lastProvenBlock uint64, requestedEndBlock uint64, l1InfoTreeLeafHash common.Hash)) *OptimisticAggregationProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(uint64), args[1].(uint64), args[2].(common.Hash)) - }) - return _c -} - -func (_c *OptimisticAggregationProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call) Return(_a0 *optimistichash.AggregationProofPublicValues, _a1 error) *OptimisticAggregationProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *OptimisticAggregationProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call) RunAndReturn(run func(uint64, uint64, common.Hash) (*optimistichash.AggregationProofPublicValues, error)) *OptimisticAggregationProofPublicValuesQuerier_GetAggregationProofPublicValuesData_Call { - _c.Call.Return(run) - return _c -} - -// NewOptimisticAggregationProofPublicValuesQuerier creates a new instance of OptimisticAggregationProofPublicValuesQuerier. 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 NewOptimisticAggregationProofPublicValuesQuerier(t interface { - mock.TestingT - Cleanup(func()) -}) *OptimisticAggregationProofPublicValuesQuerier { - mock := &OptimisticAggregationProofPublicValuesQuerier{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/aggsender/optimistic/optimistic_aggegation_proof_public_values_query.go b/aggsender/optimistic/optimistic_aggegation_proof_public_values_query.go deleted file mode 100644 index 3a703f013..000000000 --- a/aggsender/optimistic/optimistic_aggegation_proof_public_values_query.go +++ /dev/null @@ -1,76 +0,0 @@ -package optimistic - -import ( - "fmt" - - "github.com/0xPolygon/cdk-contracts-tooling/contracts/fep/aggchain-ecdsa-multisig/aggchainfep" - optimistichash "github.com/agglayer/aggkit/aggsender/optimistic/optimistichash" - "github.com/agglayer/aggkit/opnode" - "github.com/ethereum/go-ethereum/common" -) - -// This is just to check in build time that the expected objects fulfill the interfaces -var ( - _ OpNodeClienter = (*opnode.OpNodeClient)(nil) - _ FEPContractQuerier = (*aggchainfep.Aggchainfep)(nil) - _ OptimisticAggregationProofPublicValuesQuerier = (*OptimisticAggregationProofPublicValuesQuery)(nil) -) - -// OptimisticAggregationProofPublicValuesQuery implements OptimisticAggregationProofPublicValuesQuerier -type OptimisticAggregationProofPublicValuesQuery struct { - aggchainFEPContract FEPContractQuerier - aggchainFEPAddr common.Address - opNodeClient OpNodeClienter - proverAddress common.Address -} - -// NewOptimisticAggregationProofPublicValuesQuery creates a new instance of OptimisticAggregationProofPublicValuesQuery -func NewOptimisticAggregationProofPublicValuesQuery( - aggchainFEPContract FEPContractQuerier, - aggchainFEPAddr common.Address, - opNodeClient OpNodeClienter, - proverAddress common.Address, -) *OptimisticAggregationProofPublicValuesQuery { - return &OptimisticAggregationProofPublicValuesQuery{ - aggchainFEPContract: aggchainFEPContract, - aggchainFEPAddr: aggchainFEPAddr, - opNodeClient: opNodeClient, - proverAddress: proverAddress, - } -} - -// GetAggregationProofPublicValuesData retrieves the AggregationProofPublicValue required for -// the optimistic aggregation proof -func (o *OptimisticAggregationProofPublicValuesQuery) GetAggregationProofPublicValuesData( - lastProvenBlock, requestedEndBlock uint64, - l1InfoTreeLeafHash common.Hash) (*optimistichash.AggregationProofPublicValues, error) { - l2PreRoot, err := o.opNodeClient.OutputAtBlockRoot(lastProvenBlock) - if err != nil { - return nil, fmt.Errorf("optimisticModeSignQuery. l2PreRoot opNodeClient.OutputAtBlockRoot(%d). Err: %w", - lastProvenBlock, err) - } - claimRoot, err := o.opNodeClient.OutputAtBlockRoot(requestedEndBlock) - if err != nil { - return nil, fmt.Errorf("optimisticModeSignQuery. claimRoot opNodeClient.OutputAtBlockRoot(%d). Err: %w", - requestedEndBlock, err) - } - configName, err := o.aggchainFEPContract.SelectedOpSuccinctConfigName(nil) - if err != nil { - return nil, fmt.Errorf("optimisticModeSignQuery. contract.SelectedOpSuccinctConfigName from contract %s. Err: %w", - o.aggchainFEPAddr, err) - } - opConfig, err := o.aggchainFEPContract.OpSuccinctConfigs(nil, configName) - if err != nil { - return nil, fmt.Errorf("optimisticModeSignQuery. contract.OpSuccinctConfigs from contract %s. Err: %w", - o.aggchainFEPAddr, err) - } - return &optimistichash.AggregationProofPublicValues{ - L1Head: l1InfoTreeLeafHash, - L2PreRoot: l2PreRoot, - ClaimRoot: claimRoot, - L2BlockNumber: requestedEndBlock, - RollupConfigHash: opConfig.RollupConfigHash, - MultiBlockVKey: opConfig.RangeVkeyCommitment, - ProverAddress: o.proverAddress, - }, nil -} diff --git a/aggsender/optimistic/optimistic_mode_query.go b/aggsender/optimistic/optimistic_mode_query.go index d7e8bcd99..d23c73331 100644 --- a/aggsender/optimistic/optimistic_mode_query.go +++ b/aggsender/optimistic/optimistic_mode_query.go @@ -4,12 +4,13 @@ import ( "fmt" "github.com/0xPolygon/cdk-contracts-tooling/contracts/fep/aggchain-ecdsa-multisig/aggchainfep" + "github.com/agglayer/aggkit/aggsender/types" aggkittypes "github.com/agglayer/aggkit/types" "github.com/ethereum/go-ethereum/common" ) type OptimisticModeQuerierFromContract struct { - aggchainFEPContract FEPContractQuerier + aggchainFEPContract types.FEPContractQuerier aggchainFEPAddr common.Address } diff --git a/aggsender/optimistic/optimistic_mode_query_test.go b/aggsender/optimistic/optimistic_mode_query_test.go index b9e1b213f..604ecc3b1 100644 --- a/aggsender/optimistic/optimistic_mode_query_test.go +++ b/aggsender/optimistic/optimistic_mode_query_test.go @@ -4,7 +4,7 @@ import ( "errors" "testing" - "github.com/agglayer/aggkit/aggsender/optimistic/mocks" + "github.com/agglayer/aggkit/aggsender/mocks" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" diff --git a/aggsender/optimistic/optimistic_sign.go b/aggsender/optimistic/optimistic_sign.go index c06219470..14304b487 100644 --- a/aggsender/optimistic/optimistic_sign.go +++ b/aggsender/optimistic/optimistic_sign.go @@ -5,6 +5,7 @@ import ( "fmt" optimistichash "github.com/agglayer/aggkit/aggsender/optimistic/optimistichash" + "github.com/agglayer/aggkit/aggsender/query" "github.com/agglayer/aggkit/aggsender/types" "github.com/agglayer/aggkit/bridgesync" "github.com/agglayer/aggkit/log" @@ -16,7 +17,7 @@ import ( // OptimisticSignatureCalculatorImpl implements the OptimisticSignatureCalculator interface. type OptimisticSignatureCalculatorImpl struct { - queryAggregationProofPublicValues OptimisticAggregationProofPublicValuesQuerier + queryAggregationProofPublicValues types.AggProofPublicValuesQuerier signer signertypes.HashSigner logger *log.Logger } @@ -25,7 +26,7 @@ type OptimisticSignatureCalculatorImpl struct { func NewOptimisticSignatureCalculatorImpl( ctx context.Context, logger *log.Logger, - aggchainFEPContract FEPContractQuerier, + aggchainFEPContract types.FEPContractQuerier, chainID uint64, cfg Config, ) (*OptimisticSignatureCalculatorImpl, error) { @@ -54,7 +55,7 @@ func NewOptimisticSignatureCalculatorImpl( trustedSignerAddr.Hex(), ) - query := NewOptimisticAggregationProofPublicValuesQuery( + query := query.NewAggProofPublicValuesQuery( aggchainFEPContract, cfg.SovereignRollupAddr, opnode.NewOpNodeClient(cfg.OpNodeURL), @@ -72,11 +73,11 @@ func NewOptimisticSignatureCalculatorImpl( // and matches the trusted signer address if required. func validateSignerAgainstContract( logger *log.Logger, - contract FEPContractQuerier, + contract types.FEPContractQuerier, signerAddr common.Address, requireKeyMatch bool, ) (common.Address, error) { - signers, err := contract.GetAggchainSigners(nil) + trustedSignerAddress, err := query.GetTrustedSignerAddr(contract) if err != nil { err = fmt.Errorf("[OPTIMISTIC] failed to fetch the aggchain signers from the AggchainFEP contract. Err: %w", err) if requireKeyMatch { @@ -85,26 +86,17 @@ func validateSignerAgainstContract( logger.Warn(err.Error()) } - if len(signers) < 1 { - err = fmt.Errorf("[OPTIMISTIC] there should be at least one aggchain signer in the AggchainFEP contract") - if requireKeyMatch { - return common.Address{}, err - } - logger.Warn(err.Error()) - } - - trustedSignerAddr := signers[0] - if err == nil && signerAddr != trustedSignerAddr { + if err == nil && signerAddr != trustedSignerAddress { err := fmt.Errorf("[OPTIMISTIC] "+ "configured trusted signer address (%s) differs from the one initialized on the AggchainFEP contract (%s)", - signerAddr.Hex(), trustedSignerAddr.Hex()) + signerAddr.Hex(), trustedSignerAddress.Hex()) if requireKeyMatch { - return trustedSignerAddr, err + return trustedSignerAddress, err } logger.Warn(err.Error()) } - return trustedSignerAddr, nil + return trustedSignerAddress, nil } // Sign calculate hash and sign it. diff --git a/aggsender/optimistic/optimistic_sign_test.go b/aggsender/optimistic/optimistic_sign_test.go index c928b3355..d05839cfe 100644 --- a/aggsender/optimistic/optimistic_sign_test.go +++ b/aggsender/optimistic/optimistic_sign_test.go @@ -7,14 +7,13 @@ import ( "fmt" "testing" - optimisticmocks "github.com/agglayer/aggkit/aggsender/optimistic/mocks" - optimistichash "github.com/agglayer/aggkit/aggsender/optimistic/optimistichash" + "github.com/agglayer/aggkit/aggsender/mocks" "github.com/agglayer/aggkit/aggsender/types" "github.com/agglayer/aggkit/bridgesync" "github.com/agglayer/aggkit/l1infotreesync" "github.com/agglayer/aggkit/log" "github.com/agglayer/go_signer/signer" - "github.com/agglayer/go_signer/signer/mocks" + signermocks "github.com/agglayer/go_signer/signer/mocks" signertypes "github.com/agglayer/go_signer/signer/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" @@ -39,13 +38,13 @@ func TestNewOptimisticSignatureCalculatorImpl(t *testing.T) { tests := []struct { name string - setupMock func(m *optimisticmocks.FEPContractQuerier) + setupMock func(m *mocks.FEPContractQuerier) cfg Config expectedErr string }{ { name: "happy path with signer in list", - setupMock: func(m *optimisticmocks.FEPContractQuerier) { + setupMock: func(m *mocks.FEPContractQuerier) { m.EXPECT(). GetAggchainSigners(mock.Anything). Return([]common.Address{signerAddr}, nil) @@ -57,7 +56,7 @@ func TestNewOptimisticSignatureCalculatorImpl(t *testing.T) { }, { name: "aggchainFEPContract returns error and RequireKeyMatchTrustedSequencer = true", - setupMock: func(m *optimisticmocks.FEPContractQuerier) { + setupMock: func(m *mocks.FEPContractQuerier) { m.EXPECT(). GetAggchainSigners(mock.Anything). Return(nil, errors.New("internal error")) @@ -70,7 +69,7 @@ func TestNewOptimisticSignatureCalculatorImpl(t *testing.T) { }, { name: "aggchainFEPContract returns empty list and RequireKeyMatchTrustedSequencer = true", - setupMock: func(m *optimisticmocks.FEPContractQuerier) { + setupMock: func(m *mocks.FEPContractQuerier) { m.EXPECT(). GetAggchainSigners(mock.Anything). Return([]common.Address{}, nil) @@ -79,11 +78,11 @@ func TestNewOptimisticSignatureCalculatorImpl(t *testing.T) { RequireKeyMatchTrustedSequencer: true, TrustedSequencerKey: signerKeyCfg, }, - expectedErr: "there should be at least one aggchain signer", + expectedErr: "should be at least one signer", }, { name: "signer differs from trusted sequencer address and RequireKeyMatchTrustedSequencer = false", - setupMock: func(m *optimisticmocks.FEPContractQuerier) { + setupMock: func(m *mocks.FEPContractQuerier) { m.EXPECT(). GetAggchainSigners(mock.Anything). Return([]common.Address{common.HexToAddress("0xdeadbeef"), signerAddr}, nil) @@ -99,7 +98,7 @@ func TestNewOptimisticSignatureCalculatorImpl(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - mockFEP := optimisticmocks.NewFEPContractQuerier(t) + mockFEP := mocks.NewFEPContractQuerier(t) tt.setupMock(mockFEP) impl, err := NewOptimisticSignatureCalculatorImpl( @@ -111,7 +110,7 @@ func TestNewOptimisticSignatureCalculatorImpl(t *testing.T) { ) if tt.expectedErr != "" { - require.Contains(t, err.Error(), tt.expectedErr) + require.ErrorContains(t, err, tt.expectedErr) require.Nil(t, impl) } else { require.NoError(t, err) @@ -130,7 +129,7 @@ func TestOptimisticSignatureCalculatorImpl_Sign(t *testing.T) { PreviousBlockHash: common.HexToHash("0xabc"), }, } - aggProof := &optimistichash.AggregationProofPublicValues{ + aggProof := &types.AggregationProofPublicValues{ L1Head: common.HexToHash("0x123"), L2PreRoot: common.HexToHash("0x456"), ClaimRoot: common.HexToHash("0x789"), @@ -147,7 +146,7 @@ func TestOptimisticSignatureCalculatorImpl_Sign(t *testing.T) { testCases := []struct { name string - mockQueryReturn *optimistichash.AggregationProofPublicValues + mockQueryReturn *types.AggregationProofPublicValues mockQueryError error mockSignerReturn []byte mockSignerError error @@ -190,8 +189,8 @@ func TestOptimisticSignatureCalculatorImpl_Sign(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { realLogger := log.WithFields("module", "test_logger") // Replace mockLogger with a real logger - mockSigner := mocks.NewHashSigner(t) - mockQuery := optimisticmocks.NewOptimisticAggregationProofPublicValuesQuerier(t) + mockSigner := signermocks.NewHashSigner(t) + mockQuery := mocks.NewAggProofPublicValuesQuerier(t) calculator := &OptimisticSignatureCalculatorImpl{ queryAggregationProofPublicValues: mockQuery, signer: mockSigner, diff --git a/aggsender/optimistic/optimistichash/calculate_hash_test.go b/aggsender/optimistic/optimistichash/calculate_hash_test.go index 91ff38a3a..9617a6853 100644 --- a/aggsender/optimistic/optimistichash/calculate_hash_test.go +++ b/aggsender/optimistic/optimistichash/calculate_hash_test.go @@ -3,12 +3,13 @@ package optimistichash import ( "testing" + "github.com/agglayer/aggkit/aggsender/types" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" ) func TestSignatureOptimisticData_Hash(t *testing.T) { - aggregationProofPublicValues := &AggregationProofPublicValues{ + aggregationProofPublicValues := &types.AggregationProofPublicValues{ L1Head: common.HexToHash("0x502cbcfe9aa2a7c4fbd1fcf81ce71be6f1a79a904b31a2b1cf27e5179f970890"), L2PreRoot: common.HexToHash("0xb744b55eba3192d84812aa068e6db062cdccce9364d77515dee1ac3ac9e4a175"), ClaimRoot: common.HexToHash("0x98280091281a3d554b53537892f86cbb3a38ff83528c39ac0cf52be251269a7d"), diff --git a/aggsender/query/agg_proof_public_values_query.go b/aggsender/query/agg_proof_public_values_query.go new file mode 100644 index 000000000..f5b3e8bfc --- /dev/null +++ b/aggsender/query/agg_proof_public_values_query.go @@ -0,0 +1,106 @@ +package query + +import ( + "errors" + "fmt" + + "github.com/0xPolygon/cdk-contracts-tooling/contracts/fep/aggchain-ecdsa-multisig/aggchainfep" + "github.com/agglayer/aggkit/aggsender/types" + aggkitcommon "github.com/agglayer/aggkit/common" + "github.com/agglayer/aggkit/opnode" + "github.com/ethereum/go-ethereum/common" +) + +// This is just to check in build time that the expected objects fulfill the interfaces +var ( + _ types.OpNodeClienter = (*opnode.OpNodeClient)(nil) + _ types.FEPContractQuerier = (*aggchainfep.Aggchainfep)(nil) + _ types.AggProofPublicValuesQuerier = (*AggProofPublicValuesQuery)(nil) + + errNoSigners = errors.New("no signers found in the AggchainFEP contract. There should be at least one signer") +) + +// AggProofPublicValuesQuery implements AggProofPublicValuesQuerier +type AggProofPublicValuesQuery struct { + aggchainFEPContract types.FEPContractQuerier + aggchainFEPAddr common.Address + opNodeClient types.OpNodeClienter + proverAddress common.Address +} + +// NewAggProofPublicValuesQuery creates a new instance of AggProofPublicValuesQuery +func NewAggProofPublicValuesQuery( + aggchainFEPContract types.FEPContractQuerier, + aggchainFEPAddr common.Address, + opNodeClient types.OpNodeClienter, + proverAddress common.Address, +) *AggProofPublicValuesQuery { + return &AggProofPublicValuesQuery{ + aggchainFEPContract: aggchainFEPContract, + aggchainFEPAddr: aggchainFEPAddr, + opNodeClient: opNodeClient, + proverAddress: proverAddress, + } +} + +// GetAggregationProofPublicValuesData retrieves the AggregationProofPublicValue required for +// the optimistic aggregation proof +func (a *AggProofPublicValuesQuery) GetAggregationProofPublicValuesData( + lastProvenBlock, requestedEndBlock uint64, + l1InfoTreeLeafHash common.Hash) (*types.AggregationProofPublicValues, error) { + l2PreRoot, err := a.opNodeClient.OutputAtBlockRoot(lastProvenBlock) + if err != nil { + return nil, fmt.Errorf("opAggProofPublicValuesQuery. l2PreRoot opNodeClient.OutputAtBlockRoot(%d). Err: %w", + lastProvenBlock, err) + } + claimRoot, err := a.opNodeClient.OutputAtBlockRoot(requestedEndBlock) + if err != nil { + return nil, fmt.Errorf("opAggProofPublicValuesQuery. claimRoot opNodeClient.OutputAtBlockRoot(%d). Err: %w", + requestedEndBlock, err) + } + configName, err := a.aggchainFEPContract.SelectedOpSuccinctConfigName(nil) + if err != nil { + return nil, fmt.Errorf("opAggProofPublicValuesQuery. contract.SelectedOpSuccinctConfigName from contract %s. Err: %w", + a.aggchainFEPAddr, err) + } + opConfig, err := a.aggchainFEPContract.OpSuccinctConfigs(nil, configName) + if err != nil { + return nil, fmt.Errorf("opAggProofPublicValuesQuery. contract.OpSuccinctConfigs from contract %s. Err: %w", + a.aggchainFEPAddr, err) + } + + trustedSignerAddr := a.proverAddress + if trustedSignerAddr == aggkitcommon.ZeroAddress { + // if proverAddress is zero, get the trusted signer from the contract + trustedSignerAddr, err = GetTrustedSignerAddr(a.aggchainFEPContract) + if err != nil { + return nil, fmt.Errorf("opAggProofPublicValuesQuery. trustedSignerAddr from contract %s. Err: %w", + a.aggchainFEPAddr, err) + } + } + + return &types.AggregationProofPublicValues{ + L1Head: l1InfoTreeLeafHash, + L2PreRoot: l2PreRoot, + ClaimRoot: claimRoot, + L2BlockNumber: requestedEndBlock, + RollupConfigHash: opConfig.RollupConfigHash, + MultiBlockVKey: opConfig.RangeVkeyCommitment, + ProverAddress: trustedSignerAddr, + }, nil +} + +// GetTrustedSignerAddr retrieves the trusted signer address from the AggchainFEP contract +func GetTrustedSignerAddr(aggchainFEPContract types.FEPContractQuerier) (common.Address, error) { + signers, err := aggchainFEPContract.GetAggchainSigners(nil) + if err != nil { + return aggkitcommon.ZeroAddress, + fmt.Errorf("failed to get aggchain signers from AggchainFEP contract. Err: %w", err) + } + + if len(signers) < 1 { + return aggkitcommon.ZeroAddress, errNoSigners + } + + return signers[0], nil +} diff --git a/aggsender/optimistic/optimistic_aggegation_proof_public_values_query_test.go b/aggsender/query/agg_proof_public_values_query_test.go similarity index 65% rename from aggsender/optimistic/optimistic_aggegation_proof_public_values_query_test.go rename to aggsender/query/agg_proof_public_values_query_test.go index aa5ea04b0..d3e5c7a85 100644 --- a/aggsender/optimistic/optimistic_aggegation_proof_public_values_query_test.go +++ b/aggsender/query/agg_proof_public_values_query_test.go @@ -1,10 +1,10 @@ -package optimistic +package query import ( "errors" "testing" - "github.com/agglayer/aggkit/aggsender/optimistic/mocks" + "github.com/agglayer/aggkit/aggsender/mocks" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" @@ -16,7 +16,7 @@ func TestGetAggregationProofPublicValuesData_Success(t *testing.T) { contractAddr := common.HexToAddress("0x1234567890123456789012345678901234567890") proverAddress := common.HexToAddress("0x0987654321098765432109876543210987654321") - sut := NewOptimisticAggregationProofPublicValuesQuery(mockFEPContract, contractAddr, mockOPNodeClient, proverAddress) + sut := NewAggProofPublicValuesQuery(mockFEPContract, contractAddr, mockOPNodeClient, proverAddress) lastProvenBlock := uint64(1) requestedEndBlock := uint64(2) @@ -63,7 +63,7 @@ func TestGetAggregationProofPublicValuesData_Failure(t *testing.T) { t.Run("opNodeClient.OutputAtBlockRoot error on l2PreRoot", func(t *testing.T) { mockFEPContract := mocks.NewFEPContractQuerier(t) mockOPNodeClient := mocks.NewOpNodeClienter(t) - sut := NewOptimisticAggregationProofPublicValuesQuery(mockFEPContract, contractAddr, mockOPNodeClient, proverAddress) + sut := NewAggProofPublicValuesQuery(mockFEPContract, contractAddr, mockOPNodeClient, proverAddress) mockOPNodeClient.EXPECT().OutputAtBlockRoot(lastProvenBlock).Return(common.Hash{}, errors.New("mock error")).Once() @@ -75,7 +75,7 @@ func TestGetAggregationProofPublicValuesData_Failure(t *testing.T) { t.Run("opNodeClient.OutputAtBlockRoot error on claimRoot", func(t *testing.T) { mockFEPContract := mocks.NewFEPContractQuerier(t) mockOPNodeClient := mocks.NewOpNodeClienter(t) - sut := NewOptimisticAggregationProofPublicValuesQuery(mockFEPContract, contractAddr, mockOPNodeClient, proverAddress) + sut := NewAggProofPublicValuesQuery(mockFEPContract, contractAddr, mockOPNodeClient, proverAddress) mockOPNodeClient.EXPECT().OutputAtBlockRoot(lastProvenBlock).Return(common.Hash{}, nil) mockOPNodeClient.EXPECT().OutputAtBlockRoot(requestedEndBlock).Return(common.Hash{}, errors.New("mock error")) @@ -89,7 +89,7 @@ func TestGetAggregationProofPublicValuesData_Failure(t *testing.T) { t.Run("opNodeClient.OutputAtBlockRoot error on contract.SelectedOpSuccinctConfigName", func(t *testing.T) { mockFEPContract := mocks.NewFEPContractQuerier(t) mockOPNodeClient := mocks.NewOpNodeClienter(t) - sut := NewOptimisticAggregationProofPublicValuesQuery(mockFEPContract, contractAddr, mockOPNodeClient, proverAddress) + sut := NewAggProofPublicValuesQuery(mockFEPContract, contractAddr, mockOPNodeClient, proverAddress) mockOPNodeClient.EXPECT().OutputAtBlockRoot(lastProvenBlock).Return(common.Hash{}, nil) mockOPNodeClient.EXPECT().OutputAtBlockRoot(requestedEndBlock).Return(common.Hash{}, nil) @@ -104,7 +104,7 @@ func TestGetAggregationProofPublicValuesData_Failure(t *testing.T) { t.Run("opNodeClient.OutputAtBlockRoot error on contract.OpSuccinctConfigs", func(t *testing.T) { mockFEPContract := mocks.NewFEPContractQuerier(t) mockOPNodeClient := mocks.NewOpNodeClienter(t) - sut := NewOptimisticAggregationProofPublicValuesQuery(mockFEPContract, contractAddr, mockOPNodeClient, proverAddress) + sut := NewAggProofPublicValuesQuery(mockFEPContract, contractAddr, mockOPNodeClient, proverAddress) mockOPNodeClient.EXPECT().OutputAtBlockRoot(lastProvenBlock).Return(common.Hash{}, nil) mockOPNodeClient.EXPECT().OutputAtBlockRoot(requestedEndBlock).Return(common.Hash{}, nil) @@ -120,3 +120,47 @@ func TestGetAggregationProofPublicValuesData_Failure(t *testing.T) { assert.Nil(t, result) }) } + +func TestGetAggregationProofPublicValuesData_GetTrustedSequencerFromContract(t *testing.T) { + mockFEPContract := mocks.NewFEPContractQuerier(t) + mockOPNodeClient := mocks.NewOpNodeClienter(t) + + contractAddr := common.HexToAddress("0x1234567890123456789012345678901234567890") + sut := NewAggProofPublicValuesQuery(mockFEPContract, contractAddr, mockOPNodeClient, common.Address{}) + + lastProvenBlock := uint64(1) + requestedEndBlock := uint64(2) + l1InfoTreeLeafHash := common.HexToHash("0xbeef") + + expectedL2PreRoot := common.HexToHash("0xdeadbeef") + expectedClaimRoot := common.HexToHash("0xcafebabe") + expectedRollupConfigHash := [32]byte{0x01} + expectedMultiBlockVKey := [32]byte{0x02} + expectedTrustedSequencer := common.HexToAddress("0xabcdefabcdefabcdefabcdefabcdefabcdefabcd") + + mockOPNodeClient.EXPECT().OutputAtBlockRoot(lastProvenBlock).Return(expectedL2PreRoot, nil) + mockOPNodeClient.EXPECT().OutputAtBlockRoot(requestedEndBlock).Return(expectedClaimRoot, nil) + mockFEPContract.EXPECT().SelectedOpSuccinctConfigName((*bind.CallOpts)(nil)).Return([32]byte{0x00}, nil).Once() + mockFEPContract.EXPECT().OpSuccinctConfigs((*bind.CallOpts)(nil), [32]byte{0x00}).Return(struct { + AggregationVkey [32]byte + RangeVkeyCommitment [32]byte + RollupConfigHash [32]byte + }{ + AggregationVkey: [32]byte{0x01}, + RangeVkeyCommitment: [32]byte{0x02}, + RollupConfigHash: expectedRollupConfigHash, + }, nil).Once() + mockFEPContract.EXPECT().GetAggchainSigners((*bind.CallOpts)(nil)).Return([]common.Address{expectedTrustedSequencer}, nil) + + result, err := sut.GetAggregationProofPublicValuesData(lastProvenBlock, requestedEndBlock, l1InfoTreeLeafHash) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, l1InfoTreeLeafHash, result.L1Head) + assert.Equal(t, expectedL2PreRoot, result.L2PreRoot) + assert.Equal(t, expectedClaimRoot, result.ClaimRoot) + assert.Equal(t, requestedEndBlock, result.L2BlockNumber) + assert.Equal(t, expectedRollupConfigHash[:], result.RollupConfigHash.Bytes()) + assert.Equal(t, expectedMultiBlockVKey[:], result.MultiBlockVKey.Bytes()) + assert.Equal(t, expectedTrustedSequencer, result.ProverAddress) +} diff --git a/aggsender/query/aggchain_fep_rollup_query.go b/aggsender/query/aggchain_fep_rollup_query.go index 59d7bda86..a670342f3 100644 --- a/aggsender/query/aggchain_fep_rollup_query.go +++ b/aggsender/query/aggchain_fep_rollup_query.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/0xPolygon/cdk-contracts-tooling/contracts/fep/aggchain-ecdsa-multisig/aggchainfep" - "github.com/agglayer/aggkit/aggsender/optimistic" "github.com/agglayer/aggkit/aggsender/types" aggkitcommon "github.com/agglayer/aggkit/common" "github.com/agglayer/aggkit/log" @@ -32,6 +31,12 @@ func (n *noOpAggchainFEPRollupQuerier) IsFEP() bool { return false } +func (n *noOpAggchainFEPRollupQuerier) GetAggregationProofPublicValuesData( + lastProvenBlock, requestedEndBlock uint64, + l1InfoTreeLeafHash common.Hash) (*types.AggregationProofPublicValues, error) { + return &types.AggregationProofPublicValues{}, nil +} + var _ types.AggchainFEPRollupQuerier = (*aggchainFEPRollupQuerier)(nil) // aggchainFEPRollupQuerier encapsulates the necessary information and interfaces required to query @@ -39,7 +44,7 @@ var _ types.AggchainFEPRollupQuerier = (*aggchainFEPRollupQuerier)(nil) type aggchainFEPRollupQuerier struct { startL2BlockNum uint64 aggchainFEPAddr common.Address - aggchainFEPCaller optimistic.FEPContractQuerier + aggchainFEPCaller types.FEPContractQuerier } // NewAggchainFEPQuerier creates a new AggchainFEP querier instance for interacting with the AggchainFEP contract. @@ -83,7 +88,8 @@ func NewAggchainFEPQuerier( func newAggchainFEPQuerier( logger *log.Logger, aggchainFEPAddr common.Address, - aggchainFEPCaller optimistic.FEPContractQuerier) (types.AggchainFEPRollupQuerier, error) { + aggchainFEPCaller types.FEPContractQuerier, +) (types.AggchainFEPRollupQuerier, error) { startL2Block, err := aggchainFEPCaller.StartingBlockNumber(nil) if err != nil { return nil, fmt.Errorf("aggchainProverFlow - error AggChainFEPContract.StartingBlockNumber (%s): %w", diff --git a/aggsender/query/aggchain_fep_rollup_query_test.go b/aggsender/query/aggchain_fep_rollup_query_test.go index 0b2a9e021..e4c7648cf 100644 --- a/aggsender/query/aggchain_fep_rollup_query_test.go +++ b/aggsender/query/aggchain_fep_rollup_query_test.go @@ -5,7 +5,7 @@ import ( "math/big" "testing" - optimisticmocks "github.com/agglayer/aggkit/aggsender/optimistic/mocks" + "github.com/agglayer/aggkit/aggsender/mocks" "github.com/agglayer/aggkit/aggsender/types" aggkitcommon "github.com/agglayer/aggkit/common" "github.com/agglayer/aggkit/log" @@ -54,7 +54,7 @@ func TestAggchainFEPRollupQuerier(t *testing.T) { t.Run("aggchain FEP caller returns error", func(t *testing.T) { t.Parallel() - mockCaller := optimisticmocks.NewFEPContractQuerier(t) + mockCaller := mocks.NewFEPContractQuerier(t) mockCaller.EXPECT().StartingBlockNumber((*bind.CallOpts)(nil)).Return(nil, errors.New("mock error")).Once() _, err := newAggchainFEPQuerier( @@ -69,7 +69,7 @@ func TestAggchainFEPRollupQuerier(t *testing.T) { t.Run("aggchain FEP caller returns valid starting block", func(t *testing.T) { t.Parallel() - mockCaller := optimisticmocks.NewFEPContractQuerier(t) + mockCaller := mocks.NewFEPContractQuerier(t) startingBlock := big.NewInt(1000) mockCaller.EXPECT().StartingBlockNumber((*bind.CallOpts)(nil)).Return(startingBlock, nil).Once() @@ -87,7 +87,7 @@ func TestAggchainFEPRollupQuerier(t *testing.T) { t.Run("aggchain FEP caller returns error on last settled block", func(t *testing.T) { t.Parallel() - mockCaller := optimisticmocks.NewFEPContractQuerier(t) + mockCaller := mocks.NewFEPContractQuerier(t) mockCaller.EXPECT().StartingBlockNumber((*bind.CallOpts)(nil)).Return(big.NewInt(1000), nil).Once() mockCaller.EXPECT().LatestBlockNumber((*bind.CallOpts)(nil)).Return(nil, errors.New("mock error")).Once() @@ -107,7 +107,7 @@ func TestAggchainFEPRollupQuerier(t *testing.T) { t.Run("aggchain FEP caller returns valid last settled block", func(t *testing.T) { t.Parallel() - mockCaller := optimisticmocks.NewFEPContractQuerier(t) + mockCaller := mocks.NewFEPContractQuerier(t) startingBlock := big.NewInt(1000) lastSettledBlock := big.NewInt(2000) diff --git a/aggsender/query/l1info_tree_data_query.go b/aggsender/query/l1info_tree_data_query.go index d738e27c7..9dd93fe2e 100644 --- a/aggsender/query/l1info_tree_data_query.go +++ b/aggsender/query/l1info_tree_data_query.go @@ -177,3 +177,16 @@ func (l *L1InfoTreeDataQuerier) getLatestProcessedFinalizedBlock(ctx context.Con "Expected hash: %s, got: %s", lastProcessedBlockNum, lastFinalizedL1Block.Hash().String(), lastProcessedBlockHash.String()) } + +// GetInfoByIndex returns the L1 Info tree leaf for the given index +func (l *L1InfoTreeDataQuerier) GetInfoByIndex( + ctx context.Context, index uint32) (*l1infotreesync.L1InfoTreeLeaf, error) { + info, err := l.l1InfoTreeSyncer.GetInfoByIndex(ctx, index) + if err != nil { + return nil, fmt.Errorf("error getting L1 Info tree leaf by index %d: %w", index, err) + } + if info == nil { + return nil, fmt.Errorf("no L1 Info tree leaf found for index %d", index) + } + return info, nil +} diff --git a/aggsender/optimistic/optimistichash/calculate_hash_aggregation_proof_public_values.go b/aggsender/types/aggregation_proof_public_values.go similarity index 98% rename from aggsender/optimistic/optimistichash/calculate_hash_aggregation_proof_public_values.go rename to aggsender/types/aggregation_proof_public_values.go index 851f9822c..4c3f5e324 100644 --- a/aggsender/optimistic/optimistichash/calculate_hash_aggregation_proof_public_values.go +++ b/aggsender/types/aggregation_proof_public_values.go @@ -1,4 +1,4 @@ -package optimistichash +package types import ( "crypto/sha256" diff --git a/aggsender/optimistic/optimistichash/calculate_hash_aggregation_proof_public_values_test.go b/aggsender/types/aggregation_proof_public_values_test.go similarity index 98% rename from aggsender/optimistic/optimistichash/calculate_hash_aggregation_proof_public_values_test.go rename to aggsender/types/aggregation_proof_public_values_test.go index 4064ff348..261c2a715 100644 --- a/aggsender/optimistic/optimistichash/calculate_hash_aggregation_proof_public_values_test.go +++ b/aggsender/types/aggregation_proof_public_values_test.go @@ -1,4 +1,4 @@ -package optimistichash +package types import ( "testing" diff --git a/aggsender/types/interfaces.go b/aggsender/types/interfaces.go index 62f49cf50..40fb44b85 100644 --- a/aggsender/types/interfaces.go +++ b/aggsender/types/interfaces.go @@ -18,9 +18,9 @@ import ( "github.com/ethereum/go-ethereum/common" ) -// AggsenderFlow is an interface that defines the methods to manage the flow of the AggSender +// AggsenderBuilderFlow is an interface that defines the methods to manage the flow of the AggSender // based on the different prover types -type AggsenderFlow interface { +type AggsenderBuilderFlow interface { // CheckInitialStatus checks the initial status for the flow it's ok CheckInitialStatus(ctx context.Context) error // GetCertificateBuildParams returns the parameters to build a certificate @@ -37,6 +37,22 @@ type AggsenderFlow interface { Signer() signertypes.Signer } +// AggsenderVerifierFlow is an interface that defines the methods to verify the certificate +type AggsenderVerifierFlow interface { + // BuildCertificate builds a certificate based on the buildParams + BuildCertificate(ctx context.Context, + buildParams *CertificateBuildParams) (*agglayertypes.Certificate, error) + // GenerateBuildParams generates the build parameters based on the preParams + GenerateBuildParams(ctx context.Context, + preParams *CertificatePreBuildParams) (*CertificateBuildParams, error) + // VerifyCertificate verifies the certificate field for the given certificate + VerifyCertificate( + ctx context.Context, + cert *agglayertypes.Certificate, + lastBlockInCert uint64, + lastSettledBlock uint64) error +} + type AggsenderFlowBaser interface { GetCertificateBuildParamsInternal( ctx context.Context, certType CertificateType) (*CertificateBuildParams, error) @@ -129,6 +145,9 @@ type L1InfoTreeDataQuerier interface { // GetL1InfoRootByLeafIndex returns the L1 Info tree root for the given leaf index GetL1InfoRootByLeafIndex(ctx context.Context, leafCount uint32) (*treetypes.Root, error) + + // GetInfoByIndex returns the L1 Info tree leaf for the given index + GetInfoByIndex(ctx context.Context, index uint32) (*l1infotreesync.L1InfoTreeLeaf, error) } // GERQuerier is an interface defining functions that an GERQuerier should implement @@ -301,3 +320,29 @@ type CertificateQuerier interface { CalculateCertificateType(cert *agglayertypes.Certificate, certToBlock uint64) CertificateType CalculateCertificateTypeFromToBlock(certToBlock uint64) CertificateType } + +// FEPContractQuerier is an interface that defines the methods for interacting with the FEP contract. +type FEPContractQuerier interface { + StartingBlockNumber(opts *bind.CallOpts) (*big.Int, error) + LatestBlockNumber(opts *bind.CallOpts) (*big.Int, error) + GetAggchainSigners(opts *bind.CallOpts) ([]common.Address, error) + OptimisticMode(opts *bind.CallOpts) (bool, error) + SelectedOpSuccinctConfigName(opts *bind.CallOpts) ([32]byte, error) + OpSuccinctConfigs(opts *bind.CallOpts, arg0 [32]byte) (struct { + AggregationVkey [32]byte + RangeVkeyCommitment [32]byte + RollupConfigHash [32]byte + }, error) +} + +// OpNodeClienter is an interface that defines the methods for interacting with the OpNode client. +type OpNodeClienter interface { + OutputAtBlockRoot(blockNum uint64) (common.Hash, error) +} + +// AggProofPublicValuesQuerier defines an interface for +// querying aggregation proof public values. +type AggProofPublicValuesQuerier interface { + GetAggregationProofPublicValuesData(lastProvenBlock, requestedEndBlock uint64, + l1InfoTreeLeafHash common.Hash) (*AggregationProofPublicValues, error) +} diff --git a/aggsender/validator/config.go b/aggsender/validator/config.go index 628c0965f..412b00bc9 100644 --- a/aggsender/validator/config.go +++ b/aggsender/validator/config.go @@ -58,6 +58,8 @@ type FEPConfig struct { // RequireNoBlockGap is true if the AggSender should not accept a gap between // lastBlock from lastCertificate and first block of FEP RequireNoBlockGap bool `mapstructure:"RequireNoBlockGap"` + // OpNodeURL is the URL of the OP Node to query for op related data + OpNodeURL string `mapstructure:"OpNodeURL"` } type LerQuerierConfig struct { diff --git a/aggsender/validator/validate_certificate.go b/aggsender/validator/validate_certificate.go index 59dfef47f..fb7e44c5b 100644 --- a/aggsender/validator/validate_certificate.go +++ b/aggsender/validator/validate_certificate.go @@ -19,13 +19,6 @@ var ( ErrMetadataNotCompatible = errors.New("aggsender-validator metadata not compatible with the current version") ) -type FlowInterface interface { - GenerateBuildParams(ctx context.Context, - preParams *types.CertificatePreBuildParams) (*types.CertificateBuildParams, error) - BuildCertificate(ctx context.Context, - buildParams *types.CertificateBuildParams) (*agglayertypes.Certificate, error) -} - type L1InfoTreeRootByLeafQuerier interface { // GetL1InfoRootByLeafIndex returns the L1 Info tree root for the given leaf index GetL1InfoRootByLeafIndex(ctx context.Context, leafCount uint32) (*treetypes.Root, error) @@ -34,14 +27,14 @@ type L1InfoTreeRootByLeafQuerier interface { // CertificateValidator is a object to validate a certificate type CertificateValidator struct { log aggkitcommon.Logger - flow FlowInterface + flow types.AggsenderVerifierFlow l1InfoTreeDataQuerier L1InfoTreeRootByLeafQuerier certQuerier types.CertificateQuerier lerQuerier types.LERQuerier } func NewAggsenderValidator(logger aggkitcommon.Logger, - flow FlowInterface, + flow types.AggsenderVerifierFlow, l1InfoTreeDataQuerier L1InfoTreeRootByLeafQuerier, certQuerier types.CertificateQuerier, lerQuerier types.LERQuerier) *CertificateValidator { @@ -119,6 +112,15 @@ func (a *CertificateValidator) ValidateCertificate(ctx context.Context, params t return fmt.Errorf("failed to verify claim proofs: %w", err) } + // Verify AggchainData specific to each flow + if err := a.flow.VerifyCertificate( + ctx, + params.Certificate, + params.LastL2BlockInCert, + previousCertificateToBlock); err != nil { + return fmt.Errorf("failed to verify certificate in flow: %w", err) + } + return nil } diff --git a/aggsender/validator/validate_certificate_test.go b/aggsender/validator/validate_certificate_test.go index 50715b195..0af4f1580 100644 --- a/aggsender/validator/validate_certificate_test.go +++ b/aggsender/validator/validate_certificate_test.go @@ -197,6 +197,36 @@ func TestValidateCertificate(t *testing.T) { }) require.ErrorContains(t, err, "certificate not equal to expected") }) + + t.Run("fails VerifyCertificate in flow", func(t *testing.T) { + testData := newTestDataCertificateValidator(t) + certificate := &agglayertypes.Certificate{ + Height: 0, + L1InfoTreeLeafCount: 10, + PrevLocalExitRoot: types.EmptyLER, + } + + testData.mockCertQuerier.EXPECT().GetNewCertificateToBlock(testData.ctx, mock.Anything).Return(uint64(10), nil) + testData.mockLERQuerier.EXPECT().GetLastLocalExitRoot().Return(types.EmptyLER, nil) + testData.mockCertQuerier.EXPECT().CalculateCertificateType(mock.Anything, uint64(10)).Return(types.CertificateTypePP) + testData.mockL1InfoTreeQuerier.EXPECT(). + GetL1InfoRootByLeafIndex(testData.ctx, uint32(9)).Return(&testTreeRootIndex9, nil).Maybe() + testData.mockFlow.EXPECT(). + GenerateBuildParams(testData.ctx, mock.Anything).Return(&types.CertificateBuildParams{ + L1InfoTreeRootFromWhichToProve: common.HexToHash("0x123"), + }, nil) + testData.mockFlow.EXPECT(). + BuildCertificate(testData.ctx, mock.Anything).Return(certificate, nil) + testData.mockFlow.EXPECT(). + VerifyCertificate(testData.ctx, certificate, uint64(10), uint64(0)).Return(errGenericForTesting) + + err := testData.sut.ValidateCertificate(testData.ctx, types.VerifyIncomingRequest{ + Certificate: certificate, + PreviousCertificate: nil, + LastL2BlockInCert: 10, + }) + require.ErrorContains(t, err, "failed to verify certificate in flow") + }) } func TestCheckContigousCertificates(t *testing.T) { @@ -308,7 +338,7 @@ func TestCompareCertificates(t *testing.T) { type testDataCertificateValidator struct { ctx context.Context logger *log.Logger - mockFlow *mocks.AggsenderFlow + mockFlow *mocks.AggsenderVerifierFlow mockL1InfoTreeQuerier *mocks.L1InfoTreeDataQuerier mockCertQuerier *mocks.CertificateQuerier mockLERQuerier *mocks.LERQuerier @@ -318,7 +348,7 @@ type testDataCertificateValidator struct { func newTestDataCertificateValidator(t *testing.T) testDataCertificateValidator { t.Helper() mockLogger := log.WithFields("test", "TestValidateCertificate") - mockFlow := mocks.NewAggsenderFlow(t) + mockFlow := mocks.NewAggsenderVerifierFlow(t) mockL1InfoTreeQuerier := mocks.NewL1InfoTreeDataQuerier(t) mockCertQuerier := mocks.NewCertificateQuerier(t) lerQuerier := mocks.NewLERQuerier(t) diff --git a/cmd/run.go b/cmd/run.go index 93916d48c..2dc485bac 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -23,7 +23,6 @@ import ( "github.com/agglayer/aggkit/aggsender" aggsendercfg "github.com/agglayer/aggkit/aggsender/config" "github.com/agglayer/aggkit/aggsender/flows" - "github.com/agglayer/aggkit/aggsender/optimistic" "github.com/agglayer/aggkit/aggsender/prover" "github.com/agglayer/aggkit/aggsender/query" aggsendertypes "github.com/agglayer/aggkit/aggsender/types" @@ -261,72 +260,6 @@ func createAggSenderValidator(ctx context.Context, return nil, fmt.Errorf("failed to create agglayer grpc client: %w", err) } - var ( - flow validator.FlowInterface - commonFlowComponents *flows.CommonFlowComponents - ) - - switch cfg.Mode { - case aggsendertypes.PessimisticProofMode: - commonFlowComponents, err = flows.CreateCommonFlowComponents( - ctx, logger, - nil, // storage is not used in validator, - l1Client, l1InfoTreeSync, l2Syncer, rollupDataQuerier, committeeQuerier, 0, false, - cfg.MaxCertSize, cfg.LerQuerier.RollupCreationBlockL1, cfg.DelayBetweenRetries.Duration, cfg.Signer, - true, // full claims are (eventually) needed in validator mode - cfg.RequireCommitteeMembershipCheck, - ) - if err != nil { - return nil, fmt.Errorf("failed to create common flow components: %w", err) - } - - flow = flows.NewPPFlow( - logger, - commonFlowComponents.BaseFlow, - nil, // storage is not used in validator - commonFlowComponents.L1InfoTreeDataQuerier, - commonFlowComponents.L2BridgeQuerier, - commonFlowComponents.Signer, - cfg.PPConfig.RequireOneBridgeInPPCertificate, - cfg.MaxL2BlockNumber, - ) - case aggsendertypes.AggchainProofMode: - commonFlowComponents, err = flows.CreateCommonFlowComponents( - ctx, logger, - nil, // storage is not used in validator, - l1Client, l1InfoTreeSync, l2Syncer, rollupDataQuerier, committeeQuerier, - 0, cfg.FEPConfig.RequireNoBlockGap, - cfg.MaxCertSize, cfg.LerQuerier.RollupCreationBlockL1, - cfg.DelayBetweenRetries.Duration, cfg.Signer, - true, // full claims are (eventually) needed in validator mode - cfg.RequireCommitteeMembershipCheck, - ) - if err != nil { - return nil, fmt.Errorf("failed to create common flow components: %w", err) - } - - optimisticModeQuerier, err := optimistic.NewOptimisticModeQuerierFromContract( - cfg.FEPConfig.SovereignRollupAddr, l1Client) - if err != nil { - return nil, fmt.Errorf("failed to create optimistic mode querier: %w", err) - } - - flow = flows.NewAggchainProverFlow( - logger, - flows.NewAggchainProverFlowConfig(cfg.MaxL2BlockNumber), - commonFlowComponents.BaseFlow, - nil, // storage is not used in validator - commonFlowComponents.L1InfoTreeDataQuerier, - commonFlowComponents.L2BridgeQuerier, - l1Client, - commonFlowComponents.Signer, - optimisticModeQuerier, - nil, // we don't query the prover in validator mode - ) - default: - return nil, fmt.Errorf("unsupported mode %s", cfg.Mode) - } - aggchainFEPQuerier, err := query.NewAggchainFEPQuerier( logger, cfg.Mode, @@ -343,13 +276,28 @@ func createAggSenderValidator(ctx context.Context, agglayerClient, ) + flow, flowParams, err := flows.NewVerifierFlow( + ctx, + cfg, + logger, + l1Client, + l1InfoTreeSync, + l2Syncer, + rollupDataQuerier, + committeeQuerier, + ) + if err != nil { + return nil, fmt.Errorf("failed to create verifier flow: %w", err) + } + return aggsender.NewAggsenderValidator( ctx, logger, cfg, flow, - commonFlowComponents.L1InfoTreeDataQuerier, + flowParams.L1InfoTreeDataQuerier, agglayerClient, certQuerier, - commonFlowComponents.LERQuerier, - commonFlowComponents.Signer, + aggchainFEPQuerier, + flowParams.LERQuerier, + flowParams.Signer, ) } diff --git a/config/default.go b/config/default.go index 072a58a60..e1e40685e 100644 --- a/config/default.go +++ b/config/default.go @@ -291,6 +291,7 @@ RequireCommitteeMembershipCheck = {{AggSender.RequireCommitteeMembershipCheck}} [Validator.FEPConfig] SovereignRollupAddr = "{{AggSender.SovereignRollupAddr}}" RequireNoBlockGap = "{{AggSender.RequireNoFEPBlockGap}}" + OpNodeURL = "{{OpNodeURL}}" [Validator.AgglayerClient] Cached = true [Validator.AgglayerClient.ConfigurationCache]