feat(traverse): Improve MultiEraOutput ergonomics (#141)

This commit is contained in:
Santiago Carmuega 2022-06-29 10:05:38 -03:00 committed by GitHub
parent c7227c0234
commit 98f71289b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 87 additions and 13 deletions

View file

@ -1,4 +1,4 @@
use std::{borrow::Cow, fmt::Display, ops::Deref};
use std::{borrow::Cow, fmt::Display, ops::Deref, str::FromStr};
use pallas_codec::utils::CborWrap;
use pallas_crypto::hash::Hash;
@ -6,7 +6,11 @@ use pallas_primitives::{alonzo, byron};
use crate::{MultiEraInput, OutputRef};
impl OutputRef<'_> {
impl OutputRef {
pub fn new(hash: Hash<32>, index: u64) -> Self {
Self(hash, index)
}
pub fn tx_id(&self) -> &Hash<32> {
&self.0
}
@ -16,12 +20,29 @@ impl OutputRef<'_> {
}
}
impl Display for OutputRef<'_> {
impl Display for OutputRef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}#{}", self.tx_id(), self.tx_index())
}
}
impl FromStr for OutputRef {
type Err = crate::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<_> = s.trim().split('#').collect();
let (hash, idx) = match &parts[..] {
&[a, b] => (
Hash::<32>::from_str(a).map_err(|_| crate::Error::invalid_utxo_ref(s))?,
u64::from_str(b).map_err(|_| crate::Error::invalid_utxo_ref(s))?,
),
_ => return Err(crate::Error::invalid_utxo_ref(s)),
};
Ok(Self::new(hash, idx))
}
}
impl<'b> MultiEraInput<'b> {
pub fn from_byron(input: &'b byron::TxIn) -> Self {
Self::Byron(Box::new(Cow::Borrowed(input)))
@ -34,14 +55,10 @@ impl<'b> MultiEraInput<'b> {
pub fn output_ref(&self) -> Option<OutputRef> {
match self {
MultiEraInput::Byron(x) => match x.deref().deref() {
byron::TxIn::Variant0(CborWrap((tx, idx))) => {
Some(OutputRef(Cow::Borrowed(tx), *idx as u64))
}
byron::TxIn::Variant0(CborWrap((tx, idx))) => Some(OutputRef(*tx, *idx as u64)),
byron::TxIn::Other(_, _) => None,
},
MultiEraInput::AlonzoCompatible(x) => {
Some(OutputRef(Cow::Borrowed(&x.transaction_id), x.index))
}
MultiEraInput::AlonzoCompatible(x) => Some(OutputRef(x.transaction_id, x.index)),
}
}
@ -62,6 +79,8 @@ impl<'b> MultiEraInput<'b> {
#[cfg(test)]
mod tests {
use std::str::FromStr;
use crate::*;
#[test]
@ -99,4 +118,22 @@ mod tests {
}
}
}
#[test]
fn test_utxo_ref_parsing() {
let valid_vectors = [
"da832fb5ef57df5b91817e9a7448d26e92552afb34f8ee5adb491b24bbe990d5#14",
" da832fb5ef57df5b91817e9a7448d26e92552afb34f8ee5adb491b24bbe990d5#14 ",
];
for vector in valid_vectors.iter() {
let sample = OutputRef::from_str(vector).unwrap();
assert_eq!(
sample.tx_id().to_string(),
"da832fb5ef57df5b91817e9a7448d26e92552afb34f8ee5adb491b24bbe990d5"
);
assert_eq!(sample.tx_index(), 14);
}
}
}

View file

@ -67,7 +67,7 @@ pub enum MultiEraTx<'b> {
Byron(Box<Cow<'b, byron::MintedTxPayload<'b>>>),
}
#[derive(Debug)]
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum MultiEraOutput<'b> {
AlonzoCompatible(Box<Cow<'b, alonzo::TransactionOutput>>),
@ -75,7 +75,7 @@ pub enum MultiEraOutput<'b> {
Byron(Box<Cow<'b, byron::TxOut>>),
}
#[derive(Debug)]
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum MultiEraInput<'b> {
Byron(Box<Cow<'b, byron::TxIn>>),
@ -87,7 +87,8 @@ pub enum MultiEraCert<'b> {
AlonzoCompatible(Box<Cow<'b, alonzo::Certificate>>),
}
pub struct OutputRef<'a>(Cow<'a, Hash<32>>, u64);
#[derive(Debug, Clone)]
pub struct OutputRef(Hash<32>, u64);
#[derive(Debug, Error)]
pub enum Error {
@ -102,6 +103,9 @@ pub enum Error {
#[error("Invalid era for request: {0}")]
InvalidEra(Era),
#[error("Invalid UTxO ref: {0}")]
InvalidUtxoRef(String),
}
impl Error {
@ -112,4 +116,8 @@ impl Error {
pub fn unknown_cbor(bytes: &[u8]) -> Self {
Error::UnknownCbor(hex::encode(bytes))
}
pub fn invalid_utxo_ref(str: &str) -> Self {
Error::InvalidUtxoRef(str.to_owned())
}
}

View file

@ -1,8 +1,9 @@
use std::{borrow::Cow, ops::Deref};
use pallas_codec::minicbor;
use pallas_primitives::{alonzo, babbage, byron};
use crate::MultiEraOutput;
use crate::{Era, MultiEraOutput};
impl<'b> MultiEraOutput<'b> {
pub fn from_byron(output: &'b byron::TxOut) -> Self {
@ -70,4 +71,32 @@ impl<'b> MultiEraOutput<'b> {
MultiEraOutput::Byron(x) => Some(x),
}
}
pub fn encode(&self) -> Result<Vec<u8>, minicbor::encode::Error<std::io::Error>> {
match self {
Self::AlonzoCompatible(x) => minicbor::to_vec(x),
Self::Babbage(x) => minicbor::to_vec(x),
Self::Byron(x) => minicbor::to_vec(x),
}
}
pub fn decode(era: Era, cbor: &'b [u8]) -> Result<Self, minicbor::decode::Error> {
match era {
Era::Byron => {
let tx = minicbor::decode(cbor)?;
let tx = Box::new(Cow::Owned(tx));
Ok(Self::Byron(tx))
}
Era::Shelley | Era::Allegra | Era::Mary | Era::Alonzo => {
let tx = minicbor::decode(cbor)?;
let tx = Box::new(Cow::Owned(tx));
Ok(Self::AlonzoCompatible(tx))
}
Era::Babbage => {
let tx = minicbor::decode(cbor)?;
let tx = Box::new(Cow::Owned(tx));
Ok(Self::Babbage(tx))
}
}
}
}