diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml index 5a2b4cd79..a0bad59c6 100644 --- a/.github/workflows/test-e2e.yml +++ b/.github/workflows/test-e2e.yml @@ -54,7 +54,7 @@ jobs: fi else # For push/workflow_dispatch, use the fixed commit - COMMIT="5921c65d96e674b742080ceb5d19acc0e83ed0a9" + COMMIT="346e6c76bce576f29300a7de2d3b6efca09d9fdb" echo "Using fixed kurtosis-cdk commit: ${COMMIT}" fi echo "commit=${COMMIT}" >> $GITHUB_OUTPUT diff --git a/agglayer/grpc/conversion_to_agglayer.go b/agglayer/grpc/conversion_to_agglayer.go index b275e2a88..79274e1b3 100644 --- a/agglayer/grpc/conversion_to_agglayer.go +++ b/agglayer/grpc/conversion_to_agglayer.go @@ -296,7 +296,7 @@ func grpcAggchainDataToAgglayer( aggchainData *v1types.AggchainData, ) (agglayertypes.AggchainData, error) { if aggchainData == nil || aggchainData.Data == nil { - return nil, fmt.Errorf("grpcAggchainDataToAgglayer. aggchain data is nil. %w", ErrNilCertificate) + return nil, nil } switch ad := aggchainData.Data.(type) { diff --git a/agglayer/grpc/conversion_to_agglayer_test.go b/agglayer/grpc/conversion_to_agglayer_test.go index bacb4cae7..77d32eac6 100644 --- a/agglayer/grpc/conversion_to_agglayer_test.go +++ b/agglayer/grpc/conversion_to_agglayer_test.go @@ -154,14 +154,13 @@ func TestConvertProtoCertToAgglayer(t *testing.T) { require.ErrorContains(t, err, "has nil L1InfoTreeLeafCount") }) - t.Run("nil AggchainData", func(t *testing.T) { + t.Run("undefined AggchainData", func(t *testing.T) { protoCert, err := ConvertCertToProtoCertificate(exampleTestAgglayerCert) require.NoError(t, err) protoCert.AggchainData = nil result, err := ConvertProtoCertToAgglayer(protoCert) - require.Nil(t, result) - require.ErrorIs(t, err, ErrNilCertificate) - require.ErrorContains(t, err, "aggchain data is nil") + require.NoError(t, err) + require.Nil(t, result.AggchainData) }) t.Run("successful conversion", func(t *testing.T) { diff --git a/agglayer/types/types.go b/agglayer/types/types.go index c7c2f9ffd..1c2b45bcb 100644 --- a/agglayer/types/types.go +++ b/agglayer/types/types.go @@ -498,6 +498,22 @@ func (c *Certificate) CertificateID() common.Hash { ) } +// ExtractAggchainParams extracts the aggchain params field from the certificate +// with handling different types of aggchain data. +func (c *Certificate) ExtractAggchainParams() []byte { + switch data := c.AggchainData.(type) { + case *AggchainDataProof: + return data.AggchainParams.Bytes() + + case *AggchainDataMultisigWithProof: + if data.AggchainProof != nil { + return data.AggchainProof.AggchainParams.Bytes() + } + } + + return aggkitcommon.ZeroHash.Bytes() +} + // SignedCertificate is the struct that contains the certificate and the signature of the signer // NOTE: this is an old and deprecated struct, only to be used for backward compatibility type SignedCertificate struct { diff --git a/agglayer/types/types_test.go b/agglayer/types/types_test.go index fa81204d8..d096353a4 100644 --- a/agglayer/types/types_test.go +++ b/agglayer/types/types_test.go @@ -111,7 +111,7 @@ func TestCertificateHeaderString(t *testing.T) { require.Equal(t, "nil", certNil.String()) } -func TestMarshalJSON(t *testing.T) { +func TestCertificateMarshalJSON(t *testing.T) { t.Parallel() t.Run("MarshalJSON with empty proofs", func(t *testing.T) { @@ -269,6 +269,56 @@ func TestMarshalJSON(t *testing.T) { }) } +func TestCertificate_ExtractAggchainParams(t *testing.T) { + hash1 := common.HexToHash("0x1111") + hash2 := common.HexToHash("0x2222") + + tests := []struct { + name string + data AggchainData + expected []byte + }{ + { + name: "AggchainDataProof returns its params", + data: &AggchainDataProof{ + AggchainParams: hash1, + }, + expected: hash1.Bytes(), + }, + { + name: "AggchainDataMultisigWithProof returns nested params", + data: &AggchainDataMultisigWithProof{ + AggchainProof: &AggchainDataProof{ + AggchainParams: hash2, + }, + }, + expected: hash2.Bytes(), + }, + { + name: "AggchainDataMultisigWithProof with nil proof returns ZeroHash", + data: &AggchainDataMultisigWithProof{ + AggchainProof: nil, + }, + expected: aggkitcommon.ZeroHash.Bytes(), + }, + { + name: "Nil AggchainData returns ZeroHash", + data: nil, + expected: aggkitcommon.ZeroHash.Bytes(), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cert := &Certificate{ + AggchainData: tt.data, + } + actual := cert.ExtractAggchainParams() + require.Equal(t, tt.expected, actual) + }) + } +} + func TestGlobalIndex_UnmarshalFromMap(t *testing.T) { t.Parallel() diff --git a/aggsender/flows/flow_aggchain_prover.go b/aggsender/flows/flow_aggchain_prover.go index 0e0b93f51..278b72906 100644 --- a/aggsender/flows/flow_aggchain_prover.go +++ b/aggsender/flows/flow_aggchain_prover.go @@ -328,28 +328,27 @@ func (a *AggchainProverFlow) BuildCertificate(ctx context.Context, return cert, nil } -// UpdateAggchainData updates the AggchainData field in certificate with the multisig if needed +// UpdateAggchainData updates the AggchainData field in certificate with the multisig if provided. func (a *AggchainProverFlow) UpdateAggchainData( cert *agglayertypes.Certificate, multisig *agglayertypes.Multisig, ) error { if multisig == nil { - // multisig not turned on, we don't need to update the certificate + // Multisig not enabled, nothing to do return nil } - proof, ok := cert.AggchainData.(*agglayertypes.AggchainDataProof) - if !ok { - proofWithMultisig, ok := cert.AggchainData.(*agglayertypes.AggchainDataMultisigWithProof) - if !ok { - return errors.New("aggchainProverFlow - aggchain data field not " + - "AggchainDataProof nor AggchainDataMultisigWithProof") - } + var proof *agglayertypes.AggchainDataProof - proof = proofWithMultisig.AggchainProof + switch data := cert.AggchainData.(type) { + case *agglayertypes.AggchainDataProof: + proof = data + case *agglayertypes.AggchainDataMultisigWithProof: + proof = data.AggchainProof + default: + return fmt.Errorf("aggchainProverFlow: AggchainData of unknown type %T received", data) } - // update the agchain data with multisig cert.AggchainData = &agglayertypes.AggchainDataMultisigWithProof{ Multisig: multisig, AggchainProof: proof, diff --git a/aggsender/flows/flow_aggchain_prover_test.go b/aggsender/flows/flow_aggchain_prover_test.go index 33b8d395a..a6c7cb950 100644 --- a/aggsender/flows/flow_aggchain_prover_test.go +++ b/aggsender/flows/flow_aggchain_prover_test.go @@ -899,7 +899,7 @@ func Test_AggchainProverFlow_UpdateAggchainData(t *testing.T) { AggchainData: &agglayertypes.AggchainDataSignature{}, // wrong type }, multisig: &agglayertypes.Multisig{}, - expectedError: "aggchainProverFlow - aggchain data field not AggchainDataProof", + expectedError: "aggchainProverFlow: AggchainData of unknown type *types.AggchainDataSignature received", }, { name: "successful update - wraps proof with multisig", diff --git a/aggsender/query/certificate_query.go b/aggsender/query/certificate_query.go index a26a92a3f..1a8017610 100644 --- a/aggsender/query/certificate_query.go +++ b/aggsender/query/certificate_query.go @@ -138,20 +138,28 @@ func (c *certificateQuerier) GetNewCertificateToBlock( return max(lastBridgeExitBlock, lastImportedBridgeExitBlock), nil } -// CalculateCertificateType determines the type of certificate based on the last block number in certificate +// CalculateCertificateType determines the type of certificate. +// If AggchainData is present, the type is inferred from its variant (PP or FEP). +// Otherwise, it is derived from the last block number in certificate func (c *certificateQuerier) CalculateCertificateType( - cert *agglayertypes.Certificate, certToBlock uint64) types.CertificateType { - if cert.AggchainData != nil { - // if AggchainData is present, we can use it to determine the certificate type - _, ok := cert.AggchainData.(*agglayertypes.AggchainDataProof) - if !ok { - return types.CertificateTypeFEP - } - + cert *agglayertypes.Certificate, certToBlock uint64, +) types.CertificateType { + switch cert.AggchainData.(type) { + case *agglayertypes.AggchainDataSignature: + // AggchainDataSignature → PP type + return types.CertificateTypePP + case *agglayertypes.AggchainDataMultisig: + // AggchainDataMultisig → PP type return types.CertificateTypePP + case *agglayertypes.AggchainDataProof: + // AggchainDataProof → FEP type + return types.CertificateTypeFEP + case *agglayertypes.AggchainDataMultisigWithProof: + // AggchainDataMultisigWithProof → FEP type + return types.CertificateTypeFEP } - // if AggchainData is not present, must try to determine the type based on the block number + // no AggchainData → fallback on block-based logic return c.CalculateCertificateTypeFromToBlock(certToBlock) } diff --git a/aggsender/query/certificate_query_test.go b/aggsender/query/certificate_query_test.go index bc580f0dc..1d6899ac8 100644 --- a/aggsender/query/certificate_query_test.go +++ b/aggsender/query/certificate_query_test.go @@ -504,21 +504,37 @@ func TestCalculateCertificateType(t *testing.T) { expectedCertType types.CertificateType }{ { - name: "AggchainData is AggchainDataProof - returns PP", + name: "AggchainData is AggchainDataProof - returns FEP", certificate: &agglayertypes.Certificate{ AggchainData: &agglayertypes.AggchainDataProof{}, }, certToBlock: 100, - expectedCertType: types.CertificateTypePP, + expectedCertType: types.CertificateTypeFEP, }, { - name: "AggchainData is not AggchainDataProof - returns FEP", + name: "AggchainData is AggchainDataMultisigWithProof - returns FEP", certificate: &agglayertypes.Certificate{ - AggchainData: &agglayertypes.AggchainDataSignature{}, + AggchainData: &agglayertypes.AggchainDataMultisigWithProof{}, }, certToBlock: 100, expectedCertType: types.CertificateTypeFEP, }, + { + name: "AggchainData is AggchainDataSignature - returns PP", + certificate: &agglayertypes.Certificate{ + AggchainData: &agglayertypes.AggchainDataSignature{}, + }, + certToBlock: 100, + expectedCertType: types.CertificateTypePP, + }, + { + name: "AggchainData is AggchainDataMultisig - returns PP", + certificate: &agglayertypes.Certificate{ + AggchainData: &agglayertypes.AggchainDataMultisig{}, + }, + certToBlock: 100, + expectedCertType: types.CertificateTypePP, + }, { name: "AggchainData is nil - falls back to CalculateCertificateTypeFromToBlock with FEP network and block before start", certificate: &agglayertypes.Certificate{ diff --git a/aggsender/validator/cert_hash.go b/aggsender/validator/cert_hash.go index 6aa153a53..63bfd5066 100644 --- a/aggsender/validator/cert_hash.go +++ b/aggsender/validator/cert_hash.go @@ -22,8 +22,7 @@ func HashCertificateToSign(cert *agglayertypes.Certificate) (common.Hash, error) } claimsHash := crypto.Keccak256(claimsRawMetadata) - - aggchainParams := getAggchainParams(cert) + aggchainParams := cert.ExtractAggchainParams() return crypto.Keccak256Hash( cert.NewLocalExitRoot.Bytes(), @@ -33,19 +32,3 @@ func HashCertificateToSign(cert *agglayertypes.Certificate) (common.Hash, error) cert.CertificateID().Bytes(), ), nil } - -// getAggchainParams extracts the aggchain params field from the certificate -// with handling different types of aggchain data. -func getAggchainParams(cert *agglayertypes.Certificate) []byte { - aggchainDataProof, ok := cert.AggchainData.(*agglayertypes.AggchainDataProof) - if ok { - return aggchainDataProof.AggchainParams.Bytes() - } - - aggchainDataProofWithMultisig, ok := cert.AggchainData.(*agglayertypes.AggchainDataMultisigWithProof) - if ok && aggchainDataProofWithMultisig.AggchainProof != nil { - return aggchainDataProofWithMultisig.AggchainProof.AggchainParams.Bytes() - } - - return aggkitcommon.ZeroHash.Bytes() -}