sui_genesis_builder/
validator_info.rs1use anyhow::bail;
5use fastcrypto::traits::ToFromBytes;
6use serde::{Deserialize, Serialize};
7use serde_with::serde_as;
8use sui_types::base_types::SuiAddress;
9use sui_types::crypto::{
10 AuthorityPublicKey, AuthorityPublicKeyBytes, AuthoritySignature, NetworkPublicKey,
11 verify_proof_of_possession,
12};
13use sui_types::multiaddr::Multiaddr;
14
15const MAX_VALIDATOR_METADATA_LENGTH: usize = 256;
16
17#[serde_as]
19#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
20#[serde(rename_all = "kebab-case")]
21pub struct ValidatorInfo {
22 pub name: String,
23 pub account_address: SuiAddress,
24 pub protocol_key: AuthorityPublicKeyBytes,
25 pub worker_key: NetworkPublicKey,
26 pub network_key: NetworkPublicKey,
27 pub gas_price: u64,
28 pub commission_rate: u64,
29 pub network_address: Multiaddr,
30 pub p2p_address: Multiaddr,
31 pub narwhal_primary_address: Multiaddr,
32 pub narwhal_worker_address: Multiaddr,
33 pub description: String,
34 pub image_url: String,
35 pub project_url: String,
36}
37
38impl ValidatorInfo {
39 pub fn name(&self) -> &str {
40 &self.name
41 }
42
43 pub fn sui_address(&self) -> SuiAddress {
44 self.account_address
45 }
46
47 pub fn protocol_key(&self) -> AuthorityPublicKeyBytes {
48 self.protocol_key
49 }
50
51 pub fn worker_key(&self) -> &NetworkPublicKey {
52 &self.worker_key
53 }
54
55 pub fn network_key(&self) -> &NetworkPublicKey {
56 &self.network_key
57 }
58
59 pub fn gas_price(&self) -> u64 {
60 self.gas_price
61 }
62
63 pub fn commission_rate(&self) -> u64 {
64 self.commission_rate
65 }
66
67 pub fn network_address(&self) -> &Multiaddr {
68 &self.network_address
69 }
70
71 pub fn narwhal_primary_address(&self) -> &Multiaddr {
72 &self.narwhal_primary_address
73 }
74
75 pub fn narwhal_worker_address(&self) -> &Multiaddr {
76 &self.narwhal_worker_address
77 }
78
79 pub fn p2p_address(&self) -> &Multiaddr {
80 &self.p2p_address
81 }
82}
83
84#[serde_as]
85#[derive(Clone, Debug, Serialize, Deserialize)]
86pub struct GenesisValidatorInfo {
87 pub info: ValidatorInfo,
88 pub proof_of_possession: AuthoritySignature,
89}
90
91impl GenesisValidatorInfo {
92 pub fn validate(&self) -> anyhow::Result<(), anyhow::Error> {
93 if !self.info.name.is_ascii() {
94 bail!("name must be ascii");
95 }
96 if self.info.name.len() > MAX_VALIDATOR_METADATA_LENGTH {
97 bail!("name must be <= {MAX_VALIDATOR_METADATA_LENGTH} bytes long");
98 }
99
100 if !self.info.description.is_ascii() {
101 bail!("description must be ascii");
102 }
103 if self.info.description.len() > MAX_VALIDATOR_METADATA_LENGTH {
104 bail!("description must be <= {MAX_VALIDATOR_METADATA_LENGTH} bytes long");
105 }
106
107 if self.info.image_url.len() > MAX_VALIDATOR_METADATA_LENGTH {
108 bail!("image url must be <= {MAX_VALIDATOR_METADATA_LENGTH} bytes long");
109 }
110
111 if self.info.project_url.len() > MAX_VALIDATOR_METADATA_LENGTH {
112 bail!("project url must be <= {MAX_VALIDATOR_METADATA_LENGTH} bytes long");
113 }
114
115 if !self.info.network_address.to_string().is_ascii() {
116 bail!("network address must be ascii");
117 }
118 if self.info.network_address.len() > MAX_VALIDATOR_METADATA_LENGTH {
119 bail!("network address must be <= {MAX_VALIDATOR_METADATA_LENGTH} bytes long");
120 }
121
122 if !self.info.p2p_address.to_string().is_ascii() {
123 bail!("p2p address must be ascii");
124 }
125 if self.info.p2p_address.len() > MAX_VALIDATOR_METADATA_LENGTH {
126 bail!("p2p address must be <= {MAX_VALIDATOR_METADATA_LENGTH} bytes long");
127 }
128
129 if !self.info.narwhal_primary_address.to_string().is_ascii() {
130 bail!("primary address must be ascii");
131 }
132 if self.info.narwhal_primary_address.len() > MAX_VALIDATOR_METADATA_LENGTH {
133 bail!("primary address must be <= {MAX_VALIDATOR_METADATA_LENGTH} bytes long");
134 }
135
136 if !self.info.narwhal_worker_address.to_string().is_ascii() {
137 bail!("worker address must be ascii");
138 }
139 if self.info.narwhal_worker_address.len() > MAX_VALIDATOR_METADATA_LENGTH {
140 bail!("worker address must be <= {MAX_VALIDATOR_METADATA_LENGTH} bytes long");
141 }
142
143 if let Err(e) = self.info.p2p_address.to_anemo_address() {
144 bail!("p2p address must be valid anemo address: {e}");
145 }
146 if let Err(e) = self.info.narwhal_primary_address.to_anemo_address() {
147 bail!("primary address must be valid anemo address: {e}");
148 }
149 if let Err(e) = self.info.narwhal_worker_address.to_anemo_address() {
150 bail!("worker address must be valid anemo address: {e}");
151 }
152
153 if self.info.commission_rate > 10000 {
154 bail!("commissions rate must be lower than 100%");
155 }
156
157 let protocol_pubkey = AuthorityPublicKey::from_bytes(self.info.protocol_key.as_ref())?;
158 if let Err(e) = verify_proof_of_possession(
159 &self.proof_of_possession,
160 &protocol_pubkey,
161 self.info.account_address,
162 ) {
163 bail!("proof of possession is incorrect: {e}");
164 }
165
166 Ok(())
167 }
168}
169
170impl From<GenesisValidatorInfo> for GenesisValidatorMetadata {
171 fn from(
172 GenesisValidatorInfo {
173 info,
174 proof_of_possession,
175 }: GenesisValidatorInfo,
176 ) -> Self {
177 Self {
178 name: info.name,
179 description: info.description,
180 image_url: info.image_url,
181 project_url: info.project_url,
182 sui_address: info.account_address,
183 gas_price: info.gas_price,
184 commission_rate: info.commission_rate,
185 protocol_public_key: info.protocol_key.as_bytes().to_vec(),
186 proof_of_possession: proof_of_possession.as_ref().to_vec(),
187 network_public_key: info.network_key.as_bytes().to_vec(),
188 worker_public_key: info.worker_key.as_bytes().to_vec(),
189 network_address: info.network_address,
190 p2p_address: info.p2p_address,
191 primary_address: info.narwhal_primary_address,
192 worker_address: info.narwhal_worker_address,
193 }
194 }
195}
196
197#[derive(Clone, Debug, Serialize, Deserialize)]
198#[serde(rename_all = "kebab-case")]
199pub struct GenesisValidatorMetadata {
200 pub name: String,
201 pub description: String,
202 pub image_url: String,
203 pub project_url: String,
204
205 pub sui_address: SuiAddress,
206
207 pub gas_price: u64,
208 pub commission_rate: u64,
209
210 pub protocol_public_key: Vec<u8>, pub proof_of_possession: Vec<u8>, pub network_public_key: Vec<u8>, pub worker_public_key: Vec<u8>, pub network_address: Multiaddr,
217 pub p2p_address: Multiaddr,
218 pub primary_address: Multiaddr,
219 pub worker_address: Multiaddr,
220}