Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion aggsender/aggsender.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/agglayer/aggkit/aggsender/db"
"github.com/agglayer/aggkit/aggsender/flows"
"github.com/agglayer/aggkit/aggsender/metrics"
"github.com/agglayer/aggkit/aggsender/query"
aggsenderrpc "github.com/agglayer/aggkit/aggsender/rpc"
"github.com/agglayer/aggkit/aggsender/statuschecker"
"github.com/agglayer/aggkit/aggsender/types"
Expand Down Expand Up @@ -102,6 +103,18 @@ func New(
compatibility.NewKeyValueToCompatibilityStorage[db.RuntimeData](storage, aggkitcommon.AGGSENDER),
)

aggchainFEPCaller, err := query.NewAggchainFEPQuerier(logger, types.AggsenderMode(cfg.Mode),
cfg.SovereignRollupAddr, l1Client)
if err != nil {
return nil, fmt.Errorf("error creating aggchain FEP caller: %w", err)
}

certQuerier := query.NewCertificateQuerier(
l2Syncer,
aggchainFEPCaller,
aggLayerClient,
)

return &AggSender{
cfg: cfg,
log: logger,
Expand All @@ -113,7 +126,8 @@ func New(
rateLimiter: rateLimit,
compatibilityStoragedChecker: compatibilityStoragedChecker,
l2OriginNetwork: l2OriginNetwork,
certStatusChecker: statuschecker.NewCertStatusChecker(logger, storage, aggLayerClient, l2OriginNetwork),
certStatusChecker: statuschecker.NewCertStatusChecker(
logger, storage, aggLayerClient, certQuerier, l2OriginNetwork),
}, nil
}

Expand Down
2 changes: 1 addition & 1 deletion aggsender/aggsender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ func TestSendCertificate(t *testing.T) {
func TestNewAggSender(t *testing.T) {
mockBridgeSyncer := mocks.NewL2BridgeSyncer(t)
mockBridgeSyncer.EXPECT().OriginNetwork().Return(uint32(1)).Times(2)
sut, err := New(context.TODO(), log.WithFields("module", "ut"), config.Config{
sut, err := New(t.Context(), log.WithFields("module", "ut"), config.Config{
AggsenderPrivateKey: signertypes.SignerConfig{
Method: signertypes.MethodNone,
},
Expand Down
3 changes: 2 additions & 1 deletion aggsender/flows/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ func NewFlow(
return nil, fmt.Errorf("aggchainProverFlow - error creating LER data querier: %w", err)
}

aggchainFEPQuerier, err := query.NewAggchainFEPQuerier(logger, cfg.SovereignRollupAddr, l1Client)
aggchainFEPQuerier, err := query.NewAggchainFEPQuerier(logger, types.AggchainProofMode,
cfg.SovereignRollupAddr, l1Client)
if err != nil {
return nil, fmt.Errorf("aggchainProverFlow - error creating aggchain FEP querier: %w", err)
}
Expand Down
67 changes: 58 additions & 9 deletions aggsender/mocks/mock_certificate_querier.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion aggsender/query/aggchain_fep_rollup_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,10 @@ type aggchainFEPRollupQuerier struct {
// - The starting block number cannot be retrieved from the contract
func NewAggchainFEPQuerier(
logger *log.Logger,
aggsenderMode types.AggsenderMode,
aggchainFEPAddr common.Address,
l1Client aggkittypes.BaseEthereumClienter) (types.AggchainFEPRollupQuerier, error) {
if aggchainFEPAddr == aggkitcommon.ZeroAddress {
if aggchainFEPAddr == aggkitcommon.ZeroAddress || aggsenderMode == types.PessimisticProofMode {
// its a PP network without AggchainFEP contract
logger.Info("aggchainProverFlow - AggchainFEP contract address is zero, using no-op querier")
return &noOpAggchainFEPRollupQuerier{}, nil
Expand Down
3 changes: 3 additions & 0 deletions aggsender/query/aggchain_fep_rollup_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"

"github.com/agglayer/aggkit/aggsender/mocks"
"github.com/agglayer/aggkit/aggsender/types"
aggkitcommon "github.com/agglayer/aggkit/common"
"github.com/agglayer/aggkit/log"
typesmocks "github.com/agglayer/aggkit/types/mocks"
Expand All @@ -20,6 +21,7 @@ func TestNoOpAggchainFEPRollupQuerier(t *testing.T) {

querier, err := NewAggchainFEPQuerier(
log.WithFields("test", "noOpAggchainFEPRollupQuerier"),
types.PessimisticProofMode,
aggkitcommon.ZeroAddress,
nil, // No Ethereum client needed for no-op querier
)
Expand All @@ -43,6 +45,7 @@ func TestAggchainFEPRollupQuerier(t *testing.T) {

_, err := NewAggchainFEPQuerier(
log.WithFields("test", "aggchainFEPRollupQuerier"),
types.AggchainProofMode,
common.HexToAddress("0x1"),
mockL1Client,
)
Expand Down
13 changes: 13 additions & 0 deletions aggsender/query/certificate_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,16 @@ func (c *certificateQuerier) GetLastSettledCertificateToBlock(
// 4. Determine the maximum of the three values which will be the last settled certificate to block
return max(lastBridgeExitBlock, lastImportedBridgeExitBlock, lastSettledL2BlockNum), nil
}

// CalculateCertificateType determines the type of certificate based on the last block number in certificate
func (c *certificateQuerier) CalculateCertificateType(certToBlock uint64) types.CertificateType {
if certToBlock == 0 {
return types.CertificateTypeUnknown
}

if certToBlock < c.aggchainFEPQuerier.StartL2Block() {
return types.CertificateTypePP
}

return types.CertificateTypeFEP
}
91 changes: 44 additions & 47 deletions aggsender/statuschecker/cert_status_checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type certStatusChecker struct {
log *log.Logger
storage db.AggSenderStorage
agglayerClient agglayer.AgglayerClientInterface
certQuerier types.CertificateQuerier

l2OriginNetwork uint32
}
Expand All @@ -46,11 +47,13 @@ func NewCertStatusChecker(
log *log.Logger,
storage db.AggSenderStorage,
agglayerClient agglayer.AgglayerClientInterface,
certQuerier types.CertificateQuerier,
l2OriginNetwork uint32,
) types.CertificateStatusChecker {
return &certStatusChecker{
log: log,
storage: storage,
certQuerier: certQuerier,
agglayerClient: agglayerClient,
l2OriginNetwork: l2OriginNetwork,
}
Expand Down Expand Up @@ -214,7 +217,25 @@ func (c *certStatusChecker) executeInitialStatusAction(ctx context.Context,
return fmt.Errorf("recovery: error updating local storage with agglayer certificate: %w", err)
}
case InitialStatusActionInsertNewCert:
if _, err := c.updateLocalStorageWithAggLayerCert(ctx, action.cert); err != nil {
if action.cert.Status.IsInError() {
// we will not save the last certificate if it is in error on startup
// it will be rebuilt by the aggsender and sent again
// we only care about the settled certificates on startup, since we
// can not deduce the block range easily from a non settled certificate
// gotten from the agglayer
return nil
}

if action.cert.Status.IsOpen() {
// if the certificate is still pending, we need to wait for it to be settled
// before we can save it to the local storage, so we return an error here, and it will be retried in the main loop
// of the status checker in CheckInitialStatus function
// we do this because, it is not easy to deduce the block range from a non settled certificate
return fmt.Errorf("recovery: we have a non settled certificate %s on startup. Waiting for it to be settled",
action.cert.ID())
}

if _, err := c.updateLocalStorageWithSettledAggLayerCert(ctx, action.cert); err != nil {
return fmt.Errorf("recovery: error new local storage with agglayer certificate: %w", err)
}
default:
Expand All @@ -223,73 +244,49 @@ func (c *certStatusChecker) executeInitialStatusAction(ctx context.Context,
return nil
}

// updateLocalStorageWithAggLayerCert updates the local storage with the certificate from the AggLayer
func (c *certStatusChecker) updateLocalStorageWithAggLayerCert(ctx context.Context,
// updateLocalStorageWithSettledAggLayerCert updates the local storage with the
// settled certificate from the AggLayer
func (c *certStatusChecker) updateLocalStorageWithSettledAggLayerCert(ctx context.Context,
aggLayerCert *agglayertypes.CertificateHeader) (*types.Certificate, error) {
cert, err := newCertificateInfoFromAgglayerCertHeader(aggLayerCert)
cert, err := c.newSettledCertificateInfoFromAgglayerCertHeader(ctx, aggLayerCert)
if err != nil {
return nil, fmt.Errorf("error creating certificate from AggLayer header: %w", err)
}
if cert == nil {
return nil, nil
}

c.log.Infof("setting initial certificate from AggLayer: %s", cert.String())
return cert, c.storage.SaveOrUpdateCertificate(ctx, *cert)
}

func newCertificateInfoFromAgglayerCertHeader(c *agglayertypes.CertificateHeader) (*types.Certificate, error) {
if c == nil {
func (c *certStatusChecker) newSettledCertificateInfoFromAgglayerCertHeader(
ctx context.Context,
cert *agglayertypes.CertificateHeader) (*types.Certificate, error) {
if cert == nil {
return nil, nil
}
now := uint32(time.Now().UTC().Unix())
meta, err := types.NewCertificateMetadataFromHash(c.Metadata)
if err != nil {
return nil, fmt.Errorf("newCertificateInfoFromAgglayerCertHeader."+
" error creating certificate metadata from hash: %w", err)
}
var (
toBlock uint64
createdAt uint32
certType types.CertificateType
)

switch meta.Version {
case types.CertificateMetadataV0:
toBlock = meta.ToBlock
createdAt = now
certType = types.CertificateTypeUnknown
case types.CertificateMetadataV1:
toBlock = meta.FromBlock + uint64(meta.Offset)
createdAt = meta.CreatedAt
certType = types.CertificateTypeUnknown
case types.CertificateMetadataV2:
toBlock = meta.FromBlock + uint64(meta.Offset)
createdAt = meta.CreatedAt
certType = types.NewCertificateTypeFromInt(meta.CertType)
default:
return nil, fmt.Errorf("newCertificateInfoFromAgglayerCertHeader."+
" Unsupported certificate metadata version: %d", meta.Version)
toBlock, err := c.certQuerier.GetLastSettledCertificateToBlock(ctx, cert)
if err != nil {
return nil, fmt.Errorf("error getting last settled certificate to block: %w", err)
}

res := &types.Certificate{
Header: &types.CertificateHeader{
Height: c.Height,
CertificateID: c.CertificateID,
NewLocalExitRoot: c.NewLocalExitRoot,
FromBlock: meta.FromBlock,
ToBlock: toBlock,
Status: c.Status,
CreatedAt: createdAt,
UpdatedAt: now,
CertType: certType,
Height: cert.Height,
CertificateID: cert.CertificateID,
NewLocalExitRoot: cert.NewLocalExitRoot,
Status: cert.Status,
CertSource: types.CertificateSourceAggLayer,
CertType: c.certQuerier.CalculateCertificateType(toBlock),
ToBlock: toBlock,
FromBlock: 0, // We don't have block range in the header and we don't use the metadata anymore
CreatedAt: 0, // We don't have creation time in the header and we don't use the metadata anymore
UpdatedAt: 0, // We don't have creation time in the header and we don't use the metadata anymore
},
SignedCertificate: &naAgglayerHeader,
}

if c.PreviousLocalExitRoot != nil {
res.Header.PreviousLocalExitRoot = c.PreviousLocalExitRoot
if cert.PreviousLocalExitRoot != nil {
res.Header.PreviousLocalExitRoot = cert.PreviousLocalExitRoot
}

return res, nil
Expand Down
Loading
Loading