feat(network): implement GetUTxOByAddress local state query (#341)

This commit is contained in:
Alexsander Falcucci 2023-12-12 13:31:46 +01:00 committed by GitHub
parent 4e1eb79ef4
commit 27f1b3af24
5 changed files with 241 additions and 13 deletions

View file

@ -33,10 +33,10 @@ impl Encode<()> for BlockQuery {
e.array(1)?;
e.u16(5)?;
}
BlockQuery::GetUTxOByAddress(x) => {
BlockQuery::GetUTxOByAddress(addrs) => {
e.array(2)?;
e.u16(6)?;
e.encode(x)?;
e.encode(addrs)?;
}
BlockQuery::GetUTxOWhole => {
e.encode((7,))?;
@ -129,7 +129,7 @@ impl<'b> Decode<'b, ()> for BlockQuery {
3 => Ok(Self::GetCurrentPParams),
4 => Ok(Self::GetProposedPParamsUpdates),
5 => Ok(Self::GetStakeDistribution),
// 6 => Ok(Self::GetUTxOByAddress(())),
6 => Ok(Self::GetUTxOByAddress(d.decode()?)),
// 7 => Ok(Self::GetUTxOWhole),
// 8 => Ok(Self::DebugEpochState),
// 9 => Ok(Self::GetCBOR(())),
@ -264,3 +264,44 @@ impl<'b> Decode<'b, ()> for Request {
}
}
}
impl<'b, C> minicbor::decode::Decode<'b, C> for Value {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
match d.datatype()? {
minicbor::data::Type::U8 => Ok(Value::Coin(d.decode_with(ctx)?)),
minicbor::data::Type::U16 => Ok(Value::Coin(d.decode_with(ctx)?)),
minicbor::data::Type::U32 => Ok(Value::Coin(d.decode_with(ctx)?)),
minicbor::data::Type::U64 => Ok(Value::Coin(d.decode_with(ctx)?)),
minicbor::data::Type::Array => {
d.array()?;
let coin = d.decode_with(ctx)?;
let multiasset = d.decode_with(ctx)?;
Ok(Value::Multiasset(coin, multiasset))
}
_ => Err(minicbor::decode::Error::message(
"unknown cbor data type for Value enum",
)),
}
}
}
impl<C> minicbor::encode::Encode<C> for Value {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
Value::Coin(coin) => {
e.encode_with(coin, ctx)?;
}
Value::Multiasset(coin, other) => {
e.array(2)?;
e.encode_with(coin, ctx)?;
e.encode_with(other, ctx)?;
}
};
Ok(())
}
}

View file

@ -1,9 +1,11 @@
// TODO: this should move to pallas::ledger crate at some point
use pallas_crypto::hash::Hash;
use std::hash::Hash as StdHash;
// required for derive attrs to work
use pallas_codec::minicbor::{self};
use pallas_codec::utils::{Bytes, KeyValuePairs};
use pallas_codec::utils::{AnyUInt, Bytes, KeyValuePairs, TagWrap};
use pallas_codec::{
minicbor::{Decode, Encode},
utils::AnyCbor,
@ -25,7 +27,7 @@ pub enum BlockQuery {
GetCurrentPParams,
GetProposedPParamsUpdates,
GetStakeDistribution,
GetUTxOByAddress(AnyCbor),
GetUTxOByAddress(Addrs),
GetUTxOWhole,
DebugEpochState,
GetCBOR(AnyCbor),
@ -69,6 +71,12 @@ pub enum Request {
GetChainPoint,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Value {
Coin(Coin),
Multiasset(Coin, Multiasset<Coin>),
}
#[derive(Debug, Encode, Decode, PartialEq)]
pub struct SystemStart {
#[n(0)]
@ -105,6 +113,49 @@ pub struct Fraction {
pub dem: u64,
}
pub type Addr = Bytes;
pub type Addrs = Vec<Addr>;
pub type Coin = AnyUInt;
pub type PolicyId = Hash<28>;
pub type AssetName = Bytes;
pub type Multiasset<A> = KeyValuePairs<PolicyId, KeyValuePairs<AssetName, A>>;
#[derive(Debug, Encode, Decode, PartialEq, Clone)]
pub struct UTxOByAddress {
#[n(0)]
pub utxo: KeyValuePairs<UTxO, Values>,
}
// Bytes CDDL -> #6.121([ * #6.121([ *datum ]) ])
pub type Datum = (Era, TagWrap<Bytes, 24>);
#[derive(Debug, Encode, Decode, PartialEq, Clone)]
#[cbor(map)]
pub struct Values {
#[n(0)]
pub address: Bytes,
#[n(1)]
pub amount: Value,
#[n(2)]
pub inline_datum: Option<Datum>,
}
#[derive(Debug, Encode, Decode, PartialEq, Clone, StdHash, Eq)]
pub struct UTxO {
#[n(0)]
pub transaction_id: Hash<32>,
#[n(1)]
pub index: AnyUInt,
}
pub async fn get_chain_point(client: &mut Client) -> Result<Point, ClientError> {
let query = Request::GetChainPoint;
let result = client.query(query).await?;
@ -148,3 +199,16 @@ pub async fn get_stake_distribution(
Ok(result)
}
pub async fn get_utxo_by_address(
client: &mut Client,
era: u16,
addrs: Addrs,
) -> Result<UTxOByAddress, ClientError> {
let query = BlockQuery::GetUTxOByAddress(addrs);
let query = LedgerQuery::BlockQuery(era, query);
let query = Request::LedgerQuery(query);
let result = client.query(query).await?;
Ok(result)
}