use std::{
collections::{BTreeMap, BTreeSet},
marker::PhantomData,
};
use crate::{
base::*,
common::{
self, deserial_bytes, deserial_map_no_length, deserial_set_no_length, deserial_string,
deserial_vector_no_length, types::*, Buffer, Deserial, Get, ParseResult, ReadBytesExt,
SerdeDeserialize, SerdeSerialize, Serial,
},
hashes,
transactions::PayloadSize,
};
use derive_more::*;
#[derive(SerdeSerialize, SerdeDeserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ProtocolUpdate {
pub message: String,
#[serde(rename = "specificationURL")]
pub specification_url: String,
pub specification_hash: hashes::Hash,
#[serde(with = "crate::internal::byte_array_hex")]
pub specification_auxiliary_data: Vec<u8>,
}
impl Serial for ProtocolUpdate {
fn serial<B: Buffer>(&self, out: &mut B) {
let data_len = self.message.as_bytes().len()
+ 8
+ self.specification_url.as_bytes().len()
+ 8
+ 32
+ self.specification_auxiliary_data.len();
(data_len as u64).serial(out);
(self.message.as_bytes().len() as u64).serial(out);
out.write_all(self.message.as_bytes())
.expect("Serialization to a buffer always succeeds.");
(self.specification_url.as_bytes().len() as u64).serial(out);
out.write_all(self.specification_url.as_bytes())
.expect("Serialization to a buffer always succeeds.");
self.specification_hash.serial(out);
out.write_all(&self.specification_auxiliary_data)
.expect("Serialization to a buffer always succeeds.")
}
}
impl Deserial for ProtocolUpdate {
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
let data_len = u64::deserial(source)?;
let mut limited = <&mut R as std::io::Read>::take(source, data_len);
let message_len = u64::deserial(&mut limited)?;
let message = if message_len <= 4096 {
deserial_string(&mut limited, message_len as usize)?
} else {
String::from_utf8(deserial_vector_no_length(
&mut limited,
message_len as usize,
)?)?
};
let url_len = u64::deserial(&mut limited)?;
let specification_url = if message_len <= 4096 {
deserial_string(&mut limited, url_len as usize)?
} else {
String::from_utf8(deserial_vector_no_length(&mut limited, url_len as usize)?)?
};
let specification_hash = limited.get()?;
let remaining = limited.limit();
let specification_auxiliary_data = if remaining <= 4096 {
deserial_bytes(&mut limited, remaining as usize)?
} else {
deserial_vector_no_length(&mut limited, remaining as usize)?
};
Ok(Self {
message,
specification_url,
specification_hash,
specification_auxiliary_data,
})
}
}
#[derive(Debug, SerdeSerialize, SerdeDeserialize, common::Serial, Clone)]
#[serde(rename_all = "camelCase")]
#[serde(try_from = "transaction_fee_distribution::TransactionFeeDistributionUnchecked")]
pub struct TransactionFeeDistribution {
pub baker: AmountFraction,
pub gas_account: AmountFraction,
}
impl Deserial for TransactionFeeDistribution {
fn deserial<R: common::ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
let baker: AmountFraction = source.get()?;
let gas_account: AmountFraction = source.get()?;
anyhow::ensure!(
(baker + gas_account).is_some(),
"Reward fractions exceed 100%."
);
Ok(Self { baker, gas_account })
}
}
mod transaction_fee_distribution {
use super::*;
#[derive(SerdeDeserialize)]
#[serde(rename_all = "camelCase")]
pub struct TransactionFeeDistributionUnchecked {
baker: AmountFraction,
gas_account: AmountFraction,
}
impl TryFrom<TransactionFeeDistributionUnchecked> for TransactionFeeDistribution {
type Error = &'static str;
fn try_from(value: TransactionFeeDistributionUnchecked) -> Result<Self, Self::Error> {
if (value.baker + value.gas_account).is_some() {
Ok(TransactionFeeDistribution {
baker: value.baker,
gas_account: value.gas_account,
})
} else {
Err("Transaction fee fractions exceed 100%.")
}
}
}
}
#[derive(Debug, SerdeSerialize, SerdeDeserialize, common::Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct GASRewards {
pub baker: AmountFraction,
pub finalization_proof: AmountFraction,
pub account_creation: AmountFraction,
pub chain_update: AmountFraction,
}
#[derive(Debug, SerdeSerialize, SerdeDeserialize, Clone)]
#[serde(tag = "typeOfUpdate", content = "updatePayload")]
#[serde(rename_all = "camelCase")]
pub enum RootUpdate {
RootKeysUpdate(HigherLevelAccessStructure<RootKeysKind>),
Level1KeysUpdate(HigherLevelAccessStructure<Level1KeysKind>),
Level2KeysUpdate(Box<Authorizations<ChainParameterVersion0>>),
Level2KeysUpdateV1(Box<Authorizations<ChainParameterVersion1>>),
}
impl Serial for RootUpdate {
fn serial<B: Buffer>(&self, out: &mut B) {
match self {
RootUpdate::RootKeysUpdate(ruk) => {
0u8.serial(out);
ruk.serial(out)
}
RootUpdate::Level1KeysUpdate(l1k) => {
1u8.serial(out);
l1k.serial(out)
}
RootUpdate::Level2KeysUpdate(l2k) => {
2u8.serial(out);
l2k.serial(out)
}
RootUpdate::Level2KeysUpdateV1(l2k) => {
3u8.serial(out);
l2k.serial(out)
}
}
}
}
impl Deserial for RootUpdate {
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
match u8::deserial(source)? {
0u8 => Ok(RootUpdate::RootKeysUpdate(source.get()?)),
1u8 => Ok(RootUpdate::Level1KeysUpdate(source.get()?)),
2u8 => Ok(RootUpdate::Level2KeysUpdate(source.get()?)),
3u8 => Ok(RootUpdate::Level2KeysUpdateV1(source.get()?)),
tag => anyhow::bail!("Unknown RootUpdate tag {}", tag),
}
}
}
#[derive(Debug, SerdeSerialize, SerdeDeserialize, Clone)]
#[serde(tag = "typeOfUpdate", content = "updatePayload")]
#[serde(rename_all = "camelCase")]
pub enum Level1Update {
Level1KeysUpdate(HigherLevelAccessStructure<Level1KeysKind>),
Level2KeysUpdate(Box<Authorizations<ChainParameterVersion0>>),
Level2KeysUpdateV1(Box<Authorizations<ChainParameterVersion1>>),
}
impl Serial for Level1Update {
fn serial<B: Buffer>(&self, out: &mut B) {
match self {
Level1Update::Level1KeysUpdate(l1k) => {
0u8.serial(out);
l1k.serial(out)
}
Level1Update::Level2KeysUpdate(l2k) => {
1u8.serial(out);
l2k.serial(out)
}
Level1Update::Level2KeysUpdateV1(l2k) => {
2u8.serial(out);
l2k.serial(out)
}
}
}
}
impl Deserial for Level1Update {
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
match u8::deserial(source)? {
0u8 => Ok(Level1Update::Level1KeysUpdate(source.get()?)),
1u8 => Ok(Level1Update::Level2KeysUpdate(source.get()?)),
2u8 => Ok(Level1Update::Level2KeysUpdateV1(source.get()?)),
tag => anyhow::bail!("Unknown Level1Update tag {}", tag),
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
#[doc(hidden)]
pub enum RootKeysKind {}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
#[doc(hidden)]
pub enum Level1KeysKind {}
#[derive(Debug, SerdeSerialize, SerdeDeserialize, common::Serial, Clone)]
#[serde(rename_all = "camelCase")]
#[serde(bound = "Kind: Sized")]
pub struct HigherLevelAccessStructure<Kind> {
#[size_length = 2]
pub keys: Vec<UpdatePublicKey>,
pub threshold: UpdateKeysThreshold,
#[serde(skip)] pub _phantom: PhantomData<Kind>,
}
impl<Kind> Deserial for HigherLevelAccessStructure<Kind> {
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
let keys_len: u16 = source.get()?;
let keys = deserial_vector_no_length(source, keys_len as usize)?;
let threshold: UpdateKeysThreshold = source.get()?;
anyhow::ensure!(
threshold.threshold.get() <= keys_len,
"Threshold too large."
);
Ok(Self {
keys,
threshold,
_phantom: Default::default(),
})
}
}
#[derive(Debug, SerdeSerialize, SerdeDeserialize, common::Serial, Clone)]
#[serde(rename_all = "camelCase")]
pub struct AccessStructure {
#[set_size_length = 2]
pub authorized_keys: BTreeSet<UpdateKeysIndex>,
pub threshold: UpdateKeysThreshold,
}
impl Deserial for AccessStructure {
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
let authorized_keys_len: u16 = source.get()?;
let authorized_keys = deserial_set_no_length(source, authorized_keys_len as usize)?;
let threshold: UpdateKeysThreshold = source.get()?;
anyhow::ensure!(
threshold.threshold.get() <= authorized_keys_len,
"Threshold too large."
);
Ok(Self {
authorized_keys,
threshold,
})
}
}
#[derive(Debug, SerdeSerialize, SerdeDeserialize, Clone, common::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AuthorizationsV0 {
#[size_length = 2]
pub keys: Vec<UpdatePublicKey>,
pub emergency: AccessStructure,
pub protocol: AccessStructure,
pub election_difficulty: AccessStructure,
pub euro_per_energy: AccessStructure,
#[serde(rename = "microGTUPerEuro")]
pub micro_gtu_per_euro: AccessStructure,
pub foundation_account: AccessStructure,
pub mint_distribution: AccessStructure,
pub transaction_fee_distribution: AccessStructure,
#[serde(rename = "paramGASRewards")]
pub param_gas_rewards: AccessStructure,
pub pool_parameters: AccessStructure,
pub add_anonymity_revoker: AccessStructure,
pub add_identity_provider: AccessStructure,
}
impl AuthorizationsV0 {
pub fn construct_update_signer<K>(
&self,
update_key_indices: &AccessStructure,
actual_keys: impl IntoIterator<Item = K>,
) -> Option<BTreeMap<UpdateKeysIndex, K>>
where
UpdatePublicKey: for<'a> From<&'a K>, {
construct_update_signer_worker(&self.keys, update_key_indices, actual_keys)
}
}
fn construct_update_signer_worker<K>(
keys: &[UpdatePublicKey],
update_key_indices: &AccessStructure,
actual_keys: impl IntoIterator<Item = K>,
) -> Option<BTreeMap<UpdateKeysIndex, K>>
where
UpdatePublicKey: for<'a> From<&'a K>, {
let mut signer = BTreeMap::new();
for kp in actual_keys {
let known_key = &UpdatePublicKey::from(&kp);
if let Some(i) = keys.iter().position(|public| public == known_key) {
let idx = UpdateKeysIndex { index: i as u16 };
if update_key_indices.authorized_keys.contains(&idx) {
if signer.insert(idx, kp).is_some() {
return None;
}
} else {
return None;
}
} else {
return None;
}
}
Some(signer)
}
#[derive(Debug, SerdeSerialize, SerdeDeserialize, Clone, common::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AuthorizationsV1 {
#[serde(flatten)]
pub v0: AuthorizationsV0,
pub cooldown_parameters: AccessStructure,
pub time_parameters: AccessStructure,
}
impl AuthorizationsV1 {
pub fn construct_update_signer<K>(
&self,
update_key_indices: &AccessStructure,
actual_keys: impl IntoIterator<Item = K>,
) -> Option<BTreeMap<UpdateKeysIndex, K>>
where
UpdatePublicKey: for<'a> From<&'a K>, {
construct_update_signer_worker(&self.v0.keys, update_key_indices, actual_keys)
}
}
pub trait AuthorizationsFamily {
type Output: std::fmt::Debug;
}
impl AuthorizationsFamily for ChainParameterVersion0 {
type Output = AuthorizationsV0;
}
impl AuthorizationsFamily for ChainParameterVersion1 {
type Output = AuthorizationsV1;
}
pub type Authorizations<CPV> = <CPV as AuthorizationsFamily>::Output;
#[derive(SerdeSerialize, SerdeDeserialize, common::Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct BakerParameters {
pub minimum_threshold_for_baking: Amount,
}
#[derive(Debug, common::Serialize, SerdeSerialize, SerdeDeserialize, Copy, Clone)]
#[serde(rename_all = "camelCase")]
pub struct CooldownParameters {
pub pool_owner_cooldown: DurationSeconds,
pub delegator_cooldown: DurationSeconds,
}
#[derive(
Copy,
Clone,
Eq,
PartialEq,
Ord,
PartialOrd,
Debug,
FromStr,
Display,
From,
Into,
SerdeSerialize,
SerdeDeserialize,
common::Serialize,
)]
#[serde(transparent)]
pub struct RewardPeriodLength {
pub(crate) reward_period_epochs: Epoch,
}
#[derive(Debug, SerdeSerialize, SerdeDeserialize, common::Serialize, Copy, Clone)]
#[serde(rename_all = "camelCase")]
pub struct TimeParameters {
pub reward_period_length: RewardPeriodLength,
pub mint_per_payday: MintRate,
}
#[derive(Debug, common::Serialize, SerdeSerialize, SerdeDeserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct PoolParameters {
pub passive_finalization_commission: AmountFraction,
pub passive_baking_commission: AmountFraction,
pub passive_transaction_commission: AmountFraction,
#[serde(flatten)]
pub commission_bounds: CommissionRanges,
pub minimum_equity_capital: Amount,
pub capital_bound: CapitalBound,
pub leverage_bound: LeverageFactor,
}
#[derive(SerdeSerialize, SerdeDeserialize, Debug, Clone)]
#[serde(tag = "updateType", content = "update")]
pub enum UpdatePayload {
#[serde(rename = "protocol")]
Protocol(ProtocolUpdate),
#[serde(rename = "electionDifficulty")]
ElectionDifficulty(ElectionDifficulty),
#[serde(rename = "euroPerEnergy")]
EuroPerEnergy(ExchangeRate),
#[serde(rename = "microGTUPerEuro")]
MicroGTUPerEuro(ExchangeRate), #[serde(rename = "foundationAccount")]
FoundationAccount(AccountAddress),
#[serde(rename = "mintDistribution")]
MintDistribution(MintDistribution<ChainParameterVersion0>),
#[serde(rename = "transactionFeeDistribution")]
TransactionFeeDistribution(TransactionFeeDistribution),
#[serde(rename = "gASRewards")]
GASRewards(GASRewards),
#[serde(rename = "bakerStakeThreshold")]
BakerStakeThreshold(BakerParameters),
#[serde(rename = "root")]
Root(RootUpdate),
#[serde(rename = "level1")]
Level1(Level1Update),
#[serde(rename = "addAnonymityRevoker")]
AddAnonymityRevoker(Box<crate::id::types::ArInfo<crate::id::constants::ArCurve>>),
#[serde(rename = "addIdentityProvider")]
AddIdentityProvider(Box<crate::id::types::IpInfo<crate::id::constants::IpPairing>>),
#[serde(rename = "cooldownParametersCPV1")]
CooldownParametersCPV1(CooldownParameters),
#[serde(rename = "poolParametersCPV1")]
PoolParametersCPV1(PoolParameters),
#[serde(rename = "timeParametersCPV1")]
TimeParametersCPV1(TimeParameters),
#[serde(rename = "mintDistributionCPV1")]
MintDistributionCPV1(MintDistribution<ChainParameterVersion1>),
}
#[derive(SerdeSerialize, SerdeDeserialize, Debug, Clone, Copy)]
#[serde(rename_all = "camelCase")]
pub enum UpdateType {
UpdateProtocol,
UpdateElectionDifficulty,
UpdateEuroPerEnergy,
UpdateMicroGTUPerEuro,
UpdateFoundationAccount,
UpdateMintDistribution,
UpdateTransactionFeeDistribution,
UpdateGASRewards,
UpdateAddAnonymityRevoker,
UpdateAddIdentityProvider,
UpdateRootKeys,
UpdateLevel1Keys,
UpdateLevel2Keys,
UpdatePoolParameters,
UpdateCooldownParameters,
UpdateTimeParameters,
}
impl UpdatePayload {
pub fn update_type(&self) -> UpdateType {
use UpdateType::*;
match self {
UpdatePayload::Protocol(_) => UpdateProtocol,
UpdatePayload::ElectionDifficulty(_) => UpdateElectionDifficulty,
UpdatePayload::EuroPerEnergy(_) => UpdateEuroPerEnergy,
UpdatePayload::MicroGTUPerEuro(_) => UpdateMicroGTUPerEuro,
UpdatePayload::FoundationAccount(_) => UpdateFoundationAccount,
UpdatePayload::MintDistribution(_) => UpdateMintDistribution,
UpdatePayload::TransactionFeeDistribution(_) => UpdateTransactionFeeDistribution,
UpdatePayload::GASRewards(_) => UpdateGASRewards,
UpdatePayload::BakerStakeThreshold(_) => UpdatePoolParameters,
UpdatePayload::Root(_) => UpdateRootKeys,
UpdatePayload::Level1(_) => UpdateLevel1Keys,
UpdatePayload::AddAnonymityRevoker(_) => UpdateAddAnonymityRevoker,
UpdatePayload::AddIdentityProvider(_) => UpdateAddIdentityProvider,
UpdatePayload::CooldownParametersCPV1(_) => UpdateCooldownParameters,
UpdatePayload::PoolParametersCPV1(_) => UpdatePoolParameters,
UpdatePayload::TimeParametersCPV1(_) => UpdateTimeParameters,
UpdatePayload::MintDistributionCPV1(_) => UpdateMintDistribution,
}
}
}
#[derive(Debug, Clone, common::Serialize)]
pub struct UpdateInstruction {
pub header: UpdateHeader,
pub payload: UpdatePayload,
pub signatures: UpdateInstructionSignature,
}
pub trait UpdateSigner {
fn sign_update_hash(&self, hash_to_sign: &hashes::UpdateSignHash)
-> UpdateInstructionSignature;
}
impl UpdateSigner for &BTreeMap<UpdateKeysIndex, UpdateKeyPair> {
fn sign_update_hash(
&self,
hash_to_sign: &hashes::UpdateSignHash,
) -> UpdateInstructionSignature {
let signatures = self
.iter()
.map(|(ki, kp)| (*ki, kp.sign(hash_to_sign.as_ref())))
.collect::<BTreeMap<_, _>>();
UpdateInstructionSignature { signatures }
}
}
impl UpdateSigner for &[(UpdateKeysIndex, UpdateKeyPair)] {
fn sign_update_hash(
&self,
hash_to_sign: &hashes::UpdateSignHash,
) -> UpdateInstructionSignature {
let signatures = self
.iter()
.map(|(ki, kp)| (*ki, kp.sign(hash_to_sign.as_ref())))
.collect::<BTreeMap<_, _>>();
UpdateInstructionSignature { signatures }
}
}
#[derive(Debug, Clone, Copy, common::Serialize)]
pub struct UpdateHeader {
pub seq_number: UpdateSequenceNumber,
pub effective_time: TransactionTime,
pub timeout: TransactionTime,
pub payload_size: PayloadSize,
}
#[derive(Debug, Clone, common::Serial, Into)]
pub struct UpdateInstructionSignature {
#[map_size_length = 2]
pub signatures: BTreeMap<UpdateKeysIndex, Signature>,
}
impl Deserial for UpdateInstructionSignature {
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
let len = u16::deserial(source)?;
anyhow::ensure!(len != 0, "There must be at least one signature.");
let signatures = deserial_map_no_length(source, len as usize)?;
Ok(Self { signatures })
}
}
pub mod update {
use sha2::Digest;
use std::io::Write;
use super::*;
fn compute_sign_hash(
header: &UpdateHeader,
payload: &[u8], ) -> hashes::UpdateSignHash {
let mut hasher = sha2::Sha256::new();
header.serial(&mut hasher);
hasher
.write_all(payload)
.expect("Writing to hasher does not fail.");
<[u8; 32]>::from(hasher.finalize()).into()
}
pub fn update(
signer: impl UpdateSigner,
seq_number: UpdateSequenceNumber,
effective_time: TransactionTime,
timeout: TransactionTime,
payload: UpdatePayload,
) -> UpdateInstruction {
let serialized_payload = common::to_bytes(&payload);
let header = UpdateHeader {
seq_number,
effective_time,
timeout,
payload_size: PayloadSize {
size: serialized_payload.len() as u32,
},
};
let signatures = signer.sign_update_hash(&compute_sign_hash(&header, &serialized_payload));
UpdateInstruction {
header,
payload,
signatures,
}
}
}
impl Serial for UpdatePayload {
fn serial<B: Buffer>(&self, out: &mut B) {
match self {
UpdatePayload::Protocol(pu) => {
1u8.serial(out);
pu.serial(out)
}
UpdatePayload::ElectionDifficulty(ed) => {
2u8.serial(out);
ed.serial(out);
}
UpdatePayload::EuroPerEnergy(ee) => {
3u8.serial(out);
ee.serial(out);
}
UpdatePayload::MicroGTUPerEuro(me) => {
4u8.serial(out);
me.serial(out);
}
UpdatePayload::FoundationAccount(fa) => {
5u8.serial(out);
fa.serial(out);
}
UpdatePayload::MintDistribution(md) => {
6u8.serial(out);
md.serial(out);
}
UpdatePayload::TransactionFeeDistribution(tf) => {
7u8.serial(out);
tf.serial(out);
}
UpdatePayload::GASRewards(gr) => {
8u8.serial(out);
gr.serial(out);
}
UpdatePayload::BakerStakeThreshold(bs) => {
9u8.serial(out);
bs.serial(out)
}
UpdatePayload::Root(ru) => {
10u8.serial(out);
ru.serial(out)
}
UpdatePayload::Level1(l1) => {
11u8.serial(out);
l1.serial(out)
}
UpdatePayload::AddAnonymityRevoker(add_ar) => {
12u8.serial(out);
let mut inner = Vec::new();
add_ar.serial(&mut inner);
(inner.len() as u32).serial(out);
out.write_all(&inner).unwrap();
}
UpdatePayload::AddIdentityProvider(add_ip) => {
13u8.serial(out);
let mut inner = Vec::new();
add_ip.serial(&mut inner);
(inner.len() as u32).serial(out);
out.write_all(&inner).unwrap();
}
UpdatePayload::CooldownParametersCPV1(cp) => {
14u8.serial(out);
cp.serial(out)
}
UpdatePayload::PoolParametersCPV1(pp) => {
15u8.serial(out);
pp.serial(out)
}
UpdatePayload::TimeParametersCPV1(tp) => {
16u8.serial(out);
tp.serial(out)
}
UpdatePayload::MintDistributionCPV1(md) => {
17u8.serial(out);
md.serial(out)
}
}
}
}
impl Deserial for UpdatePayload {
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
match u8::deserial(source)? {
1u8 => Ok(UpdatePayload::Protocol(source.get()?)),
2u8 => Ok(UpdatePayload::ElectionDifficulty(source.get()?)),
3u8 => Ok(UpdatePayload::EuroPerEnergy(source.get()?)),
4u8 => Ok(UpdatePayload::MicroGTUPerEuro(source.get()?)),
5u8 => Ok(UpdatePayload::FoundationAccount(source.get()?)),
6u8 => Ok(UpdatePayload::MintDistribution(source.get()?)),
7u8 => Ok(UpdatePayload::TransactionFeeDistribution(source.get()?)),
8u8 => Ok(UpdatePayload::GASRewards(source.get()?)),
9u8 => Ok(UpdatePayload::BakerStakeThreshold(source.get()?)),
10u8 => Ok(UpdatePayload::Root(source.get()?)),
11u8 => Ok(UpdatePayload::Level1(source.get()?)),
12u8 => {
let len: u32 = source.get()?;
let mut limited = std::io::Read::take(source, len.into());
let ar = limited.get()?;
if limited.limit() == 0 {
Ok(UpdatePayload::AddAnonymityRevoker(ar))
} else {
anyhow::bail!(
"Incorrectly serialized anonymity revoker. Not all data was consumed."
)
}
}
13u8 => {
let len: u32 = source.get()?;
let mut limited = std::io::Read::take(source, len.into());
let ip = limited.get()?;
if limited.limit() == 0 {
Ok(UpdatePayload::AddIdentityProvider(ip))
} else {
anyhow::bail!(
"Incorrectly serialized identity provider. Not all data was consumed."
)
}
}
14u8 => Ok(UpdatePayload::CooldownParametersCPV1(source.get()?)),
15u8 => Ok(UpdatePayload::PoolParametersCPV1(source.get()?)),
16u8 => Ok(UpdatePayload::TimeParametersCPV1(source.get()?)),
17u8 => Ok(UpdatePayload::MintDistributionCPV1(source.get()?)),
tag => anyhow::bail!("Unknown update payload tag {}", tag),
}
}
}