diff --git a/agglayer/types.go b/agglayer/types.go index fa6277d9..c00b2345 100644 --- a/agglayer/types.go +++ b/agglayer/types.go @@ -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"` @@ -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 } @@ -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, ) @@ -157,7 +157,7 @@ func (c *Certificate) HashToSign() common.Hash { } return crypto.Keccak256Hash( - c.NewLocalExitRoot[:], + c.NewLocalExitRoot.Bytes(), crypto.Keccak256Hash(globalIndexHashes...).Bytes(), ) } @@ -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, }) } @@ -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, }, }) } @@ -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) @@ -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"` } @@ -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(), ) } diff --git a/agglayer/types_test.go b/agglayer/types_test.go index 6175a847..adf8e55a 100644 --- a/agglayer/types_test.go +++ b/agglayer/types_test.go @@ -2,17 +2,19 @@ package agglayer import ( "encoding/json" + "fmt" "math/big" "testing" "github.com/0xPolygon/cdk/log" + "github.com/0xPolygon/cdk/tree/types" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" ) const ( - expectedSignedCertificateEmptyMetadataJSON = `{"network_id":1,"height":1,"prev_local_exit_root":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"new_local_exit_root":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"bridge_exits":[{"leaf_type":"Transfer","token_info":null,"dest_network":0,"dest_address":"0x0000000000000000000000000000000000000000","amount":"1","metadata":[]}],"imported_bridge_exits":[{"bridge_exit":{"leaf_type":"Transfer","token_info":null,"dest_network":0,"dest_address":"0x0000000000000000000000000000000000000000","amount":"1","metadata":[]},"claim_data":null,"global_index":{"mainnet_flag":false,"rollup_index":1,"leaf_index":1}}],"metadata":"0x0000000000000000000000000000000000000000000000000000000000000000","signature":{"r":"0x0000000000000000000000000000000000000000000000000000000000000000","s":"0x0000000000000000000000000000000000000000000000000000000000000000","odd_y_parity":false}}` - expectedSignedCertificateyMetadataJSON = `{"network_id":1,"height":1,"prev_local_exit_root":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"new_local_exit_root":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"bridge_exits":[{"leaf_type":"Transfer","token_info":null,"dest_network":0,"dest_address":"0x0000000000000000000000000000000000000000","amount":"1","metadata":[1,2,3]}],"imported_bridge_exits":[{"bridge_exit":{"leaf_type":"Transfer","token_info":null,"dest_network":0,"dest_address":"0x0000000000000000000000000000000000000000","amount":"1","metadata":[]},"claim_data":null,"global_index":{"mainnet_flag":false,"rollup_index":1,"leaf_index":1}}],"metadata":"0x0000000000000000000000000000000000000000000000000000000000000000","signature":{"r":"0x0000000000000000000000000000000000000000000000000000000000000000","s":"0x0000000000000000000000000000000000000000000000000000000000000000","odd_y_parity":false}}` + expectedSignedCertificateEmptyMetadataJSON = `{"network_id":1,"height":1,"prev_local_exit_root":"0x0000000000000000000000000000000000000000000000000000000000000000","new_local_exit_root":"0x0000000000000000000000000000000000000000000000000000000000000000","bridge_exits":[{"leaf_type":"Transfer","token_info":null,"dest_network":0,"dest_address":"0x0000000000000000000000000000000000000000","amount":"1","metadata":null}],"imported_bridge_exits":[{"bridge_exit":{"leaf_type":"Transfer","token_info":null,"dest_network":0,"dest_address":"0x0000000000000000000000000000000000000000","amount":"1","metadata":null},"claim_data":null,"global_index":{"mainnet_flag":false,"rollup_index":1,"leaf_index":1}}],"metadata":"0x0000000000000000000000000000000000000000000000000000000000000000","signature":{"r":"0x0000000000000000000000000000000000000000000000000000000000000000","s":"0x0000000000000000000000000000000000000000000000000000000000000000","odd_y_parity":false}}` + expectedSignedCertificateMetadataJSON = `{"network_id":1,"height":1,"prev_local_exit_root":"0x0000000000000000000000000000000000000000000000000000000000000000","new_local_exit_root":"0x0000000000000000000000000000000000000000000000000000000000000000","bridge_exits":[{"leaf_type":"Transfer","token_info":null,"dest_network":0,"dest_address":"0x0000000000000000000000000000000000000000","amount":"1","metadata":[1,2,3]}],"imported_bridge_exits":[{"bridge_exit":{"leaf_type":"Transfer","token_info":null,"dest_network":0,"dest_address":"0x0000000000000000000000000000000000000000","amount":"1","metadata":null},"claim_data":null,"global_index":{"mainnet_flag":false,"rollup_index":1,"leaf_index":1}}],"metadata":"0x0000000000000000000000000000000000000000000000000000000000000000","signature":{"r":"0x0000000000000000000000000000000000000000000000000000000000000000","s":"0x0000000000000000000000000000000000000000000000000000000000000000","odd_y_parity":false}}` ) func TestBridgeExitHash(t *testing.T) { @@ -41,11 +43,15 @@ func TestBridgeExitHash(t *testing.T) { } func TestMGenericPPError(t *testing.T) { + t.Parallel() + err := GenericPPError{"test", "value"} require.Equal(t, "Generic error: test: value", err.String()) } func TestCertificateHeaderID(t *testing.T) { + t.Parallel() + certificate := CertificateHeader{ Height: 1, CertificateID: common.HexToHash("0x123"), @@ -57,6 +63,8 @@ func TestCertificateHeaderID(t *testing.T) { } func TestCertificateHeaderString(t *testing.T) { + t.Parallel() + certificate := CertificateHeader{ Height: 1, CertificateID: common.HexToHash("0x123"), @@ -69,53 +77,175 @@ func TestCertificateHeaderString(t *testing.T) { } func TestMarshalJSON(t *testing.T) { - cert := SignedCertificate{ - Certificate: &Certificate{ - NetworkID: 1, - Height: 1, - PrevLocalExitRoot: common.Hash{}, - NewLocalExitRoot: common.Hash{}, - BridgeExits: []*BridgeExit{ - { - LeafType: LeafTypeAsset, - DestinationAddress: common.Address{}, - Amount: big.NewInt(1), - }, - }, - ImportedBridgeExits: []*ImportedBridgeExit{ - { - BridgeExit: &BridgeExit{ + t.Parallel() + + t.Run("MarshalJSON with empty proofs", func(t *testing.T) { + t.Parallel() + + cert := SignedCertificate{ + Certificate: &Certificate{ + NetworkID: 1, + Height: 1, + PrevLocalExitRoot: common.Hash{}, + NewLocalExitRoot: common.Hash{}, + BridgeExits: []*BridgeExit{ + { LeafType: LeafTypeAsset, DestinationAddress: common.Address{}, Amount: big.NewInt(1), - Metadata: []byte{}, }, - ClaimData: nil, - GlobalIndex: &GlobalIndex{ - MainnetFlag: false, - RollupIndex: 1, - LeafIndex: 1, + }, + ImportedBridgeExits: []*ImportedBridgeExit{ + { + BridgeExit: &BridgeExit{ + LeafType: LeafTypeAsset, + DestinationAddress: common.Address{}, + Amount: big.NewInt(1), + Metadata: []byte{}, + }, + ClaimData: nil, + GlobalIndex: &GlobalIndex{ + MainnetFlag: false, + RollupIndex: 1, + LeafIndex: 1, + }, }, }, }, - }, - Signature: &Signature{ - R: common.Hash{}, - S: common.Hash{}, - OddParity: false, - }, - } - data, err := json.Marshal(cert) - require.NoError(t, err) - log.Info(string(data)) - require.Equal(t, expectedSignedCertificateEmptyMetadataJSON, string(data)) + Signature: &Signature{ + R: common.Hash{}, + S: common.Hash{}, + OddParity: false, + }, + } + data, err := json.Marshal(cert) + require.NoError(t, err) + log.Info(string(data)) + require.Equal(t, expectedSignedCertificateEmptyMetadataJSON, string(data)) - cert.BridgeExits[0].Metadata = []byte{1, 2, 3} - data, err = json.Marshal(cert) - require.NoError(t, err) - log.Info(string(data)) - require.Equal(t, expectedSignedCertificateyMetadataJSON, string(data)) + cert.BridgeExits[0].Metadata = []byte{1, 2, 3} + data, err = json.Marshal(cert) + require.NoError(t, err) + log.Info(string(data)) + require.Equal(t, expectedSignedCertificateMetadataJSON, string(data)) + }) + + t.Run("MarshalJSON with proofs", func(t *testing.T) { + t.Parallel() + + cert := SignedCertificate{ + Certificate: &Certificate{ + NetworkID: 11, + Height: 111, + PrevLocalExitRoot: common.HexToHash("0x111"), + NewLocalExitRoot: common.HexToHash("0x222"), + BridgeExits: []*BridgeExit{ + { + LeafType: LeafTypeAsset, + TokenInfo: &TokenInfo{OriginNetwork: 1, OriginTokenAddress: common.HexToAddress("0x123")}, + DestinationNetwork: 2, + DestinationAddress: common.HexToAddress("0x456"), + Amount: big.NewInt(1000), + Metadata: []byte{}, // we leave it empty on purpose to see when marshaled it will be null + }, + }, + ImportedBridgeExits: []*ImportedBridgeExit{ + { + BridgeExit: &BridgeExit{ + LeafType: LeafTypeMessage, + TokenInfo: &TokenInfo{OriginNetwork: 1, OriginTokenAddress: common.HexToAddress("0x789")}, + DestinationNetwork: 2, + DestinationAddress: common.HexToAddress("0xabc"), + Amount: big.NewInt(2000), + Metadata: []byte{0x03, 0x04}, + }, + GlobalIndex: &GlobalIndex{ + MainnetFlag: true, + RollupIndex: 0, + LeafIndex: 1, + }, + ClaimData: &ClaimFromMainnnet{ + ProofLeafMER: &MerkleProof{ + Root: common.HexToHash("0x333"), + Proof: generateTestProof(t), + }, + ProofGERToL1Root: &MerkleProof{ + Root: common.HexToHash("0x444"), + Proof: generateTestProof(t), + }, + L1Leaf: &L1InfoTreeLeaf{ + L1InfoTreeIndex: 1, + RollupExitRoot: common.HexToHash("0x555"), + MainnetExitRoot: common.HexToHash("0x123456"), + Inner: &L1InfoTreeLeafInner{ + GlobalExitRoot: common.HexToHash("0x777"), + BlockHash: common.HexToHash("0x888"), + Timestamp: 12345678, + }, + }, + }, + }, + { + BridgeExit: &BridgeExit{ + LeafType: LeafTypeAsset, + TokenInfo: &TokenInfo{OriginNetwork: 1, OriginTokenAddress: common.HexToAddress("0x789")}, + DestinationNetwork: 2, + DestinationAddress: common.HexToAddress("0xabcdef"), + Amount: big.NewInt(2201), + Metadata: []byte{0x05, 0x08}, + }, + GlobalIndex: &GlobalIndex{ + MainnetFlag: false, + RollupIndex: 1, + LeafIndex: 2, + }, + ClaimData: &ClaimFromRollup{ + ProofLeafLER: &MerkleProof{ + Root: common.HexToHash("0x333"), + Proof: generateTestProof(t), + }, + ProofLERToRER: &MerkleProof{ + Root: common.HexToHash("0x444"), + Proof: generateTestProof(t), + }, + ProofGERToL1Root: &MerkleProof{ + Root: common.HexToHash("0x555"), + Proof: generateTestProof(t), + }, + L1Leaf: &L1InfoTreeLeaf{ + L1InfoTreeIndex: 2, + RollupExitRoot: common.HexToHash("0x532"), + MainnetExitRoot: common.HexToHash("0x654321"), + Inner: &L1InfoTreeLeafInner{ + GlobalExitRoot: common.HexToHash("0x777"), + BlockHash: common.HexToHash("0x888"), + Timestamp: 12345678, + }, + }, + }, + }, + }, + Metadata: common.HexToHash("0xdef"), + }, + Signature: &Signature{ + R: common.HexToHash("0x111"), + S: common.HexToHash("0x222"), + OddParity: true, + }, + } + + expectedJSON := `{"network_id":11,"height":111,"prev_local_exit_root":"0x0000000000000000000000000000000000000000000000000000000000000111","new_local_exit_root":"0x0000000000000000000000000000000000000000000000000000000000000222","bridge_exits":[{"leaf_type":"Transfer","token_info":{"origin_network":1,"origin_token_address":"0x0000000000000000000000000000000000000123"},"dest_network":2,"dest_address":"0x0000000000000000000000000000000000000456","amount":"1000","metadata":null}],"imported_bridge_exits":[{"bridge_exit":{"leaf_type":"Message","token_info":{"origin_network":1,"origin_token_address":"0x0000000000000000000000000000000000000789"},"dest_network":2,"dest_address":"0x0000000000000000000000000000000000000abc","amount":"2000","metadata":[3,4]},"claim_data":{"Mainnet":{"l1_leaf":{"l1_info_tree_index":1,"rer":"0x0000000000000000000000000000000000000000000000000000000000000555","mer":"0x0000000000000000000000000000000000000000000000000000000000123456","inner":{"global_exit_root":"0x0000000000000000000000000000000000000000000000000000000000000777","block_hash":"0x0000000000000000000000000000000000000000000000000000000000000888","timestamp":12345678}},"proof_ger_l1root":{"root":"0x0000000000000000000000000000000000000000000000000000000000000444","proof":{"siblings":["0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000003","0x0000000000000000000000000000000000000000000000000000000000000004","0x0000000000000000000000000000000000000000000000000000000000000005","0x0000000000000000000000000000000000000000000000000000000000000006","0x0000000000000000000000000000000000000000000000000000000000000007","0x0000000000000000000000000000000000000000000000000000000000000008","0x0000000000000000000000000000000000000000000000000000000000000009","0x000000000000000000000000000000000000000000000000000000000000000a","0x000000000000000000000000000000000000000000000000000000000000000b","0x000000000000000000000000000000000000000000000000000000000000000c","0x000000000000000000000000000000000000000000000000000000000000000d","0x000000000000000000000000000000000000000000000000000000000000000e","0x000000000000000000000000000000000000000000000000000000000000000f","0x0000000000000000000000000000000000000000000000000000000000000010","0x0000000000000000000000000000000000000000000000000000000000000011","0x0000000000000000000000000000000000000000000000000000000000000012","0x0000000000000000000000000000000000000000000000000000000000000013","0x0000000000000000000000000000000000000000000000000000000000000014","0x0000000000000000000000000000000000000000000000000000000000000015","0x0000000000000000000000000000000000000000000000000000000000000016","0x0000000000000000000000000000000000000000000000000000000000000017","0x0000000000000000000000000000000000000000000000000000000000000018","0x0000000000000000000000000000000000000000000000000000000000000019","0x000000000000000000000000000000000000000000000000000000000000001a","0x000000000000000000000000000000000000000000000000000000000000001b","0x000000000000000000000000000000000000000000000000000000000000001c","0x000000000000000000000000000000000000000000000000000000000000001d","0x000000000000000000000000000000000000000000000000000000000000001e","0x000000000000000000000000000000000000000000000000000000000000001f"]}},"proof_leaf_mer":{"root":"0x0000000000000000000000000000000000000000000000000000000000000333","proof":{"siblings":["0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000003","0x0000000000000000000000000000000000000000000000000000000000000004","0x0000000000000000000000000000000000000000000000000000000000000005","0x0000000000000000000000000000000000000000000000000000000000000006","0x0000000000000000000000000000000000000000000000000000000000000007","0x0000000000000000000000000000000000000000000000000000000000000008","0x0000000000000000000000000000000000000000000000000000000000000009","0x000000000000000000000000000000000000000000000000000000000000000a","0x000000000000000000000000000000000000000000000000000000000000000b","0x000000000000000000000000000000000000000000000000000000000000000c","0x000000000000000000000000000000000000000000000000000000000000000d","0x000000000000000000000000000000000000000000000000000000000000000e","0x000000000000000000000000000000000000000000000000000000000000000f","0x0000000000000000000000000000000000000000000000000000000000000010","0x0000000000000000000000000000000000000000000000000000000000000011","0x0000000000000000000000000000000000000000000000000000000000000012","0x0000000000000000000000000000000000000000000000000000000000000013","0x0000000000000000000000000000000000000000000000000000000000000014","0x0000000000000000000000000000000000000000000000000000000000000015","0x0000000000000000000000000000000000000000000000000000000000000016","0x0000000000000000000000000000000000000000000000000000000000000017","0x0000000000000000000000000000000000000000000000000000000000000018","0x0000000000000000000000000000000000000000000000000000000000000019","0x000000000000000000000000000000000000000000000000000000000000001a","0x000000000000000000000000000000000000000000000000000000000000001b","0x000000000000000000000000000000000000000000000000000000000000001c","0x000000000000000000000000000000000000000000000000000000000000001d","0x000000000000000000000000000000000000000000000000000000000000001e","0x000000000000000000000000000000000000000000000000000000000000001f"]}}}},"global_index":{"mainnet_flag":true,"rollup_index":0,"leaf_index":1}},{"bridge_exit":{"leaf_type":"Transfer","token_info":{"origin_network":1,"origin_token_address":"0x0000000000000000000000000000000000000789"},"dest_network":2,"dest_address":"0x0000000000000000000000000000000000abcdef","amount":"2201","metadata":[5,8]},"claim_data":{"Rollup":{"l1_leaf":{"l1_info_tree_index":2,"rer":"0x0000000000000000000000000000000000000000000000000000000000000532","mer":"0x0000000000000000000000000000000000000000000000000000000000654321","inner":{"global_exit_root":"0x0000000000000000000000000000000000000000000000000000000000000777","block_hash":"0x0000000000000000000000000000000000000000000000000000000000000888","timestamp":12345678}},"proof_ger_l1root":{"root":"0x0000000000000000000000000000000000000000000000000000000000000555","proof":{"siblings":["0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000003","0x0000000000000000000000000000000000000000000000000000000000000004","0x0000000000000000000000000000000000000000000000000000000000000005","0x0000000000000000000000000000000000000000000000000000000000000006","0x0000000000000000000000000000000000000000000000000000000000000007","0x0000000000000000000000000000000000000000000000000000000000000008","0x0000000000000000000000000000000000000000000000000000000000000009","0x000000000000000000000000000000000000000000000000000000000000000a","0x000000000000000000000000000000000000000000000000000000000000000b","0x000000000000000000000000000000000000000000000000000000000000000c","0x000000000000000000000000000000000000000000000000000000000000000d","0x000000000000000000000000000000000000000000000000000000000000000e","0x000000000000000000000000000000000000000000000000000000000000000f","0x0000000000000000000000000000000000000000000000000000000000000010","0x0000000000000000000000000000000000000000000000000000000000000011","0x0000000000000000000000000000000000000000000000000000000000000012","0x0000000000000000000000000000000000000000000000000000000000000013","0x0000000000000000000000000000000000000000000000000000000000000014","0x0000000000000000000000000000000000000000000000000000000000000015","0x0000000000000000000000000000000000000000000000000000000000000016","0x0000000000000000000000000000000000000000000000000000000000000017","0x0000000000000000000000000000000000000000000000000000000000000018","0x0000000000000000000000000000000000000000000000000000000000000019","0x000000000000000000000000000000000000000000000000000000000000001a","0x000000000000000000000000000000000000000000000000000000000000001b","0x000000000000000000000000000000000000000000000000000000000000001c","0x000000000000000000000000000000000000000000000000000000000000001d","0x000000000000000000000000000000000000000000000000000000000000001e","0x000000000000000000000000000000000000000000000000000000000000001f"]}},"proof_leaf_ler":{"root":"0x0000000000000000000000000000000000000000000000000000000000000333","proof":{"siblings":["0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000003","0x0000000000000000000000000000000000000000000000000000000000000004","0x0000000000000000000000000000000000000000000000000000000000000005","0x0000000000000000000000000000000000000000000000000000000000000006","0x0000000000000000000000000000000000000000000000000000000000000007","0x0000000000000000000000000000000000000000000000000000000000000008","0x0000000000000000000000000000000000000000000000000000000000000009","0x000000000000000000000000000000000000000000000000000000000000000a","0x000000000000000000000000000000000000000000000000000000000000000b","0x000000000000000000000000000000000000000000000000000000000000000c","0x000000000000000000000000000000000000000000000000000000000000000d","0x000000000000000000000000000000000000000000000000000000000000000e","0x000000000000000000000000000000000000000000000000000000000000000f","0x0000000000000000000000000000000000000000000000000000000000000010","0x0000000000000000000000000000000000000000000000000000000000000011","0x0000000000000000000000000000000000000000000000000000000000000012","0x0000000000000000000000000000000000000000000000000000000000000013","0x0000000000000000000000000000000000000000000000000000000000000014","0x0000000000000000000000000000000000000000000000000000000000000015","0x0000000000000000000000000000000000000000000000000000000000000016","0x0000000000000000000000000000000000000000000000000000000000000017","0x0000000000000000000000000000000000000000000000000000000000000018","0x0000000000000000000000000000000000000000000000000000000000000019","0x000000000000000000000000000000000000000000000000000000000000001a","0x000000000000000000000000000000000000000000000000000000000000001b","0x000000000000000000000000000000000000000000000000000000000000001c","0x000000000000000000000000000000000000000000000000000000000000001d","0x000000000000000000000000000000000000000000000000000000000000001e","0x000000000000000000000000000000000000000000000000000000000000001f"]}},"proof_ler_rer":{"root":"0x0000000000000000000000000000000000000000000000000000000000000444","proof":{"siblings":["0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000003","0x0000000000000000000000000000000000000000000000000000000000000004","0x0000000000000000000000000000000000000000000000000000000000000005","0x0000000000000000000000000000000000000000000000000000000000000006","0x0000000000000000000000000000000000000000000000000000000000000007","0x0000000000000000000000000000000000000000000000000000000000000008","0x0000000000000000000000000000000000000000000000000000000000000009","0x000000000000000000000000000000000000000000000000000000000000000a","0x000000000000000000000000000000000000000000000000000000000000000b","0x000000000000000000000000000000000000000000000000000000000000000c","0x000000000000000000000000000000000000000000000000000000000000000d","0x000000000000000000000000000000000000000000000000000000000000000e","0x000000000000000000000000000000000000000000000000000000000000000f","0x0000000000000000000000000000000000000000000000000000000000000010","0x0000000000000000000000000000000000000000000000000000000000000011","0x0000000000000000000000000000000000000000000000000000000000000012","0x0000000000000000000000000000000000000000000000000000000000000013","0x0000000000000000000000000000000000000000000000000000000000000014","0x0000000000000000000000000000000000000000000000000000000000000015","0x0000000000000000000000000000000000000000000000000000000000000016","0x0000000000000000000000000000000000000000000000000000000000000017","0x0000000000000000000000000000000000000000000000000000000000000018","0x0000000000000000000000000000000000000000000000000000000000000019","0x000000000000000000000000000000000000000000000000000000000000001a","0x000000000000000000000000000000000000000000000000000000000000001b","0x000000000000000000000000000000000000000000000000000000000000001c","0x000000000000000000000000000000000000000000000000000000000000001d","0x000000000000000000000000000000000000000000000000000000000000001e","0x000000000000000000000000000000000000000000000000000000000000001f"]}}}},"global_index":{"mainnet_flag":false,"rollup_index":1,"leaf_index":2}}],"metadata":"0x0000000000000000000000000000000000000000000000000000000000000def","signature":{"r":"0x0000000000000000000000000000000000000000000000000000000000000111","s":"0x0000000000000000000000000000000000000000000000000000000000000222","odd_y_parity":true}}` + + data, err := json.Marshal(cert) + require.NoError(t, err) + require.Equal(t, expectedJSON, string(data)) + + require.Equal(t, "0x46da3ca29098968ffc46ed2b894757671fa73cf7ebd4b82c89e90cc36a2737ae", cert.Hash().String()) + require.Equal(t, "0xc82b12e7383d2a8c1ec290d575bf6b2ac48363ca824cd51fe9f8cd312d55cd7a", cert.BridgeExits[0].Hash().String()) + require.Equal(t, "0x23fbdb2d272c9a4ae45135986363363d2e87dd6c2f2494a62b86851396f3fed4", cert.ImportedBridgeExits[0].Hash().String()) + require.Equal(t, "0x7eb947fcd0ed89ba0f41ec3f85e600d7114ec9349eb99a9478e3dd4e456297b1", cert.ImportedBridgeExits[1].Hash().String()) + }) } func TestSignedCertificate_Copy(t *testing.T) { @@ -306,6 +436,8 @@ func TestGlobalIndex_UnmarshalFromMap(t *testing.T) { } func TestUnmarshalCertificateHeaderUnknownError(t *testing.T) { + t.Parallel() + str := "{\"network_id\":14,\"height\":0,\"epoch_number\":null,\"certificate_index\":null,\"certificate_id\":\"0x3af88c9ca106822bd141fdc680dcb888f4e9d4997fad1645ba3d5d747059eb32\",\"new_local_exit_root\":\"0x625e889ced3c31277c6653229096374d396a2fd3564a8894aaad2ff935d2fc8c\",\"metadata\":\"0x0000000000000000000000000000000000000000000000000000000000002f3d\",\"status\":{\"InError\":{\"error\":{\"ProofVerificationFailed\":{\"Plonk\":\"the verifying key does not match the inner plonk bn254 proof's committed verifying key\"}}}}}" data := []byte(str) var result *CertificateHeader @@ -315,3 +447,15 @@ func TestUnmarshalCertificateHeaderUnknownError(t *testing.T) { ppError := result.Error.String() require.Equal(t, `Generic error: ProofVerificationFailed: {"Plonk":"the verifying key does not match the inner plonk bn254 proof's committed verifying key"}`, ppError) } + +func generateTestProof(t *testing.T) types.Proof { + t.Helper() + + proof := types.Proof{} + + for i := 0; i < int(types.DefaultHeight); i++ { + proof[i] = common.HexToHash(fmt.Sprintf("0x%x", i)) + } + + return proof +} diff --git a/aggsender/aggsender.go b/aggsender/aggsender.go index 366e6950..cb3319d0 100644 --- a/aggsender/aggsender.go +++ b/aggsender/aggsender.go @@ -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", @@ -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 +} diff --git a/aggsender/aggsender_test.go b/aggsender/aggsender_test.go index 7102c745..6d82604c 100644 --- a/aggsender/aggsender_test.go +++ b/aggsender/aggsender_test.go @@ -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 ( diff --git a/aggsender/types/certificate_build_params.go b/aggsender/types/certificate_build_params.go index 9fb09aba..1ffd7563 100644 --- a/aggsender/types/certificate_build_params.go +++ b/aggsender/types/certificate_build_params.go @@ -7,8 +7,8 @@ import ( ) const ( - EstimatedSizeBridgeExit = 250 - EstimatedSizeClaim = 44000 + EstimatedSizeBridgeExit = 230 + EstimatedSizeClaim = 8000 byteArrayJSONSizeFactor = 1.5 )