Skip to content

Commit 1c39148

Browse files
Helm chart changes for Validator Scan Client Config (#3283)
Added BftScanConfig to Helm charts [ci] Signed-off-by: Pasindu Tennage <pasindu.tennage@digitalasset.com>
1 parent 0a8aa3e commit 1c39148

File tree

9 files changed

+274
-5
lines changed

9 files changed

+274
-5
lines changed

cluster/deployment/config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,9 @@ validators:
172172
nodeIdentifier: 'validator-runbook'
173173
partyHint: 'digitalasset-testValidator-1'
174174
onboardingSecret: 'validatorsecret'
175+
validatorApp:
176+
scanClient:
177+
scanType: "bft-custom"
178+
seedUrls: [ "https://scan.sv-2-eng.scratchb.network.canton.global","https://scan.sv-3-eng.scratchb.network.canton.global" ]
179+
threshold: 2
180+
trustedSvs: ["Digital-Asset-Eng-2","Digital-Asset-Eng-3"]

cluster/expected/validator-runbook/expected.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,18 @@
719719
"postgresName": "postgres",
720720
"secretName": "postgres-secrets"
721721
},
722-
"scanAddress": "https://scan.sv-2.mock.global.canton.network.digitalasset.com",
722+
"scanClient": {
723+
"scanType": "bft-custom",
724+
"seedUrls": [
725+
"https://scan.sv-2-eng.scratchb.network.canton.global",
726+
"https://scan.sv-3-eng.scratchb.network.canton.global"
727+
],
728+
"threshold": 2,
729+
"trustedSvs": [
730+
"Digital-Asset-Eng-2",
731+
"Digital-Asset-Eng-3"
732+
]
733+
},
723734
"spliceInstanceNames": {
724735
"amuletName": "Amulet",
725736
"amuletNameAcronym": "AMT",

cluster/helm/splice-validator/templates/validator.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,26 @@ spec:
108108
{{ else -}}
109109
- name: ADDITIONAL_CONFIG_BFT_SCAN
110110
value: |
111+
{{- if .Values.scanClient }}
112+
{{- if eq .Values.scanClient.scanType "trust-single" }}
113+
canton.validator-apps.validator_backend.scan-client.type = "trust-single"
114+
canton.validator-apps.validator_backend.scan-client.url = {{ .Values.scanClient.scanAddress | quote }}
115+
{{- else if eq .Values.scanClient.scanType "bft"}}
116+
canton.validator-apps.validator_backend.scan-client.type = "bft"
117+
canton.validator-apps.validator_backend.scan-client.seed-urls = {{ .Values.scanClient.seedUrls | toJson }}
118+
{{- else if eq .Values.scanClient.scanType "bft-custom"}}
119+
canton.validator-apps.validator_backend.scan-client.type = "bft-custom"
120+
canton.validator-apps.validator_backend.scan-client.seed-urls = {{ .Values.scanClient.seedUrls | toJson }}
121+
canton.validator-apps.validator_backend.scan-client.trusted-svs = {{ .Values.scanClient.trustedSvs | toJson }}
122+
canton.validator-apps.validator_backend.scan-client.threshold = {{ .Values.scanClient.threshold }}
123+
{{- else }}
124+
canton.validator-apps.validator_backend.scan-client.type = "bft"
125+
canton.validator-apps.validator_backend.scan-client.seed-urls = {{ .Values.scanClient.seedUrls | toJson }}
126+
{{- end }}
127+
{{- else }}
111128
canton.validator-apps.validator_backend.scan-client.type = "bft"
112129
canton.validator-apps.validator_backend.scan-client.seed-urls = [ ${_scan.admin-api.address} ]
130+
{{- end }}
113131
{{ end }}
114132
{{ if not .Values.useSequencerConnectionsFromScan }}
115133
- name: ADDITIONAL_CONFIG_STATIC_SEQUENCER_URL

cluster/helm/splice-validator/tests/init-containers_test.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ set:
1212
nodeIdentifier: "helm-mock-1-validator"
1313
validatorPartyHint: "helm-mock-1"
1414
validatorWalletUser: "mock-wallet-user-id"
15-
scanAddress: "trusted.scan.mock.com"
1615
topup:
1716
enabled: false
1817
auth:

cluster/helm/splice-validator/tests/uis_test.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ set:
1010
nodeIdentifier: "helm-mock-1-validator"
1111
validatorPartyHint: "helm-mock-1"
1212
validatorWalletUser: "mock-wallet-user-id"
13-
scanAddress: "trusted.scan.mock.com"
1413
spliceInstanceNames:
1514
networkName: MockNet
1615
networkFaviconUrl: https://mock.net/favicon.ico

cluster/helm/splice-validator/tests/validator_test.yaml

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ set:
1717
nodeIdentifier: "helm-mock-1-validator"
1818
validatorPartyHint: "helm-mock-1"
1919
validatorWalletUser: "mock-wallet-user-id"
20-
scanAddress: "trusted.scan.mock.com"
2120
spliceInstanceNames:
2221
networkName: MockNet
2322
networkFaviconUrl: https://mock.net/favicon.ico
@@ -126,3 +125,99 @@ tests:
126125
value: ledger-api-user
127126
- exists:
128127
path: spec.template.spec.containers[?(@.name=='validator-app')].env[?(@.name=='ADDITIONAL_CONFIG_DISABLE_AUTH')].value
128+
129+
- it: "configures scan-client for trust-single mode"
130+
set:
131+
scanClient:
132+
scanType: "trust-single"
133+
scanAddress: "https://single.scan.url:5004"
134+
documentSelector:
135+
path: kind
136+
value: Deployment
137+
asserts:
138+
- matchRegex:
139+
path: spec.template.spec.containers[?(@.name=='validator-app')].env[?(@.name=='ADDITIONAL_CONFIG_BFT_SCAN')].value
140+
pattern: "canton.validator-apps.validator_backend.scan-client.type = \"trust-single\""
141+
- matchRegex:
142+
path: spec.template.spec.containers[?(@.name=='validator-app')].env[?(@.name=='ADDITIONAL_CONFIG_BFT_SCAN')].value
143+
pattern: 'canton.validator-apps.validator_backend.scan-client.url = "https://single.scan.url:5004"'
144+
145+
- it: "configures scan-client for standard bft mode, including multiple seedUrls"
146+
set:
147+
scanClient:
148+
scanType: "bft"
149+
seedUrls: [ "https://bft-node-1.url:5003", "https://bft-node-2.url:5003" ]
150+
documentSelector:
151+
path: kind
152+
value: Deployment
153+
asserts:
154+
- matchRegex:
155+
path: spec.template.spec.containers[?(@.name=='validator-app')].env[?(@.name=='ADDITIONAL_CONFIG_BFT_SCAN')].value
156+
pattern: "canton.validator-apps.validator_backend.scan-client.type = \"bft\""
157+
- matchRegex:
158+
path: spec.template.spec.containers[?(@.name=='validator-app')].env[?(@.name=='ADDITIONAL_CONFIG_BFT_SCAN')].value
159+
pattern: 'canton.validator-apps.validator_backend.scan-client.seed-urls = \["https://bft-node-1.url:5003","https://bft-node-2.url:5003"\]'
160+
161+
- it: "configures scan-client for bft-custom mode, including trustedSvs and threshold"
162+
set:
163+
scanClient:
164+
scanType: "bft-custom"
165+
seedUrls: [ "https://custom-node-A.com", "https://custom-node-B.com" ]
166+
trustedSvs: [ "custom-sv-1", "custom-sv-2", "custom-sv-3" ]
167+
threshold: 2
168+
documentSelector:
169+
path: kind
170+
value: Deployment
171+
asserts:
172+
- matchRegex:
173+
path: spec.template.spec.containers[?(@.name=='validator-app')].env[?(@.name=='ADDITIONAL_CONFIG_BFT_SCAN')].value
174+
pattern: "canton.validator-apps.validator_backend.scan-client.type = \"bft-custom\""
175+
- matchRegex:
176+
path: spec.template.spec.containers[?(@.name=='validator-app')].env[?(@.name=='ADDITIONAL_CONFIG_BFT_SCAN')].value
177+
pattern: 'canton.validator-apps.validator_backend.scan-client.seed-urls = \["https://custom-node-A.com","https://custom-node-B.com"\]'
178+
- matchRegex:
179+
path: spec.template.spec.containers[?(@.name=='validator-app')].env[?(@.name=='ADDITIONAL_CONFIG_BFT_SCAN')].value
180+
pattern: 'canton.validator-apps.validator_backend.scan-client.trusted-svs = \["custom-sv-1","custom-sv-2","custom-sv-3"\]'
181+
- matchRegex:
182+
path: spec.template.spec.containers[?(@.name=='validator-app')].env[?(@.name=='ADDITIONAL_CONFIG_BFT_SCAN')].value
183+
pattern: "canton.validator-apps.validator_backend.scan-client.threshold = 2"
184+
185+
- it: "configures scan-client for trust-single when nonSvValidatorTrustSingleScan is true"
186+
set:
187+
nonSvValidatorTrustSingleScan: true
188+
documentSelector:
189+
path: kind
190+
value: Deployment
191+
asserts:
192+
- matchRegex:
193+
path: spec.template.spec.containers[?(@.name=='validator-app')].env[?(@.name=='ADDITIONAL_CONFIG_NON_VALIDATOR_TRUST_SINGLE_SCAN')].value
194+
pattern: "canton.validator-apps.validator_backend.scan-client.type = \"trust-single\""
195+
196+
- it: "defaults to BFT scan client with internal scan address if no config is set"
197+
set:
198+
svValidator: false
199+
documentSelector:
200+
path: kind
201+
value: Deployment
202+
asserts:
203+
- matchRegex:
204+
path: spec.template.spec.containers[?(@.name=='validator-app')].env[?(@.name=='ADDITIONAL_CONFIG_BFT_SCAN')].value
205+
pattern: "canton.validator-apps.validator_backend.scan-client.type = \"bft\""
206+
- matchRegex:
207+
path: spec.template.spec.containers[?(@.name=='validator-app')].env[?(@.name=='ADDITIONAL_CONFIG_BFT_SCAN')].value
208+
pattern: "canton\\.validator-apps\\.validator_backend\\.scan-client\\.seed-urls = \\[\\s*\\$\\{_scan\\.admin-api\\.address\\}\\s*\\]"
209+
210+
- it: "defaults to BFT scan client when scanType is not specified"
211+
set:
212+
scanClient:
213+
seedUrls: [ "https://custom-node-A.com", "https://custom-node-B.com" ]
214+
documentSelector:
215+
path: kind
216+
value: Deployment
217+
asserts:
218+
- matchRegex:
219+
path: spec.template.spec.containers[?(@.name=='validator-app')].env[?(@.name=='ADDITIONAL_CONFIG_BFT_SCAN')].value
220+
pattern: "canton.validator-apps.validator_backend.scan-client.type = \"bft\""
221+
- matchRegex:
222+
path: spec.template.spec.containers[?(@.name=='validator-app')].env[?(@.name=='ADDITIONAL_CONFIG_BFT_SCAN')].value
223+
pattern: 'canton.validator-apps.validator_backend.scan-client.seed-urls = \["https://custom-node-A.com","https://custom-node-B.com"\]'

cluster/helm/splice-validator/values.schema.json

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,45 @@
99
"type": "object",
1010
"description": "The authentication configuration for the application"
1111
},
12+
"scanClient": {
13+
"type": "object",
14+
"description": "Configuration parameters for the scan client.",
15+
"properties": {
16+
"scanType": {
17+
"type": "string",
18+
"enum": [
19+
"trust-single",
20+
"bft",
21+
"bft-custom"
22+
],
23+
"description": "The type of scan client configuration."
24+
},
25+
"scanAddress": {
26+
"type": "string",
27+
"description": "scan address for trust single type."
28+
},
29+
"threshold": {
30+
"type": "integer",
31+
"default": 0,
32+
"description": "bft-custom threshold. Optional unless scan-type is bft-custom."
33+
},
34+
"trustedSvs": {
35+
"type": "array",
36+
"items": {
37+
"type": "string"
38+
},
39+
"default": [],
40+
"description": "List of trusted scans. Optional unless scan-type is bft-custom."
41+
},
42+
"seedUrls": {
43+
"type": "array",
44+
"items": {
45+
"type": "string"
46+
},
47+
"description": "List of seed URLs for the scan client."
48+
}
49+
}
50+
},
1251
"svValidator": {
1352
"type": "boolean",
1453
"description": "Whether this validator is part of an SV node"
@@ -23,6 +62,52 @@
2362
}
2463
},
2564
"allOf": [
65+
{
66+
"if": {
67+
"properties": {
68+
"scanClient": {
69+
"type": "object"
70+
}
71+
},
72+
"required": ["scanClient"]
73+
},
74+
"then": {
75+
"properties": {
76+
"scanClient": {
77+
"properties": {
78+
"seedUrls": {
79+
"type": "array",
80+
"minItems": 1,
81+
"description": "List of seed URLs for the scan client. Must be non-empty if scanClient is set."
82+
}
83+
}
84+
}
85+
}
86+
}
87+
},
88+
{
89+
"if": {
90+
"properties": {
91+
"scanClient": {
92+
"type": "object",
93+
"properties": {
94+
"scanType": {
95+
"const": "bft-custom"
96+
}
97+
},
98+
"required": ["scanType"]
99+
}
100+
},
101+
"required": ["scanClient"]
102+
},
103+
"then": {
104+
"properties": {
105+
"scanClient": {
106+
"required": ["threshold", "trustedSvs"]
107+
}
108+
}
109+
}
110+
},
26111
{
27112
"if": {
28113
"properties": {
@@ -87,7 +172,6 @@
87172
"migration",
88173
"nodeIdentifier",
89174
"persistence",
90-
"scanAddress",
91175
"spliceInstanceNames"
92176
],
93177
"properties": {
@@ -452,6 +536,29 @@
452536
"not": { "required": ["validatorWalletUser"] }
453537
}
454538
]
539+
},
540+
{
541+
"if": {
542+
"properties": {
543+
"scanClient": {
544+
"type": "object"
545+
}
546+
},
547+
"required": ["scanClient"]
548+
},
549+
"then": {
550+
"not": {
551+
"anyOf": [
552+
{
553+
"required": ["scanAddress"]
554+
},
555+
{
556+
"required": ["nonSvValidatorTrustSingleScan"]
557+
}
558+
]
559+
},
560+
"errorMessage": "If 'scanClient' is set, 'scanAddress' and 'nonSvValidatorTrustSingleScan' must not be set. All the scan specific configuration must be done inside the 'scanClient' object."
561+
}
455562
}
456563
]
457564
}

cluster/pulumi/common-validator/src/config.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,38 @@ import {
99
import { clusterSubConfig } from '@lfdecentralizedtrust/splice-pulumi-common/src/config/config';
1010
import { z } from 'zod';
1111

12+
export const ScanClientConfigSchema = z
13+
.object({
14+
scanType: z.enum(['trust-single', 'bft', 'bft-custom']),
15+
scanAddress: z.string().optional(),
16+
threshold: z.number().default(0),
17+
trustedSvs: z.array(z.string()).default([]),
18+
seedUrls: z.array(z.string()).min(1, 'seedUrls must contain at least one element.').optional(),
19+
})
20+
.refine(
21+
data => {
22+
if (data.scanType === 'bft-custom') {
23+
const threshold = data.threshold;
24+
const trustedSvsSize = data.trustedSvs.length;
25+
const seedUrlsSize = data.seedUrls ? data.seedUrls.length : 0;
26+
return trustedSvsSize >= threshold && seedUrlsSize >= threshold;
27+
} else {
28+
return true;
29+
}
30+
},
31+
{
32+
message:
33+
"For 'bft-custom' scanType, both 'trustedSvs' and 'seedUrls' must have a length greater than or equal to 'threshold'.",
34+
path: ['scanType'],
35+
}
36+
);
37+
38+
export type ScanClientConfig = z.infer<typeof ScanClientConfigSchema>;
39+
1240
export const ValidatorAppConfigSchema = z.object({
1341
additionalEnvVars: z.array(EnvVarConfigSchema).default([]),
1442
additionalJvmOptions: z.string().optional(),
43+
scanClient: ScanClientConfigSchema.optional(),
1544
});
1645

1746
export const ParticipantConfigSchema = z.object({

cluster/pulumi/validator-runbook/src/installNode.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,10 @@ async function installValidator(
201201
),
202202
};
203203

204+
if (validatorConfig.validatorApp?.scanClient != null) {
205+
delete validatorValuesFromYamlFiles.scanAddress;
206+
}
207+
204208
const newParticipantIdentifier =
205209
validatorConfig.newParticipantId ||
206210
validatorValuesFromYamlFiles?.participantIdentitiesDumpImport?.newParticipantIdentifier;
@@ -213,6 +217,7 @@ async function installValidator(
213217
? true
214218
: validatorValuesFromYamlFiles.migration.migrating,
215219
},
220+
scanClient: validatorConfig.validatorApp?.scanClient,
216221
metrics: {
217222
enable: true,
218223
},

0 commit comments

Comments
 (0)