Skip to content

Commit

Permalink
feat(aggsender): add more data to certificate metadata (#200)
Browse files Browse the repository at this point in the history
New struct CertificateMetadata to represent the data serialized and deserialized to the Certificate.metadata field.

The new data, FromBlock and CreatedAt is stored in the hash as bigints
  • Loading branch information
vcastellm authored Nov 29, 2024
1 parent f153be1 commit 085f176
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 37 deletions.
38 changes: 19 additions & 19 deletions aggsender/aggsender.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"encoding/json"
"errors"
"fmt"
"math/big"
"os"
"time"

Expand Down Expand Up @@ -188,7 +187,8 @@ func (a *AggSender) sendCertificate(ctx context.Context) (*agglayer.SignedCertif

a.log.Infof("building certificate for block: %d to block: %d", fromBlock, toBlock)

certificate, err := a.buildCertificate(ctx, bridges, claims, lastSentCertificateInfo, toBlock)
createdTime := uint64(time.Now().UTC().UnixMilli())
certificate, err := a.buildCertificate(ctx, bridges, claims, lastSentCertificateInfo, fromBlock, toBlock, createdTime)
if err != nil {
return nil, fmt.Errorf("error building certificate: %w", err)
}
Expand All @@ -212,7 +212,6 @@ func (a *AggSender) sendCertificate(ctx context.Context) (*agglayer.SignedCertif
return nil, fmt.Errorf("error marshalling signed certificate. Cert:%s. Err: %w", signedCertificate.Brief(), err)
}

createdTime := time.Now().UTC().UnixMilli()
prevLER := common.BytesToHash(certificate.PrevLocalExitRoot[:])
certInfo := types.CertificateInfo{
Height: certificate.Height,
Expand All @@ -221,8 +220,8 @@ func (a *AggSender) sendCertificate(ctx context.Context) (*agglayer.SignedCertif
PreviousLocalExitRoot: &prevLER,
FromBlock: fromBlock,
ToBlock: toBlock,
CreatedAt: createdTime,
UpdatedAt: createdTime,
CreatedAt: int64(createdTime),
UpdatedAt: int64(createdTime),
SignedCertificate: string(raw),
}
// TODO: Improve this case, if a cert is not save in the storage, we are going to settle a unknown certificate
Expand Down Expand Up @@ -325,7 +324,9 @@ func (a *AggSender) buildCertificate(ctx context.Context,
bridges []bridgesync.Bridge,
claims []bridgesync.Claim,
lastSentCertificateInfo *types.CertificateInfo,
toBlock uint64) (*agglayer.Certificate, error) {
fromBlock, toBlock uint64,
createdAt uint64,
) (*agglayer.Certificate, error) {
if len(bridges) == 0 && len(claims) == 0 {
return nil, errNoBridgesAndClaims
}
Expand All @@ -352,14 +353,20 @@ func (a *AggSender) buildCertificate(ctx context.Context,
return nil, fmt.Errorf("error getting next height and previous LER: %w", err)
}

meta := &types.CertificateMetadata{
FromBlock: fromBlock,
ToBlock: toBlock,
CreatedAt: createdAt,
}

return &agglayer.Certificate{
NetworkID: a.l2Syncer.OriginNetwork(),
PrevLocalExitRoot: previousLER,
NewLocalExitRoot: exitRoot.Hash,
BridgeExits: bridgeExits,
ImportedBridgeExits: importedBridgeExits,
Height: height,
Metadata: createCertificateMetadata(toBlock),
Metadata: meta.ToHash(),
}, nil
}

Expand Down Expand Up @@ -722,28 +729,21 @@ func extractSignatureData(signature []byte) (r, s common.Hash, isOddParity bool,
return
}

// createCertificateMetadata creates a certificate metadata from given input
func createCertificateMetadata(toBlock uint64) common.Hash {
return common.BigToHash(new(big.Int).SetUint64(toBlock))
}

func extractFromCertificateMetadataToBlock(metadata common.Hash) uint64 {
return metadata.Big().Uint64()
}

func NewCertificateInfoFromAgglayerCertHeader(c *agglayer.CertificateHeader) *types.CertificateInfo {
if c == nil {
return nil
}
meta := types.NewCertificateMetadataFromHash(c.Metadata)
now := time.Now().UTC().UnixMilli()

res := &types.CertificateInfo{
Height: c.Height,
CertificateID: c.CertificateID,
NewLocalExitRoot: c.NewLocalExitRoot,
FromBlock: 0,
ToBlock: extractFromCertificateMetadataToBlock(c.Metadata),
FromBlock: meta.FromBlock,
ToBlock: meta.ToBlock,
Status: c.Status,
CreatedAt: now,
CreatedAt: int64(meta.CreatedAt),
UpdatedAt: now,
SignedCertificate: "na/agglayer header",
}
Expand Down
58 changes: 40 additions & 18 deletions aggsender/aggsender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ func TestBuildCertificate(t *testing.T) {
bridges []bridgesync.Bridge
claims []bridgesync.Claim
lastSentCertificateInfo aggsendertypes.CertificateInfo
fromBlock uint64
toBlock uint64
mockFn func()
expectedCert *agglayer.Certificate
Expand Down Expand Up @@ -631,12 +632,13 @@ func TestBuildCertificate(t *testing.T) {
Height: 1,
Status: agglayer.Settled,
},
toBlock: 10,
fromBlock: 0,
toBlock: 10,
expectedCert: &agglayer.Certificate{
NetworkID: 1,
PrevLocalExitRoot: common.HexToHash("0x123"),
NewLocalExitRoot: common.HexToHash("0x789"),
Metadata: createCertificateMetadata(10),
Metadata: aggsendertypes.NewCertificateMetadata(0, 10, 0).ToHash(),
BridgeExits: []*agglayer.BridgeExit{
{
LeafType: agglayer.LeafTypeAsset,
Expand Down Expand Up @@ -787,7 +789,15 @@ func TestBuildCertificate(t *testing.T) {
l1infoTreeSyncer: mockL1InfoTreeSyncer,
log: log.WithFields("test", "unittest"),
}
cert, err := aggSender.buildCertificate(context.Background(), tt.bridges, tt.claims, &tt.lastSentCertificateInfo, tt.toBlock)
cert, err := aggSender.buildCertificate(
context.Background(),
tt.bridges,
tt.claims,
&tt.lastSentCertificateInfo,
tt.fromBlock,
tt.toBlock,
0,
)

if tt.expectedError {
require.Error(t, err)
Expand Down Expand Up @@ -1711,10 +1721,15 @@ func TestSendCertificate_NoClaims(t *testing.T) {
}

func TestMetadataConversions(t *testing.T) {
fromBlock := uint64(123567890)
toBlock := uint64(123567890)
c := createCertificateMetadata(toBlock)
extractBlock := extractFromCertificateMetadataToBlock(c)
require.Equal(t, toBlock, extractBlock)
createdAt := uint64(0)
meta := aggsendertypes.NewCertificateMetadata(fromBlock, toBlock, createdAt)
c := meta.ToHash()
extractBlock := aggsendertypes.NewCertificateMetadataFromHash(c)
require.Equal(t, fromBlock, extractBlock.FromBlock)
require.Equal(t, toBlock, extractBlock.ToBlock)
require.Equal(t, createdAt, extractBlock.CreatedAt)
}

func TestExtractFromCertificateMetadataToBlock(t *testing.T) {
Expand All @@ -1723,22 +1738,25 @@ func TestExtractFromCertificateMetadataToBlock(t *testing.T) {
tests := []struct {
name string
metadata common.Hash
expected uint64
expected aggsendertypes.CertificateMetadata
}{
{
name: "Valid metadata",
metadata: common.BigToHash(big.NewInt(123567890)),
expected: 123567890,
metadata: aggsendertypes.NewCertificateMetadata(0, 123567890, 123567890).ToHash(),
expected: aggsendertypes.CertificateMetadata{
FromBlock: 0,
ToBlock: 123567890,
CreatedAt: 123567890,
},
},
{
name: "Zero metadata",
metadata: common.BigToHash(big.NewInt(0)),
expected: 0,
},
{
name: "Max uint64 metadata",
metadata: common.BigToHash(new(big.Int).SetUint64(^uint64(0))),
expected: ^uint64(0),
metadata: aggsendertypes.NewCertificateMetadata(0, 0, 0).ToHash(),
expected: aggsendertypes.CertificateMetadata{
FromBlock: 0,
ToBlock: 0,
CreatedAt: 0,
},
},
}

Expand All @@ -1748,7 +1766,7 @@ func TestExtractFromCertificateMetadataToBlock(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

result := extractFromCertificateMetadataToBlock(tt.metadata)
result := *aggsendertypes.NewCertificateMetadataFromHash(tt.metadata)
require.Equal(t, tt.expected, result)
})
}
Expand Down Expand Up @@ -1931,7 +1949,11 @@ func certInfoToCertHeader(certInfo *aggsendertypes.CertificateInfo, networkID ui
CertificateID: certInfo.CertificateID,
NewLocalExitRoot: certInfo.NewLocalExitRoot,
Status: agglayer.Pending,
Metadata: createCertificateMetadata(certInfo.ToBlock),
Metadata: aggsendertypes.NewCertificateMetadata(
certInfo.FromBlock,
certInfo.ToBlock,
uint64(certInfo.CreatedAt),
).ToHash(),
}
}

Expand Down
45 changes: 45 additions & 0 deletions aggsender/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package types

import (
"context"
"encoding/binary"
"fmt"
"math/big"
"time"
Expand Down Expand Up @@ -122,3 +123,47 @@ func (c *CertificateInfo) ElapsedTimeSinceCreation() time.Duration {
}
return time.Now().UTC().Sub(time.UnixMilli(c.CreatedAt))
}

type CertificateMetadata struct {
FromBlock uint64 `json:"fromBlock"`
ToBlock uint64 `json:"toBlock"`
CreatedAt uint64 `json:"createdAt"`
}

// NewCertificateMetadataFromHash returns a new CertificateMetadata from the given hash
func NewCertificateMetadata(fromBlock, toBlock, createdAt uint64) *CertificateMetadata {
return &CertificateMetadata{
FromBlock: fromBlock,
ToBlock: toBlock,
CreatedAt: createdAt,
}
}

// NewCertificateMetadataFromHash returns a new CertificateMetadata from the given hash
func NewCertificateMetadataFromHash(hash common.Hash) *CertificateMetadata {
b := hash.Bytes()

return NewCertificateMetadata(
binary.BigEndian.Uint64(b[0:8]),
binary.BigEndian.Uint64(b[8:16]),
binary.BigEndian.Uint64(b[16:24]),
)
}

// ToHash returns the hash of the metadata
func (c *CertificateMetadata) ToHash() common.Hash {
b := make([]byte, common.HashLength) // 32-byte hash

// Encode fromBlock into first 8 bytes
binary.BigEndian.PutUint64(b[0:8], c.FromBlock)

// Encode toBlock into next 8 bytes
binary.BigEndian.PutUint64(b[8:16], c.ToBlock)

// Encode createdAt into next 8 bytes
binary.BigEndian.PutUint64(b[16:24], c.CreatedAt)

// Last 8 bytes remain as zero padding

return common.BytesToHash(b)
}

0 comments on commit 085f176

Please sign in to comment.