Skip to content

Commit

Permalink
feat: cherry pick PR 229 to release (#233)
Browse files Browse the repository at this point in the history
* fix: use hex instead of byte arrays

* feat: UT

* fix: change estimated certificate size

* fix: UT coverage

* fix: bridge exit metadata hash

* fix: last sent certificate block (#234)
  • Loading branch information
goran-ethernal authored Dec 6, 2024
1 parent 0873bb5 commit c531821
Show file tree
Hide file tree
Showing 5 changed files with 298 additions and 87 deletions.
59 changes: 25 additions & 34 deletions agglayer/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ const (
type Certificate struct {
NetworkID uint32 `json:"network_id"`
Height uint64 `json:"height"`
PrevLocalExitRoot [32]byte `json:"prev_local_exit_root"`
NewLocalExitRoot [32]byte `json:"new_local_exit_root"`
PrevLocalExitRoot common.Hash `json:"prev_local_exit_root"`
NewLocalExitRoot common.Hash `json:"new_local_exit_root"`
BridgeExits []*BridgeExit `json:"bridge_exits"`
ImportedBridgeExits []*ImportedBridgeExit `json:"imported_bridge_exits"`
Metadata common.Hash `json:"metadata"`
Expand All @@ -118,7 +118,7 @@ func (c *Certificate) Brief() string {
return nilStr
}
res := fmt.Sprintf("agglayer.Cert {height: %d prevLER: %s newLER: %s exits: %d imported_exits: %d}", c.Height,
common.Bytes2Hex(c.PrevLocalExitRoot[:]), common.Bytes2Hex(c.NewLocalExitRoot[:]),
c.PrevLocalExitRoot.String(), c.NewLocalExitRoot.String(),
len(c.BridgeExits), len(c.ImportedBridgeExits))
return res
}
Expand All @@ -141,8 +141,8 @@ func (c *Certificate) Hash() common.Hash {
return crypto.Keccak256Hash(
cdkcommon.Uint32ToBytes(c.NetworkID),
cdkcommon.Uint64ToBytes(c.Height),
c.PrevLocalExitRoot[:],
c.NewLocalExitRoot[:],
c.PrevLocalExitRoot.Bytes(),
c.NewLocalExitRoot.Bytes(),
bridgeExitsPart,
importedBridgeExitsPart,
)
Expand All @@ -157,7 +157,7 @@ func (c *Certificate) HashToSign() common.Hash {
}

return crypto.Keccak256Hash(
c.NewLocalExitRoot[:],
c.NewLocalExitRoot.Bytes(),
crypto.Keccak256Hash(globalIndexHashes...).Bytes(),
)
}
Expand Down Expand Up @@ -310,20 +310,29 @@ func (b *BridgeExit) Hash() common.Hash {

// MarshalJSON is the implementation of the json.Marshaler interface
func (b *BridgeExit) MarshalJSON() ([]byte, error) {
var metadataString interface{}
if b.IsMetadataHashed {
metadataString = common.Bytes2Hex(b.Metadata)
} else if len(b.Metadata) > 0 {
metadataString = bytesToUints(b.Metadata)
} else {
metadataString = nil
}

return json.Marshal(&struct {
LeafType string `json:"leaf_type"`
TokenInfo *TokenInfo `json:"token_info"`
DestinationNetwork uint32 `json:"dest_network"`
DestinationAddress common.Address `json:"dest_address"`
Amount string `json:"amount"`
Metadata []uint `json:"metadata"`
Metadata interface{} `json:"metadata"`
}{
LeafType: b.LeafType.String(),
TokenInfo: b.TokenInfo,
DestinationNetwork: b.DestinationNetwork,
DestinationAddress: b.DestinationAddress,
Amount: b.Amount.String(),
Metadata: bytesToUints(b.Metadata),
Metadata: metadataString,
})
}

Expand All @@ -344,18 +353,13 @@ type MerkleProof struct {

// MarshalJSON is the implementation of the json.Marshaler interface
func (m *MerkleProof) MarshalJSON() ([]byte, error) {
proofsAsBytes := [types.DefaultHeight][types.DefaultHeight]byte{}
for i, proof := range m.Proof {
proofsAsBytes[i] = proof
}

return json.Marshal(&struct {
Root [types.DefaultHeight]byte `json:"root"`
Proof map[string][types.DefaultHeight][types.DefaultHeight]byte `json:"proof"`
Root common.Hash `json:"root"`
Proof map[string][types.DefaultHeight]common.Hash `json:"proof"`
}{
Root: m.Root,
Proof: map[string][types.DefaultHeight][types.DefaultHeight]byte{
"siblings": proofsAsBytes,
Proof: map[string][types.DefaultHeight]common.Hash{
"siblings": m.Proof,
},
})
}
Expand Down Expand Up @@ -394,19 +398,6 @@ func (l *L1InfoTreeLeafInner) Hash() common.Hash {
)
}

// MarshalJSON is the implementation of the json.Marshaler interface
func (l *L1InfoTreeLeafInner) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
GlobalExitRoot [types.DefaultHeight]byte `json:"global_exit_root"`
BlockHash [types.DefaultHeight]byte `json:"block_hash"`
Timestamp uint64 `json:"timestamp"`
}{
GlobalExitRoot: l.GlobalExitRoot,
BlockHash: l.BlockHash,
Timestamp: l.Timestamp,
})
}

func (l *L1InfoTreeLeafInner) String() string {
return fmt.Sprintf("GlobalExitRoot: %s, BlockHash: %s, Timestamp: %d",
l.GlobalExitRoot.String(), l.BlockHash.String(), l.Timestamp)
Expand All @@ -415,8 +406,8 @@ func (l *L1InfoTreeLeafInner) String() string {
// L1InfoTreeLeaf represents the leaf of the L1 info tree
type L1InfoTreeLeaf struct {
L1InfoTreeIndex uint32 `json:"l1_info_tree_index"`
RollupExitRoot [32]byte `json:"rer"`
MainnetExitRoot [32]byte `json:"mer"`
RollupExitRoot common.Hash `json:"rer"`
MainnetExitRoot common.Hash `json:"mer"`
Inner *L1InfoTreeLeafInner `json:"inner"`
}

Expand All @@ -428,8 +419,8 @@ func (l *L1InfoTreeLeaf) Hash() common.Hash {
func (l *L1InfoTreeLeaf) String() string {
return fmt.Sprintf("L1InfoTreeIndex: %d, RollupExitRoot: %s, MainnetExitRoot: %s, Inner: %s",
l.L1InfoTreeIndex,
common.Bytes2Hex(l.RollupExitRoot[:]),
common.Bytes2Hex(l.MainnetExitRoot[:]),
l.RollupExitRoot.String(),
l.MainnetExitRoot.String(),
l.Inner.String(),
)
}
Expand Down
224 changes: 184 additions & 40 deletions agglayer/types_test.go

Large diffs are not rendered by default.

36 changes: 25 additions & 11 deletions aggsender/aggsender.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,17 +155,8 @@ func (a *AggSender) sendCertificate(ctx context.Context) (*agglayer.SignedCertif
if err != nil {
return nil, err
}
previousToBlock := uint64(0)
retryCount := 0
if lastSentCertificateInfo != nil {
previousToBlock = lastSentCertificateInfo.ToBlock
if lastSentCertificateInfo.Status == agglayer.InError {
// if the last certificate was in error, we need to resend it
// from the block before the error
previousToBlock = lastSentCertificateInfo.FromBlock - 1
retryCount = lastSentCertificateInfo.RetryCount + 1
}
}

previousToBlock, retryCount := getLastSentBlockAndRetryCount(lastSentCertificateInfo)

if previousToBlock >= lasL2BlockSynced {
a.log.Infof("no new blocks to send a certificate, last certificate block: %d, last L2 block: %d",
Expand Down Expand Up @@ -823,3 +814,26 @@ func NewCertificateInfoFromAgglayerCertHeader(c *agglayer.CertificateHeader) *ty
}
return res
}

// getLastSentBlockAndRetryCount returns the last sent block of the last sent certificate
// if there is no previosly sent certificate, it returns 0 and 0
func getLastSentBlockAndRetryCount(lastSentCertificateInfo *types.CertificateInfo) (uint64, int) {
if lastSentCertificateInfo == nil {
return 0, 0
}

retryCount := 0
previousToBlock := lastSentCertificateInfo.ToBlock

if lastSentCertificateInfo.Status == agglayer.InError {
// if the last certificate was in error, we need to resend it
// from the block before the error
if lastSentCertificateInfo.FromBlock > 0 {
previousToBlock = lastSentCertificateInfo.FromBlock - 1
}

retryCount = lastSentCertificateInfo.RetryCount + 1
}

return previousToBlock, retryCount
}
62 changes: 62 additions & 0 deletions aggsender/aggsender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1959,6 +1959,68 @@ func TestLimitSize_MinNumBlocks(t *testing.T) {
require.Equal(t, uint64(1), newCert.ToBlock)
}

func TestGetLastSentBlockAndRetryCount(t *testing.T) {
t.Parallel()

tests := []struct {
name string
lastSentCertificateInfo *aggsendertypes.CertificateInfo
expectedBlock uint64
expectedRetryCount int
}{
{
name: "No last sent certificate",
lastSentCertificateInfo: nil,
expectedBlock: 0,
expectedRetryCount: 0,
},
{
name: "Last sent certificate with no error",
lastSentCertificateInfo: &aggsendertypes.CertificateInfo{
ToBlock: 10,
Status: agglayer.Settled,
},
expectedBlock: 10,
expectedRetryCount: 0,
},
{
name: "Last sent certificate with error and non-zero FromBlock",
lastSentCertificateInfo: &aggsendertypes.CertificateInfo{
FromBlock: 5,
ToBlock: 10,
Status: agglayer.InError,
RetryCount: 1,
},
expectedBlock: 4,
expectedRetryCount: 2,
},
{
name: "Last sent certificate with error and zero FromBlock",
lastSentCertificateInfo: &aggsendertypes.CertificateInfo{
FromBlock: 0,
ToBlock: 10,
Status: agglayer.InError,
RetryCount: 1,
},
expectedBlock: 10,
expectedRetryCount: 2,
},
}

for _, tt := range tests {
tt := tt

t.Run(tt.name, func(t *testing.T) {
t.Parallel()

block, retryCount := getLastSentBlockAndRetryCount(tt.lastSentCertificateInfo)

require.Equal(t, tt.expectedBlock, block)
require.Equal(t, tt.expectedRetryCount, retryCount)
})
}
}

type testDataFlags = int

const (
Expand Down
4 changes: 2 additions & 2 deletions aggsender/types/certificate_build_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
)

const (
EstimatedSizeBridgeExit = 250
EstimatedSizeClaim = 44000
EstimatedSizeBridgeExit = 230
EstimatedSizeClaim = 8000
byteArrayJSONSizeFactor = 1.5
)

Expand Down

0 comments on commit c531821

Please sign in to comment.