feat(network): implement get stake pool parameters query (#554)

This commit is contained in:
Pedro Sánchez Terraf 2024-12-17 13:04:48 -03:00 committed by GitHub
parent b483b3a17a
commit 914631adcb
5 changed files with 375 additions and 8 deletions

View file

@ -339,6 +339,29 @@ impl<C> minicbor::encode::Encode<C> for RationalNumber {
}
}
impl<'b, C> minicbor::decode::Decode<'b, C> for PoolIds {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
d.tag()?;
Ok(PoolIds {
hashes: d.decode_with(ctx)?,
})
}
}
impl<C> minicbor::encode::Encode<C> for PoolIds {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
e.tag(Tag::new(258))?;
e.encode_with(self.hashes.clone(), ctx)?;
Ok(())
}
}
impl<'b, C> minicbor::decode::Decode<'b, C> for TransactionOutput {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
match d.datatype()? {

View file

@ -1,17 +1,21 @@
// TODO: this should move to pallas::ledger crate at some point
use pallas_crypto::hash::Hash;
use std::collections::BTreeSet;
use std::collections::{BTreeMap, BTreeSet};
use std::hash::Hash as StdHash;
// required for derive attrs to work
use pallas_codec::minicbor::{self};
use pallas_codec::utils::{AnyUInt, Bytes, KeyValuePairs, TagWrap};
use pallas_codec::utils::{AnyUInt, Bytes, KeyValuePairs, Nullable, TagWrap};
use pallas_codec::{
minicbor::{Decode, Encode},
utils::AnyCbor,
};
pub mod primitives;
pub use primitives::{PoolMetadata, Relay};
use crate::miniprotocols::Point;
use super::{Client, ClientError};
@ -39,7 +43,7 @@ pub enum BlockQuery {
GetRewardProvenance,
GetUTxOByTxIn(TxIns),
GetStakePools,
GetStakePoolParams(AnyCbor),
GetStakePoolParams(PoolIds),
GetRewardInfoPools,
GetPoolState(AnyCbor),
GetStakeSnapshots(Pools),
@ -197,6 +201,19 @@ pub struct StakeDistribution {
pub pools: KeyValuePairs<Bytes, Pool>,
}
/// The use of `BTreeMap`s as per [Pools] definition ensures that the hashes are
/// in order (otherwise, the node will reject some queries).
#[derive(Debug, PartialEq, Clone)]
pub struct PoolIds {
pub hashes: Pools,
}
impl From<Pools> for PoolIds {
fn from(hashes: Pools) -> Self {
Self { hashes }
}
}
#[derive(Debug, Encode, Decode, PartialEq, Clone)]
pub struct Pool {
#[n(0)]
@ -206,6 +223,39 @@ pub struct Pool {
pub hashes: Bytes,
}
// Essentially the `PoolRegistration` component of `Certificate` at
// `pallas-primitives/src/alonzo/model.rs`, with types modified for the present
// context
#[derive(Debug, Encode, Decode, PartialEq, Clone)]
pub struct PoolParams {
#[n(0)]
pub operator: Bytes,
#[n(1)]
pub vrf_keyhash: Bytes,
#[n(2)]
pub pledge: Coin,
#[n(3)]
pub cost: Coin,
#[n(4)]
pub margin: UnitInterval,
#[n(5)]
pub reward_account: Addr,
#[n(6)]
pub pool_owners: PoolIds,
#[n(7)]
pub relays: Vec<Relay>,
#[n(8)]
pub pool_metadata: Nullable<PoolMetadata>,
}
/// Type used at [GenesisConfig], which is a fraction that is CBOR-encoded
/// as an untagged array.
#[derive(Debug, Encode, Decode, PartialEq, Clone)]
@ -504,6 +554,20 @@ pub async fn get_cbor(
Ok(result)
}
/// Get parameters for the given pools.
pub async fn get_stake_pool_params(
client: &mut Client,
era: u16,
pool_ids: PoolIds,
) -> Result<BTreeMap<Bytes, PoolParams>, ClientError> {
let query = BlockQuery::GetStakePoolParams(pool_ids);
let query = LedgerQuery::BlockQuery(era, query);
let query = Request::LedgerQuery(query);
let result: (_,) = client.query(query).await?;
Ok(result.0)
}
/// Get the genesis configuration for the given era.
pub async fn get_genesis_config(
client: &mut Client,

View file

@ -0,0 +1,91 @@
// Material brought from `pallas-primitives`
// TODO: Refactor in order to avoid repetition.
pub use pallas_codec::utils::{Bytes, Nullable};
pub use pallas_crypto::hash::Hash;
use pallas_codec::minicbor::{self, Decode, Encode};
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct PoolMetadata {
#[n(0)]
pub url: String,
#[n(1)]
pub hash: PoolMetadataHash,
}
pub type PoolMetadataHash = Hash<32>;
pub type Port = u32;
pub type IPv4 = Bytes;
pub type IPv6 = Bytes;
pub type DnsName = String;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Relay {
SingleHostAddr(Nullable<Port>, Nullable<IPv4>, Nullable<IPv6>),
SingleHostName(Nullable<Port>, DnsName),
MultiHostName(DnsName),
}
// Move to `codec.rs`?
impl<'b, C> minicbor::decode::Decode<'b, C> for Relay {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
d.array()?;
let variant = d.u16()?;
match variant {
0 => Ok(Relay::SingleHostAddr(
d.decode_with(ctx)?,
d.decode_with(ctx)?,
d.decode_with(ctx)?,
)),
1 => Ok(Relay::SingleHostName(
d.decode_with(ctx)?,
d.decode_with(ctx)?,
)),
2 => Ok(Relay::MultiHostName(d.decode_with(ctx)?)),
_ => Err(minicbor::decode::Error::message(
"invalid variant id for Relay",
)),
}
}
}
impl<C> minicbor::encode::Encode<C> for Relay {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
Relay::SingleHostAddr(a, b, c) => {
e.array(4)?;
e.encode_with(0, ctx)?;
e.encode_with(a, ctx)?;
e.encode_with(b, ctx)?;
e.encode_with(c, ctx)?;
Ok(())
}
Relay::SingleHostName(a, b) => {
e.array(3)?;
e.encode_with(1, ctx)?;
e.encode_with(a, ctx)?;
e.encode_with(b, ctx)?;
Ok(())
}
Relay::MultiHostName(a) => {
e.array(2)?;
e.encode_with(2, ctx)?;
e.encode_with(a, ctx)?;
Ok(())
}
}
}
}