1pub mod dispatch;
7
8pub use tempo_contracts::precompiles::{IValidatorConfigV2, ValidatorConfigV2Error};
9use tempo_contracts::precompiles::{VALIDATOR_CONFIG_V2_ADDRESS, ValidatorConfigV2Event};
10use tempo_precompiles_macros::{Storable, contract};
11
12use crate::{
13 error::{Result, TempoPrecompileError},
14 ip_validation::{IpWithPortParseError, ensure_address_is_ip, ensure_address_is_ip_port},
15 storage::{Handler, Mapping},
16 validator_config::ValidatorConfig,
17};
18use alloy::primitives::{Address, B256, Keccak256};
19use commonware_codec::DecodeExt;
20use commonware_cryptography::{
21 Verifier,
22 ed25519::{PublicKey, Signature},
23};
24use tracing::trace;
25
26pub const VALIDATOR_NS_ADD: &[u8] = b"TEMPO_VALIDATOR_CONFIG_V2_ADD_VALIDATOR";
28pub const VALIDATOR_NS_ROTATE: &[u8] = b"TEMPO_VALIDATOR_CONFIG_V2_ROTATE_VALIDATOR";
30
31enum SignatureKind {
33 Add { fee_recipient: Address },
34 Rotate,
35}
36
37#[derive(Debug, Storable)]
39struct Config {
40 owner: Address,
42 is_init: bool,
44 init_at_height: u64,
46 migration_skipped_count: u8,
49 v1_validator_count: u8,
52}
53
54impl Config {
55 fn new(owner: Address, is_init: bool, init_at_height: u64) -> Self {
56 Self {
57 owner,
58 is_init,
59 init_at_height,
60 migration_skipped_count: 0,
61 v1_validator_count: 0,
62 }
63 }
64
65 fn is_owner(&self, addr: Address) -> bool {
66 self.owner == addr
67 }
68
69 fn require_init(self) -> Result<Self> {
70 if self.is_init {
71 return Ok(self);
72 }
73 Err(ValidatorConfigV2Error::not_initialized())?
74 }
75
76 fn require_not_init(self) -> Result<Self> {
77 if self.is_init {
78 Err(ValidatorConfigV2Error::already_initialized())?
79 }
80 Ok(self)
81 }
82
83 fn require_owner(self, caller: Address) -> Result<Self> {
84 if !self.is_owner(caller) {
85 Err(ValidatorConfigV2Error::unauthorized())?
86 }
87 Ok(self)
88 }
89
90 fn require_owner_or_validator(self, caller: Address, validator: Address) -> Result<Self> {
91 if caller != validator && !self.is_owner(caller) {
92 Err(ValidatorConfigV2Error::unauthorized())?
93 }
94 Ok(self)
95 }
96}
97
98#[derive(Debug, Storable)]
112struct ValidatorRecord {
113 public_key: B256,
115 validator_address: Address,
117 ingress: String,
119 egress: String,
121 fee_recipient: Address,
123 index: u64,
126 active_idx: u64,
129 added_at_height: u64,
131 deactivated_at_height: u64,
133}
134
135#[contract(addr = VALIDATOR_CONFIG_V2_ADDRESS)]
156pub struct ValidatorConfigV2 {
157 config: Config,
159 validators: Vec<ValidatorRecord>,
161 address_to_index: Mapping<Address, u64>,
165 pubkey_to_index: Mapping<B256, u64>,
168 next_network_identity_rotation_epoch: u64,
170 active_ingress_ips: Mapping<B256, bool>,
172 active_indices: Vec<u64>,
175}
176
177impl ValidatorConfigV2 {
178 pub fn initialize(&mut self, owner: Address) -> Result<()> {
186 trace!(address=%self.address, %owner, "Initializing validator config v2 precompile");
187 self.__initialize()?;
188
189 let config = Config::new(owner, true, self.storage.block_number());
190
191 self.config.write(config)
192 }
193
194 pub fn owner(&self) -> Result<Address> {
200 self.config.owner.read()
201 }
202
203 pub fn get_initialized_at_height(&self) -> Result<u64> {
207 self.config.init_at_height.read()
208 }
209
210 pub fn is_initialized(&self) -> Result<bool> {
215 self.config.is_init.read()
216 }
217
218 pub fn validator_count(&self) -> Result<u64> {
221 Ok(self.validators.len()? as u64)
222 }
223
224 fn get_active_validator(&self, idx: u64) -> Result<ValidatorRecord> {
227 if idx >= self.validators.len()? as u64 {
228 Err(ValidatorConfigV2Error::validator_not_found())?
229 }
230 let v = self.validators[idx as usize].read()?;
231 if v.deactivated_at_height != 0 {
232 Err(ValidatorConfigV2Error::validator_already_deactivated())?
233 }
234 Ok(v)
235 }
236
237 fn read_validator_at(&self, index: u64) -> Result<IValidatorConfigV2::Validator> {
238 debug_assert!(index < self.validator_count()?, "OOB index");
239
240 let v = self.validators[index as usize].read()?;
241 Ok(IValidatorConfigV2::Validator {
242 publicKey: v.public_key,
243 validatorAddress: v.validator_address,
244 ingress: v.ingress,
245 egress: v.egress,
246 feeRecipient: v.fee_recipient,
247 index: v.index,
248 addedAtHeight: v.added_at_height,
249 deactivatedAtHeight: v.deactivated_at_height,
250 })
251 }
252
253 pub fn validator_by_index(&self, index: u64) -> Result<IValidatorConfigV2::Validator> {
258 if index >= self.validator_count()? {
259 Err(ValidatorConfigV2Error::validator_not_found())?
260 }
261 self.read_validator_at(index)
262 }
263
264 pub fn validator_by_address(&self, addr: Address) -> Result<IValidatorConfigV2::Validator> {
271 let idx1 = self.address_to_index[addr].read()?;
272 if idx1 == 0 {
273 Err(ValidatorConfigV2Error::validator_not_found())?
274 }
275 self.read_validator_at(idx1 - 1)
276 }
277
278 pub fn validator_by_public_key(&self, pubkey: B256) -> Result<IValidatorConfigV2::Validator> {
286 let idx1 = self.pubkey_to_index[pubkey].read()?;
287 if idx1 == 0 {
288 Err(ValidatorConfigV2Error::validator_not_found())?
289 }
290 self.read_validator_at(idx1 - 1)
291 }
292
293 pub fn get_active_validators(&self) -> Result<Vec<IValidatorConfigV2::Validator>> {
297 let count = self.active_indices.len()?;
298 let mut out = Vec::with_capacity(count);
299 for i in 0..count {
300 let global_idx1 = self.active_indices[i].read()?;
301 out.push(self.read_validator_at(global_idx1 - 1)?);
302 }
303 Ok(out)
304 }
305
306 pub fn get_next_network_identity_rotation_epoch(&self) -> Result<u64> {
310 self.next_network_identity_rotation_epoch.read()
311 }
312
313 fn validate_endpoints(ingress: &str, egress: &str) -> Result<()> {
314 ensure_address_is_ip_port(ingress).map_err(|err| {
315 TempoPrecompileError::from(ValidatorConfigV2Error::not_ip_port(
316 ingress.to_string(),
317 err.to_string(),
318 ))
319 })?;
320
321 ensure_address_is_ip(egress).map_err(|err| {
322 TempoPrecompileError::from(ValidatorConfigV2Error::not_ip(
323 egress.to_string(),
324 err.to_string(),
325 ))
326 })
327 }
328
329 fn ingress_key(ingress: &str) -> Result<B256> {
336 let ingress = ingress
337 .parse::<std::net::SocketAddr>()
338 .map_err(IpWithPortParseError::from)
339 .map_err(|err| {
340 TempoPrecompileError::from(ValidatorConfigV2Error::not_ip_port(
341 ingress.to_string(),
342 err.to_string(),
343 ))
344 })?;
345 let mut hasher = Keccak256::new();
346 match ingress {
347 std::net::SocketAddr::V4(v4) => {
348 hasher.update(v4.ip().octets());
349 hasher.update(v4.port().to_be_bytes());
350 }
351 std::net::SocketAddr::V6(v6) => {
352 hasher.update(v6.ip().octets());
353 hasher.update(v6.scope_id().to_be_bytes());
354 hasher.update(v6.port().to_be_bytes());
355 }
356 }
357 Ok(hasher.finalize())
358 }
359
360 fn require_unique_ingress(&self, ingress: &str) -> Result<B256> {
361 let ingress_hash = Self::ingress_key(ingress)?;
362 if self.active_ingress_ips[ingress_hash].read()? {
363 Err(ValidatorConfigV2Error::ingress_already_exists(
364 ingress.to_string(),
365 ))?
366 }
367 Ok(ingress_hash)
368 }
369
370 fn update_ingress_ip_tracking(&mut self, old_ingress: &str, new_ingress: &str) -> Result<()> {
371 let old_ingress_hash = Self::ingress_key(old_ingress)?;
372 let new_ingress_hash = Self::ingress_key(new_ingress)?;
373
374 if old_ingress_hash != new_ingress_hash {
375 if self.active_ingress_ips[new_ingress_hash].read()? {
376 Err(ValidatorConfigV2Error::ingress_already_exists(
377 new_ingress.to_string(),
378 ))?
379 }
380 self.active_ingress_ips[old_ingress_hash].delete()?;
381 self.active_ingress_ips[new_ingress_hash].write(true)?;
382 }
383
384 Ok(())
385 }
386
387 #[allow(clippy::too_many_arguments)]
388 fn append_validator(
389 &mut self,
390 addr: Address,
391 pubkey: B256,
392 ingress: String,
393 egress: String,
394 fee_recipient: Address,
395 added_at_height: u64,
396 deactivated_at_height: u64,
397 ) -> Result<u64> {
398 let count = self.validator_count()?;
399 let mut active_idx = 0u64;
400
401 if deactivated_at_height == 0 {
402 self.active_indices.push(count + 1)?; active_idx = self.active_indices.len()? as u64; }
405
406 let v = ValidatorRecord {
407 public_key: pubkey,
408 validator_address: addr,
409 ingress,
410 egress,
411 fee_recipient,
412 index: count,
413 active_idx,
414 added_at_height,
415 deactivated_at_height,
416 };
417
418 self.validators.push(v)?;
419
420 self.pubkey_to_index[pubkey].write(count + 1)?;
421 self.address_to_index[addr].write(count + 1)?;
423
424 Ok(count)
425 }
426
427 fn require_new_address(&self, addr: Address) -> Result<()> {
429 if addr.is_zero() {
430 Err(ValidatorConfigV2Error::invalid_validator_address())?
431 }
432 let idx1 = self.address_to_index[addr].read()?;
433 if idx1 != 0
434 && self.validators[(idx1 - 1) as usize]
435 .deactivated_at_height
436 .read()?
437 == 0
438 {
439 Err(ValidatorConfigV2Error::address_already_has_validator())?
440 }
441 Ok(())
442 }
443
444 fn require_new_pubkey(&self, pubkey: B256) -> Result<()> {
445 if pubkey.is_zero() {
446 Err(ValidatorConfigV2Error::invalid_public_key())?
447 }
448 if self.pubkey_to_index[pubkey].read()? != 0 {
449 Err(ValidatorConfigV2Error::public_key_already_exists())?
450 }
451 Ok(())
452 }
453
454 fn verify_validator_signature(
459 &self,
460 kind: SignatureKind,
461 pubkey: &B256,
462 signature: &[u8],
463 validator_address: Address,
464 ingress: &str,
465 egress: &str,
466 ) -> Result<()> {
467 let sig = Signature::decode(signature)
468 .map_err(|_| ValidatorConfigV2Error::invalid_signature_format())?;
469
470 let mut hasher = Keccak256::new();
471 hasher.update(self.storage.chain_id().to_be_bytes());
472 hasher.update(VALIDATOR_CONFIG_V2_ADDRESS.as_slice());
473 hasher.update(validator_address.as_slice());
474 hasher.update([
475 u8::try_from(ingress.len()).expect("validator ingress length must fit in uint8")
476 ]);
477 hasher.update(ingress.as_bytes());
478 hasher.update([
479 u8::try_from(egress.len()).expect("validator egress length must fit in uint8")
480 ]);
481 hasher.update(egress.as_bytes());
482
483 let namespace = match kind {
484 SignatureKind::Add { fee_recipient } => {
485 hasher.update(fee_recipient.as_slice());
486 VALIDATOR_NS_ADD
487 }
488 SignatureKind::Rotate => VALIDATOR_NS_ROTATE,
489 };
490 let message = hasher.finalize();
491
492 let public_key = PublicKey::decode(pubkey.as_slice())
493 .map_err(|_| ValidatorConfigV2Error::invalid_public_key())?;
494 if !public_key.verify(namespace, message.as_slice(), &sig) {
495 Err(ValidatorConfigV2Error::invalid_signature())?
496 }
497
498 Ok(())
499 }
500
501 pub fn add_validator(
522 &mut self,
523 sender: Address,
524 call: IValidatorConfigV2::addValidatorCall,
525 ) -> Result<u64> {
526 self.config.read()?.require_init()?.require_owner(sender)?;
527 self.require_new_pubkey(call.publicKey)?;
528 self.require_new_address(call.validatorAddress)?;
529 Self::validate_endpoints(&call.ingress, &call.egress)?;
530 let ingress_hash = self.require_unique_ingress(&call.ingress)?;
531
532 self.verify_validator_signature(
533 SignatureKind::Add {
534 fee_recipient: call.feeRecipient,
535 },
536 &call.publicKey,
537 &call.signature,
538 call.validatorAddress,
539 &call.ingress,
540 &call.egress,
541 )?;
542
543 let block_height = self.storage.block_number();
544
545 self.active_ingress_ips[ingress_hash].write(true)?;
546
547 let index = self.append_validator(
548 call.validatorAddress,
549 call.publicKey,
550 call.ingress.clone(),
551 call.egress.clone(),
552 call.feeRecipient,
553 block_height,
554 0,
555 )?;
556
557 self.emit_event(ValidatorConfigV2Event::ValidatorAdded(
558 IValidatorConfigV2::ValidatorAdded {
559 index,
560 validatorAddress: call.validatorAddress,
561 publicKey: call.publicKey,
562 ingress: call.ingress,
563 egress: call.egress,
564 feeRecipient: call.feeRecipient,
565 },
566 ))?;
567
568 Ok(index)
569 }
570
571 pub fn deactivate_validator(
586 &mut self,
587 sender: Address,
588 call: IValidatorConfigV2::deactivateValidatorCall,
589 ) -> Result<()> {
590 let v = self.get_active_validator(call.idx)?;
591 self.config
592 .read()?
593 .require_owner_or_validator(sender, v.validator_address)?;
594
595 self.active_ingress_ips[Self::ingress_key(&v.ingress)?].delete()?;
596
597 let block_height = self.storage.block_number();
598 self.validators[call.idx as usize]
599 .deactivated_at_height
600 .write(block_height)?;
601
602 let active_index = (v.active_idx - 1) as usize;
604 let last_pos = self.active_indices.len()? - 1;
605
606 if active_index != last_pos {
607 let moved_val = self.active_indices[last_pos].read()?;
608 self.active_indices[active_index].write(moved_val)?;
609 self.validators[(moved_val - 1) as usize]
610 .active_idx
611 .write((active_index + 1) as u64)?;
612 }
613 self.active_indices.pop()?;
614 self.validators[call.idx as usize].active_idx.write(0)?;
615
616 self.emit_event(ValidatorConfigV2Event::ValidatorDeactivated(
617 IValidatorConfigV2::ValidatorDeactivated {
618 index: call.idx,
619 validatorAddress: v.validator_address,
620 },
621 ))
622 }
623
624 pub fn transfer_ownership(
631 &mut self,
632 sender: Address,
633 call: IValidatorConfigV2::transferOwnershipCall,
634 ) -> Result<()> {
635 if call.newOwner.is_zero() {
636 Err(ValidatorConfigV2Error::invalid_owner())?
637 }
638 let mut config = self.config.read()?.require_init()?.require_owner(sender)?;
639 let old_owner = config.owner;
640 config.owner = call.newOwner;
641 self.config.write(config)?;
642
643 self.emit_event(ValidatorConfigV2Event::OwnershipTransferred(
644 IValidatorConfigV2::OwnershipTransferred {
645 oldOwner: old_owner,
646 newOwner: call.newOwner,
647 },
648 ))
649 }
650
651 pub fn set_network_identity_rotation_epoch(
658 &mut self,
659 sender: Address,
660 call: IValidatorConfigV2::setNetworkIdentityRotationEpochCall,
661 ) -> Result<()> {
662 self.config.read()?.require_init()?.require_owner(sender)?;
663 let previous_epoch = self.next_network_identity_rotation_epoch.read()?;
664 self.next_network_identity_rotation_epoch
665 .write(call.epoch)?;
666 self.emit_event(ValidatorConfigV2Event::NetworkIdentityRotationEpochSet(
667 IValidatorConfigV2::NetworkIdentityRotationEpochSet {
668 previousEpoch: previous_epoch,
669 nextEpoch: call.epoch,
670 },
671 ))
672 }
673
674 pub fn rotate_validator(
699 &mut self,
700 sender: Address,
701 call: IValidatorConfigV2::rotateValidatorCall,
702 ) -> Result<()> {
703 let v = self.get_active_validator(call.idx)?;
704 self.config
705 .read()?
706 .require_init()?
707 .require_owner_or_validator(sender, v.validator_address)?;
708 self.require_new_pubkey(call.publicKey)?;
709 Self::validate_endpoints(&call.ingress, &call.egress)?;
710
711 self.require_unique_ingress(&call.ingress)?;
712 self.verify_validator_signature(
713 SignatureKind::Rotate,
714 &call.publicKey,
715 &call.signature,
716 v.validator_address,
717 &call.ingress,
718 &call.egress,
719 )?;
720
721 let block_height = self.storage.block_number();
722
723 self.update_ingress_ip_tracking(&v.ingress, &call.ingress)?;
724
725 let appended_idx = self.validators.len()? as u64;
727 let snapshot = ValidatorRecord {
728 public_key: v.public_key,
729 validator_address: v.validator_address,
730 ingress: v.ingress,
731 egress: v.egress,
732 fee_recipient: v.fee_recipient,
733 index: appended_idx,
734 active_idx: 0,
735 added_at_height: v.added_at_height,
736 deactivated_at_height: block_height,
737 };
738 self.validators.push(snapshot)?;
739
740 self.pubkey_to_index[v.public_key].write(appended_idx + 1)?;
742
743 let mut updated = self.validators[call.idx as usize].read()?;
745 updated.public_key = call.publicKey;
746 updated.ingress = call.ingress.clone();
747 updated.egress = call.egress.clone();
748 updated.added_at_height = block_height;
749 self.validators[call.idx as usize].write(updated)?;
750
751 self.pubkey_to_index[call.publicKey].write(call.idx + 1)?;
753
754 self.emit_event(ValidatorConfigV2Event::ValidatorRotated(
755 IValidatorConfigV2::ValidatorRotated {
756 index: call.idx,
757 deactivatedIndex: appended_idx,
758 validatorAddress: v.validator_address,
759 oldPublicKey: v.public_key,
760 newPublicKey: call.publicKey,
761 ingress: call.ingress,
762 egress: call.egress,
763 caller: sender,
764 },
765 ))
766 }
767
768 pub fn set_fee_recipient(
775 &mut self,
776 sender: Address,
777 call: IValidatorConfigV2::setFeeRecipientCall,
778 ) -> Result<()> {
779 let mut v = self.get_active_validator(call.idx)?;
780 self.config
781 .read()?
782 .require_init()?
783 .require_owner_or_validator(sender, v.validator_address)?;
784
785 v.fee_recipient = call.feeRecipient;
786 self.validators[call.idx as usize].write(v)?;
787
788 self.emit_event(ValidatorConfigV2Event::FeeRecipientUpdated(
789 IValidatorConfigV2::FeeRecipientUpdated {
790 index: call.idx,
791 feeRecipient: call.feeRecipient,
792 caller: sender,
793 },
794 ))
795 }
796
797 pub fn set_ip_addresses(
806 &mut self,
807 sender: Address,
808 call: IValidatorConfigV2::setIpAddressesCall,
809 ) -> Result<()> {
810 let mut v = self.get_active_validator(call.idx)?;
811 self.config
812 .read()?
813 .require_init()?
814 .require_owner_or_validator(sender, v.validator_address)?;
815
816 Self::validate_endpoints(&call.ingress, &call.egress)?;
817
818 self.update_ingress_ip_tracking(&v.ingress, &call.ingress)?;
819
820 v.ingress = call.ingress.clone();
821 v.egress = call.egress.clone();
822 self.validators[call.idx as usize].write(v)?;
823
824 self.emit_event(ValidatorConfigV2Event::IpAddressesUpdated(
825 IValidatorConfigV2::IpAddressesUpdated {
826 index: call.idx,
827 ingress: call.ingress,
828 egress: call.egress,
829 caller: sender,
830 },
831 ))
832 }
833
834 pub fn transfer_validator_ownership(
845 &mut self,
846 sender: Address,
847 call: IValidatorConfigV2::transferValidatorOwnershipCall,
848 ) -> Result<()> {
849 let mut v = self.get_active_validator(call.idx)?;
850 self.config
851 .read()?
852 .require_init()?
853 .require_owner_or_validator(sender, v.validator_address)?;
854 self.require_new_address(call.newAddress)?;
855
856 let old_address = v.validator_address;
857 v.validator_address = call.newAddress;
858 self.validators[call.idx as usize].write(v)?;
859
860 self.address_to_index[old_address].delete()?;
861 self.address_to_index[call.newAddress].write(call.idx + 1)?;
862
863 self.emit_event(ValidatorConfigV2Event::ValidatorOwnershipTransferred(
864 IValidatorConfigV2::ValidatorOwnershipTransferred {
865 index: call.idx,
866 oldAddress: old_address,
867 newAddress: call.newAddress,
868 caller: sender,
869 },
870 ))
871 }
872
873 fn require_migration_owner(&mut self, caller: Address) -> Result<Config> {
884 let mut config = self.config.read()?.require_not_init()?;
885
886 if config.owner.is_zero() {
887 let v1 = v1();
888 config.owner = v1.owner()?;
889 let v1_count = v1.validator_count()?;
890 if v1_count == 0 {
891 Err(ValidatorConfigV2Error::empty_v1_validator_set())?
892 }
893 config.v1_validator_count = v1_count as u8;
894 self.config.write(Config {
895 owner: config.owner,
896 is_init: false,
897 init_at_height: 0,
898 migration_skipped_count: 0,
899 v1_validator_count: config.v1_validator_count,
900 })?;
901 }
902
903 config.require_owner(caller)
904 }
905
906 pub fn migrate_validator(
924 &mut self,
925 sender: Address,
926 call: IValidatorConfigV2::migrateValidatorCall,
927 ) -> Result<()> {
928 let config = self.require_migration_owner(sender)?;
929 let block_height = self.storage.block_number();
930
931 let v1 = v1();
932 let v1_count = u64::from(config.v1_validator_count);
933 let migrated = self.validator_count()?;
934 let skipped = config.migration_skipped_count;
935
936 let total_processed = migrated + u64::from(skipped);
937 if total_processed >= v1_count || call.idx != v1_count - total_processed - 1 {
938 Err(ValidatorConfigV2Error::invalid_migration_index())?
939 }
940
941 let v1_val = v1.validators(v1.validators_array(call.idx)?)?;
942
943 let skip = |s: &mut Self| {
945 s.emit_event(ValidatorConfigV2Event::SkippedValidatorMigration(
946 IValidatorConfigV2::SkippedValidatorMigration {
947 index: call.idx,
948 validatorAddress: v1_val.validatorAddress,
949 publicKey: v1_val.publicKey,
950 },
951 ))?;
952 s.config
953 .migration_skipped_count
954 .write(skipped.saturating_add(1))
955 };
956
957 if PublicKey::decode(v1_val.publicKey.as_slice()).is_err() {
959 return skip(self);
960 }
961
962 let egress = match v1_val.outboundAddress.parse::<std::net::SocketAddr>() {
964 Ok(sa) => sa.ip().to_string(),
965 Err(_) => return skip(self),
966 };
967
968 if self.pubkey_to_index[v1_val.publicKey].read()? != 0 {
970 return skip(self);
971 }
972
973 let addr_idx = self.address_to_index[v1_val.validatorAddress].read()?;
975 if addr_idx != 0
976 && self.validators[(addr_idx - 1) as usize]
977 .deactivated_at_height
978 .read()?
979 == 0
980 {
981 Err(ValidatorConfigV2Error::address_already_has_validator())?
982 }
983
984 let now_active = v1_val.active;
985 let ingress_hash = Self::ingress_key(&v1_val.inboundAddress)?;
986
987 if now_active && self.active_ingress_ips[ingress_hash].read()? {
989 return skip(self);
990 }
991
992 let migrated_idx = self.append_validator(
993 v1_val.validatorAddress,
994 v1_val.publicKey,
995 v1_val.inboundAddress,
996 egress,
997 Address::ZERO,
998 block_height,
999 if now_active { 0 } else { block_height },
1000 )?;
1001
1002 if now_active {
1003 self.active_ingress_ips[ingress_hash].write(true)?;
1004 }
1005
1006 self.emit_event(ValidatorConfigV2Event::ValidatorMigrated(
1007 IValidatorConfigV2::ValidatorMigrated {
1008 index: migrated_idx,
1009 validatorAddress: v1_val.validatorAddress,
1010 publicKey: v1_val.publicKey,
1011 },
1012 ))
1013 }
1014
1015 pub fn initialize_if_migrated(&mut self, sender: Address) -> Result<()> {
1027 let mut config = self.require_migration_owner(sender)?;
1028
1029 if config.v1_validator_count == 0
1032 || self.validator_count()? + u64::from(config.migration_skipped_count)
1033 < u64::from(config.v1_validator_count)
1034 {
1035 Err(ValidatorConfigV2Error::migration_not_complete())?
1036 }
1037
1038 let v1 = v1();
1039 let v1_next_dkg = v1.get_next_full_dkg_ceremony()?;
1040 self.next_network_identity_rotation_epoch
1041 .write(v1_next_dkg)?;
1042
1043 trace!(address=%self.address, "Initializing validator config v2 precompile after migration");
1044
1045 let height = self.storage.block_number();
1047 config.init_at_height = height;
1048 config.is_init = true;
1049 self.config.write(config)?;
1050
1051 self.emit_event(ValidatorConfigV2Event::Initialized(
1052 IValidatorConfigV2::Initialized { height },
1053 ))
1054 }
1055}
1056
1057fn v1() -> ValidatorConfig {
1058 ValidatorConfig::new()
1059}
1060
1061#[cfg(test)]
1062mod tests {
1063 use super::*;
1064 use crate::storage::{StorageCtx, hashmap::HashMapStorageProvider};
1065 use alloy::primitives::Address;
1066 use alloy_primitives::FixedBytes;
1067 use commonware_codec::Encode;
1068 use commonware_cryptography::{Signer, ed25519::PrivateKey};
1069
1070 fn make_test_keypair_and_signature(
1072 validator_address: Address,
1073 ingress: &str,
1074 egress: &str,
1075 kind: SignatureKind,
1076 ) -> (FixedBytes<32>, Vec<u8>) {
1077 let seed = rand_08::random::<u64>();
1079 let private_key = PrivateKey::from_seed(seed);
1080 let public_key = private_key.public_key();
1081
1082 let mut hasher = Keccak256::new();
1083 hasher.update(1u64.to_be_bytes());
1084 hasher.update(VALIDATOR_CONFIG_V2_ADDRESS.as_slice());
1085 hasher.update(validator_address.as_slice());
1086 hasher.update([
1087 u8::try_from(ingress.len()).expect("validator ingress length must fit in uint8")
1088 ]);
1089 hasher.update(ingress.as_bytes());
1090 hasher.update([
1091 u8::try_from(egress.len()).expect("validator egress length must fit in uint8")
1092 ]);
1093 hasher.update(egress.as_bytes());
1094 let namespace = match kind {
1095 SignatureKind::Add { fee_recipient } => {
1096 hasher.update(fee_recipient.as_slice());
1097 VALIDATOR_NS_ADD
1098 }
1099 SignatureKind::Rotate => VALIDATOR_NS_ROTATE,
1100 };
1101 let message = hasher.finalize();
1102
1103 let signature = private_key.sign(namespace, message.as_slice());
1105
1106 let pubkey_bytes = public_key.encode();
1108 let mut pubkey_array = [0u8; 32];
1109 pubkey_array.copy_from_slice(&pubkey_bytes);
1110
1111 (
1112 FixedBytes::<32>::from(pubkey_array),
1113 signature.encode().to_vec(),
1114 )
1115 }
1116
1117 fn make_add_call(
1118 addr: Address,
1119 pubkey: FixedBytes<32>,
1120 ingress: &str,
1121 egress: &str,
1122 fee_recipient: Address,
1123 signature: Vec<u8>,
1124 ) -> IValidatorConfigV2::addValidatorCall {
1125 IValidatorConfigV2::addValidatorCall {
1126 validatorAddress: addr,
1127 publicKey: pubkey,
1128 ingress: ingress.to_string(),
1129 egress: egress.to_string(),
1130 feeRecipient: fee_recipient,
1131 signature: signature.into(),
1132 }
1133 }
1134
1135 fn make_valid_add_call(
1137 addr: Address,
1138 ingress: &str,
1139 egress: &str,
1140 fee_recipient: Address,
1141 ) -> IValidatorConfigV2::addValidatorCall {
1142 let (pubkey, signature) = make_test_keypair_and_signature(
1143 addr,
1144 ingress,
1145 egress,
1146 SignatureKind::Add { fee_recipient },
1147 );
1148 make_add_call(addr, pubkey, ingress, egress, fee_recipient, signature)
1149 }
1150
1151 #[test]
1152 fn test_owner_initialization() -> eyre::Result<()> {
1153 let mut storage = HashMapStorageProvider::new(1);
1154 let owner = Address::random();
1155 StorageCtx::enter(&mut storage, || {
1156 let mut vc = ValidatorConfigV2::new();
1157 vc.initialize(owner)?;
1158
1159 assert_eq!(vc.owner()?, owner);
1160 assert!(vc.is_initialized()?);
1161 assert_eq!(vc.get_initialized_at_height()?, 0);
1162 assert_eq!(vc.validator_count()?, 0);
1163
1164 Ok(())
1165 })
1166 }
1167
1168 #[test]
1169 fn test_add_validator() -> eyre::Result<()> {
1170 let mut storage = HashMapStorageProvider::new(1);
1171 let owner = Address::random();
1172 let validator = Address::random();
1173 StorageCtx::enter(&mut storage, || {
1174 let mut vc = ValidatorConfigV2::new();
1175 vc.initialize(owner)?;
1176
1177 let (pubkey, signature) = make_test_keypair_and_signature(
1178 validator,
1179 "192.168.1.1:8000",
1180 "192.168.1.1",
1181 SignatureKind::Add {
1182 fee_recipient: validator,
1183 },
1184 );
1185 vc.storage.set_block_number(200);
1186 vc.add_validator(
1187 owner,
1188 make_add_call(
1189 validator,
1190 pubkey,
1191 "192.168.1.1:8000",
1192 "192.168.1.1",
1193 validator,
1194 signature,
1195 ),
1196 )?;
1197
1198 assert_eq!(vc.validator_count()?, 1);
1199
1200 let v = vc.validator_by_index(0)?;
1201 assert_eq!(v.publicKey, pubkey);
1202 assert_eq!(v.validatorAddress, validator);
1203 assert_eq!(v.addedAtHeight, 200);
1204 assert_eq!(v.deactivatedAtHeight, 0);
1205 assert_eq!(v.index, 0);
1206
1207 let v2 = vc.validator_by_address(validator)?;
1208 assert_eq!(v2.publicKey, pubkey);
1209
1210 let v3 = vc.validator_by_public_key(pubkey)?;
1211 assert_eq!(v3.validatorAddress, validator);
1212
1213 Ok(())
1214 })
1215 }
1216
1217 #[test]
1218 fn test_add_validator_rejects_unauthorized() -> eyre::Result<()> {
1219 let mut storage = HashMapStorageProvider::new(1);
1220 let owner = Address::random();
1221 let non_owner = Address::random();
1222 StorageCtx::enter(&mut storage, || {
1223 let mut vc = ValidatorConfigV2::new();
1224 vc.initialize(owner)?;
1225
1226 let result = vc.add_validator(
1227 non_owner,
1228 make_valid_add_call(
1229 Address::random(),
1230 "192.168.1.1:8000",
1231 "192.168.1.1",
1232 Address::random(),
1233 ),
1234 );
1235 assert_eq!(result, Err(ValidatorConfigV2Error::unauthorized().into()));
1236
1237 Ok(())
1238 })
1239 }
1240
1241 #[test]
1242 fn test_add_validator_rejects_zero_pubkey() -> eyre::Result<()> {
1243 let mut storage = HashMapStorageProvider::new(1);
1244 let owner = Address::random();
1245 StorageCtx::enter(&mut storage, || {
1246 let mut vc = ValidatorConfigV2::new();
1247 vc.initialize(owner)?;
1248
1249 let result = vc.add_validator(
1250 owner,
1251 make_add_call(
1252 Address::random(),
1253 FixedBytes::<32>::ZERO,
1254 "192.168.1.1:8000",
1255 "192.168.1.1",
1256 Address::random(),
1257 vec![0u8; 64],
1258 ),
1259 );
1260 assert_eq!(
1261 result,
1262 Err(ValidatorConfigV2Error::invalid_public_key().into())
1263 );
1264
1265 Ok(())
1266 })
1267 }
1268
1269 #[test]
1270 fn test_add_validator_rejects_duplicate_address() -> eyre::Result<()> {
1271 let mut storage = HashMapStorageProvider::new(1);
1272 let owner = Address::random();
1273 let validator = Address::random();
1274 StorageCtx::enter(&mut storage, || {
1275 let mut vc = ValidatorConfigV2::new();
1276 vc.initialize(owner)?;
1277
1278 vc.storage.set_block_number(200);
1279 vc.add_validator(
1280 owner,
1281 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
1282 )?;
1283
1284 vc.storage.set_block_number(201);
1285 let result = vc.add_validator(
1286 owner,
1287 make_valid_add_call(validator, "192.168.1.2:8000", "192.168.1.2", validator),
1288 );
1289 assert_eq!(
1290 result,
1291 Err(ValidatorConfigV2Error::address_already_has_validator().into())
1292 );
1293
1294 Ok(())
1295 })
1296 }
1297
1298 #[test]
1299 fn test_add_validator_rejects_duplicate_pubkey() -> eyre::Result<()> {
1300 let mut storage = HashMapStorageProvider::new(1);
1301 let owner = Address::random();
1302 StorageCtx::enter(&mut storage, || {
1303 let mut vc = ValidatorConfigV2::new();
1304 vc.initialize(owner)?;
1305
1306 let addr1 = Address::random();
1308 let (pubkey, sig1) = make_test_keypair_and_signature(
1309 addr1,
1310 "192.168.1.1:8000",
1311 "192.168.1.1",
1312 SignatureKind::Add {
1313 fee_recipient: addr1,
1314 },
1315 );
1316 vc.storage.set_block_number(200);
1317 vc.add_validator(
1318 owner,
1319 make_add_call(
1320 addr1,
1321 pubkey,
1322 "192.168.1.1:8000",
1323 "192.168.1.1",
1324 addr1,
1325 sig1,
1326 ),
1327 )?;
1328
1329 let addr2 = Address::random();
1331 let (_, sig2) = make_test_keypair_and_signature(
1332 addr2,
1333 "192.168.1.2:8000",
1334 "192.168.1.2",
1335 SignatureKind::Add {
1336 fee_recipient: addr2,
1337 },
1338 );
1339 vc.storage.set_block_number(201);
1340 let result = vc.add_validator(
1341 owner,
1342 make_add_call(
1343 addr2,
1344 pubkey,
1345 "192.168.1.2:8000",
1346 "192.168.1.2",
1347 addr2,
1348 sig2,
1349 ),
1350 );
1351 assert_eq!(
1352 result,
1353 Err(ValidatorConfigV2Error::public_key_already_exists().into())
1354 );
1355
1356 Ok(())
1357 })
1358 }
1359
1360 #[test]
1361 fn test_deactivate_validator() -> eyre::Result<()> {
1362 let mut storage = HashMapStorageProvider::new(1);
1363 let owner = Address::random();
1364 let validator = Address::random();
1365 StorageCtx::enter(&mut storage, || {
1366 let mut vc = ValidatorConfigV2::new();
1367 vc.initialize(owner)?;
1368
1369 vc.storage.set_block_number(200);
1370 vc.add_validator(
1371 owner,
1372 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
1373 )?;
1374
1375 vc.storage.set_block_number(300);
1376 vc.deactivate_validator(
1377 owner,
1378 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
1379 )?;
1380
1381 let v = vc.validator_by_index(0)?;
1382 assert_eq!(v.deactivatedAtHeight, 300);
1383
1384 vc.storage.set_block_number(301);
1386 let result = vc.deactivate_validator(
1387 owner,
1388 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
1389 );
1390 assert_eq!(
1391 result,
1392 Err(ValidatorConfigV2Error::validator_already_deactivated().into())
1393 );
1394
1395 Ok(())
1396 })
1397 }
1398
1399 #[test]
1400 fn test_deactivate_validator_dual_auth() -> eyre::Result<()> {
1401 let mut storage = HashMapStorageProvider::new(1);
1402 let owner = Address::random();
1403 let v1 = Address::random();
1404 let v2 = Address::random();
1405 let third_party = Address::random();
1406 StorageCtx::enter(&mut storage, || {
1407 let mut vc = ValidatorConfigV2::new();
1408 vc.initialize(owner)?;
1409
1410 vc.storage.set_block_number(200);
1411 vc.add_validator(
1412 owner,
1413 make_valid_add_call(v1, "192.168.1.1:8000", "192.168.1.1", v1),
1414 )?;
1415 vc.add_validator(
1416 owner,
1417 make_valid_add_call(v2, "192.168.1.2:8000", "192.168.1.2", v2),
1418 )?;
1419
1420 vc.storage.set_block_number(300);
1422 let result = vc.deactivate_validator(
1423 third_party,
1424 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
1425 );
1426 assert_eq!(result, Err(ValidatorConfigV2Error::unauthorized().into()));
1427
1428 vc.deactivate_validator(v1, IValidatorConfigV2::deactivateValidatorCall { idx: 0 })?;
1430 assert_eq!(vc.validator_by_index(0)?.deactivatedAtHeight, 300);
1431
1432 vc.storage.set_block_number(301);
1434 vc.deactivate_validator(
1435 owner,
1436 IValidatorConfigV2::deactivateValidatorCall { idx: 1 },
1437 )?;
1438 assert_eq!(vc.validator_by_index(1)?.deactivatedAtHeight, 301);
1439
1440 Ok(())
1441 })
1442 }
1443
1444 #[test]
1445 fn test_rotate_validator() -> eyre::Result<()> {
1446 let mut storage = HashMapStorageProvider::new(1);
1447 let owner = Address::random();
1448 let validator = Address::random();
1449 StorageCtx::enter(&mut storage, || {
1450 let mut vc = ValidatorConfigV2::new();
1451 vc.initialize(owner)?;
1452
1453 let (old_pubkey, old_sig) = make_test_keypair_and_signature(
1455 validator,
1456 "192.168.1.1:8000",
1457 "192.168.1.1",
1458 SignatureKind::Add {
1459 fee_recipient: validator,
1460 },
1461 );
1462 vc.storage.set_block_number(200);
1463 vc.add_validator(
1464 owner,
1465 make_add_call(
1466 validator,
1467 old_pubkey,
1468 "192.168.1.1:8000",
1469 "192.168.1.1",
1470 validator,
1471 old_sig,
1472 ),
1473 )?;
1474
1475 let (new_pubkey, new_sig) = make_test_keypair_and_signature(
1477 validator,
1478 "10.0.0.1:8000",
1479 "10.0.0.1",
1480 SignatureKind::Rotate,
1481 );
1482 vc.storage.set_block_number(300);
1483 vc.rotate_validator(
1484 owner,
1485 IValidatorConfigV2::rotateValidatorCall {
1486 idx: 0,
1487 publicKey: new_pubkey,
1488 ingress: "10.0.0.1:8000".to_string(),
1489 egress: "10.0.0.1".to_string(),
1490 signature: new_sig.into(),
1491 },
1492 )?;
1493
1494 assert_eq!(vc.validator_count()?, 2);
1496
1497 let updated = vc.validator_by_index(0)?;
1499 assert_eq!(updated.deactivatedAtHeight, 0);
1500 assert_eq!(updated.publicKey, new_pubkey);
1501 assert_eq!(updated.validatorAddress, validator);
1502 assert_eq!(updated.addedAtHeight, 300);
1503
1504 let snapshot = vc.validator_by_index(1)?;
1506 assert_eq!(snapshot.deactivatedAtHeight, 300);
1507 assert_eq!(snapshot.publicKey, old_pubkey);
1508
1509 let by_addr = vc.validator_by_address(validator)?;
1511 assert_eq!(by_addr.publicKey, new_pubkey);
1512
1513 let by_old_pk = vc.validator_by_public_key(old_pubkey)?;
1515 assert_eq!(by_old_pk.deactivatedAtHeight, 300);
1516
1517 Ok(())
1518 })
1519 }
1520
1521 #[test]
1522 fn test_get_active_validators() -> eyre::Result<()> {
1523 let mut storage = HashMapStorageProvider::new(1);
1524 let owner = Address::random();
1525 let v1 = Address::random();
1526 let v2 = Address::random();
1527 StorageCtx::enter(&mut storage, || {
1528 let mut vc = ValidatorConfigV2::new();
1529 vc.initialize(owner)?;
1530
1531 vc.storage.set_block_number(200);
1532 vc.add_validator(
1533 owner,
1534 make_valid_add_call(v1, "192.168.1.1:8000", "192.168.1.1", v1),
1535 )?;
1536 vc.storage.set_block_number(201);
1537 vc.add_validator(
1538 owner,
1539 make_valid_add_call(v2, "192.168.1.2:8000", "192.168.1.2", v2),
1540 )?;
1541
1542 assert_eq!(vc.get_active_validators()?.len(), 2);
1543
1544 vc.storage.set_block_number(300);
1545 vc.deactivate_validator(
1546 owner,
1547 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
1548 )?;
1549
1550 let active = vc.get_active_validators()?;
1551 assert_eq!(active.len(), 1);
1552 assert_eq!(active[0].validatorAddress, v2);
1553
1554 assert_eq!(vc.validator_count()?, 2);
1555
1556 Ok(())
1557 })
1558 }
1559
1560 #[test]
1561 fn test_set_fee_recipient() -> eyre::Result<()> {
1562 let mut storage = HashMapStorageProvider::new(1);
1563 let owner = Address::random();
1564 let validator = Address::random();
1565 StorageCtx::enter(&mut storage, || {
1566 let mut vc = ValidatorConfigV2::new();
1567 vc.initialize(owner)?;
1568
1569 vc.storage.set_block_number(200);
1570 vc.add_validator(
1571 owner,
1572 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
1573 )?;
1574
1575 let fee_recipient_1 = Address::random();
1576 vc.set_fee_recipient(
1577 owner,
1578 IValidatorConfigV2::setFeeRecipientCall {
1579 idx: 0,
1580 feeRecipient: fee_recipient_1,
1581 },
1582 )?;
1583
1584 let v = vc.validator_by_address(validator)?;
1585 assert_eq!(v.feeRecipient, fee_recipient_1);
1586
1587 let fee_recipient_2 = Address::random();
1589 vc.set_fee_recipient(
1590 validator,
1591 IValidatorConfigV2::setFeeRecipientCall {
1592 idx: 0,
1593 feeRecipient: fee_recipient_2,
1594 },
1595 )?;
1596
1597 let v = vc.validator_by_address(validator)?;
1598 assert_eq!(v.feeRecipient, fee_recipient_2);
1599
1600 Ok(())
1601 })
1602 }
1603
1604 #[test]
1605 fn test_set_ip_addresses() -> eyre::Result<()> {
1606 let mut storage = HashMapStorageProvider::new(1);
1607 let owner = Address::random();
1608 let validator = Address::random();
1609 StorageCtx::enter(&mut storage, || {
1610 let mut vc = ValidatorConfigV2::new();
1611 vc.initialize(owner)?;
1612
1613 vc.storage.set_block_number(200);
1614 vc.add_validator(
1615 owner,
1616 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
1617 )?;
1618
1619 vc.set_ip_addresses(
1620 owner,
1621 IValidatorConfigV2::setIpAddressesCall {
1622 idx: 0,
1623 ingress: "10.0.0.1:8000".to_string(),
1624 egress: "10.0.0.1".to_string(),
1625 },
1626 )?;
1627
1628 let v = vc.validator_by_address(validator)?;
1629 assert_eq!(v.ingress, "10.0.0.1:8000");
1630 assert_eq!(v.egress, "10.0.0.1");
1631
1632 vc.set_ip_addresses(
1634 validator,
1635 IValidatorConfigV2::setIpAddressesCall {
1636 idx: 0,
1637 ingress: "10.0.0.2:8000".to_string(),
1638 egress: "10.0.0.2".to_string(),
1639 },
1640 )?;
1641
1642 let v = vc.validator_by_address(validator)?;
1643 assert_eq!(v.ingress, "10.0.0.2:8000");
1644
1645 Ok(())
1646 })
1647 }
1648
1649 #[test]
1650 fn test_transfer_ownership() -> eyre::Result<()> {
1651 let mut storage = HashMapStorageProvider::new(1);
1652 let owner = Address::random();
1653 let new_owner = Address::random();
1654 let non_owner = Address::random();
1655 StorageCtx::enter(&mut storage, || {
1656 let mut vc = ValidatorConfigV2::new();
1657
1658 let result = vc.transfer_ownership(
1660 owner,
1661 IValidatorConfigV2::transferOwnershipCall {
1662 newOwner: new_owner,
1663 },
1664 );
1665 assert_eq!(
1666 result,
1667 Err(ValidatorConfigV2Error::not_initialized().into())
1668 );
1669
1670 vc.initialize(owner)?;
1671
1672 let result = vc.transfer_ownership(
1674 owner,
1675 IValidatorConfigV2::transferOwnershipCall {
1676 newOwner: Address::ZERO,
1677 },
1678 );
1679 assert_eq!(result, Err(ValidatorConfigV2Error::invalid_owner().into()));
1680 assert_eq!(vc.owner()?, owner);
1681
1682 let result = vc.transfer_ownership(
1684 non_owner,
1685 IValidatorConfigV2::transferOwnershipCall {
1686 newOwner: new_owner,
1687 },
1688 );
1689 assert_eq!(result, Err(ValidatorConfigV2Error::unauthorized().into()));
1690
1691 vc.transfer_ownership(
1693 owner,
1694 IValidatorConfigV2::transferOwnershipCall {
1695 newOwner: new_owner,
1696 },
1697 )?;
1698 assert_eq!(vc.owner()?, new_owner);
1699
1700 let result = vc.transfer_ownership(
1702 owner,
1703 IValidatorConfigV2::transferOwnershipCall {
1704 newOwner: Address::random(),
1705 },
1706 );
1707 assert_eq!(result, Err(ValidatorConfigV2Error::unauthorized().into()));
1708
1709 Ok(())
1710 })
1711 }
1712
1713 #[test]
1714 fn test_transfer_validator_ownership() -> eyre::Result<()> {
1715 let mut storage = HashMapStorageProvider::new(1);
1716 let owner = Address::random();
1717 let validator = Address::random();
1718 let new_address = Address::random();
1719 StorageCtx::enter(&mut storage, || {
1720 let mut vc = ValidatorConfigV2::new();
1721 vc.initialize(owner)?;
1722
1723 let (pubkey, sig) = make_test_keypair_and_signature(
1724 validator,
1725 "192.168.1.1:8000",
1726 "192.168.1.1",
1727 SignatureKind::Add {
1728 fee_recipient: validator,
1729 },
1730 );
1731 vc.storage.set_block_number(200);
1732 vc.add_validator(
1733 owner,
1734 make_add_call(
1735 validator,
1736 pubkey,
1737 "192.168.1.1:8000",
1738 "192.168.1.1",
1739 validator,
1740 sig,
1741 ),
1742 )?;
1743
1744 vc.transfer_validator_ownership(
1745 owner,
1746 IValidatorConfigV2::transferValidatorOwnershipCall {
1747 idx: 0,
1748 newAddress: new_address,
1749 },
1750 )?;
1751
1752 let result = vc.validator_by_address(validator);
1754 assert_eq!(
1755 result,
1756 Err(ValidatorConfigV2Error::validator_not_found().into())
1757 );
1758
1759 let v = vc.validator_by_address(new_address)?;
1761 assert_eq!(v.publicKey, pubkey);
1762 assert_eq!(v.validatorAddress, new_address);
1763
1764 Ok(())
1765 })
1766 }
1767
1768 #[test]
1769 fn test_transfer_validator_ownership_rejects_deactivated() -> eyre::Result<()> {
1770 let mut storage = HashMapStorageProvider::new(1);
1771 let owner = Address::random();
1772 let validator = Address::random();
1773 StorageCtx::enter(&mut storage, || {
1774 let mut vc = ValidatorConfigV2::new();
1775 vc.initialize(owner)?;
1776
1777 vc.storage.set_block_number(200);
1778 vc.add_validator(
1779 owner,
1780 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
1781 )?;
1782
1783 vc.storage.set_block_number(300);
1784 vc.deactivate_validator(
1785 owner,
1786 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
1787 )?;
1788
1789 let result = vc.transfer_validator_ownership(
1790 owner,
1791 IValidatorConfigV2::transferValidatorOwnershipCall {
1792 idx: 0,
1793 newAddress: Address::random(),
1794 },
1795 );
1796 assert_eq!(
1797 result,
1798 Err(ValidatorConfigV2Error::validator_already_deactivated().into())
1799 );
1800
1801 Ok(())
1802 })
1803 }
1804
1805 #[test]
1806 fn test_set_network_identity_rotation_epoch() -> eyre::Result<()> {
1807 let mut storage = HashMapStorageProvider::new(1);
1808 let owner = Address::random();
1809 StorageCtx::enter(&mut storage, || {
1810 let mut vc = ValidatorConfigV2::new();
1811 vc.initialize(owner)?;
1812
1813 assert_eq!(vc.get_next_network_identity_rotation_epoch()?, 0);
1814
1815 vc.set_network_identity_rotation_epoch(
1816 owner,
1817 IValidatorConfigV2::setNetworkIdentityRotationEpochCall { epoch: 42 },
1818 )?;
1819 assert_eq!(vc.get_next_network_identity_rotation_epoch()?, 42);
1820
1821 let non_owner = Address::random();
1822 let result = vc.set_network_identity_rotation_epoch(
1823 non_owner,
1824 IValidatorConfigV2::setNetworkIdentityRotationEpochCall { epoch: 100 },
1825 );
1826 assert_eq!(result, Err(ValidatorConfigV2Error::unauthorized().into()));
1827
1828 Ok(())
1829 })
1830 }
1831
1832 #[test]
1833 fn test_not_initialized_errors() -> eyre::Result<()> {
1834 let mut storage = HashMapStorageProvider::new(1);
1835 let owner = Address::random();
1836 StorageCtx::enter(&mut storage, || {
1837 let mut vc = ValidatorConfigV2::new();
1838
1839 let result = vc.add_validator(
1840 owner,
1841 make_valid_add_call(
1842 Address::random(),
1843 "192.168.1.1:8000",
1844 "192.168.1.1",
1845 Address::random(),
1846 ),
1847 );
1848 assert_eq!(
1849 result,
1850 Err(ValidatorConfigV2Error::not_initialized().into())
1851 );
1852
1853 Ok(())
1854 })
1855 }
1856
1857 #[test]
1858 fn test_egress_validates_ip_without_port() -> eyre::Result<()> {
1859 let mut storage = HashMapStorageProvider::new(1);
1860 let owner = Address::random();
1861 StorageCtx::enter(&mut storage, || {
1862 let mut vc = ValidatorConfigV2::new();
1863 vc.initialize(owner)?;
1864
1865 let addr1 = Address::random();
1866 let (pubkey1, sig1) = make_test_keypair_and_signature(
1867 addr1,
1868 "192.168.1.1:8000",
1869 "192.168.1.1:9000",
1870 SignatureKind::Add {
1871 fee_recipient: addr1,
1872 },
1873 );
1874
1875 let result = vc.add_validator(
1877 owner,
1878 make_add_call(
1879 addr1,
1880 pubkey1,
1881 "192.168.1.1:8000",
1882 "192.168.1.1:9000",
1883 addr1,
1884 sig1,
1885 ),
1886 );
1887 assert!(result.is_err(), "egress with port should be rejected");
1888
1889 vc.storage.set_block_number(200);
1891 let result = vc.add_validator(
1892 owner,
1893 make_valid_add_call(
1894 Address::random(),
1895 "192.168.1.1:8000",
1896 "192.168.1.1",
1897 Address::random(),
1898 ),
1899 );
1900 assert!(result.is_ok(), "egress with plain IP should succeed");
1901
1902 Ok(())
1903 })
1904 }
1905
1906 #[test]
1907 fn test_migration_from_v1() -> eyre::Result<()> {
1908 let mut storage = HashMapStorageProvider::new(1);
1909 let owner = Address::random();
1910 let v1_addr = Address::random();
1911 let v2_addr = Address::random();
1912
1913 StorageCtx::enter(&mut storage, || {
1914 let mut v1 = v1();
1916 v1.initialize(owner)?;
1917
1918 v1.add_validator(
1919 owner,
1920 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
1921 newValidatorAddress: v1_addr,
1922 publicKey: FixedBytes::<32>::from([0x11; 32]),
1923 active: true,
1924 inboundAddress: "192.168.1.1:8000".to_string(),
1925 outboundAddress: "192.168.1.1:9000".to_string(),
1926 },
1927 )?;
1928
1929 v1.add_validator(
1930 owner,
1931 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
1932 newValidatorAddress: v2_addr,
1933 publicKey: FixedBytes::<32>::from([0x22; 32]),
1934 active: false,
1935 inboundAddress: "192.168.1.2:8000".to_string(),
1936 outboundAddress: "192.168.1.2:9000".to_string(),
1937 },
1938 )?;
1939
1940 let mut v2 = ValidatorConfigV2::new();
1942
1943 v2.storage.set_block_number(100);
1945 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 1 })?;
1946
1947 assert_eq!(v2.validator_count()?, 1);
1948 let migrated = v2.validator_by_index(0)?;
1949 assert_eq!(migrated.validatorAddress, v2_addr);
1950 assert_eq!(migrated.publicKey, FixedBytes::<32>::from([0x22; 32]));
1951 assert_eq!(migrated.deactivatedAtHeight, 100);
1952
1953 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 })?;
1955
1956 assert_eq!(v2.validator_count()?, 2);
1957
1958 v2.storage.set_block_number(400);
1960 v2.initialize_if_migrated(owner)?;
1961
1962 assert!(v2.is_initialized()?);
1963
1964 v2.storage.set_block_number(100);
1966 let result =
1967 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 });
1968 assert_eq!(
1969 result,
1970 Err(ValidatorConfigV2Error::already_initialized().into())
1971 );
1972
1973 Ok(())
1974 })
1975 }
1976
1977 #[test]
1980 fn test_migration_strips_port_from_v1_outbound_address() -> eyre::Result<()> {
1981 let mut storage = HashMapStorageProvider::new(1);
1982 let owner = Address::random();
1983 let v1_addr = Address::random();
1984
1985 StorageCtx::enter(&mut storage, || {
1986 let mut v1 = v1();
1988 v1.initialize(owner)?;
1989 v1.add_validator(
1990 owner,
1991 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
1992 newValidatorAddress: v1_addr,
1993 publicKey: FixedBytes::<32>::from([0x11; 32]),
1994 active: true,
1995 inboundAddress: "192.168.1.1:8000".to_string(),
1996 outboundAddress: "192.168.1.1:9000".to_string(),
1997 },
1998 )?;
1999
2000 let mut v2 = ValidatorConfigV2::new();
2002
2003 v2.storage.set_block_number(100);
2004 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 })?;
2005 v2.storage.set_block_number(400);
2006 v2.initialize_if_migrated(owner)?;
2007
2008 let migrated = v2.validator_by_index(0)?;
2010 assert_eq!(
2011 migrated.egress, "192.168.1.1",
2012 "migration should strip port from V1 outboundAddress"
2013 );
2014
2015 assert_eq!(migrated.ingress, "192.168.1.1:8000");
2017
2018 v2.set_ip_addresses(
2020 owner,
2021 IValidatorConfigV2::setIpAddressesCall {
2022 idx: 0,
2023 ingress: "192.168.1.1:8000".to_string(),
2024 egress: migrated.egress,
2025 },
2026 )?;
2027
2028 Ok(())
2029 })
2030 }
2031
2032 #[test]
2033 fn test_migration_out_of_order_fails() -> eyre::Result<()> {
2034 let mut storage = HashMapStorageProvider::new(1);
2035 let owner = Address::random();
2036
2037 StorageCtx::enter(&mut storage, || {
2038 let mut v1 = v1();
2040 v1.initialize(owner)?;
2041
2042 v1.add_validator(
2043 owner,
2044 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2045 newValidatorAddress: Address::random(),
2046 publicKey: FixedBytes::<32>::from([0x11; 32]),
2047 active: true,
2048 inboundAddress: "192.168.1.1:8000".to_string(),
2049 outboundAddress: "192.168.1.1:9000".to_string(),
2050 },
2051 )?;
2052
2053 v1.add_validator(
2054 owner,
2055 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2056 newValidatorAddress: Address::random(),
2057 publicKey: FixedBytes::<32>::from([0x22; 32]),
2058 active: true,
2059 inboundAddress: "192.168.1.2:8000".to_string(),
2060 outboundAddress: "192.168.1.2:9000".to_string(),
2061 },
2062 )?;
2063
2064 let mut v2 = ValidatorConfigV2::new();
2066 v2.storage.set_block_number(100);
2067 let result =
2068 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 });
2069
2070 assert_eq!(
2071 result,
2072 Err(ValidatorConfigV2Error::invalid_migration_index().into())
2073 );
2074
2075 Ok(())
2076 })
2077 }
2078
2079 #[test]
2080 fn test_initialize_before_migration_complete_fails() -> eyre::Result<()> {
2081 let mut storage = HashMapStorageProvider::new(1);
2082 let owner = Address::random();
2083
2084 StorageCtx::enter(&mut storage, || {
2085 let mut v1 = v1();
2087 v1.initialize(owner)?;
2088
2089 v1.add_validator(
2090 owner,
2091 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2092 newValidatorAddress: Address::random(),
2093 publicKey: FixedBytes::<32>::from([0x11; 32]),
2094 active: true,
2095 inboundAddress: "192.168.1.1:8000".to_string(),
2096 outboundAddress: "192.168.1.1:9000".to_string(),
2097 },
2098 )?;
2099
2100 v1.add_validator(
2101 owner,
2102 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2103 newValidatorAddress: Address::random(),
2104 publicKey: FixedBytes::<32>::from([0x22; 32]),
2105 active: true,
2106 inboundAddress: "192.168.1.2:8000".to_string(),
2107 outboundAddress: "192.168.1.2:9000".to_string(),
2108 },
2109 )?;
2110
2111 let mut v2 = ValidatorConfigV2::new();
2113 v2.storage.set_block_number(100);
2114 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 1 })?;
2115
2116 v2.storage.set_block_number(400);
2118 let result = v2.initialize_if_migrated(owner);
2119
2120 assert_eq!(
2121 result,
2122 Err(ValidatorConfigV2Error::migration_not_complete().into())
2123 );
2124
2125 Ok(())
2126 })
2127 }
2128
2129 #[test]
2130 fn test_add_validator_reuses_deactivated_address() -> eyre::Result<()> {
2131 let mut storage = HashMapStorageProvider::new(1);
2132 let owner = Address::random();
2133 let validator_addr = Address::random();
2134 StorageCtx::enter(&mut storage, || {
2135 let mut vc = ValidatorConfigV2::new();
2136 vc.initialize(owner)?;
2137
2138 let (pubkey1, sig1) = make_test_keypair_and_signature(
2140 validator_addr,
2141 "192.168.1.1:8000",
2142 "192.168.1.1",
2143 SignatureKind::Add {
2144 fee_recipient: validator_addr,
2145 },
2146 );
2147 vc.storage.set_block_number(200);
2148 vc.add_validator(
2149 owner,
2150 make_add_call(
2151 validator_addr,
2152 pubkey1,
2153 "192.168.1.1:8000",
2154 "192.168.1.1",
2155 validator_addr,
2156 sig1,
2157 ),
2158 )?;
2159
2160 vc.storage.set_block_number(300);
2162 vc.deactivate_validator(
2163 owner,
2164 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
2165 )?;
2166
2167 let (pubkey2, sig2) = make_test_keypair_and_signature(
2169 validator_addr,
2170 "192.168.1.2:8000",
2171 "192.168.1.2",
2172 SignatureKind::Add {
2173 fee_recipient: validator_addr,
2174 },
2175 );
2176 vc.storage.set_block_number(400);
2177 vc.add_validator(
2178 owner,
2179 make_add_call(
2180 validator_addr,
2181 pubkey2,
2182 "192.168.1.2:8000",
2183 "192.168.1.2",
2184 validator_addr,
2185 sig2,
2186 ),
2187 )?;
2188
2189 assert_eq!(vc.validator_count()?, 2);
2191
2192 let v1 = vc.validator_by_index(0)?;
2194 assert_eq!(v1.validatorAddress, validator_addr);
2195 assert_eq!(v1.publicKey, pubkey1);
2196 assert_eq!(v1.deactivatedAtHeight, 300);
2197
2198 let v2 = vc.validator_by_index(1)?;
2200 assert_eq!(v2.validatorAddress, validator_addr);
2201 assert_eq!(v2.publicKey, pubkey2);
2202 assert_eq!(v2.deactivatedAtHeight, 0);
2203
2204 let by_addr = vc.validator_by_address(validator_addr)?;
2206 assert_eq!(by_addr.publicKey, pubkey2);
2207 assert_eq!(by_addr.deactivatedAtHeight, 0);
2208
2209 let by_old_pk = vc.validator_by_public_key(pubkey1)?;
2211 assert_eq!(by_old_pk.deactivatedAtHeight, 300);
2212
2213 let by_new_pk = vc.validator_by_public_key(pubkey2)?;
2215 assert_eq!(by_new_pk.deactivatedAtHeight, 0);
2216
2217 Ok(())
2218 })
2219 }
2220
2221 #[test]
2222 fn test_add_validator_rejects_duplicate_ingress() -> eyre::Result<()> {
2223 let mut storage = HashMapStorageProvider::new(1);
2224 let owner = Address::random();
2225 StorageCtx::enter(&mut storage, || {
2226 let mut vc = ValidatorConfigV2::new();
2227 vc.initialize(owner)?;
2228
2229 vc.storage.set_block_number(200);
2230 vc.add_validator(
2231 owner,
2232 make_valid_add_call(
2233 Address::random(),
2234 "192.168.1.1:8000",
2235 "192.168.1.1",
2236 Address::random(),
2237 ),
2238 )?;
2239
2240 vc.storage.set_block_number(201);
2241 let result = vc.add_validator(
2242 owner,
2243 make_valid_add_call(
2244 Address::random(),
2245 "192.168.1.1:8000",
2246 "192.168.2.1",
2247 Address::random(),
2248 ),
2249 );
2250
2251 assert!(result.is_err());
2252 Ok(())
2253 })
2254 }
2255
2256 #[test]
2257 fn test_ingress_reuse_after_deactivation() -> eyre::Result<()> {
2258 let mut storage = HashMapStorageProvider::new(1);
2259 let owner = Address::random();
2260 let v1 = Address::random();
2261 StorageCtx::enter(&mut storage, || {
2262 let mut vc = ValidatorConfigV2::new();
2263 vc.initialize(owner)?;
2264
2265 vc.storage.set_block_number(200);
2266 vc.add_validator(
2267 owner,
2268 make_valid_add_call(v1, "192.168.1.1:8000", "192.168.1.1", v1),
2269 )?;
2270
2271 vc.storage.set_block_number(300);
2272 vc.deactivate_validator(
2273 owner,
2274 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
2275 )?;
2276
2277 vc.storage.set_block_number(400);
2279 vc.add_validator(
2280 owner,
2281 make_valid_add_call(
2282 Address::random(),
2283 "192.168.1.1:8000",
2284 "192.168.1.1",
2285 Address::random(),
2286 ),
2287 )?;
2288
2289 Ok(())
2290 })
2291 }
2292
2293 #[test]
2294 fn test_ingress_reuse_after_rotation() -> eyre::Result<()> {
2295 let mut storage = HashMapStorageProvider::new(1);
2296 let owner = Address::random();
2297 let v1 = Address::random();
2298 StorageCtx::enter(&mut storage, || {
2299 let mut vc = ValidatorConfigV2::new();
2300 vc.initialize(owner)?;
2301
2302 vc.storage.set_block_number(200);
2303 vc.add_validator(
2304 owner,
2305 make_valid_add_call(v1, "[2001:db8::1]:8000", "2001:db8::1", Address::random()),
2306 )?;
2307
2308 vc.storage.set_block_number(300);
2309
2310 let (new_pubkey, new_sig) = make_test_keypair_and_signature(
2312 v1,
2313 "[2001:db8::1]:8001",
2314 "2001:db8::1",
2315 SignatureKind::Rotate,
2316 );
2317 vc.rotate_validator(
2318 owner,
2319 IValidatorConfigV2::rotateValidatorCall {
2320 idx: 0,
2321 publicKey: new_pubkey,
2322 ingress: "[2001:db8::1]:8001".to_string(),
2323 egress: "2001:db8::1".to_string(),
2324 signature: new_sig.into(),
2325 },
2326 )?;
2327 let v = vc.validator_by_address(v1)?;
2328 assert_eq!(v.ingress, "[2001:db8::1]:8001");
2329
2330 vc.storage.set_block_number(400);
2332 vc.set_ip_addresses(
2333 owner,
2334 IValidatorConfigV2::setIpAddressesCall {
2335 idx: 0,
2336 ingress: "[2001:db8::1]:8000".to_string(),
2337 egress: "2001:db8::1".to_string(),
2338 },
2339 )?;
2340 let v = vc.validator_by_address(v1)?;
2341 assert_eq!(v.ingress, "[2001:db8::1]:8000");
2342
2343 Ok(())
2344 })
2345 }
2346
2347 #[test]
2348 fn test_set_ip_addresses_rejects_pre_init() -> eyre::Result<()> {
2349 let mut storage = HashMapStorageProvider::new(1);
2350 let owner = Address::random();
2351 let v1_addr = Address::random();
2352
2353 StorageCtx::enter(&mut storage, || {
2354 let mut v1 = v1();
2356 v1.initialize(owner)?;
2357 v1.add_validator(
2358 owner,
2359 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2360 newValidatorAddress: v1_addr,
2361 publicKey: FixedBytes::<32>::from([0x11; 32]),
2362 active: true,
2363 inboundAddress: "192.168.1.1:8000".to_string(),
2364 outboundAddress: "192.168.1.1:9000".to_string(),
2365 },
2366 )?;
2367
2368 let mut v2 = ValidatorConfigV2::new();
2370 v2.storage.set_block_number(100);
2371 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 })?;
2372
2373 let result = v2.set_ip_addresses(
2374 owner,
2375 IValidatorConfigV2::setIpAddressesCall {
2376 idx: 0,
2377 ingress: "10.0.0.1:8000".to_string(),
2378 egress: "10.0.0.1".to_string(),
2379 },
2380 );
2381
2382 assert_eq!(
2383 result,
2384 Err(ValidatorConfigV2Error::not_initialized().into())
2385 );
2386 Ok(())
2387 })
2388 }
2389
2390 #[test]
2391 fn test_rotate_removes_and_checks_ips() -> eyre::Result<()> {
2392 let mut storage = HashMapStorageProvider::new(1);
2393 let owner = Address::random();
2394 let v1 = Address::random();
2395 let v2 = Address::random();
2396
2397 StorageCtx::enter(&mut storage, || {
2398 let mut vc = ValidatorConfigV2::new();
2399 vc.initialize(owner)?;
2400
2401 vc.storage.set_block_number(200);
2402 vc.add_validator(
2403 owner,
2404 make_valid_add_call(v1, "192.168.1.1:8000", "192.168.1.1", v1),
2405 )?;
2406 vc.add_validator(
2407 owner,
2408 make_valid_add_call(v2, "192.168.2.1:8000", "192.168.2.1", v2),
2409 )?;
2410
2411 let (new_pk, sig) = make_test_keypair_and_signature(
2413 v1,
2414 "192.168.2.1:8000",
2415 "192.168.2.1",
2416 SignatureKind::Rotate,
2417 );
2418
2419 vc.storage.set_block_number(300);
2420 let result = vc.rotate_validator(
2421 owner,
2422 IValidatorConfigV2::rotateValidatorCall {
2423 idx: 0,
2424 publicKey: new_pk,
2425 ingress: "192.168.2.1:8000".to_string(),
2426 egress: "192.168.2.1".to_string(),
2427 signature: sig.into(),
2428 },
2429 );
2430
2431 assert!(result.is_err());
2432 Ok(())
2433 })
2434 }
2435
2436 #[test]
2437 fn test_migrate_skips_duplicate_ingress() -> eyre::Result<()> {
2438 let mut storage = HashMapStorageProvider::new(1);
2439 let owner = Address::random();
2440
2441 StorageCtx::enter(&mut storage, || {
2442 let mut v1 = v1();
2443 v1.initialize(owner)?;
2444 v1.add_validator(
2445 owner,
2446 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2447 newValidatorAddress: Address::random(),
2448 publicKey: FixedBytes::<32>::from([0x11; 32]),
2449 active: true,
2450 inboundAddress: "192.168.1.1:8000".to_string(),
2451 outboundAddress: "192.168.1.1:9000".to_string(),
2452 },
2453 )?;
2454 v1.add_validator(
2455 owner,
2456 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2457 newValidatorAddress: Address::random(),
2458 publicKey: FixedBytes::<32>::from([0x22; 32]),
2459 active: true,
2460 inboundAddress: "192.168.1.1:8000".to_string(),
2461 outboundAddress: "192.168.2.1:9000".to_string(),
2462 },
2463 )?;
2464
2465 let mut v2 = ValidatorConfigV2::new();
2466 v2.storage.set_block_number(100);
2467 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 1 })?;
2468
2469 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 })?;
2470 assert_eq!(v2.validator_count()?, 1);
2471 assert_eq!(v2.config.migration_skipped_count.read()?, 1);
2472
2473 v2.storage.set_block_number(400);
2474 v2.initialize_if_migrated(owner)?;
2475 assert!(v2.is_initialized()?);
2476
2477 Ok(())
2478 })
2479 }
2480
2481 #[test]
2482 fn test_migrate_skips_invalid_ed25519_pubkey() -> eyre::Result<()> {
2483 let mut storage = HashMapStorageProvider::new(1);
2484 let owner = Address::random();
2485
2486 StorageCtx::enter(&mut storage, || {
2487 let mut v1 = v1();
2488 v1.initialize(owner)?;
2489 v1.add_validator(
2490 owner,
2491 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2492 newValidatorAddress: Address::random(),
2493 publicKey: FixedBytes::<32>::from([0xDD; 32]),
2494 active: true,
2495 inboundAddress: "192.168.1.1:8000".to_string(),
2496 outboundAddress: "192.168.1.1:9000".to_string(),
2497 },
2498 )?;
2499 v1.add_validator(
2500 owner,
2501 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2502 newValidatorAddress: Address::random(),
2503 publicKey: FixedBytes::<32>::from([0x22; 32]),
2504 active: true,
2505 inboundAddress: "192.168.1.2:8000".to_string(),
2506 outboundAddress: "192.168.1.2:9000".to_string(),
2507 },
2508 )?;
2509
2510 let mut v2 = ValidatorConfigV2::new();
2511 v2.storage.set_block_number(100);
2512
2513 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 1 })?;
2514 assert_eq!(v2.validator_count()?, 1);
2515
2516 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 })?;
2517 assert_eq!(v2.validator_count()?, 1);
2518 assert_eq!(v2.config.migration_skipped_count.read()?, 1);
2519
2520 v2.storage.set_block_number(400);
2521 v2.initialize_if_migrated(owner)?;
2522 assert!(v2.is_initialized()?);
2523
2524 Ok(())
2525 })
2526 }
2527
2528 #[test]
2529 fn test_migrate_overwrites_duplicate_pubkey() -> eyre::Result<()> {
2530 let mut storage = HashMapStorageProvider::new(1);
2531 let owner = Address::random();
2532 let addr1 = Address::random();
2533 let addr2 = Address::random();
2534
2535 StorageCtx::enter(&mut storage, || {
2536 let mut v1 = v1();
2537 v1.initialize(owner)?;
2538 v1.add_validator(
2539 owner,
2540 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2541 newValidatorAddress: addr1,
2542 publicKey: FixedBytes::<32>::from([0x11; 32]),
2543 active: true,
2544 inboundAddress: "192.168.1.1:8000".to_string(),
2545 outboundAddress: "192.168.1.1:9000".to_string(),
2546 },
2547 )?;
2548 v1.add_validator(
2549 owner,
2550 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2551 newValidatorAddress: addr2,
2552 publicKey: FixedBytes::<32>::from([0x11; 32]),
2553 active: true,
2554 inboundAddress: "192.168.1.2:8000".to_string(),
2555 outboundAddress: "192.168.1.2:9000".to_string(),
2556 },
2557 )?;
2558
2559 let mut v2 = ValidatorConfigV2::new();
2560 v2.storage.set_block_number(100);
2561
2562 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 1 })?;
2563 assert_eq!(v2.validator_count()?, 1);
2564
2565 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 })?;
2566 assert_eq!(v2.validator_count()?, 1);
2567 assert_eq!(v2.config.migration_skipped_count.read()?, 1);
2568
2569 let migrated = v2.validator_by_index(0)?;
2570 assert_eq!(migrated.validatorAddress, addr2);
2571 assert_eq!(migrated.ingress, "192.168.1.2:8000");
2572 assert_eq!(migrated.egress, "192.168.1.2");
2573
2574 v2.storage.set_block_number(400);
2575 v2.initialize_if_migrated(owner)?;
2576 assert!(v2.is_initialized()?);
2577
2578 Ok(())
2579 })
2580 }
2581
2582 #[test]
2583 fn test_add_validator_rejects_third_party() -> eyre::Result<()> {
2584 let mut storage = HashMapStorageProvider::new(1);
2585 let owner = Address::random();
2586 let validator = Address::random();
2587 let third_party = Address::random();
2588 StorageCtx::enter(&mut storage, || {
2589 let mut vc = ValidatorConfigV2::new();
2590 vc.initialize(owner)?;
2591
2592 vc.storage.set_block_number(200);
2593 vc.add_validator(
2594 owner,
2595 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
2596 )?;
2597
2598 let result = vc.set_ip_addresses(
2600 third_party,
2601 IValidatorConfigV2::setIpAddressesCall {
2602 idx: 0,
2603 ingress: "10.0.0.1:8000".to_string(),
2604 egress: "10.0.0.1".to_string(),
2605 },
2606 );
2607 assert_eq!(result, Err(ValidatorConfigV2Error::unauthorized().into()));
2608
2609 let result = vc.transfer_validator_ownership(
2610 third_party,
2611 IValidatorConfigV2::transferValidatorOwnershipCall {
2612 idx: 0,
2613 newAddress: Address::random(),
2614 },
2615 );
2616 assert_eq!(result, Err(ValidatorConfigV2Error::unauthorized().into()));
2617
2618 Ok(())
2619 })
2620 }
2621
2622 #[test]
2623 fn test_rotate_validator_to_different_ingress() -> eyre::Result<()> {
2624 let mut storage = HashMapStorageProvider::new(1);
2625 let owner = Address::random();
2626 let validator = Address::random();
2627 StorageCtx::enter(&mut storage, || {
2628 let mut vc = ValidatorConfigV2::new();
2629 vc.initialize(owner)?;
2630
2631 vc.storage.set_block_number(200);
2632 vc.add_validator(
2633 owner,
2634 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
2635 )?;
2636
2637 let (new_pubkey, new_sig) = make_test_keypair_and_signature(
2639 validator,
2640 "192.168.1.1:8001",
2641 "192.168.1.1",
2642 SignatureKind::Rotate,
2643 );
2644 vc.storage.set_block_number(300);
2645 vc.rotate_validator(
2646 owner,
2647 IValidatorConfigV2::rotateValidatorCall {
2648 idx: 0,
2649 publicKey: new_pubkey,
2650 ingress: "192.168.1.1:8001".to_string(),
2651 egress: "192.168.1.1".to_string(),
2652 signature: new_sig.into(),
2653 },
2654 )?;
2655
2656 assert_eq!(vc.validator_count()?, 2);
2657 assert_eq!(vc.validator_by_index(0)?.deactivatedAtHeight, 0);
2658 assert_eq!(vc.validator_by_index(1)?.deactivatedAtHeight, 300);
2659 assert_eq!(vc.validator_by_address(validator)?.publicKey, new_pubkey);
2660 assert_eq!(
2661 vc.validator_by_address(validator)?.ingress,
2662 "192.168.1.1:8001"
2663 );
2664 assert_eq!(vc.validator_by_address(validator)?.egress, "192.168.1.1");
2665
2666 Ok(())
2667 })
2668 }
2669
2670 #[test]
2671 fn test_rotate_validator_rejects_same_ingress() -> eyre::Result<()> {
2672 let mut storage = HashMapStorageProvider::new(1);
2673 let owner = Address::random();
2674 let validator = Address::random();
2675 StorageCtx::enter(&mut storage, || {
2676 let mut vc = ValidatorConfigV2::new();
2677 vc.initialize(owner)?;
2678
2679 vc.storage.set_block_number(200);
2680 vc.add_validator(
2681 owner,
2682 make_valid_add_call(
2683 validator,
2684 "192.168.1.1:8000",
2685 "192.168.1.1",
2686 Address::random(),
2687 ),
2688 )?;
2689
2690 let (new_pubkey, new_sig) = make_test_keypair_and_signature(
2692 validator,
2693 "192.168.1.1:8000",
2694 "192.168.1.1",
2695 SignatureKind::Rotate,
2696 );
2697 vc.storage.set_block_number(300);
2698 assert!(
2699 vc.rotate_validator(
2700 owner,
2701 IValidatorConfigV2::rotateValidatorCall {
2702 idx: 0,
2703 publicKey: new_pubkey,
2704 ingress: "192.168.1.1:8000".to_string(),
2705 egress: "192.168.1.1".to_string(),
2706 signature: new_sig.into(),
2707 },
2708 )
2709 .is_err()
2710 );
2711 Ok(())
2712 })
2713 }
2714
2715 #[test]
2716 fn test_set_ip_addresses_ingress_only() -> eyre::Result<()> {
2717 let mut storage = HashMapStorageProvider::new(1);
2718 let owner = Address::random();
2719 let validator = Address::random();
2720 StorageCtx::enter(&mut storage, || {
2721 let mut vc = ValidatorConfigV2::new();
2722 vc.initialize(owner)?;
2723
2724 vc.storage.set_block_number(200);
2725 vc.add_validator(
2726 owner,
2727 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
2728 )?;
2729
2730 vc.set_ip_addresses(
2732 owner,
2733 IValidatorConfigV2::setIpAddressesCall {
2734 idx: 0,
2735 ingress: "10.0.0.1:8000".to_string(),
2736 egress: "192.168.1.1".to_string(),
2737 },
2738 )?;
2739
2740 let v = vc.validator_by_address(validator)?;
2741 assert_eq!(v.ingress, "10.0.0.1:8000");
2742 assert_eq!(v.egress, "192.168.1.1");
2743
2744 Ok(())
2745 })
2746 }
2747
2748 #[test]
2749 fn test_set_ip_addresses_ingress_port_only() -> eyre::Result<()> {
2750 let mut storage = HashMapStorageProvider::new(1);
2751 let owner = Address::random();
2752 let validator = Address::random();
2753 StorageCtx::enter(&mut storage, || {
2754 let mut vc = ValidatorConfigV2::new();
2755 vc.initialize(owner)?;
2756
2757 vc.storage.set_block_number(200);
2758 vc.add_validator(
2759 owner,
2760 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
2761 )?;
2762
2763 vc.set_ip_addresses(
2765 owner,
2766 IValidatorConfigV2::setIpAddressesCall {
2767 idx: 0,
2768 ingress: "192.168.1.1:8001".to_string(),
2769 egress: "192.168.1.1".to_string(),
2770 },
2771 )?;
2772
2773 let v = vc.validator_by_address(validator)?;
2774 assert_eq!(v.ingress, "192.168.1.1:8001");
2775 assert_eq!(v.egress, "192.168.1.1");
2776
2777 Ok(())
2778 })
2779 }
2780
2781 #[test]
2782 fn test_set_ip_addresses_egress_only() -> eyre::Result<()> {
2783 let mut storage = HashMapStorageProvider::new(1);
2784 let owner = Address::random();
2785 let validator = Address::random();
2786 StorageCtx::enter(&mut storage, || {
2787 let mut vc = ValidatorConfigV2::new();
2788 vc.initialize(owner)?;
2789
2790 vc.storage.set_block_number(200);
2791 vc.add_validator(
2792 owner,
2793 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
2794 )?;
2795
2796 vc.set_ip_addresses(
2798 owner,
2799 IValidatorConfigV2::setIpAddressesCall {
2800 idx: 0,
2801 ingress: "192.168.1.1:8000".to_string(),
2802 egress: "10.0.0.1".to_string(),
2803 },
2804 )?;
2805
2806 let v = vc.validator_by_address(validator)?;
2807 assert_eq!(v.ingress, "192.168.1.1:8000");
2808 assert_eq!(v.egress, "10.0.0.1");
2809
2810 Ok(())
2811 })
2812 }
2813
2814 #[test]
2815 fn test_set_ip_addresses_rejects_duplicate_ingress() -> eyre::Result<()> {
2816 let mut storage = HashMapStorageProvider::new(1);
2817 let owner = Address::random();
2818 let v1 = Address::random();
2819 let v2 = Address::random();
2820 StorageCtx::enter(&mut storage, || {
2821 let mut vc = ValidatorConfigV2::new();
2822 vc.initialize(owner)?;
2823
2824 vc.storage.set_block_number(200);
2825 vc.add_validator(
2826 owner,
2827 make_valid_add_call(v1, "192.168.1.1:8000", "192.168.1.1", v1),
2828 )?;
2829 vc.add_validator(
2830 owner,
2831 make_valid_add_call(v2, "192.168.2.1:8000", "192.168.2.1", v2),
2832 )?;
2833
2834 let result = vc.set_ip_addresses(
2835 owner,
2836 IValidatorConfigV2::setIpAddressesCall {
2837 idx: 1,
2838 ingress: "192.168.1.1:8000".to_string(),
2839 egress: "192.168.2.1".to_string(),
2840 },
2841 );
2842
2843 assert!(result.is_err());
2844 Ok(())
2845 })
2846 }
2847
2848 #[test]
2849 fn test_set_ip_addresses_allows_same_ip_different_port() -> eyre::Result<()> {
2850 let mut storage = HashMapStorageProvider::new(1);
2851 let owner = Address::random();
2852 let validator = Address::random();
2853 StorageCtx::enter(&mut storage, || {
2854 let mut vc = ValidatorConfigV2::new();
2855 vc.initialize(owner)?;
2856
2857 vc.storage.set_block_number(200);
2858 vc.add_validator(
2859 owner,
2860 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
2861 )?;
2862
2863 vc.set_ip_addresses(
2864 owner,
2865 IValidatorConfigV2::setIpAddressesCall {
2866 idx: 0,
2867 ingress: "192.168.1.1:9000".to_string(),
2868 egress: "192.168.1.1".to_string(),
2869 },
2870 )?;
2871
2872 let v = vc.validator_by_address(validator)?;
2873 assert_eq!(v.ingress, "192.168.1.1:9000");
2874
2875 Ok(())
2876 })
2877 }
2878
2879 #[test]
2880 fn test_transfer_validator_ownership_by_validator() -> eyre::Result<()> {
2881 let mut storage = HashMapStorageProvider::new(1);
2882 let owner = Address::random();
2883 let validator = Address::random();
2884 let new_address = Address::random();
2885 StorageCtx::enter(&mut storage, || {
2886 let mut vc = ValidatorConfigV2::new();
2887 vc.initialize(owner)?;
2888
2889 vc.storage.set_block_number(200);
2890 vc.add_validator(
2891 owner,
2892 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
2893 )?;
2894
2895 vc.transfer_validator_ownership(
2897 validator,
2898 IValidatorConfigV2::transferValidatorOwnershipCall {
2899 idx: 0,
2900 newAddress: new_address,
2901 },
2902 )?;
2903
2904 let result = vc.validator_by_address(validator);
2905 assert_eq!(
2906 result,
2907 Err(ValidatorConfigV2Error::validator_not_found().into())
2908 );
2909
2910 let v = vc.validator_by_address(new_address)?;
2911 assert_eq!(v.validatorAddress, new_address);
2912
2913 Ok(())
2914 })
2915 }
2916
2917 #[test]
2918 fn test_add_validator_rejects_deleted_pubkey() -> eyre::Result<()> {
2919 let mut storage = HashMapStorageProvider::new(1);
2920 let owner = Address::random();
2921 StorageCtx::enter(&mut storage, || {
2922 let mut vc = ValidatorConfigV2::new();
2923 vc.initialize(owner)?;
2924
2925 let addr1 = Address::random();
2926 let (pubkey, sig) = make_test_keypair_and_signature(
2927 addr1,
2928 "192.168.1.1:8000",
2929 "192.168.1.1",
2930 SignatureKind::Add {
2931 fee_recipient: addr1,
2932 },
2933 );
2934 vc.storage.set_block_number(200);
2935 vc.add_validator(
2936 owner,
2937 make_add_call(addr1, pubkey, "192.168.1.1:8000", "192.168.1.1", addr1, sig),
2938 )?;
2939
2940 vc.storage.set_block_number(300);
2942 vc.deactivate_validator(
2943 owner,
2944 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
2945 )?;
2946
2947 let addr2 = Address::random();
2949 let result = vc.add_validator(
2950 owner,
2951 make_add_call(
2952 addr2,
2953 pubkey,
2954 "192.168.2.1:8000",
2955 "192.168.2.1",
2956 addr2,
2957 vec![0u8; 64],
2958 ),
2959 );
2960 assert_eq!(
2961 result,
2962 Err(ValidatorConfigV2Error::public_key_already_exists().into())
2963 );
2964
2965 Ok(())
2966 })
2967 }
2968
2969 #[test]
2970 fn test_add_validator_with_ipv6() -> eyre::Result<()> {
2971 let mut storage = HashMapStorageProvider::new(1);
2972 let owner = Address::random();
2973 let validator = Address::random();
2974 StorageCtx::enter(&mut storage, || {
2975 let mut vc = ValidatorConfigV2::new();
2976 vc.initialize(owner)?;
2977
2978 vc.storage.set_block_number(200);
2980 vc.add_validator(
2981 owner,
2982 make_valid_add_call(validator, "[::1]:8000", "::1", validator),
2983 )?;
2984
2985 assert_eq!(vc.validator_count()?, 1);
2986 let v = vc.validator_by_index(0)?;
2987 assert_eq!(v.validatorAddress, validator);
2988 assert_eq!(v.ingress, "[::1]:8000");
2989 assert_eq!(v.egress, "::1");
2990
2991 Ok(())
2992 })
2993 }
2994
2995 #[test]
2996 fn test_add_validator_rejects_duplicate_ingress_ipv6() -> eyre::Result<()> {
2997 let mut storage = HashMapStorageProvider::new(1);
2998 let owner = Address::random();
2999 StorageCtx::enter(&mut storage, || {
3000 let mut vc = ValidatorConfigV2::new();
3001 vc.initialize(owner)?;
3002
3003 vc.storage.set_block_number(200);
3004 vc.add_validator(
3005 owner,
3006 make_valid_add_call(
3007 Address::random(),
3008 "[2001:db8::1]:8000",
3009 "2001:db8::1",
3010 Address::random(),
3011 ),
3012 )?;
3013
3014 vc.storage.set_block_number(201);
3016 let result = vc.add_validator(
3017 owner,
3018 make_valid_add_call(
3019 Address::random(),
3020 "[2001:db8::1]:8000",
3021 "2001:db8::2",
3022 Address::random(),
3023 ),
3024 );
3025
3026 assert!(result.is_err());
3027 Ok(())
3028 })
3029 }
3030
3031 #[test]
3032 fn test_ipv6_reuse_after_deactivation() -> eyre::Result<()> {
3033 let mut storage = HashMapStorageProvider::new(1);
3034 let owner = Address::random();
3035 let v1 = Address::random();
3036 StorageCtx::enter(&mut storage, || {
3037 let mut vc = ValidatorConfigV2::new();
3038 vc.initialize(owner)?;
3039
3040 vc.storage.set_block_number(200);
3041 vc.add_validator(
3042 owner,
3043 make_valid_add_call(v1, "[2001:db8::1]:8000", "2001:db8::1", v1),
3044 )?;
3045
3046 vc.storage.set_block_number(300);
3047 vc.deactivate_validator(
3048 owner,
3049 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
3050 )?;
3051
3052 vc.storage.set_block_number(400);
3054 vc.add_validator(
3055 owner,
3056 make_valid_add_call(
3057 Address::random(),
3058 "[2001:db8::1]:8000",
3059 "2001:db8::1",
3060 Address::random(),
3061 ),
3062 )?;
3063
3064 Ok(())
3065 })
3066 }
3067
3068 #[test]
3069 fn test_rotate_validator_with_ipv6() -> eyre::Result<()> {
3070 let mut storage = HashMapStorageProvider::new(1);
3071 let owner = Address::random();
3072 let validator = Address::random();
3073 StorageCtx::enter(&mut storage, || {
3074 let mut vc = ValidatorConfigV2::new();
3075 vc.initialize(owner)?;
3076
3077 vc.storage.set_block_number(200);
3079 vc.add_validator(
3080 owner,
3081 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
3082 )?;
3083
3084 let (new_pubkey, new_sig) = make_test_keypair_and_signature(
3086 validator,
3087 "[2001:db8::1]:8000",
3088 "2001:db8::1",
3089 SignatureKind::Rotate,
3090 );
3091 vc.storage.set_block_number(300);
3092 vc.rotate_validator(
3093 owner,
3094 IValidatorConfigV2::rotateValidatorCall {
3095 idx: 0,
3096 publicKey: new_pubkey,
3097 ingress: "[2001:db8::1]:8000".to_string(),
3098 egress: "2001:db8::1".to_string(),
3099 signature: new_sig.into(),
3100 },
3101 )?;
3102
3103 assert_eq!(vc.validator_count()?, 2);
3104 let updated = vc.validator_by_index(0)?;
3105 assert_eq!(updated.deactivatedAtHeight, 0);
3106 assert_eq!(updated.ingress, "[2001:db8::1]:8000");
3107 assert_eq!(updated.egress, "2001:db8::1");
3108
3109 let snapshot = vc.validator_by_index(1)?;
3110 assert_eq!(snapshot.deactivatedAtHeight, 300);
3111
3112 Ok(())
3113 })
3114 }
3115
3116 #[test]
3117 fn test_ipv6_canonical_representation() -> eyre::Result<()> {
3118 let mut storage = HashMapStorageProvider::new(1);
3119 let owner = Address::random();
3120 StorageCtx::enter(&mut storage, || {
3121 let mut vc = ValidatorConfigV2::new();
3122 vc.initialize(owner)?;
3123
3124 vc.storage.set_block_number(200);
3126 vc.add_validator(
3127 owner,
3128 make_valid_add_call(Address::random(), "[::1]:8000", "::1", Address::random()),
3129 )?;
3130
3131 vc.storage.set_block_number(201);
3134 let result = vc.add_validator(
3135 owner,
3136 make_valid_add_call(
3137 Address::random(),
3138 "[0:0:0:0:0:0:0:1]:8000",
3139 "::1",
3140 Address::random(),
3141 ),
3142 );
3143
3144 assert!(
3145 result.is_err(),
3146 "Different IPv6 notations of same IP should be rejected"
3147 );
3148
3149 vc.storage.set_block_number(202);
3151 let result = vc.add_validator(
3152 owner,
3153 make_valid_add_call(Address::random(), "[::1%0]:8000", "::1", Address::random()),
3154 );
3155
3156 assert!(
3157 result.is_err(),
3158 "Different IPv6 notations of same IP should be rejected"
3159 );
3160
3161 vc.storage.set_block_number(203);
3163 let result = vc.add_validator(
3164 owner,
3165 make_valid_add_call(Address::random(), "[::1%1]:8000", "::1", Address::random()),
3166 );
3167 assert!(result.is_ok());
3168
3169 Ok(())
3170 })
3171 }
3172
3173 #[test]
3174 fn test_add_validator_rejects_wrong_key_signature() -> eyre::Result<()> {
3175 let mut storage = HashMapStorageProvider::new(1);
3176 let owner = Address::random();
3177 let validator = Address::random();
3178 let fee_recipient = Address::random();
3179 StorageCtx::enter(&mut storage, || {
3180 let mut vc = ValidatorConfigV2::new();
3181 vc.initialize(owner)?;
3182
3183 let (pubkey, _) = make_test_keypair_and_signature(
3185 validator,
3186 "192.168.1.1:8000",
3187 "192.168.1.1",
3188 SignatureKind::Add { fee_recipient },
3189 );
3190
3191 let (_, wrong_sig) = make_test_keypair_and_signature(
3193 validator,
3194 "192.168.1.1:8000",
3195 "192.168.1.1",
3196 SignatureKind::Add { fee_recipient },
3197 );
3198
3199 vc.storage.set_block_number(200);
3200 let result = vc.add_validator(
3201 owner,
3202 make_add_call(
3203 validator,
3204 pubkey,
3205 "192.168.1.1:8000",
3206 "192.168.1.1",
3207 fee_recipient,
3208 wrong_sig,
3209 ),
3210 );
3211 assert_eq!(
3212 result,
3213 Err(ValidatorConfigV2Error::invalid_signature().into())
3214 );
3215
3216 Ok(())
3217 })
3218 }
3219
3220 #[test]
3221 fn test_add_validator_rejects_wrong_namespace_signature() -> eyre::Result<()> {
3222 let mut storage = HashMapStorageProvider::new(1);
3223 let owner = Address::random();
3224 let validator = Address::random();
3225 let fee_recipient = Address::random();
3226 StorageCtx::enter(&mut storage, || {
3227 let mut vc = ValidatorConfigV2::new();
3228 vc.initialize(owner)?;
3229
3230 let (pubkey, sig) = make_test_keypair_and_signature(
3232 validator,
3233 "192.168.1.1:8000",
3234 "192.168.1.1",
3235 SignatureKind::Rotate,
3236 );
3237
3238 vc.storage.set_block_number(200);
3239 let result = vc.add_validator(
3240 owner,
3241 make_add_call(
3242 validator,
3243 pubkey,
3244 "192.168.1.1:8000",
3245 "192.168.1.1",
3246 fee_recipient,
3247 sig,
3248 ),
3249 );
3250 assert_eq!(
3251 result,
3252 Err(ValidatorConfigV2Error::invalid_signature().into())
3253 );
3254
3255 Ok(())
3256 })
3257 }
3258
3259 #[test]
3260 fn test_rotate_validator_rejects_wrong_key_signature() -> eyre::Result<()> {
3261 let mut storage = HashMapStorageProvider::new(1);
3262 let owner = Address::random();
3263 let validator = Address::random();
3264 let fee_recipient = Address::random();
3265 StorageCtx::enter(&mut storage, || {
3266 let mut vc = ValidatorConfigV2::new();
3267 vc.initialize(owner)?;
3268
3269 vc.storage.set_block_number(200);
3271 vc.add_validator(
3272 owner,
3273 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", fee_recipient),
3274 )?;
3275
3276 let (new_pubkey, _) = make_test_keypair_and_signature(
3278 validator,
3279 "10.0.0.1:8000",
3280 "10.0.0.1",
3281 SignatureKind::Rotate,
3282 );
3283
3284 let (_, wrong_sig) = make_test_keypair_and_signature(
3286 validator,
3287 "10.0.0.1:8000",
3288 "10.0.0.1",
3289 SignatureKind::Rotate,
3290 );
3291
3292 vc.storage.set_block_number(300);
3293 let result = vc.rotate_validator(
3294 owner,
3295 IValidatorConfigV2::rotateValidatorCall {
3296 idx: 0,
3297 publicKey: new_pubkey,
3298 ingress: "10.0.0.1:8000".to_string(),
3299 egress: "10.0.0.1".to_string(),
3300 signature: wrong_sig.into(),
3301 },
3302 );
3303 assert_eq!(
3304 result,
3305 Err(ValidatorConfigV2Error::invalid_signature().into())
3306 );
3307
3308 Ok(())
3309 })
3310 }
3311
3312 #[test]
3313 fn test_add_validator_rejects_malformed_signature() -> eyre::Result<()> {
3314 let mut storage = HashMapStorageProvider::new(1);
3315 let owner = Address::random();
3316 let validator = Address::random();
3317 let fee_recipient = Address::random();
3318 StorageCtx::enter(&mut storage, || {
3319 let mut vc = ValidatorConfigV2::new();
3320 vc.initialize(owner)?;
3321
3322 let (pubkey, _) = make_test_keypair_and_signature(
3323 validator,
3324 "192.168.1.1:8000",
3325 "192.168.1.1",
3326 SignatureKind::Add { fee_recipient },
3327 );
3328
3329 vc.storage.set_block_number(200);
3330 let result = vc.add_validator(
3331 owner,
3332 make_add_call(
3333 validator,
3334 pubkey,
3335 "192.168.1.1:8000",
3336 "192.168.1.1",
3337 fee_recipient,
3338 vec![0xde, 0xad],
3339 ),
3340 );
3341 assert_eq!(
3342 result,
3343 Err(ValidatorConfigV2Error::invalid_signature_format().into())
3344 );
3345
3346 Ok(())
3347 })
3348 }
3349
3350 #[test]
3351 fn test_ipv4_ipv6_different_ips() -> eyre::Result<()> {
3352 let mut storage = HashMapStorageProvider::new(1);
3353 let owner = Address::random();
3354 StorageCtx::enter(&mut storage, || {
3355 let mut vc = ValidatorConfigV2::new();
3356 vc.initialize(owner)?;
3357
3358 vc.storage.set_block_number(200);
3360 vc.add_validator(
3361 owner,
3362 make_valid_add_call(
3363 Address::random(),
3364 "192.168.1.1:8000",
3365 "192.168.1.1",
3366 Address::random(),
3367 ),
3368 )?;
3369
3370 vc.storage.set_block_number(201);
3372 vc.add_validator(
3373 owner,
3374 make_valid_add_call(
3375 Address::random(),
3376 "[2001:db8::1]:8000",
3377 "2001:db8::1",
3378 Address::random(),
3379 ),
3380 )?;
3381
3382 assert_eq!(vc.validator_count()?, 2);
3383 Ok(())
3384 })
3385 }
3386
3387 #[test]
3388 fn test_event_emission_owner_and_validator_actions() -> eyre::Result<()> {
3389 let mut storage = HashMapStorageProvider::new(1);
3390 let owner = Address::random();
3391 let validator = Address::random();
3392 let new_validator_address = Address::random();
3393
3394 StorageCtx::enter(&mut storage, || {
3395 let mut vc = ValidatorConfigV2::new();
3396 vc.initialize(owner)?;
3397
3398 let (pubkey, signature) = make_test_keypair_and_signature(
3399 validator,
3400 "192.168.1.1:8000",
3401 "192.168.1.1",
3402 SignatureKind::Add {
3403 fee_recipient: validator,
3404 },
3405 );
3406
3407 vc.storage.set_block_number(100);
3408 vc.add_validator(
3409 owner,
3410 make_add_call(
3411 validator,
3412 pubkey,
3413 "192.168.1.1:8000",
3414 "192.168.1.1",
3415 validator,
3416 signature,
3417 ),
3418 )?;
3419 vc.assert_emitted_events(vec![ValidatorConfigV2Event::ValidatorAdded(
3420 IValidatorConfigV2::ValidatorAdded {
3421 index: 0,
3422 validatorAddress: validator,
3423 publicKey: pubkey,
3424 ingress: "192.168.1.1:8000".to_string(),
3425 egress: "192.168.1.1".to_string(),
3426 feeRecipient: validator,
3427 },
3428 )]);
3429
3430 vc.clear_emitted_events();
3431 vc.set_ip_addresses(
3432 validator,
3433 IValidatorConfigV2::setIpAddressesCall {
3434 idx: 0,
3435 ingress: "10.0.0.1:8000".to_string(),
3436 egress: "10.0.0.1".to_string(),
3437 },
3438 )?;
3439 vc.assert_emitted_events(vec![ValidatorConfigV2Event::IpAddressesUpdated(
3440 IValidatorConfigV2::IpAddressesUpdated {
3441 index: 0,
3442 ingress: "10.0.0.1:8000".to_string(),
3443 egress: "10.0.0.1".to_string(),
3444 caller: validator,
3445 },
3446 )]);
3447
3448 vc.clear_emitted_events();
3449 vc.transfer_validator_ownership(
3450 owner,
3451 IValidatorConfigV2::transferValidatorOwnershipCall {
3452 idx: 0,
3453 newAddress: new_validator_address,
3454 },
3455 )?;
3456 vc.assert_emitted_events(vec![ValidatorConfigV2Event::ValidatorOwnershipTransferred(
3457 IValidatorConfigV2::ValidatorOwnershipTransferred {
3458 index: 0,
3459 oldAddress: validator,
3460 newAddress: new_validator_address,
3461 caller: owner,
3462 },
3463 )]);
3464
3465 vc.clear_emitted_events();
3466 vc.deactivate_validator(
3467 new_validator_address,
3468 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
3469 )?;
3470 vc.assert_emitted_events(vec![ValidatorConfigV2Event::ValidatorDeactivated(
3471 IValidatorConfigV2::ValidatorDeactivated {
3472 index: 0,
3473 validatorAddress: new_validator_address,
3474 },
3475 )]);
3476
3477 vc.clear_emitted_events();
3478 let new_owner = Address::random();
3479 vc.transfer_ownership(
3480 owner,
3481 IValidatorConfigV2::transferOwnershipCall {
3482 newOwner: new_owner,
3483 },
3484 )?;
3485 vc.assert_emitted_events(vec![ValidatorConfigV2Event::OwnershipTransferred(
3486 IValidatorConfigV2::OwnershipTransferred {
3487 oldOwner: owner,
3488 newOwner: new_owner,
3489 },
3490 )]);
3491
3492 Ok(())
3493 })
3494 }
3495
3496 #[test]
3497 fn test_event_emission_rotate_and_next_dkg() -> eyre::Result<()> {
3498 let mut storage = HashMapStorageProvider::new(1);
3499 let owner = Address::random();
3500 let validator = Address::random();
3501
3502 StorageCtx::enter(&mut storage, || {
3503 let mut vc = ValidatorConfigV2::new();
3504 vc.initialize(owner)?;
3505
3506 let (old_pubkey, old_sig) = make_test_keypair_and_signature(
3507 validator,
3508 "192.168.1.1:8000",
3509 "192.168.1.1",
3510 SignatureKind::Add {
3511 fee_recipient: validator,
3512 },
3513 );
3514
3515 vc.storage.set_block_number(200);
3516 vc.add_validator(
3517 owner,
3518 make_add_call(
3519 validator,
3520 old_pubkey,
3521 "192.168.1.1:8000",
3522 "192.168.1.1",
3523 validator,
3524 old_sig,
3525 ),
3526 )?;
3527
3528 vc.clear_emitted_events();
3529 let (new_pubkey, new_sig) = make_test_keypair_and_signature(
3530 validator,
3531 "10.0.0.2:8000",
3532 "10.0.0.2",
3533 SignatureKind::Rotate,
3534 );
3535 vc.storage.set_block_number(300);
3536 vc.rotate_validator(
3537 owner,
3538 IValidatorConfigV2::rotateValidatorCall {
3539 idx: 0,
3540 publicKey: new_pubkey,
3541 ingress: "10.0.0.2:8000".to_string(),
3542 egress: "10.0.0.2".to_string(),
3543 signature: new_sig.into(),
3544 },
3545 )?;
3546 vc.assert_emitted_events(vec![ValidatorConfigV2Event::ValidatorRotated(
3547 IValidatorConfigV2::ValidatorRotated {
3548 index: 0,
3549 deactivatedIndex: 1,
3550 validatorAddress: validator,
3551 oldPublicKey: old_pubkey,
3552 newPublicKey: new_pubkey,
3553 ingress: "10.0.0.2:8000".to_string(),
3554 egress: "10.0.0.2".to_string(),
3555 caller: owner,
3556 },
3557 )]);
3558
3559 vc.clear_emitted_events();
3560 vc.set_network_identity_rotation_epoch(
3561 owner,
3562 IValidatorConfigV2::setNetworkIdentityRotationEpochCall { epoch: 42 },
3563 )?;
3564 vc.assert_emitted_events(vec![
3565 ValidatorConfigV2Event::NetworkIdentityRotationEpochSet(
3566 IValidatorConfigV2::NetworkIdentityRotationEpochSet {
3567 previousEpoch: 0,
3568 nextEpoch: 42,
3569 },
3570 ),
3571 ]);
3572
3573 Ok(())
3574 })
3575 }
3576
3577 #[test]
3578 fn test_event_emission_migration_and_initialize() -> eyre::Result<()> {
3579 let mut storage = HashMapStorageProvider::new(1);
3580 let owner = Address::random();
3581 let v1_addr = Address::random();
3582 let v1_pk = FixedBytes::<32>::from([0x11; 32]);
3583
3584 StorageCtx::enter(&mut storage, || {
3585 let mut v1 = v1();
3586 v1.initialize(owner)?;
3587 v1.add_validator(
3588 owner,
3589 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
3590 newValidatorAddress: v1_addr,
3591 publicKey: v1_pk,
3592 active: true,
3593 inboundAddress: "192.168.1.1:8000".to_string(),
3594 outboundAddress: "192.168.1.1:9000".to_string(),
3595 },
3596 )?;
3597
3598 let mut v2 = ValidatorConfigV2::new();
3599 v2.storage.set_block_number(500);
3600 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 })?;
3601 v2.assert_emitted_events(vec![ValidatorConfigV2Event::ValidatorMigrated(
3602 IValidatorConfigV2::ValidatorMigrated {
3603 index: 0,
3604 validatorAddress: v1_addr,
3605 publicKey: v1_pk,
3606 },
3607 )]);
3608
3609 v2.clear_emitted_events();
3610 v2.storage.set_block_number(700);
3611 v2.initialize_if_migrated(owner)?;
3612 v2.assert_emitted_events(vec![ValidatorConfigV2Event::Initialized(
3613 IValidatorConfigV2::Initialized { height: 700 },
3614 )]);
3615
3616 Ok(())
3617 })
3618 }
3619}