From 758670b837c6fb661a53b44343dc4a7c2fb4a513 Mon Sep 17 00:00:00 2001 From: Martin Tomazic Date: Wed, 22 Apr 2026 15:53:12 +0200 Subject: [PATCH 1/7] go/registry/api: Ensure test fails for the right reason --- go/registry/api/runtime_test.go | 34 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/go/registry/api/runtime_test.go b/go/registry/api/runtime_test.go index 562f65a3278..2022e7786c7 100644 --- a/go/registry/api/runtime_test.go +++ b/go/registry/api/runtime_test.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/base64" "errors" - "fmt" "testing" "time" @@ -168,10 +167,9 @@ func TestVerifyRuntime(t *testing.T) { h.FromBytes([]byte("stateroot hash")) for _, tc := range []struct { - rr Runtime - cpFn func(*ConsensusParameters) - err error - msg string + rr Runtime + cpFn func(*ConsensusParameters) + errContains string }{ { Runtime{ @@ -252,8 +250,7 @@ func TestVerifyRuntime(t *testing.T) { }, }, nil, - nil, - "valid runtime", + "", }, { Runtime{ @@ -335,8 +332,7 @@ func TestVerifyRuntime(t *testing.T) { }, }, nil, - ErrInvalidArgument, - "invalid runtime (nil deployment)", + "nil deployment", }, { Runtime{ @@ -434,8 +430,7 @@ func TestVerifyRuntime(t *testing.T) { }, }, nil, - ErrInvalidArgument, - "invalid runtime (too many deployments)", + "too many deployments", }, { Runtime{ @@ -537,8 +532,7 @@ func TestVerifyRuntime(t *testing.T) { // Increase the maximum number of allowed deployments. cp.MaxRuntimeDeployments = 5 }, - ErrInvalidArgument, - "invalid runtime (deployment with invalid checkusm)", + "invalid bundle checksum", }, { Runtime{ @@ -640,8 +634,7 @@ func TestVerifyRuntime(t *testing.T) { // Increase the maximum number of allowed deployments. cp.MaxRuntimeDeployments = 5 }, - nil, - "valid runtime", + "", }, } { cp := ConsensusParameters{ @@ -657,12 +650,13 @@ func TestVerifyRuntime(t *testing.T) { } err := VerifyRuntime(&cp, logging.GetLogger("runtime/tests"), &tc.rr, false, true, beacon.EpochTime(10), true) - switch { - case tc.err == nil: - require.NoError(err, tc.msg) - default: - require.True(errors.Is(err, tc.err), fmt.Sprintf("expected err: '%v', got: '%v', for: %s", tc.err, err, tc.msg)) + if tc.errContains == "" { + require.NoError(err) + continue } + require.Error(err) + require.ErrorContains(err, tc.errContains) + require.True(errors.Is(err, ErrInvalidArgument)) } } From ea0adb43c7e2abd24eeb2a8f19b4df78b32b17da Mon Sep 17 00:00:00 2001 From: Martin Tomazic Date: Wed, 22 Apr 2026 19:28:36 +0200 Subject: [PATCH 2/7] go/registry/api: Simplify invalid bundle checksum test --- go/registry/api/runtime_test.go | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/go/registry/api/runtime_test.go b/go/registry/api/runtime_test.go index 2022e7786c7..f24ff809d39 100644 --- a/go/registry/api/runtime_test.go +++ b/go/registry/api/runtime_test.go @@ -458,15 +458,7 @@ func TestVerifyRuntime(t *testing.T) { Minor: 0, Patch: 2, }, - ValidFrom: 1, - }, - { - Version: version.Version{ - Major: 44, - Minor: 0, - Patch: 3, - }, - ValidFrom: 2, + ValidFrom: 1, BundleChecksum: []byte{1, 2, 3, 4, 5, 6, 7}, }, }, @@ -528,10 +520,7 @@ func TestVerifyRuntime(t *testing.T) { MinInMessageFee: quantity.Quantity{}, }, }, - func(cp *ConsensusParameters) { - // Increase the maximum number of allowed deployments. - cp.MaxRuntimeDeployments = 5 - }, + nil, "invalid bundle checksum", }, { From 14e71b3809cb64e1b7241a1d0e7295bdcee11b69 Mon Sep 17 00:00:00 2001 From: Martin Tomazic Date: Wed, 22 Apr 2026 19:48:28 +0200 Subject: [PATCH 3/7] go/registry/api: Stop duplicating inside TestVerifyRuntime --- .changelog/6512.trivial.md | 0 go/registry/api/runtime_test.go | 517 +++++++------------------------- 2 files changed, 110 insertions(+), 407 deletions(-) create mode 100644 .changelog/6512.trivial.md diff --git a/.changelog/6512.trivial.md b/.changelog/6512.trivial.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/go/registry/api/runtime_test.go b/go/registry/api/runtime_test.go index f24ff809d39..236d8e6c841 100644 --- a/go/registry/api/runtime_test.go +++ b/go/registry/api/runtime_test.go @@ -166,195 +166,104 @@ func TestVerifyRuntime(t *testing.T) { var h hash.Hash h.FromBytes([]byte("stateroot hash")) - for _, tc := range []struct { - rr Runtime - cpFn func(*ConsensusParameters) - errContains string - }{ - { - Runtime{ - Versioned: cbor.NewVersioned(3), - EntityID: signature.NewPublicKey("1234567890000000000000000000000000000000000000000000000000000000"), - ID: runtimeID, - Genesis: RuntimeGenesis{ - Round: 43, - StateRoot: h, - }, - Kind: KindCompute, - TEEHardware: node.TEEHardwareInvalid, - Deployments: []*VersionInfo{ - { - Version: version.Version{ - Major: 44, - Minor: 0, - Patch: 1, - }, + newValidRuntime := func() Runtime { + return Runtime{ + Versioned: cbor.NewVersioned(3), + EntityID: signature.NewPublicKey("1234567890000000000000000000000000000000000000000000000000000000"), + ID: runtimeID, + Genesis: RuntimeGenesis{ + Round: 43, + StateRoot: h, + }, + Kind: KindCompute, + TEEHardware: node.TEEHardwareInvalid, + Deployments: []*VersionInfo{ + { + Version: version.Version{ + Major: 44, + Minor: 0, + Patch: 1, }, }, - KeyManager: &keymanagerID, - Executor: ExecutorParameters{ - GroupSize: 9, - GroupBackupSize: 8, - AllowedStragglers: 7, - RoundTimeout: 6, - MaxMessages: 5, - MinLiveRoundsPercent: 4, - MaxMissedProposalsPercent: 3, - MinLiveRoundsForEvaluation: 2, - MaxLivenessFailures: 1, - }, - TxnScheduler: TxnSchedulerParameters{ - BatchFlushTimeout: time.Second, - MaxBatchSize: 10_000, - MaxBatchSizeBytes: 10_000_000, - MaxInMessages: 32, - ProposerTimeout: 2 * time.Second, - }, - Storage: StorageParameters{ - CheckpointInterval: 33, - CheckpointNumKept: 6, - CheckpointChunkSize: 1_000_000_000, - }, - AdmissionPolicy: RuntimeAdmissionPolicy{ - EntityWhitelist: &EntityWhitelistRuntimeAdmissionPolicy{ - Entities: map[signature.PublicKey]EntityWhitelistConfig{ - signature.NewPublicKey("1234567890000000000000000000000000000000000000000000000000000000"): { - MaxNodes: map[node.RolesMask]uint16{ - node.RoleComputeWorker: 3, - node.RoleKeyManager: 1, - }, + }, + KeyManager: &keymanagerID, + Executor: ExecutorParameters{ + GroupSize: 9, + GroupBackupSize: 8, + AllowedStragglers: 7, + RoundTimeout: 6, + MaxMessages: 5, + MinLiveRoundsPercent: 4, + MaxMissedProposalsPercent: 3, + MinLiveRoundsForEvaluation: 2, + MaxLivenessFailures: 1, + }, + TxnScheduler: TxnSchedulerParameters{ + BatchFlushTimeout: time.Second, + MaxBatchSize: 10_000, + MaxBatchSizeBytes: 10_000_000, + MaxInMessages: 32, + ProposerTimeout: 2 * time.Second, + }, + Storage: StorageParameters{ + CheckpointInterval: 33, + CheckpointNumKept: 6, + CheckpointChunkSize: 1_000_000_000, + }, + AdmissionPolicy: RuntimeAdmissionPolicy{ + EntityWhitelist: &EntityWhitelistRuntimeAdmissionPolicy{ + Entities: map[signature.PublicKey]EntityWhitelistConfig{ + signature.NewPublicKey("1234567890000000000000000000000000000000000000000000000000000000"): { + MaxNodes: map[node.RolesMask]uint16{ + node.RoleComputeWorker: 3, + node.RoleKeyManager: 1, }, }, }, }, - Constraints: map[api.CommitteeKind]map[api.Role]SchedulingConstraints{ - api.KindComputeExecutor: { - api.RoleWorker: { - MaxNodes: &MaxNodesConstraint{ - Limit: 10, - }, - MinPoolSize: &MinPoolSizeConstraint{ - Limit: 5, - }, - ValidatorSet: &ValidatorSetConstraint{}, + }, + Constraints: map[api.CommitteeKind]map[api.Role]SchedulingConstraints{ + api.KindComputeExecutor: { + api.RoleWorker: { + MaxNodes: &MaxNodesConstraint{ + Limit: 10, + }, + MinPoolSize: &MinPoolSizeConstraint{ + Limit: 5, }, + ValidatorSet: &ValidatorSetConstraint{}, }, }, - GovernanceModel: GovernanceConsensus, - Staking: RuntimeStakingParameters{ - Thresholds: nil, - Slashing: nil, - RewardSlashBadResultsRuntimePercent: 10, - RewardSlashEquvocationRuntimePercent: 0, - MinInMessageFee: quantity.Quantity{}, - }, }, - nil, - "", + GovernanceModel: GovernanceConsensus, + Staking: RuntimeStakingParameters{ + Thresholds: nil, + Slashing: nil, + RewardSlashBadResultsRuntimePercent: 10, + RewardSlashEquvocationRuntimePercent: 0, + MinInMessageFee: quantity.Quantity{}, + }, + } + } + + for _, tc := range []struct { + modify func(*Runtime) + modifyParams func(*ConsensusParameters) + errContains string + }{ + { + errContains: "", }, { - Runtime{ - Versioned: cbor.NewVersioned(3), - EntityID: signature.NewPublicKey("1234567890000000000000000000000000000000000000000000000000000000"), - ID: runtimeID, - Genesis: RuntimeGenesis{ - Round: 43, - StateRoot: h, - }, - Kind: KindCompute, - TEEHardware: node.TEEHardwareInvalid, - Deployments: []*VersionInfo{ - { - Version: version.Version{ - Major: 44, - Minor: 0, - Patch: 1, - }, - }, - nil, - }, - KeyManager: &keymanagerID, - Executor: ExecutorParameters{ - GroupSize: 9, - GroupBackupSize: 8, - AllowedStragglers: 7, - RoundTimeout: 6, - MaxMessages: 5, - MinLiveRoundsPercent: 4, - MaxMissedProposalsPercent: 3, - MinLiveRoundsForEvaluation: 2, - MaxLivenessFailures: 1, - }, - TxnScheduler: TxnSchedulerParameters{ - BatchFlushTimeout: time.Second, - MaxBatchSize: 10_000, - MaxBatchSizeBytes: 10_000_000, - MaxInMessages: 32, - ProposerTimeout: 2 * time.Second, - }, - Storage: StorageParameters{ - CheckpointInterval: 33, - CheckpointNumKept: 6, - CheckpointChunkSize: 1_000_000_000, - }, - AdmissionPolicy: RuntimeAdmissionPolicy{ - EntityWhitelist: &EntityWhitelistRuntimeAdmissionPolicy{ - Entities: map[signature.PublicKey]EntityWhitelistConfig{ - signature.NewPublicKey("1234567890000000000000000000000000000000000000000000000000000000"): { - MaxNodes: map[node.RolesMask]uint16{ - node.RoleComputeWorker: 3, - node.RoleKeyManager: 1, - }, - }, - }, - }, - }, - Constraints: map[api.CommitteeKind]map[api.Role]SchedulingConstraints{ - api.KindComputeExecutor: { - api.RoleWorker: { - MaxNodes: &MaxNodesConstraint{ - Limit: 10, - }, - MinPoolSize: &MinPoolSizeConstraint{ - Limit: 5, - }, - ValidatorSet: &ValidatorSetConstraint{}, - }, - }, - }, - GovernanceModel: GovernanceConsensus, - Staking: RuntimeStakingParameters{ - Thresholds: nil, - Slashing: nil, - RewardSlashBadResultsRuntimePercent: 10, - RewardSlashEquvocationRuntimePercent: 0, - MinInMessageFee: quantity.Quantity{}, - }, + modify: func(rt *Runtime) { + rt.Deployments = append(rt.Deployments, nil) }, - nil, - "nil deployment", + errContains: "nil deployment", }, { - Runtime{ - Versioned: cbor.NewVersioned(3), - EntityID: signature.NewPublicKey("1234567890000000000000000000000000000000000000000000000000000000"), - ID: runtimeID, - Genesis: RuntimeGenesis{ - Round: 43, - StateRoot: h, - }, - Kind: KindCompute, - TEEHardware: node.TEEHardwareInvalid, - Deployments: []*VersionInfo{ - { - Version: version.Version{ - Major: 44, - Minor: 0, - Patch: 1, - }, - ValidFrom: 0, - }, - { + modify: func(rt *Runtime) { + rt.Deployments = append(rt.Deployments, + &VersionInfo{ Version: version.Version{ Major: 44, Minor: 0, @@ -362,7 +271,7 @@ func TestVerifyRuntime(t *testing.T) { }, ValidFrom: 1, }, - { + &VersionInfo{ Version: version.Version{ Major: 44, Minor: 0, @@ -370,180 +279,28 @@ func TestVerifyRuntime(t *testing.T) { }, ValidFrom: 2, }, - }, - KeyManager: &keymanagerID, - Executor: ExecutorParameters{ - GroupSize: 9, - GroupBackupSize: 8, - AllowedStragglers: 7, - RoundTimeout: 6, - MaxMessages: 5, - MinLiveRoundsPercent: 4, - MaxMissedProposalsPercent: 3, - MinLiveRoundsForEvaluation: 2, - MaxLivenessFailures: 1, - }, - TxnScheduler: TxnSchedulerParameters{ - BatchFlushTimeout: time.Second, - MaxBatchSize: 10_000, - MaxBatchSizeBytes: 10_000_000, - MaxInMessages: 32, - ProposerTimeout: 2 * time.Second, - }, - Storage: StorageParameters{ - CheckpointInterval: 33, - CheckpointNumKept: 6, - CheckpointChunkSize: 1_000_000_000, - }, - AdmissionPolicy: RuntimeAdmissionPolicy{ - EntityWhitelist: &EntityWhitelistRuntimeAdmissionPolicy{ - Entities: map[signature.PublicKey]EntityWhitelistConfig{ - signature.NewPublicKey("1234567890000000000000000000000000000000000000000000000000000000"): { - MaxNodes: map[node.RolesMask]uint16{ - node.RoleComputeWorker: 3, - node.RoleKeyManager: 1, - }, - }, - }, - }, - }, - Constraints: map[api.CommitteeKind]map[api.Role]SchedulingConstraints{ - api.KindComputeExecutor: { - api.RoleWorker: { - MaxNodes: &MaxNodesConstraint{ - Limit: 10, - }, - MinPoolSize: &MinPoolSizeConstraint{ - Limit: 5, - }, - ValidatorSet: &ValidatorSetConstraint{}, - }, - }, - }, - GovernanceModel: GovernanceConsensus, - Staking: RuntimeStakingParameters{ - Thresholds: nil, - Slashing: nil, - RewardSlashBadResultsRuntimePercent: 10, - RewardSlashEquvocationRuntimePercent: 0, - MinInMessageFee: quantity.Quantity{}, - }, + ) }, - nil, - "too many deployments", + errContains: "too many deployments", }, { - Runtime{ - Versioned: cbor.NewVersioned(3), - EntityID: signature.NewPublicKey("1234567890000000000000000000000000000000000000000000000000000000"), - ID: runtimeID, - Genesis: RuntimeGenesis{ - Round: 43, - StateRoot: h, - }, - Kind: KindCompute, - TEEHardware: node.TEEHardwareInvalid, - Deployments: []*VersionInfo{ - { - Version: version.Version{ - Major: 44, - Minor: 0, - Patch: 1, - }, - ValidFrom: 0, - }, - { - Version: version.Version{ - Major: 44, - Minor: 0, - Patch: 2, - }, - ValidFrom: 1, - BundleChecksum: []byte{1, 2, 3, 4, 5, 6, 7}, - }, - }, - KeyManager: &keymanagerID, - Executor: ExecutorParameters{ - GroupSize: 9, - GroupBackupSize: 8, - AllowedStragglers: 7, - RoundTimeout: 6, - MaxMessages: 5, - MinLiveRoundsPercent: 4, - MaxMissedProposalsPercent: 3, - MinLiveRoundsForEvaluation: 2, - MaxLivenessFailures: 1, - }, - TxnScheduler: TxnSchedulerParameters{ - BatchFlushTimeout: time.Second, - MaxBatchSize: 10_000, - MaxBatchSizeBytes: 10_000_000, - MaxInMessages: 32, - ProposerTimeout: 2 * time.Second, - }, - Storage: StorageParameters{ - CheckpointInterval: 33, - CheckpointNumKept: 6, - CheckpointChunkSize: 1_000_000_000, - }, - AdmissionPolicy: RuntimeAdmissionPolicy{ - EntityWhitelist: &EntityWhitelistRuntimeAdmissionPolicy{ - Entities: map[signature.PublicKey]EntityWhitelistConfig{ - signature.NewPublicKey("1234567890000000000000000000000000000000000000000000000000000000"): { - MaxNodes: map[node.RolesMask]uint16{ - node.RoleComputeWorker: 3, - node.RoleKeyManager: 1, - }, - }, - }, - }, - }, - Constraints: map[api.CommitteeKind]map[api.Role]SchedulingConstraints{ - api.KindComputeExecutor: { - api.RoleWorker: { - MaxNodes: &MaxNodesConstraint{ - Limit: 10, - }, - MinPoolSize: &MinPoolSizeConstraint{ - Limit: 5, - }, - ValidatorSet: &ValidatorSetConstraint{}, - }, + modify: func(rt *Runtime) { + rt.Deployments = append(rt.Deployments, &VersionInfo{ + Version: version.Version{ + Major: 44, + Minor: 0, + Patch: 2, }, - }, - GovernanceModel: GovernanceConsensus, - Staking: RuntimeStakingParameters{ - Thresholds: nil, - Slashing: nil, - RewardSlashBadResultsRuntimePercent: 10, - RewardSlashEquvocationRuntimePercent: 0, - MinInMessageFee: quantity.Quantity{}, - }, + ValidFrom: 1, + BundleChecksum: []byte{1, 2, 3, 4, 5, 6, 7}, + }) }, - nil, - "invalid bundle checksum", + errContains: "invalid bundle checksum", }, { - Runtime{ - Versioned: cbor.NewVersioned(3), - EntityID: signature.NewPublicKey("1234567890000000000000000000000000000000000000000000000000000000"), - ID: runtimeID, - Genesis: RuntimeGenesis{ - Round: 43, - StateRoot: h, - }, - Kind: KindCompute, - TEEHardware: node.TEEHardwareInvalid, - Deployments: []*VersionInfo{ - { - Version: version.Version{ - Major: 44, - Minor: 0, - Patch: 1, - }, - ValidFrom: 0, - }, - { + modify: func(rt *Runtime) { + rt.Deployments = append(rt.Deployments, + &VersionInfo{ Version: version.Version{ Major: 44, Minor: 0, @@ -551,7 +308,7 @@ func TestVerifyRuntime(t *testing.T) { }, ValidFrom: 1, }, - { + &VersionInfo{ Version: version.Version{ Major: 44, Minor: 0, @@ -560,72 +317,18 @@ func TestVerifyRuntime(t *testing.T) { ValidFrom: 2, BundleChecksum: bytes.Repeat([]byte{0x01}, 32), }, - }, - KeyManager: &keymanagerID, - Executor: ExecutorParameters{ - GroupSize: 9, - GroupBackupSize: 8, - AllowedStragglers: 7, - RoundTimeout: 6, - MaxMessages: 5, - MinLiveRoundsPercent: 4, - MaxMissedProposalsPercent: 3, - MinLiveRoundsForEvaluation: 2, - MaxLivenessFailures: 1, - }, - TxnScheduler: TxnSchedulerParameters{ - BatchFlushTimeout: time.Second, - MaxBatchSize: 10_000, - MaxBatchSizeBytes: 10_000_000, - MaxInMessages: 32, - ProposerTimeout: 2 * time.Second, - }, - Storage: StorageParameters{ - CheckpointInterval: 33, - CheckpointNumKept: 6, - CheckpointChunkSize: 1_000_000_000, - }, - AdmissionPolicy: RuntimeAdmissionPolicy{ - EntityWhitelist: &EntityWhitelistRuntimeAdmissionPolicy{ - Entities: map[signature.PublicKey]EntityWhitelistConfig{ - signature.NewPublicKey("1234567890000000000000000000000000000000000000000000000000000000"): { - MaxNodes: map[node.RolesMask]uint16{ - node.RoleComputeWorker: 3, - node.RoleKeyManager: 1, - }, - }, - }, - }, - }, - Constraints: map[api.CommitteeKind]map[api.Role]SchedulingConstraints{ - api.KindComputeExecutor: { - api.RoleWorker: { - MaxNodes: &MaxNodesConstraint{ - Limit: 10, - }, - MinPoolSize: &MinPoolSizeConstraint{ - Limit: 5, - }, - ValidatorSet: &ValidatorSetConstraint{}, - }, - }, - }, - GovernanceModel: GovernanceConsensus, - Staking: RuntimeStakingParameters{ - Thresholds: nil, - Slashing: nil, - RewardSlashBadResultsRuntimePercent: 10, - RewardSlashEquvocationRuntimePercent: 0, - MinInMessageFee: quantity.Quantity{}, - }, + ) }, - func(cp *ConsensusParameters) { - // Increase the maximum number of allowed deployments. + modifyParams: func(cp *ConsensusParameters) { cp.MaxRuntimeDeployments = 5 }, - "", + errContains: "", }, } { + rt := newValidRuntime() + if tc.modify != nil { + tc.modify(&rt) + } cp := ConsensusParameters{ MaxNodeExpiration: 10, EnableRuntimeGovernanceModels: map[RuntimeGovernanceModel]bool{ @@ -634,11 +337,11 @@ func TestVerifyRuntime(t *testing.T) { GovernanceRuntime: true, }, } - if tc.cpFn != nil { - tc.cpFn(&cp) + if tc.modifyParams != nil { + tc.modifyParams(&cp) } - err := VerifyRuntime(&cp, logging.GetLogger("runtime/tests"), &tc.rr, false, true, beacon.EpochTime(10), true) + err := VerifyRuntime(&cp, logging.GetLogger("runtime/tests"), &rt, false, true, beacon.EpochTime(10), true) if tc.errContains == "" { require.NoError(err) continue From 1f7808467ec74f558d6fa8aa02c3226091d563f2 Mon Sep 17 00:00:00 2001 From: Martin Tomazic Date: Wed, 22 Apr 2026 21:16:38 +0200 Subject: [PATCH 4/7] go/registry/api: Group VerifyRuntime deployments tests --- go/registry/api/runtime_test.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/go/registry/api/runtime_test.go b/go/registry/api/runtime_test.go index 236d8e6c841..52226052dfd 100644 --- a/go/registry/api/runtime_test.go +++ b/go/registry/api/runtime_test.go @@ -283,20 +283,6 @@ func TestVerifyRuntime(t *testing.T) { }, errContains: "too many deployments", }, - { - modify: func(rt *Runtime) { - rt.Deployments = append(rt.Deployments, &VersionInfo{ - Version: version.Version{ - Major: 44, - Minor: 0, - Patch: 2, - }, - ValidFrom: 1, - BundleChecksum: []byte{1, 2, 3, 4, 5, 6, 7}, - }) - }, - errContains: "invalid bundle checksum", - }, { modify: func(rt *Runtime) { rt.Deployments = append(rt.Deployments, @@ -324,6 +310,20 @@ func TestVerifyRuntime(t *testing.T) { }, errContains: "", }, + { + modify: func(rt *Runtime) { + rt.Deployments = append(rt.Deployments, &VersionInfo{ + Version: version.Version{ + Major: 44, + Minor: 0, + Patch: 2, + }, + ValidFrom: 1, + BundleChecksum: []byte{1, 2, 3, 4, 5, 6, 7}, + }) + }, + errContains: "invalid bundle checksum", + }, } { rt := newValidRuntime() if tc.modify != nil { From 90839128c848273ff0a57e6d635d88880119a80a Mon Sep 17 00:00:00 2001 From: Martin Tomazic Date: Wed, 22 Apr 2026 20:01:47 +0200 Subject: [PATCH 5/7] go/registry/api: Refactor TestVerifyRuntime to named subtests Subtest failing should not stop the whole table test. --- go/registry/api/runtime_test.go | 61 ++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/go/registry/api/runtime_test.go b/go/registry/api/runtime_test.go index 52226052dfd..2d1e41a9cd6 100644 --- a/go/registry/api/runtime_test.go +++ b/go/registry/api/runtime_test.go @@ -157,12 +157,10 @@ func TestRuntimeSerialization(t *testing.T) { } func TestVerifyRuntime(t *testing.T) { - require := require.New(t) - var runtimeID common.Namespace - require.NoError(runtimeID.UnmarshalHex("0000000000000000000000000000000000000000000000000000000000000000"), "runtime id") + require.NoError(t, runtimeID.UnmarshalHex("0000000000000000000000000000000000000000000000000000000000000000"), "runtime id") var keymanagerID common.Namespace - require.NoError(keymanagerID.UnmarshalHex("c000000000000000000000000000000000000000000000000000000000000001"), "keymanager id") + require.NoError(t, keymanagerID.UnmarshalHex("c000000000000000000000000000000000000000000000000000000000000001"), "keymanager id") var h hash.Hash h.FromBytes([]byte("stateroot hash")) @@ -247,20 +245,24 @@ func TestVerifyRuntime(t *testing.T) { } for _, tc := range []struct { + name string modify func(*Runtime) modifyParams func(*ConsensusParameters) errContains string }{ { + name: "valid", errContains: "", }, { + name: "nil deployment", modify: func(rt *Runtime) { rt.Deployments = append(rt.Deployments, nil) }, errContains: "nil deployment", }, { + name: "too many deployments", modify: func(rt *Runtime) { rt.Deployments = append(rt.Deployments, &VersionInfo{ @@ -284,6 +286,7 @@ func TestVerifyRuntime(t *testing.T) { errContains: "too many deployments", }, { + name: "max runtime deployment config increases allowed deployments", modify: func(rt *Runtime) { rt.Deployments = append(rt.Deployments, &VersionInfo{ @@ -311,6 +314,7 @@ func TestVerifyRuntime(t *testing.T) { errContains: "", }, { + name: "invalid bundle checksum", modify: func(rt *Runtime) { rt.Deployments = append(rt.Deployments, &VersionInfo{ Version: version.Version{ @@ -325,30 +329,33 @@ func TestVerifyRuntime(t *testing.T) { errContains: "invalid bundle checksum", }, } { - rt := newValidRuntime() - if tc.modify != nil { - tc.modify(&rt) - } - cp := ConsensusParameters{ - MaxNodeExpiration: 10, - EnableRuntimeGovernanceModels: map[RuntimeGovernanceModel]bool{ - GovernanceConsensus: true, - GovernanceEntity: true, - GovernanceRuntime: true, - }, - } - if tc.modifyParams != nil { - tc.modifyParams(&cp) - } + t.Run(tc.name, func(t *testing.T) { + rt := newValidRuntime() + if tc.modify != nil { + tc.modify(&rt) + } - err := VerifyRuntime(&cp, logging.GetLogger("runtime/tests"), &rt, false, true, beacon.EpochTime(10), true) - if tc.errContains == "" { - require.NoError(err) - continue - } - require.Error(err) - require.ErrorContains(err, tc.errContains) - require.True(errors.Is(err, ErrInvalidArgument)) + cp := ConsensusParameters{ + MaxNodeExpiration: 10, + EnableRuntimeGovernanceModels: map[RuntimeGovernanceModel]bool{ + GovernanceConsensus: true, + GovernanceEntity: true, + GovernanceRuntime: true, + }, + } + if tc.modifyParams != nil { + tc.modifyParams(&cp) + } + + err := VerifyRuntime(&cp, logging.GetLogger("runtime/tests"), &rt, false, true, beacon.EpochTime(10), true) + if tc.errContains == "" { + require.NoError(t, err) + return + } + require.Error(t, err) + require.ErrorContains(t, err, tc.errContains) + require.True(t, errors.Is(err, ErrInvalidArgument)) + }) } } From 2c4e314cb7a83f7c39713df8f414ebdb4f12d354 Mon Sep 17 00:00:00 2001 From: Martin Tomazic Date: Wed, 22 Apr 2026 20:23:18 +0200 Subject: [PATCH 6/7] go/registry/api: Add VerifyRuntimeOptions --- .../apps/keymanager/common/genesis.go | 3 ++- .../cometbft/apps/registry/genesis.go | 3 ++- .../cometbft/apps/registry/transactions.go | 3 ++- go/registry/api/api.go | 22 +++++++++++++------ go/registry/api/runtime_test.go | 3 ++- go/registry/api/sanity_check.go | 10 +++++++-- 6 files changed, 31 insertions(+), 13 deletions(-) diff --git a/go/consensus/cometbft/apps/keymanager/common/genesis.go b/go/consensus/cometbft/apps/keymanager/common/genesis.go index 9e4a5b86341..a349f923452 100644 --- a/go/consensus/cometbft/apps/keymanager/common/genesis.go +++ b/go/consensus/cometbft/apps/keymanager/common/genesis.go @@ -16,7 +16,8 @@ func RegistryRuntimes(ctx *tmapi.Context, doc *genesis.Document, epoch beacon.Ep regSt := doc.Registry rtMap := make(map[common.Namespace]*registry.Runtime) for _, rt := range regSt.Runtimes { - err := registry.VerifyRuntime(®St.Parameters, ctx.Logger(), rt, true, false, epoch, true) + verifyOpts := registry.VerifyRuntimeOptions{IsGenesis: true, IsFeatureVersion242: true} + err := registry.VerifyRuntime(®St.Parameters, ctx.Logger(), rt, epoch, verifyOpts) if err != nil { ctx.Logger().Error("InitChain: Invalid runtime", "err", err, diff --git a/go/consensus/cometbft/apps/registry/genesis.go b/go/consensus/cometbft/apps/registry/genesis.go index 120ef50e8c3..02721235cc6 100644 --- a/go/consensus/cometbft/apps/registry/genesis.go +++ b/go/consensus/cometbft/apps/registry/genesis.go @@ -55,7 +55,8 @@ func (app *Application) InitChain(ctx *abciAPI.Context, _ types.RequestInitChain if rt == nil { return fmt.Errorf("registry: genesis runtime index %d is nil", i) } - err := registry.VerifyRuntime(&st.Parameters, ctx.Logger(), rt, ctx.IsInitChain(), false, epoch, true) + verifyOpts := registry.VerifyRuntimeOptions{IsGenesis: ctx.IsInitChain(), IsFeatureVersion242: true} + err := registry.VerifyRuntime(&st.Parameters, ctx.Logger(), rt, epoch, verifyOpts) if err != nil { return err } diff --git a/go/consensus/cometbft/apps/registry/transactions.go b/go/consensus/cometbft/apps/registry/transactions.go index f6b0fb24601..34d9e2013c7 100644 --- a/go/consensus/cometbft/apps/registry/transactions.go +++ b/go/consensus/cometbft/apps/registry/transactions.go @@ -598,7 +598,8 @@ func (app *Application) registerRuntime( // nolint: gocyclo } } - if err = registry.VerifyRuntime(params, ctx.Logger(), rt, ctx.IsInitChain(), false, epoch, isFeatureVersion242); err != nil { + verifyOpts := registry.VerifyRuntimeOptions{IsGenesis: ctx.IsInitChain(), IsFeatureVersion242: isFeatureVersion242} + if err = registry.VerifyRuntime(params, ctx.Logger(), rt, epoch, verifyOpts); err != nil { return nil, err } diff --git a/go/registry/api/api.go b/go/registry/api/api.go index 88810da2feb..dd2ab46e684 100644 --- a/go/registry/api/api.go +++ b/go/registry/api/api.go @@ -1101,21 +1101,29 @@ func VerifyNodeUpdate( return nil } +// VerifyRuntimeOptions contains the options for VerifyRuntime. +type VerifyRuntimeOptions struct { + // IsGenesis is true if the runtime is being verified during genesis. + IsGenesis bool + // IsSanityCheck is true if this is a sanity check and not a live transaction verification. + IsSanityCheck bool + // IsFeatureVersion242 is true if consensus version 24.2 or higher is active. + IsFeatureVersion242 bool +} + // VerifyRuntime verifies the given runtime. -func VerifyRuntime( // nolint: gocyclo +func VerifyRuntime( params *ConsensusParameters, logger *logging.Logger, rt *Runtime, - isGenesis bool, - isSanityCheck bool, now beacon.EpochTime, - isFeatureVersion242 bool, + opts VerifyRuntimeOptions, ) error { if rt == nil { return fmt.Errorf("%w: no runtime given", ErrInvalidArgument) } - if err := rt.ValidateBasic(!isGenesis && !isSanityCheck); err != nil { + if err := rt.ValidateBasic(!opts.IsGenesis && !opts.IsSanityCheck); err != nil { logger.Error("RegisterRuntime: invalid runtime descriptor", "runtime", rt, "err", err, @@ -1130,7 +1138,7 @@ func VerifyRuntime( // nolint: gocyclo return fmt.Errorf("%w: test runtime not allowed", ErrInvalidArgument) } - if err := rt.Genesis.SanityCheck(isGenesis); err != nil { + if err := rt.Genesis.SanityCheck(opts.IsGenesis); err != nil { return err } @@ -1154,7 +1162,7 @@ func VerifyRuntime( // nolint: gocyclo // Validate the deployments. This also handles validating that the // appropriate TEE configuration is present in each deployment. - if err := rt.ValidateDeployments(now, params, isFeatureVersion242); err != nil { + if err := rt.ValidateDeployments(now, params, opts.IsFeatureVersion242); err != nil { logger.Error("RegisterRuntime: invalid deployments", "runtime_id", rt.ID, "err", err, diff --git a/go/registry/api/runtime_test.go b/go/registry/api/runtime_test.go index 2d1e41a9cd6..f8f5e3d2de5 100644 --- a/go/registry/api/runtime_test.go +++ b/go/registry/api/runtime_test.go @@ -347,7 +347,8 @@ func TestVerifyRuntime(t *testing.T) { tc.modifyParams(&cp) } - err := VerifyRuntime(&cp, logging.GetLogger("runtime/tests"), &rt, false, true, beacon.EpochTime(10), true) + verifyOpts := VerifyRuntimeOptions{IsSanityCheck: true, IsFeatureVersion242: true} + err := VerifyRuntime(&cp, logging.GetLogger("runtime/tests"), &rt, beacon.EpochTime(10), verifyOpts) if tc.errContains == "" { require.NoError(t, err) return diff --git a/go/registry/api/sanity_check.go b/go/registry/api/sanity_check.go index 8a7e23cd685..bcd1aa9ae85 100644 --- a/go/registry/api/sanity_check.go +++ b/go/registry/api/sanity_check.go @@ -147,10 +147,16 @@ func SanityCheckRuntimes( now beacon.EpochTime, isFeatureVersion242 bool, ) (RuntimeLookup, error) { + verifyOpts := VerifyRuntimeOptions{ + IsGenesis: isGenesis, + IsSanityCheck: true, + IsFeatureVersion242: isFeatureVersion242, + } + // First go through all runtimes and perform general sanity checks. seenRuntimes := []*Runtime{} for _, rt := range runtimes { - if err := VerifyRuntime(params, logger, rt, isGenesis, true, now, isFeatureVersion242); err != nil { + if err := VerifyRuntime(params, logger, rt, now, verifyOpts); err != nil { return nil, fmt.Errorf("runtime sanity check failed: %w", err) } seenRuntimes = append(seenRuntimes, rt) @@ -158,7 +164,7 @@ func SanityCheckRuntimes( seenSuspendedRuntimes := []*Runtime{} for _, rt := range suspendedRuntimes { - if err := VerifyRuntime(params, logger, rt, isGenesis, true, now, isFeatureVersion242); err != nil { + if err := VerifyRuntime(params, logger, rt, now, verifyOpts); err != nil { return nil, fmt.Errorf("runtime sanity check failed: %w", err) } seenSuspendedRuntimes = append(seenSuspendedRuntimes, rt) From de236269092a5ef213de52f12a6fce5bfb11f61c Mon Sep 17 00:00:00 2001 From: Martin Tomazic Date: Wed, 22 Apr 2026 20:26:12 +0200 Subject: [PATCH 7/7] go/registry/api: Test in non-sanity mode --- go/registry/api/runtime_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/registry/api/runtime_test.go b/go/registry/api/runtime_test.go index f8f5e3d2de5..287ca005d45 100644 --- a/go/registry/api/runtime_test.go +++ b/go/registry/api/runtime_test.go @@ -347,7 +347,7 @@ func TestVerifyRuntime(t *testing.T) { tc.modifyParams(&cp) } - verifyOpts := VerifyRuntimeOptions{IsSanityCheck: true, IsFeatureVersion242: true} + verifyOpts := VerifyRuntimeOptions{IsFeatureVersion242: true} err := VerifyRuntime(&cp, logging.GetLogger("runtime/tests"), &rt, beacon.EpochTime(10), verifyOpts) if tc.errContains == "" { require.NoError(t, err)