Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 80 additions & 68 deletions packages/wasm-sdk/src/queries/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,55 +16,105 @@ use wasm_dpp2::{ProTxHashLikeNullableJs, ProTxHashWasm};
pub struct ProtocolVersionUpgradeStateWasm {
current_protocol_version: u32,
next_protocol_version: Option<u32>,
activation_height: Option<u64>,
vote_count: Option<u32>,
#[serde(rename = "thresholdReached")]
is_threshold_reached: bool,
vote_count: Option<u64>,
}

impl ProtocolVersionUpgradeStateWasm {
fn new(
current_protocol_version: u32,
next_protocol_version: Option<u32>,
activation_height: Option<u64>,
vote_count: Option<u32>,
is_threshold_reached: bool,
vote_count: Option<u64>,
) -> Self {
Self {
current_protocol_version,
next_protocol_version,
activation_height,
vote_count,
is_threshold_reached,
}
}
}

#[wasm_bindgen(js_class = ProtocolVersionUpgradeState)]
impl ProtocolVersionUpgradeStateWasm {
/// Protocol version the chain was running when this response was produced.
#[wasm_bindgen(getter = "currentProtocolVersion")]
pub fn current_protocol_version(&self) -> u32 {
self.current_protocol_version
}

/// Candidate upgrade version: the version above the current one with the
/// most evonode votes, if any votes exist.
#[wasm_bindgen(getter = "nextProtocolVersion")]
pub fn next_protocol_version(&self) -> Option<u32> {
self.next_protocol_version
}

#[wasm_bindgen(getter = "activationHeight")]
pub fn activation_height(&self) -> Option<u64> {
self.activation_height
}

/// Number of evonode votes cast for `nextProtocolVersion`.
#[wasm_bindgen(getter = "voteCount")]
pub fn vote_count(&self) -> Option<u32> {
pub fn vote_count(&self) -> Option<u64> {
self.vote_count
}
}

/// Pick the candidate upgrade version from the vote counts: among versions
/// newer than `current_version`, the one with the most votes; equal vote
/// counts resolve to the highest version.
fn next_version_upgrade(
upgrades: &drive_proof_verifier::types::ProtocolVersionUpgrades,
current_version: u32,
) -> (Option<u32>, Option<u64>) {
upgrades
.iter()
.filter_map(|(version, votes)| votes.map(|votes| (*version, votes)))
.filter(|(version, _)| *version > current_version)
.max_by_key(|&(version, votes)| (votes, version))
.map_or((None, None), |(version, votes)| {
(Some(version), Some(votes))
})
}
Comment thread
QuantumExplorer marked this conversation as resolved.

#[cfg(test)]
mod tests {
use super::next_version_upgrade;
use drive_proof_verifier::types::ProtocolVersionUpgrades;

#[wasm_bindgen(getter = "isThresholdReached")]
pub fn is_threshold_reached(&self) -> bool {
self.is_threshold_reached
#[test]
fn empty_upgrades_yield_no_candidate() {
let upgrades = ProtocolVersionUpgrades::new();

assert_eq!(next_version_upgrade(&upgrades, 12), (None, None));
}

#[test]
fn none_vote_counts_are_skipped() {
let upgrades = ProtocolVersionUpgrades::from_iter([(13, None), (14, None)]);

assert_eq!(next_version_upgrade(&upgrades, 12), (None, None));
}

#[test]
fn versions_at_or_below_current_are_excluded() {
let upgrades = ProtocolVersionUpgrades::from_iter([(11, Some(50)), (12, Some(80))]);

assert_eq!(next_version_upgrade(&upgrades, 12), (None, None));
}

#[test]
fn picks_future_version_with_most_votes() {
let upgrades = ProtocolVersionUpgrades::from_iter([
(11, Some(200)),
(13, Some(7)),
(14, Some(132)),
(15, Some(3)),
]);

assert_eq!(next_version_upgrade(&upgrades, 12), (Some(14), Some(132)));
}

#[test]
fn equal_votes_resolve_to_highest_version() {
let upgrades = ProtocolVersionUpgrades::from_iter([(13, Some(9)), (14, Some(9))]);

assert_eq!(next_version_upgrade(&upgrades, 12), (Some(14), Some(9)));
}
}

Expand Down Expand Up @@ -108,36 +158,18 @@ impl WasmSdk {
use dash_sdk::platform::FetchMany;
use drive_proof_verifier::types::ProtocolVersionVoteCount;

let upgrade_result: drive_proof_verifier::types::ProtocolVersionUpgrades =
ProtocolVersionVoteCount::fetch_many(self.as_ref(), ()).await?;

// Get the current protocol version from the SDK
let current_version = self.version();

// Find the next version with votes
let mut next_version = None;
let mut activation_height = None;
let mut vote_count = None;
let mut threshold_reached = false;

// The result is an IndexMap<u32, Option<u64>> where u32 is version and Option<u64> is activation height
for (version, height_opt) in upgrade_result.iter() {
if *version > current_version {
next_version = Some(*version);
activation_height = *height_opt;
// TODO: Get actual vote count and threshold from platform
vote_count = None;
threshold_reached = height_opt.is_some();
break;
}
}
let (upgrade_result, metadata): (drive_proof_verifier::types::ProtocolVersionUpgrades, _) =
ProtocolVersionVoteCount::fetch_many_with_metadata(self.as_ref(), (), None).await?;

// The chain's protocol version at the time of the response
let current_version = metadata.protocol_version;

let (next_version, vote_count) = next_version_upgrade(&upgrade_result, current_version);

Ok(ProtocolVersionUpgradeStateWasm::new(
current_version,
next_version,
activation_height,
vote_count,
threshold_reached,
))
}

Expand Down Expand Up @@ -194,32 +226,12 @@ impl WasmSdk {
) = ProtocolVersionVoteCount::fetch_many_with_metadata_and_proof(self.as_ref(), (), None)
.await?;

// Get the current protocol version from the SDK
let current_version = self.version();

// Find the next version with votes
let mut next_version = None;
let mut activation_height = None;
let mut vote_count = None;
let mut threshold_reached = false;

for (version, height_opt) in upgrade_result.iter() {
if *version > current_version {
next_version = Some(*version);
activation_height = *height_opt;
vote_count = None;
threshold_reached = height_opt.is_some();
break;
}
}
// The chain's protocol version at the time of the response
let current_version = metadata.protocol_version;

let state = ProtocolVersionUpgradeStateWasm::new(
current_version,
next_version,
activation_height,
vote_count,
threshold_reached,
);
let (next_version, vote_count) = next_version_upgrade(&upgrade_result, current_version);

let state = ProtocolVersionUpgradeStateWasm::new(current_version, next_version, vote_count);

Ok(ProofMetadataResponseWasm::from_sdk_parts(
state, metadata, proof,
Expand Down
13 changes: 2 additions & 11 deletions packages/wasm-sdk/tests/unit/conversion-simple-types.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,13 @@ describe('Simple Type Conversions', () => {
const jsonFixture = {
currentProtocolVersion: 7,
nextProtocolVersion: 8,
activationHeight: 50000,
voteCount: 100,
thresholdReached: false,
};

const objectFixture = {
currentProtocolVersion: 7,
nextProtocolVersion: 8,
activationHeight: 50000n,
voteCount: 100,
thresholdReached: false,
voteCount: 100n,
};

describe('toJSON()', () => {
Expand All @@ -84,8 +80,7 @@ describe('Simple Type Conversions', () => {
const result = sdk.ProtocolVersionUpgradeState.fromJSON(jsonFixture);
expect(result.currentProtocolVersion).to.equal(7);
expect(result.nextProtocolVersion).to.equal(8);
expect(result.voteCount).to.equal(100);
expect(result.isThresholdReached).to.equal(false);
expect(result.voteCount).to.equal(100n);
});
});

Expand All @@ -94,17 +89,13 @@ describe('Simple Type Conversions', () => {
const fixture = {
currentProtocolVersion: 7,
nextProtocolVersion: null,
activationHeight: null,
voteCount: null,
thresholdReached: true,
};

const result = sdk.ProtocolVersionUpgradeState.fromJSON(fixture);
expect(result.currentProtocolVersion).to.equal(7);
expect(result.nextProtocolVersion).to.be.undefined();
expect(result.activationHeight).to.be.undefined();
expect(result.voteCount).to.be.undefined();
expect(result.isThresholdReached).to.equal(true);
});
});
});
Expand Down
Loading