Skip to content

Commit 92db034

Browse files
feat: support FEP in aggsender-validator (#876)
## πŸ”„ Changes Summary This PR adds support for FEP certificates validation in `aggsender-validator`. ## ⚠️ Breaking Changes NA ## πŸ“‹ Config Updates Added new config parameters to `Validator` config: - `Mode` - mode of the validator. Similar to regular `aggsender` (proposer) it can be `PessimisticProof` or `AggchainProof` based on if the network is a `PP` or `FEP`. - `FEPConfig` - `FEP` (`AggchainProof` mode) network specific configuration: - `SovereignRollupAddr` - address of the `AggchainFEP` contract. - `RequireNoFEPBlockGap` - true if the AggSender should not accept a gap between last block from last certificate and first block of `FEP` network. - 🧾 **Diff/Config snippet**: ```toml [Validator] # PessimisticProof or AggchainProof Mode = "PessimisticProof" [Validator.FEPConfig] SovereignRollupAddr = "{{AggSender.SovereignRollupAddr}}" RequireNoFEPBlockGap = "{{AggSender.RequireNoFEPBlockGap}}" ``` ## βœ… Testing - πŸ€– **Automatic**: `aggkit` CI ## 🐞 Issues - Closes #803
1 parent 4858f06 commit 92db034

19 files changed

+726
-169
lines changed

β€Žaggsender/aggsender_validator.goβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ type AggsenderValidator struct {
3131
func NewAggsenderValidator(ctx context.Context,
3232
logger aggkitcommon.Logger,
3333
cfg validator.Config,
34-
flowPP validator.FlowInterface,
34+
flow validator.FlowInterface,
3535
l1InfoTreeDataQuerier validator.L1InfoTreeRootByLeafQuerier,
3636
aggLayerClient agglayer.AggLayerClientCertificateIDQuerier,
3737
certQuerier types.CertificateQuerier,
3838
lerQuerier types.LERQuerier,
3939
signer signertypes.Signer) (*AggsenderValidator, error) {
4040
validatorCert := validator.NewAggsenderValidator(
41-
logger, flowPP, l1InfoTreeDataQuerier, certQuerier, lerQuerier)
41+
logger, flow, l1InfoTreeDataQuerier, certQuerier, lerQuerier)
4242
grpcServer, err := grpc.NewServer(cfg.ServerConfig)
4343
if err != nil {
4444
return nil, err

β€Žaggsender/config/config.goβ€Ž

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,11 @@ func (c Config) String() string {
119119
// Validate checks if the configuration is valid
120120
func (c Config) Validate() error {
121121
if c.RequireValidatorCall {
122-
if c.Mode != aggsendertypes.PessimisticProofMode.String() {
123-
return fmt.Errorf("RequireValidatorCall can only be true in PessimisticProof mode, got %s", c.Mode)
122+
if c.Mode != aggsendertypes.PessimisticProofMode.String() &&
123+
c.Mode != aggsendertypes.AggchainProofMode.String() {
124+
return fmt.Errorf(
125+
"RequireValidatorCall can only be true in PessimisticProof or AggchainProof mode, got %s",
126+
c.Mode)
124127
}
125128

126129
if c.ValidatorClient == nil || c.ValidatorClient.URL == "" {

β€Žaggsender/config/config_test.goβ€Ž

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,16 @@ func TestValidate(t *testing.T) {
2020
expectedErr string
2121
}{
2222
{
23-
name: "RequireValidatorCall not PP mode",
23+
name: "RequireValidatorCall not PP or FEP mode",
2424
config: Config{
25-
Mode: aggsendertypes.AggchainProofMode.String(),
25+
Mode: "some-other-mode",
2626
RequireValidatorCall: true,
2727
ValidatorClient: &grpc.ClientConfig{
2828
URL: "http://localhost:8080",
2929
MinConnectTimeout: types.NewDuration(5 * time.Second),
3030
},
3131
},
32-
expectedErr: "RequireValidatorCall can only be true in PessimisticProof mode",
32+
expectedErr: "RequireValidatorCall can only be true in PessimisticProof or AggchainProof mode",
3333
},
3434
{
3535
name: "RequireValidatorCall is true with ValidatorClient URL set",

β€Žaggsender/flows/factory.goβ€Ž

Lines changed: 44 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package flows
33
import (
44
"context"
55
"fmt"
6+
"time"
67

78
"github.com/agglayer/aggkit/aggsender/aggchainproofclient"
89
"github.com/agglayer/aggkit/aggsender/config"
@@ -15,15 +16,14 @@ import (
1516
"github.com/agglayer/aggkit/log"
1617
aggkittypes "github.com/agglayer/aggkit/types"
1718
"github.com/agglayer/go_signer/signer"
18-
signerTypes "github.com/agglayer/go_signer/signer/types"
19+
signertypes "github.com/agglayer/go_signer/signer/types"
1920
)
2021

2122
var (
2223
// l2GERReaderFactory is a factory function to create L2 GER reader
2324
l2GERReaderFactory = l2gersync.NewL2EVMGERReader
2425
)
2526

26-
// NewFlow creates a new Aggsender flow based on the provided configuration.
2727
func NewFlow(
2828
ctx context.Context,
2929
cfg config.Config,
@@ -37,28 +37,25 @@ func NewFlow(
3737
) (types.AggsenderFlow, error) {
3838
switch types.AggsenderMode(cfg.Mode) {
3939
case types.PessimisticProofMode:
40-
commonFlowComponents, err := createCommonComponents(
41-
ctx, cfg, logger, storage, l1Client, l1InfoTreeSyncer, l2Syncer, rollupDataQuerier, 0, false,
40+
commonFlowComponents, err := CreateCommonFlowComponents(
41+
ctx, logger, storage, l1Client, l1InfoTreeSyncer, l2Syncer, rollupDataQuerier, 0, false,
42+
cfg.MaxCertSize, cfg.RollupCreationBlockL1, cfg.DelayBetweenRetries.Duration, cfg.AggsenderPrivateKey,
4243
)
4344
if err != nil {
4445
return nil, fmt.Errorf("failed to create common flow components: %w", err)
4546
}
4647

4748
return NewPPFlow(
4849
logger,
49-
commonFlowComponents.baseFlow,
50+
commonFlowComponents.BaseFlow,
5051
storage,
51-
commonFlowComponents.l1InfoTreeDataQuerier,
52-
commonFlowComponents.l2BridgeQuerier,
53-
commonFlowComponents.signer,
52+
commonFlowComponents.L1InfoTreeDataQuerier,
53+
commonFlowComponents.L2BridgeQuerier,
54+
commonFlowComponents.Signer,
5455
cfg.RequireOneBridgeInPPCertificate,
5556
cfg.MaxL2BlockNumber,
5657
), nil
5758
case types.AggchainProofMode:
58-
if err := cfg.AggkitProverClient.Validate(); err != nil {
59-
return nil, fmt.Errorf("invalid aggkit prover client config: %w", err)
60-
}
61-
6259
aggchainProofClient, err := aggchainproofclient.NewAggchainProofClient(cfg.AggkitProverClient)
6360
if err != nil {
6461
return nil, fmt.Errorf("aggchainProverFlow - error creating aggkit prover client: %w", err)
@@ -76,9 +73,10 @@ func NewFlow(
7673
return nil, fmt.Errorf("aggchainProverFlow - error creating aggchain FEP querier: %w", err)
7774
}
7875

79-
commonFlowComponents, err := createCommonComponents(
80-
ctx, cfg, logger, storage, l1Client, l1InfoTreeSyncer, l2Syncer, rollupDataQuerier,
76+
commonFlowComponents, err := CreateCommonFlowComponents(
77+
ctx, logger, storage, l1Client, l1InfoTreeSyncer, l2Syncer, rollupDataQuerier,
8178
aggchainFEPQuerier.StartL2Block(), cfg.RequireNoFEPBlockGap,
79+
cfg.MaxCertSize, cfg.RollupCreationBlockL1, cfg.DelayBetweenRetries.Duration, cfg.AggsenderPrivateKey,
8280
)
8381
if err != nil {
8482
return nil, fmt.Errorf("failed to create common flow components: %w", err)
@@ -89,27 +87,24 @@ func NewFlow(
8987
return nil, fmt.Errorf("failed to create L2 GER reader: %w", err)
9088
}
9189

92-
gerQuerier := query.NewGERDataQuerier(commonFlowComponents.l1InfoTreeDataQuerier, l2GERReader)
93-
9490
aggchainProofQuerier := query.NewAggchainProofQuery(
9591
logger,
9692
aggchainProofClient,
97-
commonFlowComponents.l1InfoTreeDataQuerier,
93+
commonFlowComponents.L1InfoTreeDataQuerier,
9894
optimisticSigner,
99-
commonFlowComponents.baseFlow,
100-
gerQuerier,
95+
commonFlowComponents.BaseFlow,
96+
query.NewGERDataQuerier(commonFlowComponents.L1InfoTreeDataQuerier, l2GERReader),
10197
)
10298

10399
return NewAggchainProverFlow(
104100
logger,
105101
NewAggchainProverFlowConfig(cfg.MaxL2BlockNumber),
106-
commonFlowComponents.baseFlow,
102+
commonFlowComponents.BaseFlow,
107103
storage,
108-
commonFlowComponents.l1InfoTreeDataQuerier,
109-
commonFlowComponents.l2BridgeQuerier,
110-
gerQuerier,
104+
commonFlowComponents.L1InfoTreeDataQuerier,
105+
commonFlowComponents.L2BridgeQuerier,
111106
l1Client,
112-
commonFlowComponents.signer,
107+
commonFlowComponents.Signer,
113108
optimisticModeQuerier,
114109
aggchainProofQuerier,
115110
), nil
@@ -119,17 +114,16 @@ func NewFlow(
119114
}
120115
}
121116

122-
type commonFlowComponents struct {
123-
l2BridgeQuerier types.BridgeQuerier
124-
l1InfoTreeDataQuerier types.L1InfoTreeDataQuerier
125-
lerQuerier types.LERQuerier
126-
baseFlow types.AggsenderFlowBaser
127-
signer signerTypes.Signer
117+
type CommonFlowComponents struct {
118+
L2BridgeQuerier types.BridgeQuerier
119+
L1InfoTreeDataQuerier types.L1InfoTreeDataQuerier
120+
LERQuerier types.LERQuerier
121+
BaseFlow types.AggsenderFlowBaser
122+
Signer signertypes.Signer
128123
}
129124

130-
func createCommonComponents(
125+
func CreateCommonFlowComponents(
131126
ctx context.Context,
132-
cfg config.Config,
133127
logger *log.Logger,
134128
storage db.AggSenderStorage,
135129
l1Client aggkittypes.BaseEthereumClienter,
@@ -138,35 +132,39 @@ func createCommonComponents(
138132
rollupDataQuerier types.RollupDataQuerier,
139133
startL2Block uint64,
140134
requireNoFEPBlockGap bool,
141-
) (commonFlowComponents, error) {
142-
signer, err := initializeSigner(ctx, cfg.AggsenderPrivateKey, logger)
135+
maxCertSize uint,
136+
rollupCreationBlockL1 uint64,
137+
delayBetweenRetries time.Duration,
138+
signerCfg signertypes.SignerConfig,
139+
) (*CommonFlowComponents, error) {
140+
signer, err := initializeSigner(ctx, signerCfg, logger)
143141
if err != nil {
144-
return commonFlowComponents{}, err
142+
return nil, err
145143
}
146144

147-
l2BridgeQuerier := query.NewBridgeDataQuerier(logger, l2Syncer, cfg.DelayBetweenRetries.Duration)
145+
l2BridgeQuerier := query.NewBridgeDataQuerier(logger, l2Syncer, delayBetweenRetries)
148146
l1InfoTreeQuerier := query.NewL1InfoTreeDataQuerier(l1Client, l1InfoTreeSyncer)
149-
lerQuerier := query.NewLERDataQuerier(cfg.RollupCreationBlockL1, rollupDataQuerier)
147+
lerQuerier := query.NewLERDataQuerier(rollupCreationBlockL1, rollupDataQuerier)
150148

151149
baseFlow := NewBaseFlow(
152150
logger, l2BridgeQuerier, storage, l1InfoTreeQuerier, lerQuerier,
153-
NewBaseFlowConfig(cfg.MaxCertSize, startL2Block, requireNoFEPBlockGap),
151+
NewBaseFlowConfig(maxCertSize, startL2Block, requireNoFEPBlockGap),
154152
)
155153

156-
return commonFlowComponents{
157-
l2BridgeQuerier: l2BridgeQuerier,
158-
l1InfoTreeDataQuerier: l1InfoTreeQuerier,
159-
lerQuerier: lerQuerier,
160-
baseFlow: baseFlow,
161-
signer: signer,
154+
return &CommonFlowComponents{
155+
L2BridgeQuerier: l2BridgeQuerier,
156+
L1InfoTreeDataQuerier: l1InfoTreeQuerier,
157+
LERQuerier: lerQuerier,
158+
BaseFlow: baseFlow,
159+
Signer: signer,
162160
}, nil
163161
}
164162

165163
func initializeSigner(
166164
ctx context.Context,
167-
signerCfg signerTypes.SignerConfig,
165+
signerCfg signertypes.SignerConfig,
168166
logger *log.Logger,
169-
) (signerTypes.Signer, error) {
167+
) (signertypes.Signer, error) {
170168
signer, err := signer.NewSigner(ctx, 0, signerCfg, aggkitcommon.AGGSENDER, logger)
171169
if err != nil {
172170
return nil, fmt.Errorf("error NewSigner. Err: %w", err)

β€Žaggsender/flows/factory_test.goβ€Ž

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,6 @@ func TestNewFlow(t *testing.T) {
4848
},
4949
expectedError: "error signer.Initialize",
5050
},
51-
{
52-
name: "error missing AggkitProverClient in AggchainProofMode",
53-
cfg: config.Config{
54-
Mode: string(types.AggchainProofMode),
55-
AggsenderPrivateKey: signertypes.SignerConfig{Method: signertypes.MethodNone},
56-
},
57-
expectedError: "invalid aggkit prover client config: gRPC client configuration cannot be nil",
58-
},
5951
{
6052
name: "unsupported Aggsender mode",
6153
cfg: config.Config{

β€Žaggsender/flows/flow_aggchain_prover.goβ€Ž

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import (
1515
"github.com/ethereum/go-ethereum/common"
1616
)
1717

18+
var _ types.AggsenderFlow = (*AggchainProverFlow)(nil)
19+
1820
// AggchainProverFlow is a struct that holds the logic for the AggchainProver prover type flow
1921
type AggchainProverFlow struct {
2022
baseFlow types.AggsenderFlowBaser
@@ -24,7 +26,6 @@ type AggchainProverFlow struct {
2426
l1InfoTreeDataQuerier types.L1InfoTreeDataQuerier
2527
l2BridgeQuerier types.BridgeQuerier
2628

27-
gerQuerier types.GERQuerier
2829
certificateSigner signertypes.Signer
2930
optimisticModeQuerier types.OptimisticModeQuerier
3031
aggchainProofQuerier types.AggchainProofQuerier
@@ -77,7 +78,6 @@ func NewAggchainProverFlow(
7778
storage db.AggSenderStorage,
7879
l1InfoTreeQuerier types.L1InfoTreeDataQuerier,
7980
l2BridgeQuerier types.BridgeQuerier,
80-
gerQuerier types.GERQuerier,
8181
l1Client aggkittypes.BaseEthereumClienter,
8282
signer signertypes.Signer,
8383
optimisticModeQuerier types.OptimisticModeQuerier,
@@ -94,7 +94,6 @@ func NewAggchainProverFlow(
9494
storage: storage,
9595
l1InfoTreeDataQuerier: l1InfoTreeQuerier,
9696
l2BridgeQuerier: l2BridgeQuerier,
97-
gerQuerier: gerQuerier,
9897
config: aggChainProverConfig,
9998
certificateSigner: signer,
10099
optimisticModeQuerier: optimisticModeQuerier,
@@ -144,9 +143,25 @@ func (a *AggchainProverFlow) getCertificateTypeToGenerate() (types.CertificateTy
144143
return types.CertificateTypeFEP, nil
145144
}
146145

146+
// GeneratePreBuildParams generates the pre-build parameters for the AggchainProverFlow
147+
// Only used in aggsender validator
147148
func (a *AggchainProverFlow) GenerateBuildParams(ctx context.Context,
148149
preParams *types.CertificatePreBuildParams) (*types.CertificateBuildParams, error) {
149-
return nil, fmt.Errorf("aggchainProverFlow - GenerateBuildParams is not implemented")
150+
if preParams == nil {
151+
return nil, fmt.Errorf("ppFlow - preParams is nil")
152+
}
153+
154+
params, err := a.baseFlow.GenerateBuildParams(ctx, *preParams)
155+
if err != nil {
156+
return nil, fmt.Errorf("ppFlow - error generating build params: %w", err)
157+
}
158+
159+
// we do not limit the size of the certificate in FEP flow,
160+
// it was already resized and limited by the prover when proposer called it
161+
// when building the certificate, so the block range is already limited
162+
// when it gets to the validator
163+
164+
return params, nil
150165
}
151166

152167
// GetCertificateBuildParams returns the parameters to build a certificate
@@ -296,15 +311,19 @@ func (a *AggchainProverFlow) BuildCertificate(ctx context.Context,
296311
return nil, fmt.Errorf("aggchainProverFlow - error building certificate: %w", err)
297312
}
298313

299-
cert.AggchainData = &agglayertypes.AggchainDataProof{
300-
Proof: buildParams.AggchainProof.SP1StarkProof.Proof,
301-
Version: buildParams.AggchainProof.SP1StarkProof.Version,
302-
Vkey: buildParams.AggchainProof.SP1StarkProof.Vkey,
303-
AggchainParams: buildParams.AggchainProof.AggchainParams,
304-
Context: buildParams.AggchainProof.Context,
305-
}
314+
if buildParams.AggchainProof != nil {
315+
// this case can happen only when aggsender validator calls this function
316+
// since the validator does not call the aggchain prover to get the proof
317+
cert.AggchainData = &agglayertypes.AggchainDataProof{
318+
Proof: buildParams.AggchainProof.SP1StarkProof.Proof,
319+
Version: buildParams.AggchainProof.SP1StarkProof.Version,
320+
Vkey: buildParams.AggchainProof.SP1StarkProof.Vkey,
321+
AggchainParams: buildParams.AggchainProof.AggchainParams,
322+
Context: buildParams.AggchainProof.Context,
323+
}
306324

307-
cert.CustomChainData = buildParams.AggchainProof.CustomChainData
325+
cert.CustomChainData = buildParams.AggchainProof.CustomChainData
326+
}
308327

309328
signedCert, err := a.signCertificate(ctx, cert)
310329
if err != nil {
@@ -381,3 +400,17 @@ func (a *AggchainProverFlow) signCertificate(
381400

382401
return cert, nil
383402
}
403+
404+
// ValidateCertificate validates the certificate for the FEP specific things
405+
func (a *AggchainProverFlow) ValidateCertificate(ctx context.Context, cert *agglayertypes.Certificate) error {
406+
if cert == nil {
407+
return fmt.Errorf("aggchainProverFlow - ValidateCertificate - certificate is nil")
408+
}
409+
410+
_, ok := cert.AggchainData.(*agglayertypes.AggchainDataProof)
411+
if !ok {
412+
return fmt.Errorf("aggchainProverFlow - ValidateCertificate - AggchainData is not of type AggchainDataProof")
413+
}
414+
415+
return nil
416+
}

β€Žaggsender/flows/flow_aggchain_prover_optimistic_test.goβ€Ž

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ type AggchainProverFlowTestData struct {
107107
mockStorage *mocks.AggSenderStorage
108108
mockL2BridgeQuerier *mocks.BridgeQuerier
109109
mockL1InfoTreeQuerier *mocks.L1InfoTreeDataQuerier
110-
mockGERQuerier *mocks.GERQuerier
111110
mockL1Client *aggkittypesmocks.BaseEthereumClienter
112111
mockOptimisticModeQuerier *mocks.OptimisticModeQuerier
113112
mockSigner *mocks.Signer
@@ -125,7 +124,6 @@ func NewAggchainProverFlowTestData(t *testing.T, cfgBase BaseFlowConfig) *Aggcha
125124
mockStorage: mocks.NewAggSenderStorage(t),
126125
mockL2BridgeQuerier: mocks.NewBridgeQuerier(t),
127126
mockL1InfoTreeQuerier: mocks.NewL1InfoTreeDataQuerier(t),
128-
mockGERQuerier: mocks.NewGERQuerier(t),
129127
mockL1Client: aggkittypesmocks.NewBaseEthereumClienter(t),
130128
mockOptimisticModeQuerier: mocks.NewOptimisticModeQuerier(t),
131129
mockSigner: mocks.NewSigner(t),
@@ -144,7 +142,6 @@ func NewAggchainProverFlowTestData(t *testing.T, cfgBase BaseFlowConfig) *Aggcha
144142
res.mockStorage,
145143
res.mockL1InfoTreeQuerier,
146144
res.mockL2BridgeQuerier,
147-
res.mockGERQuerier,
148145
res.mockL1Client,
149146
res.mockSigner,
150147
res.mockOptimisticModeQuerier,

0 commit comments

Comments
Β (0)