1use std::path::Path;
2use std::sync::Arc;
3
4use unc_crypto::{InMemorySigner, KeyType, PublicKey, Signature, Signer};
5
6use crate::block::{Approval, ApprovalInner, BlockHeader};
7use crate::challenge::ChallengeBody;
8use crate::chunk_validation::ChunkEndorsementInner;
9use crate::hash::CryptoHash;
10use crate::network::{AnnounceAccount, PeerId};
11use crate::sharding::ChunkHash;
12use crate::telemetry::TelemetryInfo;
13use crate::types::{AccountId, BlockHeight, EpochId};
14
15pub trait ValidatorSigner: Sync + Send {
17 fn validator_id(&self) -> &AccountId;
19
20 fn public_key(&self) -> PublicKey;
22
23 fn sign_telemetry(&self, info: &TelemetryInfo) -> serde_json::Value;
25
26 fn sign_block_header_parts(
28 &self,
29 prev_hash: CryptoHash,
30 inner_lite: &[u8],
31 inner_rest: &[u8],
32 ) -> (CryptoHash, Signature);
33
34 fn sign_chunk_hash(&self, chunk_hash: &ChunkHash) -> Signature;
36
37 fn sign_approval(&self, inner: &ApprovalInner, target_height: BlockHeight) -> Signature;
39
40 fn sign_chunk_endorsement(&self, inner: &ChunkEndorsementInner) -> Signature;
42
43 fn sign_challenge(&self, challenge_body: &ChallengeBody) -> (CryptoHash, Signature);
45
46 fn sign_account_announce(
48 &self,
49 account_id: &AccountId,
50 peer_id: &PeerId,
51 epoch_id: &EpochId,
52 ) -> Signature;
53
54 fn sign_account_key_payload(&self, proto_bytes: &[u8]) -> Signature;
66
67 fn compute_vrf_with_proof(
68 &self,
69 data: &[u8],
70 ) -> (unc_crypto::vrf::Value, unc_crypto::vrf::Proof);
71
72 fn write_to_file(&self, path: &Path) -> std::io::Result<()>;
74}
75
76#[derive(smart_default::SmartDefault)]
79pub struct EmptyValidatorSigner {
80 #[default("test".parse().unwrap())]
81 account_id: AccountId,
82}
83
84impl ValidatorSigner for EmptyValidatorSigner {
85 fn validator_id(&self) -> &AccountId {
86 &self.account_id
87 }
88
89 fn public_key(&self) -> PublicKey {
90 PublicKey::empty(KeyType::ED25519)
91 }
92
93 fn sign_telemetry(&self, _info: &TelemetryInfo) -> serde_json::Value {
94 serde_json::Value::default()
95 }
96
97 fn sign_block_header_parts(
98 &self,
99 prev_hash: CryptoHash,
100 inner_lite: &[u8],
101 inner_rest: &[u8],
102 ) -> (CryptoHash, Signature) {
103 let hash = BlockHeader::compute_hash(prev_hash, inner_lite, inner_rest);
104 (hash, Signature::default())
105 }
106
107 fn sign_chunk_hash(&self, _chunk_hash: &ChunkHash) -> Signature {
108 Signature::default()
109 }
110
111 fn sign_approval(&self, _inner: &ApprovalInner, _target_height: BlockHeight) -> Signature {
112 Signature::default()
113 }
114
115 fn sign_chunk_endorsement(&self, _inner: &ChunkEndorsementInner) -> Signature {
116 Signature::default()
117 }
118
119 fn sign_challenge(&self, challenge_body: &ChallengeBody) -> (CryptoHash, Signature) {
120 (CryptoHash::hash_borsh(challenge_body), Signature::default())
121 }
122
123 fn sign_account_announce(
124 &self,
125 _account_id: &AccountId,
126 _peer_id: &PeerId,
127 _epoch_id: &EpochId,
128 ) -> Signature {
129 Signature::default()
130 }
131
132 fn sign_account_key_payload(&self, _proto_bytes: &[u8]) -> Signature {
133 Signature::default()
134 }
135
136 fn compute_vrf_with_proof(
137 &self,
138 _data: &[u8],
139 ) -> (unc_crypto::vrf::Value, unc_crypto::vrf::Proof) {
140 unimplemented!()
141 }
142
143 fn write_to_file(&self, _path: &Path) -> std::io::Result<()> {
144 unimplemented!()
145 }
146}
147
148#[derive(Clone)]
150pub struct InMemoryValidatorSigner {
151 account_id: AccountId,
152 signer: Arc<dyn Signer>,
153}
154
155impl InMemoryValidatorSigner {
156 pub fn from_random(account_id: AccountId, key_type: KeyType) -> Self {
157 let signer = Arc::new(InMemorySigner::from_random(account_id.clone(), key_type));
158 Self { account_id, signer }
159 }
160
161 pub fn from_seed(account_id: AccountId, key_type: KeyType, seed: &str) -> Self {
162 let signer = Arc::new(InMemorySigner::from_seed(account_id.clone(), key_type, seed));
163 Self { account_id, signer }
164 }
165
166 pub fn public_key(&self) -> PublicKey {
167 self.signer.public_key()
168 }
169
170 pub fn from_file(path: &Path) -> std::io::Result<Self> {
171 let signer = InMemorySigner::from_file(path)?;
172 Ok(Self { account_id: signer.account_id.clone(), signer: Arc::new(signer) })
173 }
174}
175
176impl ValidatorSigner for InMemoryValidatorSigner {
177 fn validator_id(&self) -> &AccountId {
178 &self.account_id
179 }
180
181 fn public_key(&self) -> PublicKey {
182 self.signer.public_key()
183 }
184
185 fn sign_telemetry(&self, info: &TelemetryInfo) -> serde_json::Value {
186 let mut value = serde_json::to_value(info).expect("Telemetry must serialize to JSON");
187 let content = serde_json::to_string(&value).expect("Telemetry must serialize to JSON");
188 value["signature"] = self.signer.sign(content.as_bytes()).to_string().into();
189 value
190 }
191
192 fn sign_block_header_parts(
193 &self,
194 prev_hash: CryptoHash,
195 inner_lite: &[u8],
196 inner_rest: &[u8],
197 ) -> (CryptoHash, Signature) {
198 let hash = BlockHeader::compute_hash(prev_hash, inner_lite, inner_rest);
199 (hash, self.signer.sign(hash.as_ref()))
200 }
201
202 fn sign_chunk_hash(&self, chunk_hash: &ChunkHash) -> Signature {
203 self.signer.sign(chunk_hash.as_ref())
204 }
205
206 fn sign_approval(&self, inner: &ApprovalInner, target_height: BlockHeight) -> Signature {
207 self.signer.sign(&Approval::get_data_for_sig(inner, target_height))
208 }
209
210 fn sign_chunk_endorsement(&self, inner: &ChunkEndorsementInner) -> Signature {
211 self.signer.sign(&borsh::to_vec(inner).unwrap())
212 }
213
214 fn sign_challenge(&self, challenge_body: &ChallengeBody) -> (CryptoHash, Signature) {
215 let hash = CryptoHash::hash_borsh(challenge_body);
216 let signature = self.signer.sign(hash.as_ref());
217 (hash, signature)
218 }
219
220 fn sign_account_announce(
221 &self,
222 account_id: &AccountId,
223 peer_id: &PeerId,
224 epoch_id: &EpochId,
225 ) -> Signature {
226 let hash = AnnounceAccount::build_header_hash(account_id, peer_id, epoch_id);
227 self.signer.sign(hash.as_ref())
228 }
229
230 fn sign_account_key_payload(&self, proto_bytes: &[u8]) -> Signature {
231 self.signer.sign(proto_bytes)
232 }
233
234 fn compute_vrf_with_proof(
235 &self,
236 data: &[u8],
237 ) -> (unc_crypto::vrf::Value, unc_crypto::vrf::Proof) {
238 self.signer.compute_vrf_with_proof(data)
239 }
240
241 fn write_to_file(&self, path: &Path) -> std::io::Result<()> {
242 self.signer.write_to_file(path)
243 }
244}