Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support protocol 7 API changes #198

Merged
Show file tree
Hide file tree
Changes from 6 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
2 changes: 1 addition & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let spec = repo.revparse_single("HEAD")?.id();
std::fs::write(
"./src/v2/proto_schema_version.rs",
format!("pub const PROTO_SCHEMA_VERSION: &str = \"{}\";", spec),
format!("pub const PROTO_SCHEMA_VERSION: &str = \"{}\";\n", spec),
)?;
}
Ok(())
Expand Down
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
//! - [`common`] has some common type definitions, as well as traits and helpers
//! for binary serialization
//! - [`encrypted_transfers`] implements structures and zero knowledge proofs
//! related to encrypted transfers
//! related to encrypted transfers. Note that this functionality has been
//! deprecated in protocol version 7.
//! - [`eddsa_ed25519`] is a re-export of the signature scheme used for blocks
//! and accounts on the Concordium blockchain.
//! - [`aggregate_sig`] is a re-export of the BLS signature scheme, used by the
Expand Down
52 changes: 52 additions & 0 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,46 @@ impl AccountStakingInfo {
}
}

/// The status of a cooldown. When stake is removed from a baker or delegator
/// (from protocol version 7) it first enters the pre-pre-cooldown state.
/// The next time the stake snaphot is taken (at the epoch transition before
/// a payday) it enters the pre-cooldown state. At the subsequent payday, it
/// enters the cooldown state. At the payday after the end of the cooldown
/// period, the stake is finally released.
#[derive(SerdeSerialize, SerdeDeserialize, Debug, PartialEq)]
pub enum CooldownStatus {
Victor-N-Suadicani marked this conversation as resolved.
Show resolved Hide resolved
/// The amount is in cooldown and will expire at the specified time,
/// becoming available at the subsequent pay day.
Cooldown,

/// The amount will enter cooldown at the next pay day. The specified
/// end time is projected to be the end of the cooldown period,
/// but the actual end time will be determined at the payday,
/// and may be different if the global cooldown period changes.
PreCooldown,

/// The amount will enter pre-cooldown at the next snapshot epoch (i.e.
/// the epoch transition before a pay day transition). As with
/// pre-cooldown, the specified end time is projected, but the
/// actual end time will be determined later.
PrePreCooldown,
}

#[derive(SerdeSerialize, SerdeDeserialize, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Cooldown {
/// The time in milliseconds since the Unix epoch when the cooldown period
/// ends.
pub end_time: Timestamp,

/// The amount that is in cooldown and set to be released at the end of the
/// cooldown period.
pub amount: Amount,

/// The status of the cooldown.
pub status: CooldownStatus,
}

#[derive(SerdeSerialize, SerdeDeserialize, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
/// Account information exposed via the node's API. This is always the state of
Expand Down Expand Up @@ -327,6 +367,18 @@ pub struct AccountInfo {
pub account_stake: Option<AccountStakingInfo>,
/// Canonical address of the account.
pub account_address: AccountAddress,

/// The stake on the account that is in cooldown.
/// There can be multiple amounts in cooldown that expire at different
/// times.
pub cooldowns: Vec<Cooldown>,
Victor-N-Suadicani marked this conversation as resolved.
Show resolved Hide resolved

/// The available (unencrypted) balance of the account (i.e. that can be
/// transferred or used to pay for transactions). This is the balance
/// minus the locked amount. The locked amount is the maximum of the
/// amount in the release schedule and the total amount that is actively
/// staked or in cooldown (inactive stake).
pub available_balance: Amount,
}

impl From<&AccountInfo> for AccountAccessStructure {
Expand Down
73 changes: 69 additions & 4 deletions src/v2/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ use super::generated::*;

use super::Require;
use crate::{
types::{queries::ConcordiumBFTDetails, UpdateKeysCollectionSkeleton},
types::{queries::ConcordiumBFTDetails, AccountReleaseSchedule, UpdateKeysCollectionSkeleton},
v2::generated::BlockCertificates,
};
use chrono::TimeZone;
use concordium_base::{
base,
base, common,
common::{Deserial, Versioned, VERSION_0},
id::{
constants::{ArCurve, AttributeKind, IpPairing},
Expand All @@ -21,6 +21,7 @@ use concordium_base::{
},
updates,
};
use cooldown::CooldownStatus;
use std::collections::{BTreeMap, BTreeSet};

fn consume<A: Deserial>(bytes: &[u8]) -> Result<A, tonic::Status> {
Expand Down Expand Up @@ -899,6 +900,35 @@ impl TryFrom<DelegatorRewardPeriodInfo> for super::types::DelegatorRewardPeriodI
}
}

impl From<CooldownStatus> for super::types::CooldownStatus {
fn from(cds: CooldownStatus) -> Self {
match cds {
CooldownStatus::Cooldown => Self::Cooldown,
CooldownStatus::PreCooldown => Self::PreCooldown,
CooldownStatus::PrePreCooldown => Self::PrePreCooldown,
}
}
}

impl TryFrom<Cooldown> for super::types::Cooldown {
type Error = tonic::Status;

fn try_from(cd: Cooldown) -> Result<Self, Self::Error> {
Ok(Self {
status: CooldownStatus::try_from(cd.status)
.map_err(|_| {
tonic::Status::invalid_argument(format!(
"unknown cooldown status value {}",
cd.status
))
})?
.into(),
end_time: cd.end_time.require()?.into(),
amount: cd.amount.require()?.into(),
})
}
}

impl TryFrom<AccountInfo> for super::types::AccountInfo {
type Error = tonic::Status;

Expand All @@ -914,19 +944,52 @@ impl TryFrom<AccountInfo> for super::types::AccountInfo {
index,
stake,
address,
cooldowns,
available_balance,
} = value;
let account_nonce = sequence_number.require()?.into();
let account_amount = amount.require()?.into();
let account_release_schedule = schedule.require()?.try_into()?;
let account_release_schedule: AccountReleaseSchedule = schedule.require()?.try_into()?;
let account_threshold = threshold.require()?.try_into()?;
let account_encrypted_amount = encrypted_balance.require()?.try_into()?;
let account_encryption_key = encryption_key.require()?.try_into()?;
let account_index = index.require()?.into();
let account_stake = match stake {
let account_stake: Option<super::types::AccountStakingInfo> = match stake {
Some(stake) => Some(stake.try_into()?),
None => None,
};
let account_address = address.require()?.try_into()?;
let mut cds = Vec::with_capacity(cooldowns.len());
for cooldown in cooldowns.into_iter() {
cds.push(cooldown.try_into()?)
}
let cooldowns = cds;

// The available balance is only provided as convenience and in case the
// calculation of it changes in the future. If the available balance is
// not present, we calculate it manually instead. Note that changes in the
// calculation method may make this calculation invalid.
Victor-N-Suadicani marked this conversation as resolved.
Show resolved Hide resolved
let available_balance = available_balance.map(|ab| ab.into()).unwrap_or_else(|| {
// According to the protobuf documentation:
// The available (unencrypted) balance of the account is the balance...
let balance = account_amount;

// ... minus the locked amount. The locked amount is the maximum of the
// amount in the release schedule...
let release_schedule_amount = account_release_schedule.total;

// ... and the total amount that is actively staked or in cooldown (inactive
// stake).
let staked_amount = account_stake.as_ref()
.map(|s| s.staked_amount())
// FIXME: Give common::types::Amount a `Default` impl and use .unwrap_or_default();
Victor-N-Suadicani marked this conversation as resolved.
Show resolved Hide resolved
.unwrap_or(common::types::Amount::zero());
Victor-N-Suadicani marked this conversation as resolved.
Show resolved Hide resolved

let locked_amount = Ord::max(release_schedule_amount, staked_amount);

balance - locked_amount
});

Ok(Self {
account_nonce,
account_amount,
Expand All @@ -947,6 +1010,8 @@ impl TryFrom<AccountInfo> for super::types::AccountInfo {
account_index,
account_stake,
account_address,
cooldowns,
available_balance,
})
}
}
Expand Down
Loading