Skip to content

Commit c027750

Browse files
authored
2 parents 25de6a7 + 4c21958 commit c027750

File tree

25 files changed

+675
-10
lines changed

25 files changed

+675
-10
lines changed

spartan/aztec-keystore/Chart.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
apiVersion: v2
2+
name: aztec-mnemonic
3+
description: This chart derives private keys and addresses from a mnemonic
4+
type: application
5+
version: 0.1.0
6+
appVersion: "0.1.0"
7+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{{/*
2+
Expand the name of the chart.
3+
*/}}
4+
{{- define "aztec-keystore.serviceAccountName" -}}
5+
{{- .Values.serviceAccount.name | default (printf "%s-%s" .Release.Name "keystore") }}
6+
{{- end }}
7+
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
apiVersion: batch/v1
2+
kind: Job
3+
metadata:
4+
name: {{ .Release.Name }}-derive-accounts
5+
annotations:
6+
"helm.sh/hook": post-install,post-upgrade
7+
"helm.sh/hook-delete-policy": hook-succeeded
8+
spec:
9+
template:
10+
spec:
11+
serviceAccountName: {{ include "aztec-keystore.serviceAccountName" . }}
12+
restartPolicy: OnFailure
13+
volumes:
14+
- name: shared
15+
emptyDir: {}
16+
{{- if .Values.mnemonic.fromSecret.name }}
17+
- name: mnemonic
18+
secret:
19+
secretName: {{ .Values.mnemonic.fromSecret.name }}
20+
items:
21+
- key: {{ .Values.mnemonic.fromSecret.key | default "mnemonic" }}
22+
path: mnemonic
23+
{{- end }}
24+
initContainers:
25+
- name: derive
26+
image: {{ printf "%s:%s" .Values.global.aztecImage.repository .Values.global.aztecImage.tag }}
27+
imagePullPolicy: {{ .Values.global.aztecImage.pullPolicy }}
28+
command:
29+
- /bin/bash
30+
- -c
31+
- |
32+
set -euo pipefail
33+
NODES="{{ .Values.attesters.nodeCount }}"
34+
ATTESTERS_PER_NODE="{{ .Values.attesters.attestersPerNode }}"
35+
PUBLISHERS_PER_VALIDATOR_KEY="{{ .Values.publishers.perValidatorKey }}"
36+
ATTESTER_KEY_INDEX_START="{{ .Values.attesters.mnemonicStartIndex }}"
37+
PUBLISHER_KEY_INDEX_START="{{ .Values.publishers.mnemonicStartIndex }}"
38+
39+
{{- if .Values.mnemonic.fromSecret.name }}
40+
MNEMONIC="/mnemonic/mnemonic"
41+
{{- else }}
42+
MNEMONIC="{{ .Values.mnemonic.value }}"
43+
{{- end }}
44+
45+
for ((i=0;i<NODES;i++)); do
46+
KS_FILE=/shared/attesters/keystores/node_$i.yaml
47+
ADDR_FILE=/shared/attesters/addresses/node_$i
48+
PUB_KS_FILE=/shared/publishers/keystores/node_$i.yaml
49+
PUB_ADDR_FILE=/shared/publishers/addresses/node_$i
50+
51+
mkdir -p $(dirname $KS_FILE) $(dirname $ADDR_FILE) $(dirname $PUB_KS_FILE) $(dirname $PUB_ADDR_FILE)
52+
53+
truncate -s 0 "$ADDR_FILE"
54+
truncate -s 0 "$KS_FILE"
55+
truncate -s 0 "$PUB_ADDR_FILE"
56+
truncate -s 0 "$PUB_KS_FILE"
57+
58+
for ((j=0;j<ATTESTERS_PER_NODE;j++)); do
59+
idx=$((ATTESTER_KEY_INDEX_START + ATTESTERS_PER_NODE * i + j))
60+
pk="$(cast wallet private-key --mnemonic "$MNEMONIC" --mnemonic-index "$idx")"
61+
addr="$(cast wallet address --private-key $pk)"
62+
63+
[[ $j -gt 0 ]] && echo '---' >> "$KS_FILE"
64+
printf 'type: file-raw\nkeyType: SECP256K1\nprivateKey: %s\n' "$pk" >> "$KS_FILE"
65+
66+
[[ $j -gt 0 ]] && printf ',' >> "$ADDR_FILE"
67+
printf '%s' "$addr" >> "$ADDR_FILE"
68+
done
69+
70+
# Publishers: start index per node, then pack by validator j and publisher p
71+
pub_base=$((PUBLISHER_KEY_INDEX_START + i * ATTESTERS_PER_NODE * PUBLISHERS_PER_VALIDATOR_KEY))
72+
for ((j=0;j<ATTESTERS_PER_NODE;j++)); do
73+
for ((p=0;p<PUBLISHERS_PER_VALIDATOR_KEY;p++)); do
74+
pub_idx=$((pub_base + j * PUBLISHERS_PER_VALIDATOR_KEY + p))
75+
ppk="$(cast wallet private-key --mnemonic "$MNEMONIC" --mnemonic-index "$pub_idx")"
76+
paddr="$(cast wallet address --private-key $ppk)"
77+
78+
# write keystore file-separated entries
79+
[[ $j -gt 0 || $p -gt 0 ]] && echo '---' >> "$PUB_KS_FILE"
80+
printf 'type: file-raw\nkeyType: SECP256K1\nprivateKey: %s\n' "$ppk" >> "$PUB_KS_FILE"
81+
82+
# write addresses CSV per node
83+
if [[ $j -gt 0 || $p -gt 0 ]]; then printf ',' >> "$PUB_ADDR_FILE"; fi
84+
printf '%s' "$paddr" >> "$PUB_ADDR_FILE"
85+
done
86+
done
87+
88+
echo "Generated config for attesters on node $i"
89+
done
90+
volumeMounts:
91+
- name: shared
92+
mountPath: /shared
93+
{{- if .Values.mnemonic.fromSecret.name }}
94+
- name: mnemonic
95+
mountPath: /mnemonic
96+
{{- end }}
97+
containers:
98+
- name: publish
99+
image: {{ printf "%s:%s" .Values.global.kubectlImage.repository .Values.global.kubectlImage.tag }}
100+
imagePullPolicy: {{ .Values.global.kubectlImage.pullPolicy }}
101+
env:
102+
- name: K8S_NAMESPACE_NAME
103+
valueFrom:
104+
fieldRef:
105+
fieldPath: metadata.namespace
106+
command:
107+
- /bin/bash
108+
- -c
109+
- |
110+
set -euo pipefail
111+
112+
ATTESTER_KEYSTORE_SECRET_NAME="{{ .Values.attesters.keyStoreSecret.name | default (printf "%s-%s" .Release.Name "attester-keystores") }}"
113+
114+
kubectl -n "$K8S_NAMESPACE_NAME" create secret generic "$ATTESTER_KEYSTORE_SECRET_NAME" \
115+
--from-file /shared/attesters/keystores \
116+
--dry-run=client -o yaml | kubectl apply -f -
117+
118+
ATTESTER_ADDRESS_CM_NAME="{{ .Values.attesters.addressConfigMap.name | default (printf "%s-%s" .Release.Name "attester-addresses") }}"
119+
PUBLISHER_KEYSTORE_SECRET_NAME="{{ .Values.publishers.keyStoreSecret.name | default (printf "%s-%s" .Release.Name "publisher-keystores") }}"
120+
kubectl -n "$K8S_NAMESPACE_NAME" create secret generic "$PUBLISHER_KEYSTORE_SECRET_NAME" \
121+
--from-file /shared/publishers/keystores \
122+
--dry-run=client -o yaml | kubectl apply -f -
123+
124+
PUBLISHER_ADDRESS_CM_NAME="{{ .Values.publishers.addressConfigMap.name | default (printf "%s-%s" .Release.Name "publisher-addresses") }}"
125+
kubectl -n "$K8S_NAMESPACE_NAME" create configmap "$PUBLISHER_ADDRESS_CM_NAME" \
126+
--from-file /shared/publishers/addresses \
127+
--dry-run=client -o yaml | kubectl apply -f -
128+
kubectl -n "$K8S_NAMESPACE_NAME" create configmap "$ATTESTER_ADDRESS_CM_NAME" \
129+
--from-file /shared/attesters/addresses \
130+
--dry-run=client -o yaml | kubectl apply -f -
131+
volumeMounts:
132+
- name: shared
133+
mountPath: /shared
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{{- if .Values.serviceAccount.create }}
2+
apiVersion: rbac.authorization.k8s.io/v1
3+
kind: Role
4+
metadata:
5+
name: {{ include "aztec-keystore.serviceAccountName" . }}-role
6+
rules:
7+
- apiGroups: [""]
8+
resources: ["configmaps","secrets"]
9+
verbs: ["get", "create","update","patch"]
10+
---
11+
apiVersion: rbac.authorization.k8s.io/v1
12+
kind: RoleBinding
13+
metadata:
14+
name: {{ include "aztec-keystore.serviceAccountName" . }}-role-binding
15+
subjects:
16+
- kind: ServiceAccount
17+
name: {{ include "aztec-keystore.serviceAccountName" . }}
18+
roleRef:
19+
apiGroup: rbac.authorization.k8s.io
20+
kind: Role
21+
name: {{ include "aztec-keystore.serviceAccountName" . }}-role
22+
{{- end }}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{{- if .Values.serviceAccount.create }}
2+
apiVersion: v1
3+
kind: ServiceAccount
4+
metadata:
5+
name: {{ include "aztec-keystore.serviceAccountName" . }}
6+
annotations:
7+
{{- toYaml .Values.serviceAccount.annotations | nindent 4 }}
8+
{{- end }}
9+

spartan/aztec-keystore/values.yaml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
global:
2+
aztecImage:
3+
repository: aztecprotocol/aztec
4+
tag: latest
5+
pullPolicy: IfNotPresent
6+
kubectlImage:
7+
repository: bitnami/kubectl
8+
tag: 1.33.4
9+
pullPolicy: Always
10+
11+
mnemonic:
12+
value: ""
13+
fromSecret:
14+
name: ""
15+
key: mnemonic
16+
17+
attesters:
18+
attestersPerNode: 1
19+
nodeCount: 1
20+
mnemonicStartIndex: 2000
21+
keyStoreSecret:
22+
create: true
23+
name: "" # if empty name will be generated based on Release.Name
24+
addressConfigMap:
25+
create: true
26+
name: "" # if empty name will be generated based on Release.Name
27+
28+
publishers:
29+
perValidatorKey: 1
30+
mnemonicStartIndex: 5000
31+
keyStoreSecret:
32+
create: true
33+
name: "" # if empty name will be generated based on Release.Name
34+
addressConfigMap:
35+
create: true
36+
name: "" # if empty name will be generated based on Release.Name
37+
38+
serviceAccount:
39+
create: true
40+
name: "" # leave empty to generate a name based on Release.Name
41+
annotations: {}

spartan/aztec-network/files/config/setup-attester-keystore.sh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,7 @@ publishers=()
6565
if [ -n "$WEB3_SIGNER_URL" ]; then
6666
remoteSigner=$(jq -n '{remoteSignerUrl: $url}' --arg url "$WEB3_SIGNER_URL")
6767
attesters=(${addresses[*]})
68-
# TODO: use addresses here when web3signer supports EIP-4844 txs. See PR https://github.com/Consensys/web3signer/pull/1096
69-
# publishers=(${publisher_addresses[*]})
68+
# TODO: switch to addresses once web3signer supports EIP-4844 txs. See https://github.com/Consensys/web3signer/pull/1096
7069
publishers=(${publisher_private_keys[*]})
7170
else
7271
remoteSigner="null"
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#!/usr/bin/env bash
2+
set -eu
3+
4+
VALIDATORS_PER_NODE=${VALIDATORS_PER_NODE:-1}
5+
PUBLISHERS_PER_VALIDATOR_KEY=${PUBLISHERS_PER_VALIDATOR_KEY:-1}
6+
7+
# We get the index in the config map from the pod name, which will have the service index within it
8+
# For multiple validators per node, we need to multiply the pod index by VALIDATORS_PER_NODE
9+
POD_INDEX=$(echo $K8S_POD_NAME | awk -F'-' '{print $NF}')
10+
KEY_INDEX=$((POD_INDEX * VALIDATORS_PER_NODE))
11+
# Add the index to the start index to get the private key index
12+
PRIVATE_KEY_INDEX=$((KEY_INDEX_START + KEY_INDEX))
13+
14+
# Calculate publisher key starting index for this pod
15+
PUBLISHER_KEY_INDEX=$((POD_INDEX * VALIDATORS_PER_NODE * PUBLISHERS_PER_VALIDATOR_KEY + PUBLISHER_KEY_INDEX_START))
16+
17+
WEB3_SIGNER_URL=${WEB3_SIGNER_URL:-""}
18+
19+
echo "POD_INDEX: $POD_INDEX"
20+
echo "KEY_INDEX: $KEY_INDEX"
21+
echo "KEY_INDEX_START: $KEY_INDEX_START"
22+
echo "PRIVATE_KEY_INDEX: $PRIVATE_KEY_INDEX"
23+
echo "PUBLISHER_KEY_INDEX_START: $PUBLISHER_KEY_INDEX_START"
24+
echo "PUBLISHER_KEY_INDEX: $PUBLISHER_KEY_INDEX"
25+
echo "WEB3_SIGNER_URL: ${WEB3_SIGNER_URL}"
26+
# Specific for validators that can hold multiple keys on one node
27+
echo "VALIDATORS_PER_NODE: ${VALIDATORS_PER_NODE}"
28+
echo "PUBLISHERS_PER_VALIDATOR_KEY: ${PUBLISHERS_PER_VALIDATOR_KEY}"
29+
echo "MNEMONIC: $(echo $MNEMONIC | cut -d' ' -f1-2)..."
30+
31+
private_keys=()
32+
addresses=()
33+
34+
# Generate validator keys (attesters)
35+
for ((i = 0; i < VALIDATORS_PER_NODE; i++)); do
36+
current_index=$((PRIVATE_KEY_INDEX + i))
37+
private_key=$(cast wallet private-key "$MNEMONIC" --mnemonic-index $current_index)
38+
address=$(cast wallet address --private-key $private_key)
39+
40+
if [ -z "$WEB3_SIGNER_URL" ]; then
41+
private_keys+=("$private_key")
42+
fi
43+
addresses+=("$address")
44+
done
45+
46+
# Generate publisher keys
47+
publisher_private_keys=()
48+
publisher_addresses=()
49+
50+
total_publishers=$((VALIDATORS_PER_NODE * PUBLISHERS_PER_VALIDATOR_KEY))
51+
52+
for ((i = 0; i < total_publishers; i++)); do
53+
current_pub_index=$((PUBLISHER_KEY_INDEX + i))
54+
pub_private_key=$(cast wallet private-key "$MNEMONIC" --mnemonic-index $current_pub_index)
55+
pub_address=$(cast wallet address --private-key $pub_private_key)
56+
57+
publisher_private_keys+=("$pub_private_key")
58+
publisher_addresses+=("$pub_address")
59+
done
60+
61+
remoteSigner=""
62+
attesters=()
63+
publishers=()
64+
65+
if [ -n "$WEB3_SIGNER_URL" ]; then
66+
remoteSigner=$(jq -n '{remoteSignerUrl: $url}' --arg url "$WEB3_SIGNER_URL")
67+
attesters=(${addresses[*]})
68+
# TODO: switch to addresses once web3signer supports EIP-4844 txs. See https://github.com/Consensys/web3signer/pull/1096
69+
publishers=(${publisher_private_keys[*]})
70+
else
71+
remoteSigner="null"
72+
attesters=(${private_keys[*]})
73+
# Without web3signer, use private keys for publishers
74+
publishers=(${publisher_private_keys[*]})
75+
fi
76+
77+
export KEY_STORE_DIRECTORY="/shared/config/keys"
78+
mkdir -p "$KEY_STORE_DIRECTORY"
79+
80+
# Build validators array with multiple entries
81+
validators_json="["
82+
for ((v = 0; v < VALIDATORS_PER_NODE; v++)); do
83+
if [ $v -gt 0 ]; then
84+
validators_json+=","
85+
fi
86+
87+
# Get the attester for this validator
88+
if [ -n "$WEB3_SIGNER_URL" ]; then
89+
attester="${addresses[$v]}"
90+
else
91+
attester="${private_keys[$v]}"
92+
fi
93+
94+
# Get the publisher keys for this validator
95+
validator_publishers="["
96+
for ((p = 0; p < PUBLISHERS_PER_VALIDATOR_KEY; p++)); do
97+
if [ $p -gt 0 ]; then
98+
validator_publishers+=","
99+
fi
100+
pub_index=$((v * PUBLISHERS_PER_VALIDATOR_KEY + p))
101+
validator_publishers+="\"${publishers[$pub_index]}\""
102+
done
103+
validator_publishers+="]"
104+
105+
106+
validators_json+="{
107+
\"attester\": \"$attester\",
108+
\"coinbase\": \"$attester\",
109+
\"publisher\": $validator_publishers,
110+
\"feeRecipient\": \"0x0000000000000000000000000000000000000000000000000000000000000000\"
111+
}"
112+
done
113+
validators_json+="]"
114+
115+
# Create final JSON structure
116+
jq -n --argjson remoteSigner "$remoteSigner" \
117+
--argjson validators "$validators_json" \
118+
'{
119+
schemaVersion: 1,
120+
remoteSigner: $remoteSigner,
121+
validators: $validators
122+
}' > "$KEY_STORE_DIRECTORY/attesters.json"
123+
124+
echo "Generated configuration for $VALIDATORS_PER_NODE validators with $PUBLISHERS_PER_VALIDATOR_KEY publishers each"

0 commit comments

Comments
 (0)