Skip to content

Commit

Permalink
chore: tests for multiple timelock instances wip
Browse files Browse the repository at this point in the history
  • Loading branch information
jadepark-dev committed Jan 8, 2025
1 parent 657135d commit 211e364
Show file tree
Hide file tree
Showing 10 changed files with 349 additions and 189 deletions.
2 changes: 1 addition & 1 deletion chains/solana/contracts/tests/config/mcm_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ var (
}

// [0,0,0,...'t','e','s','t','-','m','c','m',]
TestMsigNamePaddedBuffer = [32]byte{
TestMsigName = [32]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x6d, 0x63, 0x6d,
}
MaxNumSigners = 180
Expand Down
2 changes: 1 addition & 1 deletion chains/solana/contracts/tests/config/timelock_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ var (
TimelockProgram = solana.MustPublicKeyFromBase58("LoCoNsJFuhTkSQjfdDfn3yuwqhSYoPujmviRHVCzsqn")

// [0,0,0,...'t','e','s','t','-','t','i','m','e','l','o','c','k']
TestTimelockIDPaddedBuffer = [32]byte{
TestTimelockID = [32]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x6f, 0x63, 0x6b,
}
NumAccountsPerRole = 63 // max 64 accounts per role(access list) * 4 - 1(to keep test accounts fits single funding)
Expand Down
2 changes: 1 addition & 1 deletion chains/solana/contracts/tests/mcms/mcm_set_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func TestMcmSetConfig(t *testing.T) {
solanaGoClient := testutils.DeployAllPrograms(t, testutils.PathToAnchorConfig, admin)

// mcm name
testMsigName := config.TestMsigNamePaddedBuffer
testMsigName := config.TestMsigName

// test mcm pdas
multisigConfigPDA := mcms.GetConfigPDA(testMsigName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func TestMcmSetRootAndExecute(t *testing.T) {

t.Run("mcm:general test cases", func(t *testing.T) {
// mcm name
testMsigName := config.TestMsigNamePaddedBuffer
testMsigName := config.TestMsigName

// test mcm pdas
multisigConfigPDA := mcms.GetConfigPDA(testMsigName)
Expand Down Expand Up @@ -95,7 +95,7 @@ func TestMcmSetRootAndExecute(t *testing.T) {
IsWritable: true,
},
{
PublicKey: mcms.GetSignerPDA(config.TestMsigNamePaddedBuffer),
PublicKey: mcms.GetSignerPDA(config.TestMsigName),
IsSigner: false,
IsWritable: true,
},
Expand Down Expand Up @@ -149,7 +149,7 @@ func TestMcmSetRootAndExecute(t *testing.T) {
IsWritable: true,
},
{
PublicKey: mcms.GetSignerPDA(config.TestMsigNamePaddedBuffer),
PublicKey: mcms.GetSignerPDA(config.TestMsigName),
IsSigner: false,
IsWritable: true,
},
Expand Down
145 changes: 76 additions & 69 deletions chains/solana/contracts/tests/mcms/mcm_timelock_test.go

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ func TestTimelockBypasserExecute(t *testing.T) {
require.NoError(t, bin.UnmarshalBorsh(&programData, data.Bytes()))

initTimelockIx, initErr := timelock.NewInitializeInstruction(
config.TestTimelockIDPaddedBuffer,
config.TestTimelockID,
config.MinDelay,
timelockutil.GetConfigPDA(config.TestTimelockIDPaddedBuffer),
timelockutil.GetConfigPDA(config.TestTimelockID),
admin.PublicKey(),
solana.SystemProgramID,
config.TimelockProgram,
Expand All @@ -115,7 +115,7 @@ func TestTimelockBypasserExecute(t *testing.T) {
testutils.SendAndConfirm(ctx, t, solanaGoClient, []solana.Instruction{initTimelockIx}, admin, config.DefaultCommitment)

var configAccount timelock.Config
cfgErr := common.GetAccountDataBorshInto(ctx, solanaGoClient, timelockutil.GetConfigPDA(config.TestTimelockIDPaddedBuffer), config.DefaultCommitment, &configAccount)
cfgErr := common.GetAccountDataBorshInto(ctx, solanaGoClient, timelockutil.GetConfigPDA(config.TestTimelockID), config.DefaultCommitment, &configAccount)
if cfgErr != nil {
require.NoError(t, cfgErr, "failed to get account info")
}
Expand All @@ -134,7 +134,7 @@ func TestTimelockBypasserExecute(t *testing.T) {
for _, account := range data.Accounts {
addresses = append(addresses, account.PublicKey())
}
batchAddAccessIxs, batchAddAccessIxsErr := timelockutil.GetBatchAddAccessIxs(ctx, config.TestTimelockIDPaddedBuffer, data.AccessController.PublicKey(), role, addresses, admin, config.BatchAddAccessChunkSize, solanaGoClient)
batchAddAccessIxs, batchAddAccessIxsErr := timelockutil.GetBatchAddAccessIxs(ctx, config.TestTimelockID, data.AccessController.PublicKey(), role, addresses, admin, config.BatchAddAccessChunkSize, solanaGoClient)
require.NoError(t, batchAddAccessIxsErr)

for _, ix := range batchAddAccessIxs {
Expand All @@ -153,7 +153,7 @@ func TestTimelockBypasserExecute(t *testing.T) {
t.Run("setup: wsol transfer operation", func(t *testing.T) {
requiredAmount := allowance.recipient

fundPDAIx := system.NewTransferInstruction(allowance.timelockAuthority, admin.PublicKey(), timelockutil.GetSignerPDA(config.TestTimelockIDPaddedBuffer)).Build()
fundPDAIx := system.NewTransferInstruction(allowance.timelockAuthority, admin.PublicKey(), timelockutil.GetSignerPDA(config.TestTimelockID)).Build()

createAdminATAIx, _, caErr := tokens.CreateAssociatedTokenAccount(tokenProgram, wsol, admin.PublicKey(), admin.PublicKey())
require.NoError(t, caErr)
Expand All @@ -178,7 +178,7 @@ func TestTimelockBypasserExecute(t *testing.T) {
tokenProgram,
adminATA,
wsol,
timelockutil.GetSignerPDA(config.TestTimelockIDPaddedBuffer),
timelockutil.GetSignerPDA(config.TestTimelockID),
admin.PublicKey(),
nil,
)
Expand All @@ -192,7 +192,7 @@ func TestTimelockBypasserExecute(t *testing.T) {
// check results
timelockAuthorityBalance, tlBalanceErr := solanaGoClient.GetBalance(
ctx,
timelockutil.GetSignerPDA(config.TestTimelockIDPaddedBuffer),
timelockutil.GetSignerPDA(config.TestTimelockID),
config.DefaultCommitment,
)
require.NoError(t, tlBalanceErr)
Expand All @@ -211,6 +211,7 @@ func TestTimelockBypasserExecute(t *testing.T) {
salt, err := mcms.SimpleSalt()
require.NoError(t, err)
op := timelockutil.Operation{
TimelockID: config.TestTimelockID,
Predecessor: config.TimelockEmptyOpID,
Salt: salt,
Delay: uint64(1000),
Expand All @@ -220,7 +221,7 @@ func TestTimelockBypasserExecute(t *testing.T) {
tokenProgram,
wsol,
recipient.PublicKey(),
timelockutil.GetSignerPDA(config.TestTimelockIDPaddedBuffer),
timelockutil.GetSignerPDA(config.TestTimelockID),
)
require.NoError(t, ciErr)
op.AddInstruction(
Expand All @@ -235,7 +236,7 @@ func TestTimelockBypasserExecute(t *testing.T) {
adminATA,
wsol,
recipientATA,
timelockutil.GetSignerPDA(config.TestTimelockIDPaddedBuffer),
timelockutil.GetSignerPDA(config.TestTimelockID),
nil,
)
require.NoError(t, tiErr)
Expand All @@ -245,7 +246,7 @@ func TestTimelockBypasserExecute(t *testing.T) {
operationPDA := op.OperationPDA()
signer := roleMap[timelock.Proposer_Role].RandomPick()

ixs, err := timelockutil.GetPreloadOperationIxs(config.TestTimelockIDPaddedBuffer, op, signer.PublicKey())
ixs, err := timelockutil.GetPreloadOperationIxs(config.TestTimelockID, op, signer.PublicKey())
require.NoError(t, err)
for _, ix := range ixs {
testutils.SendAndConfirm(ctx, t, solanaGoClient, []solana.Instruction{ix}, signer, config.DefaultCommitment)
Expand All @@ -268,11 +269,11 @@ func TestTimelockBypasserExecute(t *testing.T) {
ac := roleMap[timelock.Bypasser_Role].AccessController

ix := timelock.NewBypasserExecuteBatchInstruction(
config.TestTimelockIDPaddedBuffer,
config.TestTimelockID,
id,
operationPDA,
timelockutil.GetConfigPDA(config.TestTimelockIDPaddedBuffer),
timelockutil.GetSignerPDA(config.TestTimelockIDPaddedBuffer),
timelockutil.GetConfigPDA(config.TestTimelockID),
timelockutil.GetSignerPDA(config.TestTimelockID),
ac.PublicKey(),
signer.PublicKey(),
)
Expand Down
146 changes: 146 additions & 0 deletions chains/solana/contracts/tests/mcms/timelock_multiple_instances_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,4 +210,150 @@ func TestTimelockMultipleInstances(t *testing.T) {
}
}
})
// todo: config / signer seeds constraints
t.Run("instance isolation tests", func(t *testing.T) {
t.Run("config isolation", func(t *testing.T) {
t.Run("cannot access other instance config using own roles", func(t *testing.T) {
// try to use instance1's proposer to schedule on instance2
proposer := timelockInstances[0].RoleMap[timelock.Proposer_Role].RandomPick()
salt, err := mcms.SimpleSalt()
require.NoError(t, err)

// create test operation for instance2 but using instance1's proposer
op := timelockutil.Operation{
TimelockID: timelockInstances[1].ID,
Predecessor: config.TimelockEmptyOpID,
Salt: salt,
Delay: uint64(1),
}

// preload operation instructions
preloadIxs, prierr := timelockutil.GetPreloadOperationIxs(
timelockInstances[1].ID,
op,
proposer.PublicKey(),
)
require.NoError(t, prierr)

for _, ix := range preloadIxs {
testutils.SendAndConfirm(
ctx,
t,
solanaGoClient,
[]solana.Instruction{ix},
proposer,
config.DefaultCommitment,
)
}

// Try to schedule operation on instance2 using instance1's proposer
ix, ierr := timelock.NewScheduleBatchInstruction(
timelockInstances[1].ID, // instance2's ID
op.OperationID(),
op.Delay,
op.OperationPDA(),
timelockInstances[1].ConfigPDA, // instance2's config
timelockInstances[0].RoleMap[timelock.Proposer_Role].AccessController.PublicKey(), // instance1's proposer AC
proposer.PublicKey(),
).ValidateAndBuild()
require.NoError(t, ierr)

result := testutils.SendAndFailWith(
ctx,
t,
solanaGoClient,
[]solana.Instruction{ix},
proposer, // signing with instance1's proposer
config.DefaultCommitment,
[]string{"Error Code: " + timelock.InvalidAccessController_TimelockError.String()},
)
require.NotNil(t, result)
})

t.Run("cannot update delay using other instance's admin", func(t *testing.T) {
// try to update instance2's delay using instance1's admin
newMinDelay := uint64(14000)

ix, ierr := timelock.NewUpdateDelayInstruction(
timelockInstances[1].ID, // instance2's ID
newMinDelay,
timelockInstances[1].ConfigPDA,
timelockInstances[0].Admin.PublicKey(), // instance1's admin trying to update
).ValidateAndBuild()
require.NoError(t, ierr)

result := testutils.SendAndFailWith(
ctx,
t,
solanaGoClient,
[]solana.Instruction{ix},
timelockInstances[0].Admin, // signing with instance1's admin
config.DefaultCommitment,
[]string{"Error Code: " + timelockutil.UnauthorizedError.String()},
)
require.NotNil(t, result)
})

t.Run("cannot modify access controllers of another instance", func(t *testing.T) {
// try to use instance1's admin to modify instance2's access controller
randomKey, err := solana.NewRandomPrivateKey()
require.NoError(t, err)

// try to add access to instance2's proposer role using instance1's admin
ix, ierr := access_controller.NewAddAccessInstruction(
timelockInstances[1].RoleMap[timelock.Proposer_Role].AccessController.PublicKey(), // instance2's proposer AC
timelockInstances[0].Admin.PublicKey(), // instance1's admin trying to modify
randomKey.PublicKey(), // random key to add
).ValidateAndBuild()
require.NoError(t, ierr)

result := testutils.SendAndFailWith(
ctx,
t,
solanaGoClient,
[]solana.Instruction{ix},
timelockInstances[0].Admin, // signing with instance1's admin
config.DefaultCommitment,
[]string{"Error Code: ConstraintHasOne"},
)
require.NotNil(t, result)
})

t.Run("cannot transfer ownership of another instance", func(t *testing.T) {
// try to transfer instance2's ownership using instance1's admin
ix, ierr := timelock.NewTransferOwnershipInstruction(
timelockInstances[1].ID, // instance2's ID
timelockInstances[0].Admin.PublicKey(), // trying to transfer to instance1's admin
timelockInstances[1].ConfigPDA,
timelockInstances[0].Admin.PublicKey(), // instance1's admin trying to transfer
).ValidateAndBuild()
require.NoError(t, ierr)

result := testutils.SendAndFailWith(
ctx,
t,
solanaGoClient,
[]solana.Instruction{ix},
timelockInstances[0].Admin, // signing with instance1's admin
config.DefaultCommitment,
[]string{"Error Code: " + timelockutil.UnauthorizedError.String()},
)
require.NotNil(t, result)
})
})

t.Run("operation isolation", func(t *testing.T) {
t.Run("cannot schedule operation using other instance's signer PDA", func(t *testing.T) {})
t.Run("cannot execute operation scheduled on another instance", func(t *testing.T) {})
t.Run("cannot cancel operation from another instance", func(t *testing.T) {})
t.Run("cannot reuse operation ID between instances", func(t *testing.T) {})
})

t.Run("role isolation", func(t *testing.T) {
t.Run("proposer cannot schedule on other instance", func(t *testing.T) {})
t.Run("executor cannot execute on other instance", func(t *testing.T) {})
t.Run("canceller cannot cancel on other instance", func(t *testing.T) {})
t.Run("bypasser cannot bypass on other instance", func(t *testing.T) {})
})
})
}
Loading

0 comments on commit 211e364

Please sign in to comment.