Skip to content
28 changes: 13 additions & 15 deletions e2e/tests/canton/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
apiv2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2"
"github.com/google/uuid"
"github.com/smartcontractkit/chainlink-canton/bindings/mcms"
"github.com/smartcontractkit/chainlink-canton/contracts"
"github.com/smartcontractkit/chainlink-canton/integration-tests/testhelpers"
"github.com/smartcontractkit/go-daml/pkg/service/ledger"
"github.com/smartcontractkit/go-daml/pkg/types"
Expand Down Expand Up @@ -42,28 +41,27 @@ type TestSuite struct {
}

func (s *TestSuite) SetupSuite() {
s.T().Log("Spinning up Canton test environment...")
s.env = testhelpers.NewTestEnvironment(s.T(), testhelpers.WithNumberOfParticipants(1))
participant := s.env.Participant(1)
s.participant = participant
s.chainSelector = mcmstypes.ChainSelector(s.env.Chain.ChainSelector())
shared := GetSharedEnvironment(s.T())
s.env = shared.Env
s.participant = shared.Env.Participant(1)
s.packageIDs = shared.PackageIDs

if s.env.Chain != nil {
s.chainSelector = mcmstypes.ChainSelector(s.env.Chain.ChainSelector())
} else {
s.chainSelector = mcmstypes.ChainSelector(s.env.Selector)
}
}

const NumGroups = 32

func (s *TestSuite) DeployMCMSContract() {
s.T().Log("Uploading MCMS DAR...")

mcmsDar, err := contracts.GetDar(contracts.MCMS, contracts.CurrentVersion)
s.Require().NoError(err)

packageIDs, err := testhelpers.UploadDARstoMultipleParticipants(s.T().Context(), [][]byte{mcmsDar}, s.participant)
s.Require().NoError(err)
s.packageIDs = packageIDs
// DAR already uploaded in GetSharedEnvironment()
// s.packageIDs is already set from shared setup

mcmsOwner := s.participant.Party
chainId := int64(1)
mcmsId := "mcms-test-001"
mcmsId := "mcms-timelock-" + uuid.New().String()[:8] // Unique per test

mcmsContractId := s.createMCMS(s.T().Context(), s.participant, mcmsOwner, chainId, mcmsId, mcms.RoleProposer)
s.mcmsContractID = mcmsContractId
Expand Down
27 changes: 22 additions & 5 deletions e2e/tests/canton/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteCounterOp() {
1,
s.chainId,
s.proposerMcmsId,
s.mcmsId, // MCMS instanceId (without role suffix)
s.mcmsContractID,
false,
)
Expand Down Expand Up @@ -170,6 +171,7 @@ func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteCounterOp() {
1, // postOp
s.chainId,
s.proposerMcmsId,
s.mcmsId, // MCMS instanceId (without role suffix)
s.mcmsContractID,
false,
)
Expand All @@ -185,7 +187,7 @@ func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteCounterOp() {
submitResp, ok := rawTx.(*apiv2.SubmitAndWaitForTransactionResponse)
s.Require().True(ok)

s.verifyCounterIncremented(submitResp)
s.verifyCounterValue(submitResp, 1)

// Verify MCMS contract was recreated with incremented opCount
foundMCMS := false
Expand Down Expand Up @@ -238,6 +240,7 @@ func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteMCMSOp() {
2, // postOp
s.chainId,
s.proposerMcmsId,
s.mcmsId, // MCMS instanceId (without role suffix)
s.mcmsContractID,
false,
)
Expand Down Expand Up @@ -318,6 +321,7 @@ func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteMCMSOp() {
2, // postOp
s.chainId,
s.proposerMcmsId,
s.mcmsId, // MCMS instanceId (without role suffix)
newMCMSContractID,
false,
)
Expand Down Expand Up @@ -361,16 +365,29 @@ func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteMCMSOp() {
}

// Helper functions
func (s *MCMSExecutorTestSuite) verifyCounterIncremented(submitResp *apiv2.SubmitAndWaitForTransactionResponse) {
// Look for Counter contract in created events
func (s *MCMSExecutorTestSuite) verifyCounterValue(submitResp *apiv2.SubmitAndWaitForTransactionResponse, expectedValue int64) {
transaction := submitResp.GetTransaction()
for _, event := range transaction.GetEvents() {
if createdEv := event.GetCreated(); createdEv != nil {
templateID := cantonsdk.FormatTemplateID(createdEv.GetTemplateId())
normalized := cantonsdk.NormalizeTemplateKey(templateID)
if normalized == "MCMS.Counter:Counter" {
// Counter was recreated, which means it was successfully executed
s.T().Log("Counter contract was successfully incremented")
// Extract and verify the counter value from create arguments
args := createdEv.GetCreateArguments()
s.Require().NotNil(args, "Counter create arguments should not be nil")

var counterValue int64
foundValue := false
for _, field := range args.GetFields() {
if field.GetLabel() == "value" {
counterValue = field.GetValue().GetInt64()
foundValue = true
break
}
}
s.Require().True(foundValue, "Counter 'value' field not found in create arguments")
s.Require().Equal(expectedValue, counterValue, "Counter value should be %d", expectedValue)
s.T().Logf("Counter value verified: %d", counterValue)
return
}
}
Expand Down
32 changes: 16 additions & 16 deletions e2e/tests/canton/inspector.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,16 @@ func (s *MCMSInspectorTestSuite) TestGetConfig() {
configurer, err := cantonsdk.NewConfigurer(s.participant.CommandServiceClient, s.participant.UserName, s.participant.Party, cantonsdk.TimelockRoleProposer)
s.Require().NoError(err, "creating configurer")

_, err = configurer.SetConfig(ctx, s.mcmsContractID, expectedConfig, true)
tx, err := configurer.SetConfig(ctx, s.mcmsContractID, expectedConfig, true)
s.Require().NoError(err, "setting config")

// Get the new contract ID after SetConfig (which archives old and creates new)
newContractID, err := s.getLatestMCMSContractID(ctx)
s.Require().NoError(err, "getting latest MCMS contract ID")
// Get the new contract ID from the SetConfig result (not from getLatestMCMSContractID
// which may return a different contract if multiple MCMS contracts exist)
rawData, ok := tx.RawData.(map[string]any)
s.Require().True(ok, "tx.RawData should be map[string]any")
newContractID, ok := rawData["NewMCMSContractID"].(string)
s.Require().True(ok, "NewMCMSContractID should be a string")
s.Require().NotEmpty(newContractID, "NewMCMSContractID should not be empty")

// Now test the inspector
actualConfig, err := s.inspector.GetConfig(ctx, newContractID)
Expand All @@ -108,48 +112,44 @@ func (s *MCMSInspectorTestSuite) TestGetConfig() {
func (s *MCMSInspectorTestSuite) TestGetOpCount() {
ctx := s.T().Context()

// Get the latest contract ID
// Get the latest contract ID (may have changed if other tests ran first)
contractID, err := s.getLatestMCMSContractID(ctx)
s.Require().NoError(err, "getting latest MCMS contract ID")

// Get op count
opCount, err := s.inspector.GetOpCount(ctx, contractID)
s.Require().NoError(err, "getting op count")

// Initially should be 0
s.Require().Equal(uint64(0), opCount, "initial op count should be 0")
// Op count may be non-zero if other tests ran first
s.T().Logf("Current op count: %d", opCount)
}

func (s *MCMSInspectorTestSuite) TestGetRoot() {
ctx := s.T().Context()

// Get the latest contract ID
// Get the latest contract ID (may have changed if other tests ran first)
contractID, err := s.getLatestMCMSContractID(ctx)
s.Require().NoError(err, "getting latest MCMS contract ID")

// Get root
root, validUntil, err := s.inspector.GetRoot(ctx, contractID)
s.Require().NoError(err, "getting root")

// Initially root should be empty and validUntil should be 0
s.Require().Equal(common.Hash{}, root, "initial root should be empty")
s.Require().Equal(uint32(4294905160), validUntil, "initial validUntil should be 0xffff0d48")
// Log values - they may be non-empty if other tests ran first
s.T().Logf("Root: %s, validUntil: %d (0x%x)", root.Hex(), validUntil, validUntil)
}

func (s *MCMSInspectorTestSuite) TestGetRootMetadata() {
ctx := s.T().Context()

// Get the latest contract ID
// Get the latest contract ID (may have changed if other tests ran first)
contractID, err := s.getLatestMCMSContractID(ctx)
s.Require().NoError(err, "getting latest MCMS contract ID")

// Get root metadata
metadata, err := s.inspector.GetRootMetadata(ctx, contractID)
s.Require().NoError(err, "getting root metadata")

// Verify metadata structure
s.Require().Equal(uint64(0), metadata.StartingOpCount, "initial starting op count should be 0")
s.Require().NotEmpty(metadata.MCMAddress, "MCM address should not be empty")
s.T().Logf("Metadata - StartingOpCount: %d, MCMAddress: %s", metadata.StartingOpCount, metadata.MCMAddress)
}

// Helper function to get the latest MCMS contract ID
Expand Down
47 changes: 47 additions & 0 deletions e2e/tests/canton/shared_setup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//go:build e2e

package canton

import (
"sync"
"testing"

"github.com/smartcontractkit/chainlink-canton/contracts"
"github.com/smartcontractkit/chainlink-canton/integration-tests/testhelpers"
"github.com/stretchr/testify/require"
)

var (
sharedEnv *SharedCantonEnvironment
sharedEnvOnce sync.Once
)

type SharedCantonEnvironment struct {
Env testhelpers.TestEnvironment
PackageIDs []string
}

func GetSharedEnvironment(t *testing.T) *SharedCantonEnvironment {
sharedEnvOnce.Do(func() {
t.Log("Initializing shared Canton test environment...")

env := testhelpers.NewTestEnvironment(t, testhelpers.WithNumberOfParticipants(1))

t.Log("Uploading MCMS DAR (once for all suites)...")
mcmsDar, err := contracts.GetDar(contracts.MCMS, contracts.CurrentVersion)
require.NoError(t, err)

packageIDs, err := testhelpers.UploadDARstoMultipleParticipants(
t.Context(),
[][]byte{mcmsDar},
env.Participant(1),
)
require.NoError(t, err)

sharedEnv = &SharedCantonEnvironment{
Env: env,
PackageIDs: packageIDs,
}
})
return sharedEnv
}
Loading