Skip to content

Commit 93b2167

Browse files
committed
Add tests for determine_global_state and determine_global_burn_view
Signed-off-by: Jacinta Ferrant <[email protected]>
1 parent 9ef0747 commit 93b2167

File tree

1 file changed

+207
-80
lines changed

1 file changed

+207
-80
lines changed

stacks-signer/src/v0/signer_state.rs

Lines changed: 207 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,9 @@ impl GlobalStateEvaluator {
115115
..
116116
} = update.content;
117117

118-
let entry = burn_blocks.entry(burn_block).or_insert_with(|| 0);
118+
let entry = burn_blocks
119+
.entry((burn_block, burn_block_height))
120+
.or_insert_with(|| 0);
119121
*entry += weight;
120122
if self.reached_agreement(*entry) {
121123
return Some((burn_block, burn_block_height));
@@ -160,38 +162,6 @@ impl GlobalStateEvaluator {
160162
None
161163
}
162164

163-
/// Check if there is an agreed upon global current miner viewpoint
164-
pub fn determine_global_current_miner(
165-
&mut self,
166-
local_address: StacksAddress,
167-
local_update: StateMachineUpdateMessage,
168-
) -> Option<StateMachineUpdateMinerState> {
169-
let (global_burn_block, _) =
170-
self.determine_global_burn_view(local_address, local_update)?;
171-
let mut miner_views = HashMap::new();
172-
for (address, update) in &self.address_updates {
173-
let Some(weight) = self.address_weights.get(address) else {
174-
continue;
175-
};
176-
let StateMachineUpdateContent::V0 {
177-
burn_block,
178-
current_miner,
179-
..
180-
} = &update.content;
181-
182-
if *burn_block != global_burn_block {
183-
continue;
184-
}
185-
186-
let entry = miner_views.entry(current_miner).or_insert_with(|| 0);
187-
*entry += weight;
188-
if self.reached_agreement(*entry) {
189-
return Some(current_miner.clone());
190-
}
191-
}
192-
None
193-
}
194-
195165
/// Determines whether a signer with the `local_address` and `local_update` should
196166
/// should capitulate its current miner view to a new state. This is not necessarily the same as the current global view
197167
/// of the miner as it is up to signers to capitulate before this becomes the finalized view.
@@ -856,30 +826,12 @@ mod tests {
856826

857827
use super::*;
858828

859-
fn generate_random_address_with_equal_weights(
860-
num_addresses: u32,
861-
) -> HashMap<StacksAddress, u32> {
862-
let mut address_weights = HashMap::new();
863-
for _ in 0..num_addresses {
864-
let stacks_address = StacksAddress::p2pkh(
865-
false,
866-
&StacksPublicKey::from_private(&StacksPrivateKey::random()),
867-
);
868-
address_weights.insert(stacks_address, 10);
869-
}
870-
address_weights
871-
}
872-
873-
#[test]
874-
fn determine_latest_supported_signer_protocol_versions() {
875-
let address_weights = generate_random_address_with_equal_weights(5);
829+
fn generate_global_state_evaluator(num_addresses: u32) -> GlobalStateEvaluator {
830+
let address_weights = generate_random_address_with_equal_weights(num_addresses);
876831
let active_protocol_version = 0;
877832
let local_supported_signer_protocol_version = 1;
878833

879-
let addresses: Vec<_> = address_weights.keys().cloned().collect();
880-
let local_address = addresses[0];
881-
882-
let local_update = StateMachineUpdateMessage::new(
834+
let update = StateMachineUpdateMessage::new(
883835
active_protocol_version,
884836
local_supported_signer_protocol_version,
885837
StateMachineUpdateContent::V0 {
@@ -897,37 +849,74 @@ mod tests {
897849
.unwrap();
898850

899851
let mut address_updates = HashMap::new();
900-
for address in &addresses {
901-
address_updates.insert(*address, local_update.clone());
852+
for address in address_weights.keys() {
853+
address_updates.insert(*address, update.clone());
902854
}
855+
GlobalStateEvaluator::new(address_updates, address_weights)
856+
}
903857

904-
let mut global_eval = GlobalStateEvaluator::new(address_updates, address_weights);
858+
fn generate_random_address_with_equal_weights(
859+
num_addresses: u32,
860+
) -> HashMap<StacksAddress, u32> {
861+
let mut address_weights = HashMap::new();
862+
for _ in 0..num_addresses {
863+
let stacks_address = StacksAddress::p2pkh(
864+
false,
865+
&StacksPublicKey::from_private(&StacksPrivateKey::random()),
866+
);
867+
address_weights.insert(stacks_address, 10);
868+
}
869+
address_weights
870+
}
871+
872+
#[test]
873+
fn determine_latest_supported_signer_protocol_versions() {
874+
let mut global_eval = generate_global_state_evaluator(5);
875+
876+
let addresses: Vec<_> = global_eval.address_weights.keys().cloned().collect();
877+
let local_address = addresses[0];
878+
879+
let local_update = global_eval
880+
.address_updates
881+
.get(&local_address)
882+
.unwrap()
883+
.clone();
905884
assert_eq!(
906885
global_eval
907886
.determine_latest_supported_signer_protocol_version(
908887
local_address,
909-
local_update.clone()
888+
global_eval
889+
.address_updates
890+
.get(&local_address)
891+
.unwrap()
892+
.clone(),
910893
)
911894
.unwrap(),
912-
local_supported_signer_protocol_version
895+
local_update.local_supported_signer_protocol_version
913896
);
914897

898+
let StateMachineUpdateMessage {
899+
active_signer_protocol_version,
900+
local_supported_signer_protocol_version,
901+
content:
902+
StateMachineUpdateContent::V0 {
903+
burn_block,
904+
burn_block_height,
905+
current_miner,
906+
},
907+
..
908+
} = local_update.clone();
909+
915910
// Let's update 3 signers (60 percent) to support seperate but greater protocol versions
916911
for (i, address) in addresses.into_iter().skip(1).take(3).enumerate() {
917-
let new_version = local_supported_signer_protocol_version + i as u64 + 1;
912+
let new_version = local_update.local_supported_signer_protocol_version + i as u64 + 1;
918913
let new_update = StateMachineUpdateMessage::new(
919-
0,
914+
active_signer_protocol_version,
920915
new_version,
921916
StateMachineUpdateContent::V0 {
922-
burn_block: ConsensusHash([0x55; 20]),
923-
burn_block_height: 100,
924-
current_miner: StateMachineUpdateMinerState::ActiveMiner {
925-
current_miner_pkh: Hash160([0xab; 20]),
926-
tenure_id: ConsensusHash([0x44; 20]),
927-
parent_tenure_id: ConsensusHash([0x22; 20]),
928-
parent_tenure_last_block: StacksBlockId([0x33; 32]),
929-
parent_tenure_last_block_height: 1,
930-
},
917+
burn_block,
918+
burn_block_height,
919+
current_miner: current_miner.clone(),
931920
},
932921
)
933922
.unwrap();
@@ -944,18 +933,12 @@ mod tests {
944933
// Let's tip the scales over to version number 2 by updating the local signer's version...
945934
// i.e. > 70% will have version 2 or higher in their map
946935
let local_update = StateMachineUpdateMessage::new(
947-
active_protocol_version,
936+
active_signer_protocol_version,
948937
3,
949938
StateMachineUpdateContent::V0 {
950-
burn_block: ConsensusHash([0x55; 20]),
951-
burn_block_height: 100,
952-
current_miner: StateMachineUpdateMinerState::ActiveMiner {
953-
current_miner_pkh: Hash160([0xab; 20]),
954-
tenure_id: ConsensusHash([0x44; 20]),
955-
parent_tenure_id: ConsensusHash([0x22; 20]),
956-
parent_tenure_last_block: StacksBlockId([0x33; 32]),
957-
parent_tenure_last_block_height: 1,
958-
},
939+
burn_block,
940+
burn_block_height,
941+
current_miner,
959942
},
960943
)
961944
.unwrap();
@@ -967,4 +950,148 @@ mod tests {
967950
local_supported_signer_protocol_version + 1
968951
);
969952
}
953+
954+
#[test]
955+
fn determine_global_burn_views() {
956+
let mut global_eval = generate_global_state_evaluator(5);
957+
958+
let addresses: Vec<_> = global_eval.address_weights.keys().cloned().collect();
959+
let local_address = addresses[0];
960+
let local_update = global_eval
961+
.address_updates
962+
.get(&local_address)
963+
.unwrap()
964+
.clone();
965+
let StateMachineUpdateMessage {
966+
active_signer_protocol_version,
967+
local_supported_signer_protocol_version,
968+
content:
969+
StateMachineUpdateContent::V0 {
970+
burn_block,
971+
burn_block_height,
972+
current_miner,
973+
},
974+
..
975+
} = local_update.clone();
976+
977+
assert_eq!(
978+
global_eval
979+
.determine_global_burn_view(local_address, local_update.clone(),)
980+
.unwrap(),
981+
(burn_block, burn_block_height)
982+
);
983+
984+
// Let's update 3 signers (60 percent) to support a new burn block view
985+
let new_update = StateMachineUpdateMessage::new(
986+
active_signer_protocol_version,
987+
local_supported_signer_protocol_version,
988+
StateMachineUpdateContent::V0 {
989+
burn_block,
990+
burn_block_height: burn_block_height.wrapping_add(1),
991+
current_miner: current_miner.clone(),
992+
},
993+
)
994+
.unwrap();
995+
for address in addresses.into_iter().skip(1).take(3) {
996+
global_eval.insert_update(address, new_update.clone());
997+
}
998+
999+
assert!(
1000+
global_eval
1001+
.determine_global_burn_view(local_address, local_update,)
1002+
.is_none(),
1003+
"We should not have reached agreement on the burn block height"
1004+
);
1005+
1006+
// Let's tip the scales over to burn block height + 1
1007+
assert_eq!(
1008+
global_eval
1009+
.determine_global_burn_view(local_address, new_update,)
1010+
.unwrap(),
1011+
(burn_block, burn_block_height.wrapping_add(1))
1012+
);
1013+
}
1014+
1015+
#[test]
1016+
fn determine_global_states() {
1017+
let mut global_eval = generate_global_state_evaluator(5);
1018+
1019+
let addresses: Vec<_> = global_eval.address_weights.keys().cloned().collect();
1020+
let local_address = addresses[0];
1021+
let local_update = global_eval
1022+
.address_updates
1023+
.get(&local_address)
1024+
.unwrap()
1025+
.clone();
1026+
let StateMachineUpdateMessage {
1027+
active_signer_protocol_version,
1028+
local_supported_signer_protocol_version,
1029+
content:
1030+
StateMachineUpdateContent::V0 {
1031+
burn_block,
1032+
burn_block_height,
1033+
current_miner,
1034+
},
1035+
..
1036+
} = local_update.clone();
1037+
1038+
let state_machine = SignerStateMachine {
1039+
burn_block,
1040+
burn_block_height,
1041+
current_miner: (&current_miner).into(),
1042+
active_signer_protocol_version: local_supported_signer_protocol_version, // a majority of signers are saying they support version the same local_supported_signer_protocol_version, so update it here...
1043+
};
1044+
1045+
assert_eq!(
1046+
global_eval
1047+
.determine_global_state(local_address, local_update.clone(),)
1048+
.unwrap(),
1049+
state_machine
1050+
);
1051+
let new_miner = StateMachineUpdateMinerState::ActiveMiner {
1052+
current_miner_pkh: Hash160([0x00; 20]),
1053+
tenure_id: ConsensusHash([0x44; 20]),
1054+
parent_tenure_id: ConsensusHash([0x22; 20]),
1055+
parent_tenure_last_block: StacksBlockId([0x33; 32]),
1056+
parent_tenure_last_block_height: 1,
1057+
};
1058+
1059+
let new_update = StateMachineUpdateMessage::new(
1060+
active_signer_protocol_version,
1061+
local_supported_signer_protocol_version,
1062+
StateMachineUpdateContent::V0 {
1063+
burn_block,
1064+
burn_block_height,
1065+
current_miner: new_miner.clone(),
1066+
},
1067+
)
1068+
.unwrap();
1069+
1070+
// Let's update 3 signers to some new miner key (60 percent)
1071+
for address in addresses.into_iter().skip(1).take(3) {
1072+
global_eval.insert_update(address, new_update.clone());
1073+
}
1074+
1075+
assert!(
1076+
global_eval
1077+
.determine_global_state(local_address, local_update,)
1078+
.is_none(),
1079+
"We should have a disagreement about the current miner"
1080+
);
1081+
1082+
let state_machine = SignerStateMachine {
1083+
burn_block,
1084+
burn_block_height,
1085+
current_miner: (&new_miner).into(),
1086+
active_signer_protocol_version: local_supported_signer_protocol_version, // a majority of signers are saying they support version the same local_supported_signer_protocol_version, so update it here...
1087+
};
1088+
1089+
// Let's tip the scales over to a different miner
1090+
assert_eq!(
1091+
global_eval
1092+
.determine_global_state(local_address, new_update,)
1093+
.unwrap(),
1094+
state_machine
1095+
)
1096+
}
9701097
}

0 commit comments

Comments
 (0)