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::new();
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::validator_added(
558 index,
559 call.validatorAddress,
560 call.publicKey,
561 call.ingress,
562 call.egress,
563 call.feeRecipient,
564 ))?;
565
566 Ok(index)
567 }
568
569 pub fn deactivate_validator(
584 &mut self,
585 sender: Address,
586 call: IValidatorConfigV2::deactivateValidatorCall,
587 ) -> Result<()> {
588 let v = self.get_active_validator(call.idx)?;
589 self.config
590 .read()?
591 .require_owner_or_validator(sender, v.validator_address)?;
592
593 self.active_ingress_ips[Self::ingress_key(&v.ingress)?].delete()?;
594
595 let block_height = self.storage.block_number();
596 self.validators[call.idx as usize]
597 .deactivated_at_height
598 .write(block_height)?;
599
600 let active_index = (v.active_idx - 1) as usize;
602 let last_pos = self.active_indices.len()? - 1;
603
604 if active_index != last_pos {
605 let moved_val = self.active_indices[last_pos].read()?;
606 self.active_indices[active_index].write(moved_val)?;
607 self.validators[(moved_val - 1) as usize]
608 .active_idx
609 .write((active_index + 1) as u64)?;
610 }
611 self.active_indices.pop()?;
612 self.validators[call.idx as usize].active_idx.write(0)?;
613
614 self.emit_event(ValidatorConfigV2Event::validator_deactivated(
615 call.idx,
616 v.validator_address,
617 ))
618 }
619
620 pub fn transfer_ownership(
627 &mut self,
628 sender: Address,
629 call: IValidatorConfigV2::transferOwnershipCall,
630 ) -> Result<()> {
631 if call.newOwner.is_zero() {
632 Err(ValidatorConfigV2Error::invalid_owner())?
633 }
634 let mut config = self.config.read()?.require_init()?.require_owner(sender)?;
635 let old_owner = config.owner;
636 config.owner = call.newOwner;
637 self.config.write(config)?;
638
639 self.emit_event(ValidatorConfigV2Event::ownership_transferred(
640 old_owner,
641 call.newOwner,
642 ))
643 }
644
645 pub fn set_network_identity_rotation_epoch(
652 &mut self,
653 sender: Address,
654 call: IValidatorConfigV2::setNetworkIdentityRotationEpochCall,
655 ) -> Result<()> {
656 self.config.read()?.require_init()?.require_owner(sender)?;
657 let previous_epoch = self.next_network_identity_rotation_epoch.read()?;
658 self.next_network_identity_rotation_epoch
659 .write(call.epoch)?;
660 self.emit_event(ValidatorConfigV2Event::network_identity_rotation_epoch_set(
661 previous_epoch,
662 call.epoch,
663 ))
664 }
665
666 pub fn rotate_validator(
691 &mut self,
692 sender: Address,
693 call: IValidatorConfigV2::rotateValidatorCall,
694 ) -> Result<()> {
695 let v = self.get_active_validator(call.idx)?;
696 self.config
697 .read()?
698 .require_init()?
699 .require_owner_or_validator(sender, v.validator_address)?;
700 self.require_new_pubkey(call.publicKey)?;
701 Self::validate_endpoints(&call.ingress, &call.egress)?;
702
703 self.require_unique_ingress(&call.ingress)?;
704 self.verify_validator_signature(
705 SignatureKind::Rotate,
706 &call.publicKey,
707 &call.signature,
708 v.validator_address,
709 &call.ingress,
710 &call.egress,
711 )?;
712
713 let block_height = self.storage.block_number();
714
715 self.update_ingress_ip_tracking(&v.ingress, &call.ingress)?;
716
717 let appended_idx = self.validators.len()? as u64;
719 let snapshot = ValidatorRecord {
720 public_key: v.public_key,
721 validator_address: v.validator_address,
722 ingress: v.ingress,
723 egress: v.egress,
724 fee_recipient: v.fee_recipient,
725 index: appended_idx,
726 active_idx: 0,
727 added_at_height: v.added_at_height,
728 deactivated_at_height: block_height,
729 };
730 self.validators.push(snapshot)?;
731
732 self.pubkey_to_index[v.public_key].write(appended_idx + 1)?;
734
735 let mut updated = self.validators[call.idx as usize].read()?;
737 updated.public_key = call.publicKey;
738 updated.ingress = call.ingress.clone();
739 updated.egress = call.egress.clone();
740 updated.added_at_height = block_height;
741 self.validators[call.idx as usize].write(updated)?;
742
743 self.pubkey_to_index[call.publicKey].write(call.idx + 1)?;
745
746 self.emit_event(ValidatorConfigV2Event::validator_rotated(
747 call.idx,
748 appended_idx,
749 v.validator_address,
750 v.public_key,
751 call.publicKey,
752 call.ingress,
753 call.egress,
754 sender,
755 ))
756 }
757
758 pub fn set_fee_recipient(
765 &mut self,
766 sender: Address,
767 call: IValidatorConfigV2::setFeeRecipientCall,
768 ) -> Result<()> {
769 let mut v = self.get_active_validator(call.idx)?;
770 self.config
771 .read()?
772 .require_init()?
773 .require_owner_or_validator(sender, v.validator_address)?;
774
775 v.fee_recipient = call.feeRecipient;
776 self.validators[call.idx as usize].write(v)?;
777
778 self.emit_event(ValidatorConfigV2Event::fee_recipient_updated(
779 call.idx,
780 call.feeRecipient,
781 sender,
782 ))
783 }
784
785 pub fn set_ip_addresses(
794 &mut self,
795 sender: Address,
796 call: IValidatorConfigV2::setIpAddressesCall,
797 ) -> Result<()> {
798 let mut v = self.get_active_validator(call.idx)?;
799 self.config
800 .read()?
801 .require_init()?
802 .require_owner_or_validator(sender, v.validator_address)?;
803
804 Self::validate_endpoints(&call.ingress, &call.egress)?;
805
806 self.update_ingress_ip_tracking(&v.ingress, &call.ingress)?;
807
808 v.ingress = call.ingress.clone();
809 v.egress = call.egress.clone();
810 self.validators[call.idx as usize].write(v)?;
811
812 self.emit_event(ValidatorConfigV2Event::ip_addresses_updated(
813 call.idx,
814 call.ingress,
815 call.egress,
816 sender,
817 ))
818 }
819
820 pub fn transfer_validator_ownership(
831 &mut self,
832 sender: Address,
833 call: IValidatorConfigV2::transferValidatorOwnershipCall,
834 ) -> Result<()> {
835 let mut v = self.get_active_validator(call.idx)?;
836 self.config
837 .read()?
838 .require_init()?
839 .require_owner_or_validator(sender, v.validator_address)?;
840 self.require_new_address(call.newAddress)?;
841
842 let old_address = v.validator_address;
843 v.validator_address = call.newAddress;
844 self.validators[call.idx as usize].write(v)?;
845
846 self.address_to_index[old_address].delete()?;
847 self.address_to_index[call.newAddress].write(call.idx + 1)?;
848
849 self.emit_event(ValidatorConfigV2Event::validator_ownership_transferred(
850 call.idx,
851 old_address,
852 call.newAddress,
853 sender,
854 ))
855 }
856
857 fn require_migration_owner(&mut self, caller: Address) -> Result<Config> {
868 let mut config = self.config.read()?.require_not_init()?;
869
870 if config.owner.is_zero() {
871 let v1 = v1();
872 config.owner = v1.owner()?;
873 let v1_count = v1.validator_count()?;
874 if v1_count == 0 {
875 Err(ValidatorConfigV2Error::empty_v_1_validator_set())?
876 }
877 config.v1_validator_count = v1_count as u8;
878 self.config.write(Config {
879 owner: config.owner,
880 is_init: false,
881 init_at_height: 0,
882 migration_skipped_count: 0,
883 v1_validator_count: config.v1_validator_count,
884 })?;
885 }
886
887 config.require_owner(caller)
888 }
889
890 pub fn migrate_validator(
908 &mut self,
909 sender: Address,
910 call: IValidatorConfigV2::migrateValidatorCall,
911 ) -> Result<()> {
912 let config = self.require_migration_owner(sender)?;
913 let block_height = self.storage.block_number();
914
915 let v1 = v1();
916 let v1_count = u64::from(config.v1_validator_count);
917 let migrated = self.validator_count()?;
918 let skipped = config.migration_skipped_count;
919
920 let total_processed = migrated + u64::from(skipped);
921 if total_processed >= v1_count || call.idx != v1_count - total_processed - 1 {
922 Err(ValidatorConfigV2Error::invalid_migration_index())?
923 }
924
925 let v1_val = v1.validators(v1.validators_array(call.idx)?)?;
926
927 let skip = |s: &mut Self| {
929 s.emit_event(ValidatorConfigV2Event::skipped_validator_migration(
930 call.idx,
931 v1_val.validatorAddress,
932 v1_val.publicKey,
933 ))?;
934 s.config
935 .migration_skipped_count
936 .write(skipped.saturating_add(1))
937 };
938
939 if PublicKey::decode(v1_val.publicKey.as_slice()).is_err() {
941 return skip(self);
942 }
943
944 let egress = match v1_val.outboundAddress.parse::<std::net::SocketAddr>() {
946 Ok(sa) => sa.ip().to_string(),
947 Err(_) => return skip(self),
948 };
949
950 if self.pubkey_to_index[v1_val.publicKey].read()? != 0 {
952 return skip(self);
953 }
954
955 let addr_idx = self.address_to_index[v1_val.validatorAddress].read()?;
957 if addr_idx != 0
958 && self.validators[(addr_idx - 1) as usize]
959 .deactivated_at_height
960 .read()?
961 == 0
962 {
963 Err(ValidatorConfigV2Error::address_already_has_validator())?
964 }
965
966 let now_active = v1_val.active;
967 let ingress_hash = Self::ingress_key(&v1_val.inboundAddress)?;
968
969 if now_active && self.active_ingress_ips[ingress_hash].read()? {
971 return skip(self);
972 }
973
974 let migrated_idx = self.append_validator(
975 v1_val.validatorAddress,
976 v1_val.publicKey,
977 v1_val.inboundAddress,
978 egress,
979 Address::ZERO,
980 block_height,
981 if now_active { 0 } else { block_height },
982 )?;
983
984 if now_active {
985 self.active_ingress_ips[ingress_hash].write(true)?;
986 }
987
988 self.emit_event(ValidatorConfigV2Event::validator_migrated(
989 migrated_idx,
990 v1_val.validatorAddress,
991 v1_val.publicKey,
992 ))
993 }
994
995 pub fn initialize_if_migrated(&mut self, sender: Address) -> Result<()> {
1007 let mut config = self.require_migration_owner(sender)?;
1008
1009 if config.v1_validator_count == 0
1012 || self.validator_count()? + u64::from(config.migration_skipped_count)
1013 < u64::from(config.v1_validator_count)
1014 {
1015 Err(ValidatorConfigV2Error::migration_not_complete())?
1016 }
1017
1018 let v1 = v1();
1019 let v1_next_dkg = v1.get_next_full_dkg_ceremony()?;
1020 self.next_network_identity_rotation_epoch
1021 .write(v1_next_dkg)?;
1022
1023 trace!(address=%self.address, "Initializing validator config v2 precompile after migration");
1024
1025 let height = self.storage.block_number();
1027 config.init_at_height = height;
1028 config.is_init = true;
1029 self.config.write(config)?;
1030
1031 self.emit_event(ValidatorConfigV2Event::initialized(height))
1032 }
1033}
1034
1035fn v1() -> ValidatorConfig {
1036 ValidatorConfig::new()
1037}
1038
1039#[cfg(test)]
1040mod tests {
1041 use super::*;
1042 use crate::storage::{StorageCtx, hashmap::HashMapStorageProvider};
1043 use alloy::primitives::Address;
1044 use alloy_primitives::FixedBytes;
1045 use commonware_codec::Encode;
1046 use commonware_cryptography::{Signer, ed25519::PrivateKey};
1047
1048 fn make_test_keypair_and_signature(
1050 validator_address: Address,
1051 ingress: &str,
1052 egress: &str,
1053 kind: SignatureKind,
1054 ) -> (FixedBytes<32>, Vec<u8>) {
1055 let seed = rand_08::random::<u64>();
1057 let private_key = PrivateKey::from_seed(seed);
1058 let public_key = private_key.public_key();
1059
1060 let mut hasher = Keccak256::new();
1061 hasher.update(1u64.to_be_bytes());
1062 hasher.update(VALIDATOR_CONFIG_V2_ADDRESS.as_slice());
1063 hasher.update(validator_address.as_slice());
1064 hasher.update([
1065 u8::try_from(ingress.len()).expect("validator ingress length must fit in uint8")
1066 ]);
1067 hasher.update(ingress.as_bytes());
1068 hasher.update([
1069 u8::try_from(egress.len()).expect("validator egress length must fit in uint8")
1070 ]);
1071 hasher.update(egress.as_bytes());
1072 let namespace = match kind {
1073 SignatureKind::Add { fee_recipient } => {
1074 hasher.update(fee_recipient.as_slice());
1075 VALIDATOR_NS_ADD
1076 }
1077 SignatureKind::Rotate => VALIDATOR_NS_ROTATE,
1078 };
1079 let message = hasher.finalize();
1080
1081 let signature = private_key.sign(namespace, message.as_slice());
1083
1084 let pubkey_bytes = public_key.encode();
1086 let mut pubkey_array = [0u8; 32];
1087 pubkey_array.copy_from_slice(&pubkey_bytes);
1088
1089 (
1090 FixedBytes::<32>::from(pubkey_array),
1091 signature.encode().to_vec(),
1092 )
1093 }
1094
1095 fn make_add_call(
1096 addr: Address,
1097 pubkey: FixedBytes<32>,
1098 ingress: &str,
1099 egress: &str,
1100 fee_recipient: Address,
1101 signature: Vec<u8>,
1102 ) -> IValidatorConfigV2::addValidatorCall {
1103 IValidatorConfigV2::addValidatorCall {
1104 validatorAddress: addr,
1105 publicKey: pubkey,
1106 ingress: ingress.to_string(),
1107 egress: egress.to_string(),
1108 feeRecipient: fee_recipient,
1109 signature: signature.into(),
1110 }
1111 }
1112
1113 fn make_valid_add_call(
1115 addr: Address,
1116 ingress: &str,
1117 egress: &str,
1118 fee_recipient: Address,
1119 ) -> IValidatorConfigV2::addValidatorCall {
1120 let (pubkey, signature) = make_test_keypair_and_signature(
1121 addr,
1122 ingress,
1123 egress,
1124 SignatureKind::Add { fee_recipient },
1125 );
1126 make_add_call(addr, pubkey, ingress, egress, fee_recipient, signature)
1127 }
1128
1129 #[test]
1130 fn test_owner_initialization() -> eyre::Result<()> {
1131 let mut storage = HashMapStorageProvider::new(1);
1132 let owner = Address::random();
1133 StorageCtx::enter(&mut storage, || {
1134 let mut vc = ValidatorConfigV2::new();
1135 vc.initialize(owner)?;
1136
1137 assert_eq!(vc.owner()?, owner);
1138 assert!(vc.is_initialized()?);
1139 assert_eq!(vc.get_initialized_at_height()?, 0);
1140 assert_eq!(vc.validator_count()?, 0);
1141
1142 Ok(())
1143 })
1144 }
1145
1146 #[test]
1147 fn test_add_validator() -> eyre::Result<()> {
1148 let mut storage = HashMapStorageProvider::new(1);
1149 let owner = Address::random();
1150 let validator = Address::random();
1151 StorageCtx::enter(&mut storage, || {
1152 let mut vc = ValidatorConfigV2::new();
1153 vc.initialize(owner)?;
1154
1155 let (pubkey, signature) = make_test_keypair_and_signature(
1156 validator,
1157 "192.168.1.1:8000",
1158 "192.168.1.1",
1159 SignatureKind::Add {
1160 fee_recipient: validator,
1161 },
1162 );
1163 vc.storage.set_block_number(200);
1164 vc.add_validator(
1165 owner,
1166 make_add_call(
1167 validator,
1168 pubkey,
1169 "192.168.1.1:8000",
1170 "192.168.1.1",
1171 validator,
1172 signature,
1173 ),
1174 )?;
1175
1176 assert_eq!(vc.validator_count()?, 1);
1177
1178 let v = vc.validator_by_index(0)?;
1179 assert_eq!(v.publicKey, pubkey);
1180 assert_eq!(v.validatorAddress, validator);
1181 assert_eq!(v.addedAtHeight, 200);
1182 assert_eq!(v.deactivatedAtHeight, 0);
1183 assert_eq!(v.index, 0);
1184
1185 let v2 = vc.validator_by_address(validator)?;
1186 assert_eq!(v2.publicKey, pubkey);
1187
1188 let v3 = vc.validator_by_public_key(pubkey)?;
1189 assert_eq!(v3.validatorAddress, validator);
1190
1191 Ok(())
1192 })
1193 }
1194
1195 #[test]
1196 fn test_add_validator_rejects_unauthorized() -> eyre::Result<()> {
1197 let mut storage = HashMapStorageProvider::new(1);
1198 let owner = Address::random();
1199 let non_owner = Address::random();
1200 StorageCtx::enter(&mut storage, || {
1201 let mut vc = ValidatorConfigV2::new();
1202 vc.initialize(owner)?;
1203
1204 let result = vc.add_validator(
1205 non_owner,
1206 make_valid_add_call(
1207 Address::random(),
1208 "192.168.1.1:8000",
1209 "192.168.1.1",
1210 Address::random(),
1211 ),
1212 );
1213 assert_eq!(result, Err(ValidatorConfigV2Error::unauthorized().into()));
1214
1215 Ok(())
1216 })
1217 }
1218
1219 #[test]
1220 fn test_add_validator_rejects_zero_pubkey() -> eyre::Result<()> {
1221 let mut storage = HashMapStorageProvider::new(1);
1222 let owner = Address::random();
1223 StorageCtx::enter(&mut storage, || {
1224 let mut vc = ValidatorConfigV2::new();
1225 vc.initialize(owner)?;
1226
1227 let result = vc.add_validator(
1228 owner,
1229 make_add_call(
1230 Address::random(),
1231 FixedBytes::<32>::ZERO,
1232 "192.168.1.1:8000",
1233 "192.168.1.1",
1234 Address::random(),
1235 vec![0u8; 64],
1236 ),
1237 );
1238 assert_eq!(
1239 result,
1240 Err(ValidatorConfigV2Error::invalid_public_key().into())
1241 );
1242
1243 Ok(())
1244 })
1245 }
1246
1247 #[test]
1248 fn test_add_validator_rejects_duplicate_address() -> eyre::Result<()> {
1249 let mut storage = HashMapStorageProvider::new(1);
1250 let owner = Address::random();
1251 let validator = Address::random();
1252 StorageCtx::enter(&mut storage, || {
1253 let mut vc = ValidatorConfigV2::new();
1254 vc.initialize(owner)?;
1255
1256 vc.storage.set_block_number(200);
1257 vc.add_validator(
1258 owner,
1259 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
1260 )?;
1261
1262 vc.storage.set_block_number(201);
1263 let result = vc.add_validator(
1264 owner,
1265 make_valid_add_call(validator, "192.168.1.2:8000", "192.168.1.2", validator),
1266 );
1267 assert_eq!(
1268 result,
1269 Err(ValidatorConfigV2Error::address_already_has_validator().into())
1270 );
1271
1272 Ok(())
1273 })
1274 }
1275
1276 #[test]
1277 fn test_add_validator_rejects_duplicate_pubkey() -> eyre::Result<()> {
1278 let mut storage = HashMapStorageProvider::new(1);
1279 let owner = Address::random();
1280 StorageCtx::enter(&mut storage, || {
1281 let mut vc = ValidatorConfigV2::new();
1282 vc.initialize(owner)?;
1283
1284 let addr1 = Address::random();
1286 let (pubkey, sig1) = make_test_keypair_and_signature(
1287 addr1,
1288 "192.168.1.1:8000",
1289 "192.168.1.1",
1290 SignatureKind::Add {
1291 fee_recipient: addr1,
1292 },
1293 );
1294 vc.storage.set_block_number(200);
1295 vc.add_validator(
1296 owner,
1297 make_add_call(
1298 addr1,
1299 pubkey,
1300 "192.168.1.1:8000",
1301 "192.168.1.1",
1302 addr1,
1303 sig1,
1304 ),
1305 )?;
1306
1307 let addr2 = Address::random();
1309 let (_, sig2) = make_test_keypair_and_signature(
1310 addr2,
1311 "192.168.1.2:8000",
1312 "192.168.1.2",
1313 SignatureKind::Add {
1314 fee_recipient: addr2,
1315 },
1316 );
1317 vc.storage.set_block_number(201);
1318 let result = vc.add_validator(
1319 owner,
1320 make_add_call(
1321 addr2,
1322 pubkey,
1323 "192.168.1.2:8000",
1324 "192.168.1.2",
1325 addr2,
1326 sig2,
1327 ),
1328 );
1329 assert_eq!(
1330 result,
1331 Err(ValidatorConfigV2Error::public_key_already_exists().into())
1332 );
1333
1334 Ok(())
1335 })
1336 }
1337
1338 #[test]
1339 fn test_deactivate_validator() -> eyre::Result<()> {
1340 let mut storage = HashMapStorageProvider::new(1);
1341 let owner = Address::random();
1342 let validator = Address::random();
1343 StorageCtx::enter(&mut storage, || {
1344 let mut vc = ValidatorConfigV2::new();
1345 vc.initialize(owner)?;
1346
1347 vc.storage.set_block_number(200);
1348 vc.add_validator(
1349 owner,
1350 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
1351 )?;
1352
1353 vc.storage.set_block_number(300);
1354 vc.deactivate_validator(
1355 owner,
1356 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
1357 )?;
1358
1359 let v = vc.validator_by_index(0)?;
1360 assert_eq!(v.deactivatedAtHeight, 300);
1361
1362 vc.storage.set_block_number(301);
1364 let result = vc.deactivate_validator(
1365 owner,
1366 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
1367 );
1368 assert_eq!(
1369 result,
1370 Err(ValidatorConfigV2Error::validator_already_deactivated().into())
1371 );
1372
1373 Ok(())
1374 })
1375 }
1376
1377 #[test]
1378 fn test_deactivate_validator_dual_auth() -> eyre::Result<()> {
1379 let mut storage = HashMapStorageProvider::new(1);
1380 let owner = Address::random();
1381 let v1 = Address::random();
1382 let v2 = Address::random();
1383 let third_party = Address::random();
1384 StorageCtx::enter(&mut storage, || {
1385 let mut vc = ValidatorConfigV2::new();
1386 vc.initialize(owner)?;
1387
1388 vc.storage.set_block_number(200);
1389 vc.add_validator(
1390 owner,
1391 make_valid_add_call(v1, "192.168.1.1:8000", "192.168.1.1", v1),
1392 )?;
1393 vc.add_validator(
1394 owner,
1395 make_valid_add_call(v2, "192.168.1.2:8000", "192.168.1.2", v2),
1396 )?;
1397
1398 vc.storage.set_block_number(300);
1400 let result = vc.deactivate_validator(
1401 third_party,
1402 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
1403 );
1404 assert_eq!(result, Err(ValidatorConfigV2Error::unauthorized().into()));
1405
1406 vc.deactivate_validator(v1, IValidatorConfigV2::deactivateValidatorCall { idx: 0 })?;
1408 assert_eq!(vc.validator_by_index(0)?.deactivatedAtHeight, 300);
1409
1410 vc.storage.set_block_number(301);
1412 vc.deactivate_validator(
1413 owner,
1414 IValidatorConfigV2::deactivateValidatorCall { idx: 1 },
1415 )?;
1416 assert_eq!(vc.validator_by_index(1)?.deactivatedAtHeight, 301);
1417
1418 Ok(())
1419 })
1420 }
1421
1422 #[test]
1423 fn test_rotate_validator() -> eyre::Result<()> {
1424 let mut storage = HashMapStorageProvider::new(1);
1425 let owner = Address::random();
1426 let validator = Address::random();
1427 StorageCtx::enter(&mut storage, || {
1428 let mut vc = ValidatorConfigV2::new();
1429 vc.initialize(owner)?;
1430
1431 let (old_pubkey, old_sig) = make_test_keypair_and_signature(
1433 validator,
1434 "192.168.1.1:8000",
1435 "192.168.1.1",
1436 SignatureKind::Add {
1437 fee_recipient: validator,
1438 },
1439 );
1440 vc.storage.set_block_number(200);
1441 vc.add_validator(
1442 owner,
1443 make_add_call(
1444 validator,
1445 old_pubkey,
1446 "192.168.1.1:8000",
1447 "192.168.1.1",
1448 validator,
1449 old_sig,
1450 ),
1451 )?;
1452
1453 let (new_pubkey, new_sig) = make_test_keypair_and_signature(
1455 validator,
1456 "10.0.0.1:8000",
1457 "10.0.0.1",
1458 SignatureKind::Rotate,
1459 );
1460 vc.storage.set_block_number(300);
1461 vc.rotate_validator(
1462 owner,
1463 IValidatorConfigV2::rotateValidatorCall {
1464 idx: 0,
1465 publicKey: new_pubkey,
1466 ingress: "10.0.0.1:8000".to_string(),
1467 egress: "10.0.0.1".to_string(),
1468 signature: new_sig.into(),
1469 },
1470 )?;
1471
1472 assert_eq!(vc.validator_count()?, 2);
1474
1475 let updated = vc.validator_by_index(0)?;
1477 assert_eq!(updated.deactivatedAtHeight, 0);
1478 assert_eq!(updated.publicKey, new_pubkey);
1479 assert_eq!(updated.validatorAddress, validator);
1480 assert_eq!(updated.addedAtHeight, 300);
1481
1482 let snapshot = vc.validator_by_index(1)?;
1484 assert_eq!(snapshot.deactivatedAtHeight, 300);
1485 assert_eq!(snapshot.publicKey, old_pubkey);
1486
1487 let by_addr = vc.validator_by_address(validator)?;
1489 assert_eq!(by_addr.publicKey, new_pubkey);
1490
1491 let by_old_pk = vc.validator_by_public_key(old_pubkey)?;
1493 assert_eq!(by_old_pk.deactivatedAtHeight, 300);
1494
1495 Ok(())
1496 })
1497 }
1498
1499 #[test]
1500 fn test_get_active_validators() -> eyre::Result<()> {
1501 let mut storage = HashMapStorageProvider::new(1);
1502 let owner = Address::random();
1503 let v1 = Address::random();
1504 let v2 = Address::random();
1505 StorageCtx::enter(&mut storage, || {
1506 let mut vc = ValidatorConfigV2::new();
1507 vc.initialize(owner)?;
1508
1509 vc.storage.set_block_number(200);
1510 vc.add_validator(
1511 owner,
1512 make_valid_add_call(v1, "192.168.1.1:8000", "192.168.1.1", v1),
1513 )?;
1514 vc.storage.set_block_number(201);
1515 vc.add_validator(
1516 owner,
1517 make_valid_add_call(v2, "192.168.1.2:8000", "192.168.1.2", v2),
1518 )?;
1519
1520 assert_eq!(vc.get_active_validators()?.len(), 2);
1521
1522 vc.storage.set_block_number(300);
1523 vc.deactivate_validator(
1524 owner,
1525 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
1526 )?;
1527
1528 let active = vc.get_active_validators()?;
1529 assert_eq!(active.len(), 1);
1530 assert_eq!(active[0].validatorAddress, v2);
1531
1532 assert_eq!(vc.validator_count()?, 2);
1533
1534 Ok(())
1535 })
1536 }
1537
1538 #[test]
1539 fn test_set_fee_recipient() -> eyre::Result<()> {
1540 let mut storage = HashMapStorageProvider::new(1);
1541 let owner = Address::random();
1542 let validator = Address::random();
1543 StorageCtx::enter(&mut storage, || {
1544 let mut vc = ValidatorConfigV2::new();
1545 vc.initialize(owner)?;
1546
1547 vc.storage.set_block_number(200);
1548 vc.add_validator(
1549 owner,
1550 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
1551 )?;
1552
1553 let fee_recipient_1 = Address::random();
1554 vc.set_fee_recipient(
1555 owner,
1556 IValidatorConfigV2::setFeeRecipientCall {
1557 idx: 0,
1558 feeRecipient: fee_recipient_1,
1559 },
1560 )?;
1561
1562 let v = vc.validator_by_address(validator)?;
1563 assert_eq!(v.feeRecipient, fee_recipient_1);
1564
1565 let fee_recipient_2 = Address::random();
1567 vc.set_fee_recipient(
1568 validator,
1569 IValidatorConfigV2::setFeeRecipientCall {
1570 idx: 0,
1571 feeRecipient: fee_recipient_2,
1572 },
1573 )?;
1574
1575 let v = vc.validator_by_address(validator)?;
1576 assert_eq!(v.feeRecipient, fee_recipient_2);
1577
1578 Ok(())
1579 })
1580 }
1581
1582 #[test]
1583 fn test_set_ip_addresses() -> eyre::Result<()> {
1584 let mut storage = HashMapStorageProvider::new(1);
1585 let owner = Address::random();
1586 let validator = Address::random();
1587 StorageCtx::enter(&mut storage, || {
1588 let mut vc = ValidatorConfigV2::new();
1589 vc.initialize(owner)?;
1590
1591 vc.storage.set_block_number(200);
1592 vc.add_validator(
1593 owner,
1594 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
1595 )?;
1596
1597 vc.set_ip_addresses(
1598 owner,
1599 IValidatorConfigV2::setIpAddressesCall {
1600 idx: 0,
1601 ingress: "10.0.0.1:8000".to_string(),
1602 egress: "10.0.0.1".to_string(),
1603 },
1604 )?;
1605
1606 let v = vc.validator_by_address(validator)?;
1607 assert_eq!(v.ingress, "10.0.0.1:8000");
1608 assert_eq!(v.egress, "10.0.0.1");
1609
1610 vc.set_ip_addresses(
1612 validator,
1613 IValidatorConfigV2::setIpAddressesCall {
1614 idx: 0,
1615 ingress: "10.0.0.2:8000".to_string(),
1616 egress: "10.0.0.2".to_string(),
1617 },
1618 )?;
1619
1620 let v = vc.validator_by_address(validator)?;
1621 assert_eq!(v.ingress, "10.0.0.2:8000");
1622
1623 Ok(())
1624 })
1625 }
1626
1627 #[test]
1628 fn test_transfer_ownership() -> eyre::Result<()> {
1629 let mut storage = HashMapStorageProvider::new(1);
1630 let owner = Address::random();
1631 let new_owner = Address::random();
1632 let non_owner = Address::random();
1633 StorageCtx::enter(&mut storage, || {
1634 let mut vc = ValidatorConfigV2::new();
1635
1636 let result = vc.transfer_ownership(
1638 owner,
1639 IValidatorConfigV2::transferOwnershipCall {
1640 newOwner: new_owner,
1641 },
1642 );
1643 assert_eq!(
1644 result,
1645 Err(ValidatorConfigV2Error::not_initialized().into())
1646 );
1647
1648 vc.initialize(owner)?;
1649
1650 let result = vc.transfer_ownership(
1652 owner,
1653 IValidatorConfigV2::transferOwnershipCall {
1654 newOwner: Address::ZERO,
1655 },
1656 );
1657 assert_eq!(result, Err(ValidatorConfigV2Error::invalid_owner().into()));
1658 assert_eq!(vc.owner()?, owner);
1659
1660 let result = vc.transfer_ownership(
1662 non_owner,
1663 IValidatorConfigV2::transferOwnershipCall {
1664 newOwner: new_owner,
1665 },
1666 );
1667 assert_eq!(result, Err(ValidatorConfigV2Error::unauthorized().into()));
1668
1669 vc.transfer_ownership(
1671 owner,
1672 IValidatorConfigV2::transferOwnershipCall {
1673 newOwner: new_owner,
1674 },
1675 )?;
1676 assert_eq!(vc.owner()?, new_owner);
1677
1678 let result = vc.transfer_ownership(
1680 owner,
1681 IValidatorConfigV2::transferOwnershipCall {
1682 newOwner: Address::random(),
1683 },
1684 );
1685 assert_eq!(result, Err(ValidatorConfigV2Error::unauthorized().into()));
1686
1687 Ok(())
1688 })
1689 }
1690
1691 #[test]
1692 fn test_transfer_validator_ownership() -> eyre::Result<()> {
1693 let mut storage = HashMapStorageProvider::new(1);
1694 let owner = Address::random();
1695 let validator = Address::random();
1696 let new_address = Address::random();
1697 StorageCtx::enter(&mut storage, || {
1698 let mut vc = ValidatorConfigV2::new();
1699 vc.initialize(owner)?;
1700
1701 let (pubkey, sig) = make_test_keypair_and_signature(
1702 validator,
1703 "192.168.1.1:8000",
1704 "192.168.1.1",
1705 SignatureKind::Add {
1706 fee_recipient: validator,
1707 },
1708 );
1709 vc.storage.set_block_number(200);
1710 vc.add_validator(
1711 owner,
1712 make_add_call(
1713 validator,
1714 pubkey,
1715 "192.168.1.1:8000",
1716 "192.168.1.1",
1717 validator,
1718 sig,
1719 ),
1720 )?;
1721
1722 vc.transfer_validator_ownership(
1723 owner,
1724 IValidatorConfigV2::transferValidatorOwnershipCall {
1725 idx: 0,
1726 newAddress: new_address,
1727 },
1728 )?;
1729
1730 let result = vc.validator_by_address(validator);
1732 assert_eq!(
1733 result,
1734 Err(ValidatorConfigV2Error::validator_not_found().into())
1735 );
1736
1737 let v = vc.validator_by_address(new_address)?;
1739 assert_eq!(v.publicKey, pubkey);
1740 assert_eq!(v.validatorAddress, new_address);
1741
1742 Ok(())
1743 })
1744 }
1745
1746 #[test]
1747 fn test_transfer_validator_ownership_rejects_deactivated() -> eyre::Result<()> {
1748 let mut storage = HashMapStorageProvider::new(1);
1749 let owner = Address::random();
1750 let validator = Address::random();
1751 StorageCtx::enter(&mut storage, || {
1752 let mut vc = ValidatorConfigV2::new();
1753 vc.initialize(owner)?;
1754
1755 vc.storage.set_block_number(200);
1756 vc.add_validator(
1757 owner,
1758 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
1759 )?;
1760
1761 vc.storage.set_block_number(300);
1762 vc.deactivate_validator(
1763 owner,
1764 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
1765 )?;
1766
1767 let result = vc.transfer_validator_ownership(
1768 owner,
1769 IValidatorConfigV2::transferValidatorOwnershipCall {
1770 idx: 0,
1771 newAddress: Address::random(),
1772 },
1773 );
1774 assert_eq!(
1775 result,
1776 Err(ValidatorConfigV2Error::validator_already_deactivated().into())
1777 );
1778
1779 Ok(())
1780 })
1781 }
1782
1783 #[test]
1784 fn test_set_network_identity_rotation_epoch() -> eyre::Result<()> {
1785 let mut storage = HashMapStorageProvider::new(1);
1786 let owner = Address::random();
1787 StorageCtx::enter(&mut storage, || {
1788 let mut vc = ValidatorConfigV2::new();
1789 vc.initialize(owner)?;
1790
1791 assert_eq!(vc.get_next_network_identity_rotation_epoch()?, 0);
1792
1793 vc.set_network_identity_rotation_epoch(
1794 owner,
1795 IValidatorConfigV2::setNetworkIdentityRotationEpochCall { epoch: 42 },
1796 )?;
1797 assert_eq!(vc.get_next_network_identity_rotation_epoch()?, 42);
1798
1799 let non_owner = Address::random();
1800 let result = vc.set_network_identity_rotation_epoch(
1801 non_owner,
1802 IValidatorConfigV2::setNetworkIdentityRotationEpochCall { epoch: 100 },
1803 );
1804 assert_eq!(result, Err(ValidatorConfigV2Error::unauthorized().into()));
1805
1806 Ok(())
1807 })
1808 }
1809
1810 #[test]
1811 fn test_not_initialized_errors() -> eyre::Result<()> {
1812 let mut storage = HashMapStorageProvider::new(1);
1813 let owner = Address::random();
1814 StorageCtx::enter(&mut storage, || {
1815 let mut vc = ValidatorConfigV2::new();
1816
1817 let result = vc.add_validator(
1818 owner,
1819 make_valid_add_call(
1820 Address::random(),
1821 "192.168.1.1:8000",
1822 "192.168.1.1",
1823 Address::random(),
1824 ),
1825 );
1826 assert_eq!(
1827 result,
1828 Err(ValidatorConfigV2Error::not_initialized().into())
1829 );
1830
1831 Ok(())
1832 })
1833 }
1834
1835 #[test]
1836 fn test_egress_validates_ip_without_port() -> eyre::Result<()> {
1837 let mut storage = HashMapStorageProvider::new(1);
1838 let owner = Address::random();
1839 StorageCtx::enter(&mut storage, || {
1840 let mut vc = ValidatorConfigV2::new();
1841 vc.initialize(owner)?;
1842
1843 let addr1 = Address::random();
1844 let (pubkey1, sig1) = make_test_keypair_and_signature(
1845 addr1,
1846 "192.168.1.1:8000",
1847 "192.168.1.1:9000",
1848 SignatureKind::Add {
1849 fee_recipient: addr1,
1850 },
1851 );
1852
1853 let result = vc.add_validator(
1855 owner,
1856 make_add_call(
1857 addr1,
1858 pubkey1,
1859 "192.168.1.1:8000",
1860 "192.168.1.1:9000",
1861 addr1,
1862 sig1,
1863 ),
1864 );
1865 assert!(result.is_err(), "egress with port should be rejected");
1866
1867 vc.storage.set_block_number(200);
1869 let result = vc.add_validator(
1870 owner,
1871 make_valid_add_call(
1872 Address::random(),
1873 "192.168.1.1:8000",
1874 "192.168.1.1",
1875 Address::random(),
1876 ),
1877 );
1878 assert!(result.is_ok(), "egress with plain IP should succeed");
1879
1880 Ok(())
1881 })
1882 }
1883
1884 #[test]
1885 fn test_migration_from_v1() -> eyre::Result<()> {
1886 let mut storage = HashMapStorageProvider::new(1);
1887 let owner = Address::random();
1888 let v1_addr = Address::random();
1889 let v2_addr = Address::random();
1890
1891 StorageCtx::enter(&mut storage, || {
1892 let mut v1 = v1();
1894 v1.initialize(owner)?;
1895
1896 v1.add_validator(
1897 owner,
1898 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
1899 newValidatorAddress: v1_addr,
1900 publicKey: FixedBytes::<32>::from([0x11; 32]),
1901 active: true,
1902 inboundAddress: "192.168.1.1:8000".to_string(),
1903 outboundAddress: "192.168.1.1:9000".to_string(),
1904 },
1905 )?;
1906
1907 v1.add_validator(
1908 owner,
1909 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
1910 newValidatorAddress: v2_addr,
1911 publicKey: FixedBytes::<32>::from([0x22; 32]),
1912 active: false,
1913 inboundAddress: "192.168.1.2:8000".to_string(),
1914 outboundAddress: "192.168.1.2:9000".to_string(),
1915 },
1916 )?;
1917
1918 let mut v2 = ValidatorConfigV2::new();
1920
1921 v2.storage.set_block_number(100);
1923 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 1 })?;
1924
1925 assert_eq!(v2.validator_count()?, 1);
1926 let migrated = v2.validator_by_index(0)?;
1927 assert_eq!(migrated.validatorAddress, v2_addr);
1928 assert_eq!(migrated.publicKey, FixedBytes::<32>::from([0x22; 32]));
1929 assert_eq!(migrated.deactivatedAtHeight, 100);
1930
1931 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 })?;
1933
1934 assert_eq!(v2.validator_count()?, 2);
1935
1936 v2.storage.set_block_number(400);
1938 v2.initialize_if_migrated(owner)?;
1939
1940 assert!(v2.is_initialized()?);
1941
1942 v2.storage.set_block_number(100);
1944 let result =
1945 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 });
1946 assert_eq!(
1947 result,
1948 Err(ValidatorConfigV2Error::already_initialized().into())
1949 );
1950
1951 Ok(())
1952 })
1953 }
1954
1955 #[test]
1958 fn test_migration_strips_port_from_v1_outbound_address() -> eyre::Result<()> {
1959 let mut storage = HashMapStorageProvider::new(1);
1960 let owner = Address::random();
1961 let v1_addr = Address::random();
1962
1963 StorageCtx::enter(&mut storage, || {
1964 let mut v1 = v1();
1966 v1.initialize(owner)?;
1967 v1.add_validator(
1968 owner,
1969 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
1970 newValidatorAddress: v1_addr,
1971 publicKey: FixedBytes::<32>::from([0x11; 32]),
1972 active: true,
1973 inboundAddress: "192.168.1.1:8000".to_string(),
1974 outboundAddress: "192.168.1.1:9000".to_string(),
1975 },
1976 )?;
1977
1978 let mut v2 = ValidatorConfigV2::new();
1980
1981 v2.storage.set_block_number(100);
1982 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 })?;
1983 v2.storage.set_block_number(400);
1984 v2.initialize_if_migrated(owner)?;
1985
1986 let migrated = v2.validator_by_index(0)?;
1988 assert_eq!(
1989 migrated.egress, "192.168.1.1",
1990 "migration should strip port from V1 outboundAddress"
1991 );
1992
1993 assert_eq!(migrated.ingress, "192.168.1.1:8000");
1995
1996 v2.set_ip_addresses(
1998 owner,
1999 IValidatorConfigV2::setIpAddressesCall {
2000 idx: 0,
2001 ingress: "192.168.1.1:8000".to_string(),
2002 egress: migrated.egress,
2003 },
2004 )?;
2005
2006 Ok(())
2007 })
2008 }
2009
2010 #[test]
2011 fn test_migration_out_of_order_fails() -> eyre::Result<()> {
2012 let mut storage = HashMapStorageProvider::new(1);
2013 let owner = Address::random();
2014
2015 StorageCtx::enter(&mut storage, || {
2016 let mut v1 = v1();
2018 v1.initialize(owner)?;
2019
2020 v1.add_validator(
2021 owner,
2022 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2023 newValidatorAddress: Address::random(),
2024 publicKey: FixedBytes::<32>::from([0x11; 32]),
2025 active: true,
2026 inboundAddress: "192.168.1.1:8000".to_string(),
2027 outboundAddress: "192.168.1.1:9000".to_string(),
2028 },
2029 )?;
2030
2031 v1.add_validator(
2032 owner,
2033 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2034 newValidatorAddress: Address::random(),
2035 publicKey: FixedBytes::<32>::from([0x22; 32]),
2036 active: true,
2037 inboundAddress: "192.168.1.2:8000".to_string(),
2038 outboundAddress: "192.168.1.2:9000".to_string(),
2039 },
2040 )?;
2041
2042 let mut v2 = ValidatorConfigV2::new();
2044 v2.storage.set_block_number(100);
2045 let result =
2046 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 });
2047
2048 assert_eq!(
2049 result,
2050 Err(ValidatorConfigV2Error::invalid_migration_index().into())
2051 );
2052
2053 Ok(())
2054 })
2055 }
2056
2057 #[test]
2058 fn test_initialize_before_migration_complete_fails() -> eyre::Result<()> {
2059 let mut storage = HashMapStorageProvider::new(1);
2060 let owner = Address::random();
2061
2062 StorageCtx::enter(&mut storage, || {
2063 let mut v1 = v1();
2065 v1.initialize(owner)?;
2066
2067 v1.add_validator(
2068 owner,
2069 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2070 newValidatorAddress: Address::random(),
2071 publicKey: FixedBytes::<32>::from([0x11; 32]),
2072 active: true,
2073 inboundAddress: "192.168.1.1:8000".to_string(),
2074 outboundAddress: "192.168.1.1:9000".to_string(),
2075 },
2076 )?;
2077
2078 v1.add_validator(
2079 owner,
2080 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2081 newValidatorAddress: Address::random(),
2082 publicKey: FixedBytes::<32>::from([0x22; 32]),
2083 active: true,
2084 inboundAddress: "192.168.1.2:8000".to_string(),
2085 outboundAddress: "192.168.1.2:9000".to_string(),
2086 },
2087 )?;
2088
2089 let mut v2 = ValidatorConfigV2::new();
2091 v2.storage.set_block_number(100);
2092 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 1 })?;
2093
2094 v2.storage.set_block_number(400);
2096 let result = v2.initialize_if_migrated(owner);
2097
2098 assert_eq!(
2099 result,
2100 Err(ValidatorConfigV2Error::migration_not_complete().into())
2101 );
2102
2103 Ok(())
2104 })
2105 }
2106
2107 #[test]
2108 fn test_add_validator_reuses_deactivated_address() -> eyre::Result<()> {
2109 let mut storage = HashMapStorageProvider::new(1);
2110 let owner = Address::random();
2111 let validator_addr = Address::random();
2112 StorageCtx::enter(&mut storage, || {
2113 let mut vc = ValidatorConfigV2::new();
2114 vc.initialize(owner)?;
2115
2116 let (pubkey1, sig1) = make_test_keypair_and_signature(
2118 validator_addr,
2119 "192.168.1.1:8000",
2120 "192.168.1.1",
2121 SignatureKind::Add {
2122 fee_recipient: validator_addr,
2123 },
2124 );
2125 vc.storage.set_block_number(200);
2126 vc.add_validator(
2127 owner,
2128 make_add_call(
2129 validator_addr,
2130 pubkey1,
2131 "192.168.1.1:8000",
2132 "192.168.1.1",
2133 validator_addr,
2134 sig1,
2135 ),
2136 )?;
2137
2138 vc.storage.set_block_number(300);
2140 vc.deactivate_validator(
2141 owner,
2142 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
2143 )?;
2144
2145 let (pubkey2, sig2) = make_test_keypair_and_signature(
2147 validator_addr,
2148 "192.168.1.2:8000",
2149 "192.168.1.2",
2150 SignatureKind::Add {
2151 fee_recipient: validator_addr,
2152 },
2153 );
2154 vc.storage.set_block_number(400);
2155 vc.add_validator(
2156 owner,
2157 make_add_call(
2158 validator_addr,
2159 pubkey2,
2160 "192.168.1.2:8000",
2161 "192.168.1.2",
2162 validator_addr,
2163 sig2,
2164 ),
2165 )?;
2166
2167 assert_eq!(vc.validator_count()?, 2);
2169
2170 let v1 = vc.validator_by_index(0)?;
2172 assert_eq!(v1.validatorAddress, validator_addr);
2173 assert_eq!(v1.publicKey, pubkey1);
2174 assert_eq!(v1.deactivatedAtHeight, 300);
2175
2176 let v2 = vc.validator_by_index(1)?;
2178 assert_eq!(v2.validatorAddress, validator_addr);
2179 assert_eq!(v2.publicKey, pubkey2);
2180 assert_eq!(v2.deactivatedAtHeight, 0);
2181
2182 let by_addr = vc.validator_by_address(validator_addr)?;
2184 assert_eq!(by_addr.publicKey, pubkey2);
2185 assert_eq!(by_addr.deactivatedAtHeight, 0);
2186
2187 let by_old_pk = vc.validator_by_public_key(pubkey1)?;
2189 assert_eq!(by_old_pk.deactivatedAtHeight, 300);
2190
2191 let by_new_pk = vc.validator_by_public_key(pubkey2)?;
2193 assert_eq!(by_new_pk.deactivatedAtHeight, 0);
2194
2195 Ok(())
2196 })
2197 }
2198
2199 #[test]
2200 fn test_add_validator_rejects_duplicate_ingress() -> eyre::Result<()> {
2201 let mut storage = HashMapStorageProvider::new(1);
2202 let owner = Address::random();
2203 StorageCtx::enter(&mut storage, || {
2204 let mut vc = ValidatorConfigV2::new();
2205 vc.initialize(owner)?;
2206
2207 vc.storage.set_block_number(200);
2208 vc.add_validator(
2209 owner,
2210 make_valid_add_call(
2211 Address::random(),
2212 "192.168.1.1:8000",
2213 "192.168.1.1",
2214 Address::random(),
2215 ),
2216 )?;
2217
2218 vc.storage.set_block_number(201);
2219 let result = vc.add_validator(
2220 owner,
2221 make_valid_add_call(
2222 Address::random(),
2223 "192.168.1.1:8000",
2224 "192.168.2.1",
2225 Address::random(),
2226 ),
2227 );
2228
2229 assert!(result.is_err());
2230 Ok(())
2231 })
2232 }
2233
2234 #[test]
2235 fn test_ingress_reuse_after_deactivation() -> eyre::Result<()> {
2236 let mut storage = HashMapStorageProvider::new(1);
2237 let owner = Address::random();
2238 let v1 = Address::random();
2239 StorageCtx::enter(&mut storage, || {
2240 let mut vc = ValidatorConfigV2::new();
2241 vc.initialize(owner)?;
2242
2243 vc.storage.set_block_number(200);
2244 vc.add_validator(
2245 owner,
2246 make_valid_add_call(v1, "192.168.1.1:8000", "192.168.1.1", v1),
2247 )?;
2248
2249 vc.storage.set_block_number(300);
2250 vc.deactivate_validator(
2251 owner,
2252 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
2253 )?;
2254
2255 vc.storage.set_block_number(400);
2257 vc.add_validator(
2258 owner,
2259 make_valid_add_call(
2260 Address::random(),
2261 "192.168.1.1:8000",
2262 "192.168.1.1",
2263 Address::random(),
2264 ),
2265 )?;
2266
2267 Ok(())
2268 })
2269 }
2270
2271 #[test]
2272 fn test_ingress_reuse_after_rotation() -> eyre::Result<()> {
2273 let mut storage = HashMapStorageProvider::new(1);
2274 let owner = Address::random();
2275 let v1 = Address::random();
2276 StorageCtx::enter(&mut storage, || {
2277 let mut vc = ValidatorConfigV2::new();
2278 vc.initialize(owner)?;
2279
2280 vc.storage.set_block_number(200);
2281 vc.add_validator(
2282 owner,
2283 make_valid_add_call(v1, "[2001:db8::1]:8000", "2001:db8::1", Address::random()),
2284 )?;
2285
2286 vc.storage.set_block_number(300);
2287
2288 let (new_pubkey, new_sig) = make_test_keypair_and_signature(
2290 v1,
2291 "[2001:db8::1]:8001",
2292 "2001:db8::1",
2293 SignatureKind::Rotate,
2294 );
2295 vc.rotate_validator(
2296 owner,
2297 IValidatorConfigV2::rotateValidatorCall {
2298 idx: 0,
2299 publicKey: new_pubkey,
2300 ingress: "[2001:db8::1]:8001".to_string(),
2301 egress: "2001:db8::1".to_string(),
2302 signature: new_sig.into(),
2303 },
2304 )?;
2305 let v = vc.validator_by_address(v1)?;
2306 assert_eq!(v.ingress, "[2001:db8::1]:8001");
2307
2308 vc.storage.set_block_number(400);
2310 vc.set_ip_addresses(
2311 owner,
2312 IValidatorConfigV2::setIpAddressesCall {
2313 idx: 0,
2314 ingress: "[2001:db8::1]:8000".to_string(),
2315 egress: "2001:db8::1".to_string(),
2316 },
2317 )?;
2318 let v = vc.validator_by_address(v1)?;
2319 assert_eq!(v.ingress, "[2001:db8::1]:8000");
2320
2321 Ok(())
2322 })
2323 }
2324
2325 #[test]
2326 fn test_set_ip_addresses_rejects_pre_init() -> eyre::Result<()> {
2327 let mut storage = HashMapStorageProvider::new(1);
2328 let owner = Address::random();
2329 let v1_addr = Address::random();
2330
2331 StorageCtx::enter(&mut storage, || {
2332 let mut v1 = v1();
2334 v1.initialize(owner)?;
2335 v1.add_validator(
2336 owner,
2337 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2338 newValidatorAddress: v1_addr,
2339 publicKey: FixedBytes::<32>::from([0x11; 32]),
2340 active: true,
2341 inboundAddress: "192.168.1.1:8000".to_string(),
2342 outboundAddress: "192.168.1.1:9000".to_string(),
2343 },
2344 )?;
2345
2346 let mut v2 = ValidatorConfigV2::new();
2348 v2.storage.set_block_number(100);
2349 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 })?;
2350
2351 let result = v2.set_ip_addresses(
2352 owner,
2353 IValidatorConfigV2::setIpAddressesCall {
2354 idx: 0,
2355 ingress: "10.0.0.1:8000".to_string(),
2356 egress: "10.0.0.1".to_string(),
2357 },
2358 );
2359
2360 assert_eq!(
2361 result,
2362 Err(ValidatorConfigV2Error::not_initialized().into())
2363 );
2364 Ok(())
2365 })
2366 }
2367
2368 #[test]
2369 fn test_rotate_removes_and_checks_ips() -> eyre::Result<()> {
2370 let mut storage = HashMapStorageProvider::new(1);
2371 let owner = Address::random();
2372 let v1 = Address::random();
2373 let v2 = Address::random();
2374
2375 StorageCtx::enter(&mut storage, || {
2376 let mut vc = ValidatorConfigV2::new();
2377 vc.initialize(owner)?;
2378
2379 vc.storage.set_block_number(200);
2380 vc.add_validator(
2381 owner,
2382 make_valid_add_call(v1, "192.168.1.1:8000", "192.168.1.1", v1),
2383 )?;
2384 vc.add_validator(
2385 owner,
2386 make_valid_add_call(v2, "192.168.2.1:8000", "192.168.2.1", v2),
2387 )?;
2388
2389 let (new_pk, sig) = make_test_keypair_and_signature(
2391 v1,
2392 "192.168.2.1:8000",
2393 "192.168.2.1",
2394 SignatureKind::Rotate,
2395 );
2396
2397 vc.storage.set_block_number(300);
2398 let result = vc.rotate_validator(
2399 owner,
2400 IValidatorConfigV2::rotateValidatorCall {
2401 idx: 0,
2402 publicKey: new_pk,
2403 ingress: "192.168.2.1:8000".to_string(),
2404 egress: "192.168.2.1".to_string(),
2405 signature: sig.into(),
2406 },
2407 );
2408
2409 assert!(result.is_err());
2410 Ok(())
2411 })
2412 }
2413
2414 #[test]
2415 fn test_migrate_skips_duplicate_ingress() -> eyre::Result<()> {
2416 let mut storage = HashMapStorageProvider::new(1);
2417 let owner = Address::random();
2418
2419 StorageCtx::enter(&mut storage, || {
2420 let mut v1 = v1();
2421 v1.initialize(owner)?;
2422 v1.add_validator(
2423 owner,
2424 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2425 newValidatorAddress: Address::random(),
2426 publicKey: FixedBytes::<32>::from([0x11; 32]),
2427 active: true,
2428 inboundAddress: "192.168.1.1:8000".to_string(),
2429 outboundAddress: "192.168.1.1:9000".to_string(),
2430 },
2431 )?;
2432 v1.add_validator(
2433 owner,
2434 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2435 newValidatorAddress: Address::random(),
2436 publicKey: FixedBytes::<32>::from([0x22; 32]),
2437 active: true,
2438 inboundAddress: "192.168.1.1:8000".to_string(),
2439 outboundAddress: "192.168.2.1:9000".to_string(),
2440 },
2441 )?;
2442
2443 let mut v2 = ValidatorConfigV2::new();
2444 v2.storage.set_block_number(100);
2445 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 1 })?;
2446
2447 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 })?;
2448 assert_eq!(v2.validator_count()?, 1);
2449 assert_eq!(v2.config.migration_skipped_count.read()?, 1);
2450
2451 v2.storage.set_block_number(400);
2452 v2.initialize_if_migrated(owner)?;
2453 assert!(v2.is_initialized()?);
2454
2455 Ok(())
2456 })
2457 }
2458
2459 #[test]
2460 fn test_migrate_skips_invalid_ed25519_pubkey() -> eyre::Result<()> {
2461 let mut storage = HashMapStorageProvider::new(1);
2462 let owner = Address::random();
2463
2464 StorageCtx::enter(&mut storage, || {
2465 let mut v1 = v1();
2466 v1.initialize(owner)?;
2467 v1.add_validator(
2468 owner,
2469 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2470 newValidatorAddress: Address::random(),
2471 publicKey: FixedBytes::<32>::from([0xDD; 32]),
2472 active: true,
2473 inboundAddress: "192.168.1.1:8000".to_string(),
2474 outboundAddress: "192.168.1.1:9000".to_string(),
2475 },
2476 )?;
2477 v1.add_validator(
2478 owner,
2479 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2480 newValidatorAddress: Address::random(),
2481 publicKey: FixedBytes::<32>::from([0x22; 32]),
2482 active: true,
2483 inboundAddress: "192.168.1.2:8000".to_string(),
2484 outboundAddress: "192.168.1.2:9000".to_string(),
2485 },
2486 )?;
2487
2488 let mut v2 = ValidatorConfigV2::new();
2489 v2.storage.set_block_number(100);
2490
2491 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 1 })?;
2492 assert_eq!(v2.validator_count()?, 1);
2493
2494 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 })?;
2495 assert_eq!(v2.validator_count()?, 1);
2496 assert_eq!(v2.config.migration_skipped_count.read()?, 1);
2497
2498 v2.storage.set_block_number(400);
2499 v2.initialize_if_migrated(owner)?;
2500 assert!(v2.is_initialized()?);
2501
2502 Ok(())
2503 })
2504 }
2505
2506 #[test]
2507 fn test_migrate_overwrites_duplicate_pubkey() -> eyre::Result<()> {
2508 let mut storage = HashMapStorageProvider::new(1);
2509 let owner = Address::random();
2510 let addr1 = Address::random();
2511 let addr2 = Address::random();
2512
2513 StorageCtx::enter(&mut storage, || {
2514 let mut v1 = v1();
2515 v1.initialize(owner)?;
2516 v1.add_validator(
2517 owner,
2518 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2519 newValidatorAddress: addr1,
2520 publicKey: FixedBytes::<32>::from([0x11; 32]),
2521 active: true,
2522 inboundAddress: "192.168.1.1:8000".to_string(),
2523 outboundAddress: "192.168.1.1:9000".to_string(),
2524 },
2525 )?;
2526 v1.add_validator(
2527 owner,
2528 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
2529 newValidatorAddress: addr2,
2530 publicKey: FixedBytes::<32>::from([0x11; 32]),
2531 active: true,
2532 inboundAddress: "192.168.1.2:8000".to_string(),
2533 outboundAddress: "192.168.1.2:9000".to_string(),
2534 },
2535 )?;
2536
2537 let mut v2 = ValidatorConfigV2::new();
2538 v2.storage.set_block_number(100);
2539
2540 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 1 })?;
2541 assert_eq!(v2.validator_count()?, 1);
2542
2543 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 })?;
2544 assert_eq!(v2.validator_count()?, 1);
2545 assert_eq!(v2.config.migration_skipped_count.read()?, 1);
2546
2547 let migrated = v2.validator_by_index(0)?;
2548 assert_eq!(migrated.validatorAddress, addr2);
2549 assert_eq!(migrated.ingress, "192.168.1.2:8000");
2550 assert_eq!(migrated.egress, "192.168.1.2");
2551
2552 v2.storage.set_block_number(400);
2553 v2.initialize_if_migrated(owner)?;
2554 assert!(v2.is_initialized()?);
2555
2556 Ok(())
2557 })
2558 }
2559
2560 #[test]
2561 fn test_add_validator_rejects_third_party() -> eyre::Result<()> {
2562 let mut storage = HashMapStorageProvider::new(1);
2563 let owner = Address::random();
2564 let validator = Address::random();
2565 let third_party = Address::random();
2566 StorageCtx::enter(&mut storage, || {
2567 let mut vc = ValidatorConfigV2::new();
2568 vc.initialize(owner)?;
2569
2570 vc.storage.set_block_number(200);
2571 vc.add_validator(
2572 owner,
2573 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
2574 )?;
2575
2576 let result = vc.set_ip_addresses(
2578 third_party,
2579 IValidatorConfigV2::setIpAddressesCall {
2580 idx: 0,
2581 ingress: "10.0.0.1:8000".to_string(),
2582 egress: "10.0.0.1".to_string(),
2583 },
2584 );
2585 assert_eq!(result, Err(ValidatorConfigV2Error::unauthorized().into()));
2586
2587 let result = vc.transfer_validator_ownership(
2588 third_party,
2589 IValidatorConfigV2::transferValidatorOwnershipCall {
2590 idx: 0,
2591 newAddress: Address::random(),
2592 },
2593 );
2594 assert_eq!(result, Err(ValidatorConfigV2Error::unauthorized().into()));
2595
2596 Ok(())
2597 })
2598 }
2599
2600 #[test]
2601 fn test_rotate_validator_to_different_ingress() -> eyre::Result<()> {
2602 let mut storage = HashMapStorageProvider::new(1);
2603 let owner = Address::random();
2604 let validator = Address::random();
2605 StorageCtx::enter(&mut storage, || {
2606 let mut vc = ValidatorConfigV2::new();
2607 vc.initialize(owner)?;
2608
2609 vc.storage.set_block_number(200);
2610 vc.add_validator(
2611 owner,
2612 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
2613 )?;
2614
2615 let (new_pubkey, new_sig) = make_test_keypair_and_signature(
2617 validator,
2618 "192.168.1.1:8001",
2619 "192.168.1.1",
2620 SignatureKind::Rotate,
2621 );
2622 vc.storage.set_block_number(300);
2623 vc.rotate_validator(
2624 owner,
2625 IValidatorConfigV2::rotateValidatorCall {
2626 idx: 0,
2627 publicKey: new_pubkey,
2628 ingress: "192.168.1.1:8001".to_string(),
2629 egress: "192.168.1.1".to_string(),
2630 signature: new_sig.into(),
2631 },
2632 )?;
2633
2634 assert_eq!(vc.validator_count()?, 2);
2635 assert_eq!(vc.validator_by_index(0)?.deactivatedAtHeight, 0);
2636 assert_eq!(vc.validator_by_index(1)?.deactivatedAtHeight, 300);
2637 assert_eq!(vc.validator_by_address(validator)?.publicKey, new_pubkey);
2638 assert_eq!(
2639 vc.validator_by_address(validator)?.ingress,
2640 "192.168.1.1:8001"
2641 );
2642 assert_eq!(vc.validator_by_address(validator)?.egress, "192.168.1.1");
2643
2644 Ok(())
2645 })
2646 }
2647
2648 #[test]
2649 fn test_rotate_validator_rejects_same_ingress() -> eyre::Result<()> {
2650 let mut storage = HashMapStorageProvider::new(1);
2651 let owner = Address::random();
2652 let validator = Address::random();
2653 StorageCtx::enter(&mut storage, || {
2654 let mut vc = ValidatorConfigV2::new();
2655 vc.initialize(owner)?;
2656
2657 vc.storage.set_block_number(200);
2658 vc.add_validator(
2659 owner,
2660 make_valid_add_call(
2661 validator,
2662 "192.168.1.1:8000",
2663 "192.168.1.1",
2664 Address::random(),
2665 ),
2666 )?;
2667
2668 let (new_pubkey, new_sig) = make_test_keypair_and_signature(
2670 validator,
2671 "192.168.1.1:8000",
2672 "192.168.1.1",
2673 SignatureKind::Rotate,
2674 );
2675 vc.storage.set_block_number(300);
2676 assert!(
2677 vc.rotate_validator(
2678 owner,
2679 IValidatorConfigV2::rotateValidatorCall {
2680 idx: 0,
2681 publicKey: new_pubkey,
2682 ingress: "192.168.1.1:8000".to_string(),
2683 egress: "192.168.1.1".to_string(),
2684 signature: new_sig.into(),
2685 },
2686 )
2687 .is_err()
2688 );
2689 Ok(())
2690 })
2691 }
2692
2693 #[test]
2694 fn test_set_ip_addresses_ingress_only() -> eyre::Result<()> {
2695 let mut storage = HashMapStorageProvider::new(1);
2696 let owner = Address::random();
2697 let validator = Address::random();
2698 StorageCtx::enter(&mut storage, || {
2699 let mut vc = ValidatorConfigV2::new();
2700 vc.initialize(owner)?;
2701
2702 vc.storage.set_block_number(200);
2703 vc.add_validator(
2704 owner,
2705 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
2706 )?;
2707
2708 vc.set_ip_addresses(
2710 owner,
2711 IValidatorConfigV2::setIpAddressesCall {
2712 idx: 0,
2713 ingress: "10.0.0.1:8000".to_string(),
2714 egress: "192.168.1.1".to_string(),
2715 },
2716 )?;
2717
2718 let v = vc.validator_by_address(validator)?;
2719 assert_eq!(v.ingress, "10.0.0.1:8000");
2720 assert_eq!(v.egress, "192.168.1.1");
2721
2722 Ok(())
2723 })
2724 }
2725
2726 #[test]
2727 fn test_set_ip_addresses_ingress_port_only() -> eyre::Result<()> {
2728 let mut storage = HashMapStorageProvider::new(1);
2729 let owner = Address::random();
2730 let validator = Address::random();
2731 StorageCtx::enter(&mut storage, || {
2732 let mut vc = ValidatorConfigV2::new();
2733 vc.initialize(owner)?;
2734
2735 vc.storage.set_block_number(200);
2736 vc.add_validator(
2737 owner,
2738 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
2739 )?;
2740
2741 vc.set_ip_addresses(
2743 owner,
2744 IValidatorConfigV2::setIpAddressesCall {
2745 idx: 0,
2746 ingress: "192.168.1.1:8001".to_string(),
2747 egress: "192.168.1.1".to_string(),
2748 },
2749 )?;
2750
2751 let v = vc.validator_by_address(validator)?;
2752 assert_eq!(v.ingress, "192.168.1.1:8001");
2753 assert_eq!(v.egress, "192.168.1.1");
2754
2755 Ok(())
2756 })
2757 }
2758
2759 #[test]
2760 fn test_set_ip_addresses_egress_only() -> eyre::Result<()> {
2761 let mut storage = HashMapStorageProvider::new(1);
2762 let owner = Address::random();
2763 let validator = Address::random();
2764 StorageCtx::enter(&mut storage, || {
2765 let mut vc = ValidatorConfigV2::new();
2766 vc.initialize(owner)?;
2767
2768 vc.storage.set_block_number(200);
2769 vc.add_validator(
2770 owner,
2771 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
2772 )?;
2773
2774 vc.set_ip_addresses(
2776 owner,
2777 IValidatorConfigV2::setIpAddressesCall {
2778 idx: 0,
2779 ingress: "192.168.1.1:8000".to_string(),
2780 egress: "10.0.0.1".to_string(),
2781 },
2782 )?;
2783
2784 let v = vc.validator_by_address(validator)?;
2785 assert_eq!(v.ingress, "192.168.1.1:8000");
2786 assert_eq!(v.egress, "10.0.0.1");
2787
2788 Ok(())
2789 })
2790 }
2791
2792 #[test]
2793 fn test_set_ip_addresses_rejects_duplicate_ingress() -> eyre::Result<()> {
2794 let mut storage = HashMapStorageProvider::new(1);
2795 let owner = Address::random();
2796 let v1 = Address::random();
2797 let v2 = Address::random();
2798 StorageCtx::enter(&mut storage, || {
2799 let mut vc = ValidatorConfigV2::new();
2800 vc.initialize(owner)?;
2801
2802 vc.storage.set_block_number(200);
2803 vc.add_validator(
2804 owner,
2805 make_valid_add_call(v1, "192.168.1.1:8000", "192.168.1.1", v1),
2806 )?;
2807 vc.add_validator(
2808 owner,
2809 make_valid_add_call(v2, "192.168.2.1:8000", "192.168.2.1", v2),
2810 )?;
2811
2812 let result = vc.set_ip_addresses(
2813 owner,
2814 IValidatorConfigV2::setIpAddressesCall {
2815 idx: 1,
2816 ingress: "192.168.1.1:8000".to_string(),
2817 egress: "192.168.2.1".to_string(),
2818 },
2819 );
2820
2821 assert!(result.is_err());
2822 Ok(())
2823 })
2824 }
2825
2826 #[test]
2827 fn test_set_ip_addresses_allows_same_ip_different_port() -> eyre::Result<()> {
2828 let mut storage = HashMapStorageProvider::new(1);
2829 let owner = Address::random();
2830 let validator = Address::random();
2831 StorageCtx::enter(&mut storage, || {
2832 let mut vc = ValidatorConfigV2::new();
2833 vc.initialize(owner)?;
2834
2835 vc.storage.set_block_number(200);
2836 vc.add_validator(
2837 owner,
2838 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
2839 )?;
2840
2841 vc.set_ip_addresses(
2842 owner,
2843 IValidatorConfigV2::setIpAddressesCall {
2844 idx: 0,
2845 ingress: "192.168.1.1:9000".to_string(),
2846 egress: "192.168.1.1".to_string(),
2847 },
2848 )?;
2849
2850 let v = vc.validator_by_address(validator)?;
2851 assert_eq!(v.ingress, "192.168.1.1:9000");
2852
2853 Ok(())
2854 })
2855 }
2856
2857 #[test]
2858 fn test_transfer_validator_ownership_by_validator() -> eyre::Result<()> {
2859 let mut storage = HashMapStorageProvider::new(1);
2860 let owner = Address::random();
2861 let validator = Address::random();
2862 let new_address = Address::random();
2863 StorageCtx::enter(&mut storage, || {
2864 let mut vc = ValidatorConfigV2::new();
2865 vc.initialize(owner)?;
2866
2867 vc.storage.set_block_number(200);
2868 vc.add_validator(
2869 owner,
2870 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
2871 )?;
2872
2873 vc.transfer_validator_ownership(
2875 validator,
2876 IValidatorConfigV2::transferValidatorOwnershipCall {
2877 idx: 0,
2878 newAddress: new_address,
2879 },
2880 )?;
2881
2882 let result = vc.validator_by_address(validator);
2883 assert_eq!(
2884 result,
2885 Err(ValidatorConfigV2Error::validator_not_found().into())
2886 );
2887
2888 let v = vc.validator_by_address(new_address)?;
2889 assert_eq!(v.validatorAddress, new_address);
2890
2891 Ok(())
2892 })
2893 }
2894
2895 #[test]
2896 fn test_add_validator_rejects_deleted_pubkey() -> eyre::Result<()> {
2897 let mut storage = HashMapStorageProvider::new(1);
2898 let owner = Address::random();
2899 StorageCtx::enter(&mut storage, || {
2900 let mut vc = ValidatorConfigV2::new();
2901 vc.initialize(owner)?;
2902
2903 let addr1 = Address::random();
2904 let (pubkey, sig) = make_test_keypair_and_signature(
2905 addr1,
2906 "192.168.1.1:8000",
2907 "192.168.1.1",
2908 SignatureKind::Add {
2909 fee_recipient: addr1,
2910 },
2911 );
2912 vc.storage.set_block_number(200);
2913 vc.add_validator(
2914 owner,
2915 make_add_call(addr1, pubkey, "192.168.1.1:8000", "192.168.1.1", addr1, sig),
2916 )?;
2917
2918 vc.storage.set_block_number(300);
2920 vc.deactivate_validator(
2921 owner,
2922 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
2923 )?;
2924
2925 let addr2 = Address::random();
2927 let result = vc.add_validator(
2928 owner,
2929 make_add_call(
2930 addr2,
2931 pubkey,
2932 "192.168.2.1:8000",
2933 "192.168.2.1",
2934 addr2,
2935 vec![0u8; 64],
2936 ),
2937 );
2938 assert_eq!(
2939 result,
2940 Err(ValidatorConfigV2Error::public_key_already_exists().into())
2941 );
2942
2943 Ok(())
2944 })
2945 }
2946
2947 #[test]
2948 fn test_add_validator_with_ipv6() -> eyre::Result<()> {
2949 let mut storage = HashMapStorageProvider::new(1);
2950 let owner = Address::random();
2951 let validator = Address::random();
2952 StorageCtx::enter(&mut storage, || {
2953 let mut vc = ValidatorConfigV2::new();
2954 vc.initialize(owner)?;
2955
2956 vc.storage.set_block_number(200);
2958 vc.add_validator(
2959 owner,
2960 make_valid_add_call(validator, "[::1]:8000", "::1", validator),
2961 )?;
2962
2963 assert_eq!(vc.validator_count()?, 1);
2964 let v = vc.validator_by_index(0)?;
2965 assert_eq!(v.validatorAddress, validator);
2966 assert_eq!(v.ingress, "[::1]:8000");
2967 assert_eq!(v.egress, "::1");
2968
2969 Ok(())
2970 })
2971 }
2972
2973 #[test]
2974 fn test_add_validator_rejects_duplicate_ingress_ipv6() -> eyre::Result<()> {
2975 let mut storage = HashMapStorageProvider::new(1);
2976 let owner = Address::random();
2977 StorageCtx::enter(&mut storage, || {
2978 let mut vc = ValidatorConfigV2::new();
2979 vc.initialize(owner)?;
2980
2981 vc.storage.set_block_number(200);
2982 vc.add_validator(
2983 owner,
2984 make_valid_add_call(
2985 Address::random(),
2986 "[2001:db8::1]:8000",
2987 "2001:db8::1",
2988 Address::random(),
2989 ),
2990 )?;
2991
2992 vc.storage.set_block_number(201);
2994 let result = vc.add_validator(
2995 owner,
2996 make_valid_add_call(
2997 Address::random(),
2998 "[2001:db8::1]:8000",
2999 "2001:db8::2",
3000 Address::random(),
3001 ),
3002 );
3003
3004 assert!(result.is_err());
3005 Ok(())
3006 })
3007 }
3008
3009 #[test]
3010 fn test_ipv6_reuse_after_deactivation() -> eyre::Result<()> {
3011 let mut storage = HashMapStorageProvider::new(1);
3012 let owner = Address::random();
3013 let v1 = Address::random();
3014 StorageCtx::enter(&mut storage, || {
3015 let mut vc = ValidatorConfigV2::new();
3016 vc.initialize(owner)?;
3017
3018 vc.storage.set_block_number(200);
3019 vc.add_validator(
3020 owner,
3021 make_valid_add_call(v1, "[2001:db8::1]:8000", "2001:db8::1", v1),
3022 )?;
3023
3024 vc.storage.set_block_number(300);
3025 vc.deactivate_validator(
3026 owner,
3027 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
3028 )?;
3029
3030 vc.storage.set_block_number(400);
3032 vc.add_validator(
3033 owner,
3034 make_valid_add_call(
3035 Address::random(),
3036 "[2001:db8::1]:8000",
3037 "2001:db8::1",
3038 Address::random(),
3039 ),
3040 )?;
3041
3042 Ok(())
3043 })
3044 }
3045
3046 #[test]
3047 fn test_rotate_validator_with_ipv6() -> eyre::Result<()> {
3048 let mut storage = HashMapStorageProvider::new(1);
3049 let owner = Address::random();
3050 let validator = Address::random();
3051 StorageCtx::enter(&mut storage, || {
3052 let mut vc = ValidatorConfigV2::new();
3053 vc.initialize(owner)?;
3054
3055 vc.storage.set_block_number(200);
3057 vc.add_validator(
3058 owner,
3059 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", validator),
3060 )?;
3061
3062 let (new_pubkey, new_sig) = make_test_keypair_and_signature(
3064 validator,
3065 "[2001:db8::1]:8000",
3066 "2001:db8::1",
3067 SignatureKind::Rotate,
3068 );
3069 vc.storage.set_block_number(300);
3070 vc.rotate_validator(
3071 owner,
3072 IValidatorConfigV2::rotateValidatorCall {
3073 idx: 0,
3074 publicKey: new_pubkey,
3075 ingress: "[2001:db8::1]:8000".to_string(),
3076 egress: "2001:db8::1".to_string(),
3077 signature: new_sig.into(),
3078 },
3079 )?;
3080
3081 assert_eq!(vc.validator_count()?, 2);
3082 let updated = vc.validator_by_index(0)?;
3083 assert_eq!(updated.deactivatedAtHeight, 0);
3084 assert_eq!(updated.ingress, "[2001:db8::1]:8000");
3085 assert_eq!(updated.egress, "2001:db8::1");
3086
3087 let snapshot = vc.validator_by_index(1)?;
3088 assert_eq!(snapshot.deactivatedAtHeight, 300);
3089
3090 Ok(())
3091 })
3092 }
3093
3094 #[test]
3095 fn test_ipv6_canonical_representation() -> eyre::Result<()> {
3096 let mut storage = HashMapStorageProvider::new(1);
3097 let owner = Address::random();
3098 StorageCtx::enter(&mut storage, || {
3099 let mut vc = ValidatorConfigV2::new();
3100 vc.initialize(owner)?;
3101
3102 vc.storage.set_block_number(200);
3104 vc.add_validator(
3105 owner,
3106 make_valid_add_call(Address::random(), "[::1]:8000", "::1", Address::random()),
3107 )?;
3108
3109 vc.storage.set_block_number(201);
3112 let result = vc.add_validator(
3113 owner,
3114 make_valid_add_call(
3115 Address::random(),
3116 "[0:0:0:0:0:0:0:1]:8000",
3117 "::1",
3118 Address::random(),
3119 ),
3120 );
3121
3122 assert!(
3123 result.is_err(),
3124 "Different IPv6 notations of same IP should be rejected"
3125 );
3126
3127 vc.storage.set_block_number(202);
3129 let result = vc.add_validator(
3130 owner,
3131 make_valid_add_call(Address::random(), "[::1%0]:8000", "::1", Address::random()),
3132 );
3133
3134 assert!(
3135 result.is_err(),
3136 "Different IPv6 notations of same IP should be rejected"
3137 );
3138
3139 vc.storage.set_block_number(203);
3141 let result = vc.add_validator(
3142 owner,
3143 make_valid_add_call(Address::random(), "[::1%1]:8000", "::1", Address::random()),
3144 );
3145 assert!(result.is_ok());
3146
3147 Ok(())
3148 })
3149 }
3150
3151 #[test]
3152 fn test_add_validator_rejects_wrong_key_signature() -> eyre::Result<()> {
3153 let mut storage = HashMapStorageProvider::new(1);
3154 let owner = Address::random();
3155 let validator = Address::random();
3156 let fee_recipient = Address::random();
3157 StorageCtx::enter(&mut storage, || {
3158 let mut vc = ValidatorConfigV2::new();
3159 vc.initialize(owner)?;
3160
3161 let (pubkey, _) = make_test_keypair_and_signature(
3163 validator,
3164 "192.168.1.1:8000",
3165 "192.168.1.1",
3166 SignatureKind::Add { fee_recipient },
3167 );
3168
3169 let (_, wrong_sig) = make_test_keypair_and_signature(
3171 validator,
3172 "192.168.1.1:8000",
3173 "192.168.1.1",
3174 SignatureKind::Add { fee_recipient },
3175 );
3176
3177 vc.storage.set_block_number(200);
3178 let result = vc.add_validator(
3179 owner,
3180 make_add_call(
3181 validator,
3182 pubkey,
3183 "192.168.1.1:8000",
3184 "192.168.1.1",
3185 fee_recipient,
3186 wrong_sig,
3187 ),
3188 );
3189 assert_eq!(
3190 result,
3191 Err(ValidatorConfigV2Error::invalid_signature().into())
3192 );
3193
3194 Ok(())
3195 })
3196 }
3197
3198 #[test]
3199 fn test_add_validator_rejects_wrong_namespace_signature() -> eyre::Result<()> {
3200 let mut storage = HashMapStorageProvider::new(1);
3201 let owner = Address::random();
3202 let validator = Address::random();
3203 let fee_recipient = Address::random();
3204 StorageCtx::enter(&mut storage, || {
3205 let mut vc = ValidatorConfigV2::new();
3206 vc.initialize(owner)?;
3207
3208 let (pubkey, sig) = make_test_keypair_and_signature(
3210 validator,
3211 "192.168.1.1:8000",
3212 "192.168.1.1",
3213 SignatureKind::Rotate,
3214 );
3215
3216 vc.storage.set_block_number(200);
3217 let result = vc.add_validator(
3218 owner,
3219 make_add_call(
3220 validator,
3221 pubkey,
3222 "192.168.1.1:8000",
3223 "192.168.1.1",
3224 fee_recipient,
3225 sig,
3226 ),
3227 );
3228 assert_eq!(
3229 result,
3230 Err(ValidatorConfigV2Error::invalid_signature().into())
3231 );
3232
3233 Ok(())
3234 })
3235 }
3236
3237 #[test]
3238 fn test_rotate_validator_rejects_wrong_key_signature() -> eyre::Result<()> {
3239 let mut storage = HashMapStorageProvider::new(1);
3240 let owner = Address::random();
3241 let validator = Address::random();
3242 let fee_recipient = Address::random();
3243 StorageCtx::enter(&mut storage, || {
3244 let mut vc = ValidatorConfigV2::new();
3245 vc.initialize(owner)?;
3246
3247 vc.storage.set_block_number(200);
3249 vc.add_validator(
3250 owner,
3251 make_valid_add_call(validator, "192.168.1.1:8000", "192.168.1.1", fee_recipient),
3252 )?;
3253
3254 let (new_pubkey, _) = make_test_keypair_and_signature(
3256 validator,
3257 "10.0.0.1:8000",
3258 "10.0.0.1",
3259 SignatureKind::Rotate,
3260 );
3261
3262 let (_, wrong_sig) = make_test_keypair_and_signature(
3264 validator,
3265 "10.0.0.1:8000",
3266 "10.0.0.1",
3267 SignatureKind::Rotate,
3268 );
3269
3270 vc.storage.set_block_number(300);
3271 let result = vc.rotate_validator(
3272 owner,
3273 IValidatorConfigV2::rotateValidatorCall {
3274 idx: 0,
3275 publicKey: new_pubkey,
3276 ingress: "10.0.0.1:8000".to_string(),
3277 egress: "10.0.0.1".to_string(),
3278 signature: wrong_sig.into(),
3279 },
3280 );
3281 assert_eq!(
3282 result,
3283 Err(ValidatorConfigV2Error::invalid_signature().into())
3284 );
3285
3286 Ok(())
3287 })
3288 }
3289
3290 #[test]
3291 fn test_add_validator_rejects_malformed_signature() -> eyre::Result<()> {
3292 let mut storage = HashMapStorageProvider::new(1);
3293 let owner = Address::random();
3294 let validator = Address::random();
3295 let fee_recipient = Address::random();
3296 StorageCtx::enter(&mut storage, || {
3297 let mut vc = ValidatorConfigV2::new();
3298 vc.initialize(owner)?;
3299
3300 let (pubkey, _) = make_test_keypair_and_signature(
3301 validator,
3302 "192.168.1.1:8000",
3303 "192.168.1.1",
3304 SignatureKind::Add { fee_recipient },
3305 );
3306
3307 vc.storage.set_block_number(200);
3308 let result = vc.add_validator(
3309 owner,
3310 make_add_call(
3311 validator,
3312 pubkey,
3313 "192.168.1.1:8000",
3314 "192.168.1.1",
3315 fee_recipient,
3316 vec![0xde, 0xad],
3317 ),
3318 );
3319 assert_eq!(
3320 result,
3321 Err(ValidatorConfigV2Error::invalid_signature_format().into())
3322 );
3323
3324 Ok(())
3325 })
3326 }
3327
3328 #[test]
3329 fn test_ipv4_ipv6_different_ips() -> eyre::Result<()> {
3330 let mut storage = HashMapStorageProvider::new(1);
3331 let owner = Address::random();
3332 StorageCtx::enter(&mut storage, || {
3333 let mut vc = ValidatorConfigV2::new();
3334 vc.initialize(owner)?;
3335
3336 vc.storage.set_block_number(200);
3338 vc.add_validator(
3339 owner,
3340 make_valid_add_call(
3341 Address::random(),
3342 "192.168.1.1:8000",
3343 "192.168.1.1",
3344 Address::random(),
3345 ),
3346 )?;
3347
3348 vc.storage.set_block_number(201);
3350 vc.add_validator(
3351 owner,
3352 make_valid_add_call(
3353 Address::random(),
3354 "[2001:db8::1]:8000",
3355 "2001:db8::1",
3356 Address::random(),
3357 ),
3358 )?;
3359
3360 assert_eq!(vc.validator_count()?, 2);
3361 Ok(())
3362 })
3363 }
3364
3365 #[test]
3366 fn test_event_emission_owner_and_validator_actions() -> eyre::Result<()> {
3367 let mut storage = HashMapStorageProvider::new(1);
3368 let owner = Address::random();
3369 let validator = Address::random();
3370 let new_validator_address = Address::random();
3371
3372 StorageCtx::enter(&mut storage, || {
3373 let mut vc = ValidatorConfigV2::new();
3374 vc.initialize(owner)?;
3375
3376 let (pubkey, signature) = make_test_keypair_and_signature(
3377 validator,
3378 "192.168.1.1:8000",
3379 "192.168.1.1",
3380 SignatureKind::Add {
3381 fee_recipient: validator,
3382 },
3383 );
3384
3385 vc.storage.set_block_number(100);
3386 vc.add_validator(
3387 owner,
3388 make_add_call(
3389 validator,
3390 pubkey,
3391 "192.168.1.1:8000",
3392 "192.168.1.1",
3393 validator,
3394 signature,
3395 ),
3396 )?;
3397 vc.assert_emitted_events(vec![ValidatorConfigV2Event::validator_added(
3398 0,
3399 validator,
3400 pubkey,
3401 "192.168.1.1:8000".to_string(),
3402 "192.168.1.1".to_string(),
3403 validator,
3404 )]);
3405
3406 vc.clear_emitted_events();
3407 vc.set_ip_addresses(
3408 validator,
3409 IValidatorConfigV2::setIpAddressesCall {
3410 idx: 0,
3411 ingress: "10.0.0.1:8000".to_string(),
3412 egress: "10.0.0.1".to_string(),
3413 },
3414 )?;
3415 vc.assert_emitted_events(vec![ValidatorConfigV2Event::ip_addresses_updated(
3416 0,
3417 "10.0.0.1:8000".to_string(),
3418 "10.0.0.1".to_string(),
3419 validator,
3420 )]);
3421
3422 vc.clear_emitted_events();
3423 vc.transfer_validator_ownership(
3424 owner,
3425 IValidatorConfigV2::transferValidatorOwnershipCall {
3426 idx: 0,
3427 newAddress: new_validator_address,
3428 },
3429 )?;
3430 vc.assert_emitted_events(vec![
3431 ValidatorConfigV2Event::validator_ownership_transferred(
3432 0,
3433 validator,
3434 new_validator_address,
3435 owner,
3436 ),
3437 ]);
3438
3439 vc.clear_emitted_events();
3440 vc.deactivate_validator(
3441 new_validator_address,
3442 IValidatorConfigV2::deactivateValidatorCall { idx: 0 },
3443 )?;
3444 vc.assert_emitted_events(vec![ValidatorConfigV2Event::validator_deactivated(
3445 0,
3446 new_validator_address,
3447 )]);
3448
3449 vc.clear_emitted_events();
3450 let new_owner = Address::random();
3451 vc.transfer_ownership(
3452 owner,
3453 IValidatorConfigV2::transferOwnershipCall {
3454 newOwner: new_owner,
3455 },
3456 )?;
3457 vc.assert_emitted_events(vec![ValidatorConfigV2Event::ownership_transferred(
3458 owner, new_owner,
3459 )]);
3460
3461 Ok(())
3462 })
3463 }
3464
3465 #[test]
3466 fn test_event_emission_rotate_and_next_dkg() -> eyre::Result<()> {
3467 let mut storage = HashMapStorageProvider::new(1);
3468 let owner = Address::random();
3469 let validator = Address::random();
3470
3471 StorageCtx::enter(&mut storage, || {
3472 let mut vc = ValidatorConfigV2::new();
3473 vc.initialize(owner)?;
3474
3475 let (old_pubkey, old_sig) = make_test_keypair_and_signature(
3476 validator,
3477 "192.168.1.1:8000",
3478 "192.168.1.1",
3479 SignatureKind::Add {
3480 fee_recipient: validator,
3481 },
3482 );
3483
3484 vc.storage.set_block_number(200);
3485 vc.add_validator(
3486 owner,
3487 make_add_call(
3488 validator,
3489 old_pubkey,
3490 "192.168.1.1:8000",
3491 "192.168.1.1",
3492 validator,
3493 old_sig,
3494 ),
3495 )?;
3496
3497 vc.clear_emitted_events();
3498 let (new_pubkey, new_sig) = make_test_keypair_and_signature(
3499 validator,
3500 "10.0.0.2:8000",
3501 "10.0.0.2",
3502 SignatureKind::Rotate,
3503 );
3504 vc.storage.set_block_number(300);
3505 vc.rotate_validator(
3506 owner,
3507 IValidatorConfigV2::rotateValidatorCall {
3508 idx: 0,
3509 publicKey: new_pubkey,
3510 ingress: "10.0.0.2:8000".to_string(),
3511 egress: "10.0.0.2".to_string(),
3512 signature: new_sig.into(),
3513 },
3514 )?;
3515 vc.assert_emitted_events(vec![ValidatorConfigV2Event::validator_rotated(
3516 0,
3517 1,
3518 validator,
3519 old_pubkey,
3520 new_pubkey,
3521 "10.0.0.2:8000".to_string(),
3522 "10.0.0.2".to_string(),
3523 owner,
3524 )]);
3525
3526 vc.clear_emitted_events();
3527 vc.set_network_identity_rotation_epoch(
3528 owner,
3529 IValidatorConfigV2::setNetworkIdentityRotationEpochCall { epoch: 42 },
3530 )?;
3531 vc.assert_emitted_events(vec![
3532 ValidatorConfigV2Event::network_identity_rotation_epoch_set(0, 42),
3533 ]);
3534
3535 Ok(())
3536 })
3537 }
3538
3539 #[test]
3540 fn test_event_emission_migration_and_initialize() -> eyre::Result<()> {
3541 let mut storage = HashMapStorageProvider::new(1);
3542 let owner = Address::random();
3543 let v1_addr = Address::random();
3544 let v1_pk = FixedBytes::<32>::from([0x11; 32]);
3545
3546 StorageCtx::enter(&mut storage, || {
3547 let mut v1 = v1();
3548 v1.initialize(owner)?;
3549 v1.add_validator(
3550 owner,
3551 tempo_contracts::precompiles::IValidatorConfig::addValidatorCall {
3552 newValidatorAddress: v1_addr,
3553 publicKey: v1_pk,
3554 active: true,
3555 inboundAddress: "192.168.1.1:8000".to_string(),
3556 outboundAddress: "192.168.1.1:9000".to_string(),
3557 },
3558 )?;
3559
3560 let mut v2 = ValidatorConfigV2::new();
3561 v2.storage.set_block_number(500);
3562 v2.migrate_validator(owner, IValidatorConfigV2::migrateValidatorCall { idx: 0 })?;
3563 v2.assert_emitted_events(vec![ValidatorConfigV2Event::validator_migrated(
3564 0, v1_addr, v1_pk,
3565 )]);
3566
3567 v2.clear_emitted_events();
3568 v2.storage.set_block_number(700);
3569 v2.initialize_if_migrated(owner)?;
3570 v2.assert_emitted_events(vec![ValidatorConfigV2Event::initialized(700)]);
3571
3572 Ok(())
3573 })
3574 }
3575}