From 7612888ffa53aff557bf3f3e33bfc516a3759d66 Mon Sep 17 00:00:00 2001 From: Goran Rojovic Date: Thu, 3 Oct 2024 12:38:41 +0200 Subject: [PATCH] feat: incorporate getCertificateHeader call --- agglayer/client.go | 37 ++++++++++++++++++++++---- agglayer/types.go | 24 +++++++++++++++++ aggsender/aggsender.go | 57 +++++++++++++++++++++++----------------- bridgesync/bridgesync.go | 4 +-- 4 files changed, 91 insertions(+), 31 deletions(-) diff --git a/agglayer/client.go b/agglayer/client.go index 954444cf..15790305 100644 --- a/agglayer/client.go +++ b/agglayer/client.go @@ -17,7 +17,8 @@ import ( type AgglayerClientInterface interface { SendTx(signedTx SignedTx) (common.Hash, error) WaitTxToBeMined(hash common.Hash, ctx context.Context) error - SendCertificate(certificate *SignedCertificate) error + SendCertificate(certificate *SignedCertificate) (common.Hash, error) + GetCertificateHeader(certificateHash common.Hash) (*CertificateHeader, error) } // AggLayerClient is the client that will be used to interact with the AggLayer @@ -82,15 +83,41 @@ func (c *AggLayerClient) WaitTxToBeMined(hash common.Hash, ctx context.Context) } // SendCertificate sends a certificate to the AggLayer -func (c *AggLayerClient) SendCertificate(certificate *SignedCertificate) error { +func (c *AggLayerClient) SendCertificate(certificate *SignedCertificate) (common.Hash, error) { response, err := rpc.JSONRPCCall(c.url, "interop_sendCertificate", certificate) if err != nil { - return err + return common.Hash{}, err } if response.Error != nil { - return fmt.Errorf("%v %v", response.Error.Code, response.Error.Message) + return common.Hash{}, fmt.Errorf("%v %v", response.Error.Code, response.Error.Message) + } + + var result types.ArgHash + err = json.Unmarshal(response.Result, &result) + if err != nil { + return common.Hash{}, err + } + + return result.Hash(), nil +} + +// GetCertificateHeader returns the certificate header associated to the hash +func (c *AggLayerClient) GetCertificateHeader(certificateHash common.Hash) (*CertificateHeader, error) { + response, err := rpc.JSONRPCCall(c.url, "interop_getCertificateHeader", certificateHash) + if err != nil { + return nil, err + } + + if response.Error != nil { + return nil, fmt.Errorf("%v %v", response.Error.Code, response.Error.Message) + } + + var result *CertificateHeader + err = json.Unmarshal(response.Result, &result) + if err != nil { + return nil, err } - return nil + return result, nil } diff --git a/agglayer/types.go b/agglayer/types.go index caf4ae8f..d7ec932a 100644 --- a/agglayer/types.go +++ b/agglayer/types.go @@ -10,6 +10,19 @@ import ( "github.com/ethereum/go-ethereum/crypto" ) +type CertificateStatus int + +const ( + Pending CertificateStatus = iota + InError + Settled +) + +// String representation of the enum +func (c CertificateStatus) String() string { + return [...]string{"Pending", "InError", "Settled"}[c] +} + type LeafType uint8 func (l LeafType) Uint8() uint8 { @@ -151,3 +164,14 @@ func (c *ImportedBridgeExit) Hash() common.Hash { c.GlobalIndex.RollupIndex, c.GlobalIndex.LeafIndex) return crypto.Keccak256Hash(globalIndexBig.Bytes()) } + +// CertificateHeader is the structure returned by the interop_getCertificateHeader RPC call +type CertificateHeader struct { + NetworkID uint32 `json:"network_id"` + Height uint64 `json:"height"` + EpochNumber *uint64 `json:"epoch_number"` + CertificateIndex *uint64 `json:"certificate_index"` + CertificateID common.Hash `json:"certificate_id"` + NewLocalExitRoot common.Hash `json:"new_local_exit_root"` + Status CertificateStatus `json:"status"` +} diff --git a/aggsender/aggsender.go b/aggsender/aggsender.go index 4f44d215..abffd278 100644 --- a/aggsender/aggsender.go +++ b/aggsender/aggsender.go @@ -103,12 +103,12 @@ func (a *AggSender) sendCertificates(ctx context.Context) { func (a *AggSender) sendCertificate(ctx context.Context) error { a.log.Info("trying to send a new certificate...") - lastSentCertificateBlock, lastSentCertificate, err := a.getLastSentCertificate(ctx) + lastSentCertificateHash, _, err := a.getLastSentCertificate(ctx) if err != nil { return fmt.Errorf("error getting last sent certificate: %w", err) } - a.log.Info("last sent certificate block: %d", lastSentCertificateBlock) + a.log.Info("last sent certificate: %s", lastSentCertificateHash) finality := a.l2Syncer.BlockFinality() blockFinality, err := finality.ToBlockNum() @@ -116,13 +116,28 @@ func (a *AggSender) sendCertificate(ctx context.Context) error { return fmt.Errorf("error getting block finality: %w", err) } - lastFinalizedBlock, err := a.l2Client.HeaderByNumber(ctx, blockFinality) + lastL2Block, err := a.l2Client.HeaderByNumber(ctx, blockFinality) if err != nil { - return fmt.Errorf("error getting block number: %w", err) + return fmt.Errorf("error getting block from l2: %w", err) } - fromBlock := lastSentCertificateBlock + 1 - toBlock := lastFinalizedBlock.Nonce.Uint64() + lastSentCertificateHeader, err := a.aggLayerClient.GetCertificateHeader(lastSentCertificateHash) + if err != nil { + return fmt.Errorf("error getting certificate %s header: %w", lastSentCertificateHash, err) + } + + block, err := a.l2Syncer.GetBlockByLER(ctx, lastSentCertificateHeader.NewLocalExitRoot) + if err != nil { + return fmt.Errorf("error getting block by LER %s: %w", lastSentCertificateHash, err) + } + + if lastL2Block.Number.Uint64() <= block { + a.log.Info("no new blocks to send a certificate") + return nil + } + + fromBlock := block + 1 + toBlock := lastL2Block.Number.Uint64() bridges, err := a.l2Syncer.GetBridges(ctx, fromBlock, toBlock) if err != nil { @@ -139,14 +154,7 @@ func (a *AggSender) sendCertificate(ctx context.Context) error { return fmt.Errorf("error getting claims: %w", err) } - previousExitRoot := common.Hash{} - lastHeight := uint64(0) - if lastSentCertificate != nil { - previousExitRoot = lastSentCertificate.NewLocalExitRoot - lastHeight = lastSentCertificate.Height - } - - certificate, err := a.buildCertificate(ctx, bridges, claims, previousExitRoot, lastHeight) + certificate, err := a.buildCertificate(ctx, bridges, claims, lastSentCertificateHeader.NewLocalExitRoot, lastSentCertificateHeader.Height) if err != nil { return fmt.Errorf("error building certificate: %w", err) } @@ -156,15 +164,16 @@ func (a *AggSender) sendCertificate(ctx context.Context) error { return fmt.Errorf("error signing certificate: %w", err) } - if err := a.aggLayerClient.SendCertificate(signedCertificate); err != nil { + certificateHash, err := a.aggLayerClient.SendCertificate(signedCertificate) + if err != nil { return fmt.Errorf("error sending certificate: %w", err) } - if err := a.saveLastSentCertificate(ctx, lastFinalizedBlock.Nonce.Uint64(), certificate); err != nil { + if err := a.saveLastSentCertificate(ctx, certificateHash, certificate); err != nil { return fmt.Errorf("error saving last sent certificate in db: %w", err) } - a.log.Info("certificate sent successfully for block: %d", lastFinalizedBlock.Nonce.Uint64()) + a.log.Info("certificate: %s sent successfully for block: %d", certificateHash, lastL2Block.Nonce.Uint64()) return nil } @@ -343,7 +352,7 @@ func (a *AggSender) getImportedBridgeExits(ctx context.Context, } // saveLastSentCertificate saves the last sent certificate -func (a *AggSender) saveLastSentCertificate(ctx context.Context, blockNum uint64, +func (a *AggSender) saveLastSentCertificate(ctx context.Context, certificateHash common.Hash, certificate *agglayer.Certificate) error { return a.db.Update(ctx, func(tx kv.RwTx) error { raw, err := json.Marshal(certificate) @@ -351,15 +360,15 @@ func (a *AggSender) saveLastSentCertificate(ctx context.Context, blockNum uint64 return err } - return tx.Put(sentCertificatesL2Table, cdkcommon.Uint64ToBytes(blockNum), raw) + return tx.Put(sentCertificatesL2Table, certificateHash.Bytes(), raw) }) } // getLastSentCertificate returns the last sent certificate -func (a *AggSender) getLastSentCertificate(ctx context.Context) (uint64, *agglayer.Certificate, error) { +func (a *AggSender) getLastSentCertificate(ctx context.Context) (common.Hash, *agglayer.Certificate, error) { var ( - lastSentCertificateBlock uint64 - lastCertificate *agglayer.Certificate + lastSentCertificateHash common.Hash + lastCertificate *agglayer.Certificate ) err := a.db.View(ctx, func(tx kv.Tx) error { @@ -374,7 +383,7 @@ func (a *AggSender) getLastSentCertificate(ctx context.Context) (uint64, *agglay } if k != nil { - lastSentCertificateBlock = cdkcommon.BytesToUint64(k) + lastSentCertificateHash = common.BytesToHash(k) if err := json.Unmarshal(v, &lastCertificate); err != nil { return err } @@ -383,7 +392,7 @@ func (a *AggSender) getLastSentCertificate(ctx context.Context) (uint64, *agglay return nil }) - return lastSentCertificateBlock, lastCertificate, err + return lastSentCertificateHash, lastCertificate, err } // signCertificate signs a certificate with the sequencer key diff --git a/bridgesync/bridgesync.go b/bridgesync/bridgesync.go index 7e89f0ff..e27f2a2f 100644 --- a/bridgesync/bridgesync.go +++ b/bridgesync/bridgesync.go @@ -186,8 +186,8 @@ func (s *BridgeSync) GetProof(ctx context.Context, depositCount uint32, localExi return s.processor.exitTree.GetProof(ctx, depositCount, localExitRoot) } -func (p *processor) GetBlockByLER(ctx context.Context, ler common.Hash) (uint64, error) { - root, err := p.exitTree.GetRootByHash(ctx, ler) +func (p *BridgeSync) GetBlockByLER(ctx context.Context, ler common.Hash) (uint64, error) { + root, err := p.processor.exitTree.GetRootByHash(ctx, ler) if err != nil { return 0, err }