feat: scaffold Byron phase-1 validations (#300)
Co-authored-by: Santiago Carmuega <santiago@carmuega.me>
This commit is contained in:
parent
aafe37573a
commit
986ee75761
14 changed files with 306 additions and 19 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
|
"pallas-applying",
|
||||||
"pallas-codec",
|
"pallas-codec",
|
||||||
"pallas-addresses",
|
"pallas-addresses",
|
||||||
"pallas-network",
|
"pallas-network",
|
||||||
|
|
|
||||||
20
pallas-applying/Cargo.toml
Normal file
20
pallas-applying/Cargo.toml
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
[package]
|
||||||
|
name = "pallas-applying"
|
||||||
|
description = "Logic for validating and applying new blocks and txs to the chain state"
|
||||||
|
version = "0.19.1"
|
||||||
|
edition = "2021"
|
||||||
|
repository = "https://github.com/MaicoLeberle/pallas"
|
||||||
|
homepage = "https://github.com/MaicoLeberle/pallas"
|
||||||
|
license = "Apache-2.0"
|
||||||
|
readme = "README.md"
|
||||||
|
authors = ["Maico Leberle <maico.leberle@gmail.com>"]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
doctest = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
pallas-codec = { path = "../pallas-codec" }
|
||||||
|
pallas-crypto = { path = "../pallas-crypto" }
|
||||||
|
pallas-primitives = { path = "../pallas-primitives" }
|
||||||
|
pallas-traverse = { path = "../pallas-traverse" }
|
||||||
|
rand = "0.8"
|
||||||
3
pallas-applying/README.md
Normal file
3
pallas-applying/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Pallas Applying
|
||||||
|
|
||||||
|
Crate for performing transaction validation according to the Cardano protocol.
|
||||||
14
pallas-applying/src/byron.rs
Normal file
14
pallas-applying/src/byron.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
//! Utilities required for Byron-era transaction validation.
|
||||||
|
|
||||||
|
use crate::types::{ByronProtParams, UTxOs, ValidationResult};
|
||||||
|
|
||||||
|
use pallas_primitives::byron::MintedTxPayload;
|
||||||
|
|
||||||
|
// TODO: implement each of the validation rules.
|
||||||
|
pub fn validate_byron_tx(
|
||||||
|
_mtxp: &MintedTxPayload,
|
||||||
|
_utxos: &UTxOs,
|
||||||
|
_prot_pps: &ByronProtParams,
|
||||||
|
) -> ValidationResult {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
24
pallas-applying/src/lib.rs
Normal file
24
pallas-applying/src/lib.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
//! Logic for validating and applying new blocks and txs to the chain state
|
||||||
|
|
||||||
|
pub mod byron;
|
||||||
|
pub mod types;
|
||||||
|
|
||||||
|
use byron::validate_byron_tx;
|
||||||
|
|
||||||
|
use pallas_traverse::{MultiEraTx, MultiEraTx::Byron as ByronTxPayload};
|
||||||
|
|
||||||
|
pub use types::{
|
||||||
|
MultiEraProtParams, MultiEraProtParams::Byron as ByronProtParams, UTxOs, ValidationResult,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn validate(
|
||||||
|
metx: &MultiEraTx,
|
||||||
|
utxos: &UTxOs,
|
||||||
|
prot_pps: &MultiEraProtParams,
|
||||||
|
) -> ValidationResult {
|
||||||
|
match (metx, prot_pps) {
|
||||||
|
(ByronTxPayload(mtxp), ByronProtParams(bpp)) => validate_byron_tx(mtxp, utxos, bpp),
|
||||||
|
// TODO: implement the rest of the eras.
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
27
pallas-applying/src/types.rs
Normal file
27
pallas-applying/src/types.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
//! Base types used for validating transactions in each era.
|
||||||
|
|
||||||
|
use std::{borrow::Cow, collections::HashMap};
|
||||||
|
|
||||||
|
pub use pallas_traverse::{MultiEraInput, MultiEraOutput};
|
||||||
|
|
||||||
|
pub type UTxOs<'b> = HashMap<MultiEraInput<'b>, MultiEraOutput<'b>>;
|
||||||
|
|
||||||
|
// TODO: add a field for each protocol parameter in the Byron era.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ByronProtParams;
|
||||||
|
|
||||||
|
// TODO: add variants for the other eras.
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum MultiEraProtParams<'b> {
|
||||||
|
Byron(Box<Cow<'b, ByronProtParams>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: replace this generic variant with validation-rule-specific ones.
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum ValidationError {
|
||||||
|
ValidationError,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type ValidationResult = Result<(), ValidationError>;
|
||||||
192
pallas-applying/tests/byron.rs
Normal file
192
pallas-applying/tests/byron.rs
Normal file
|
|
@ -0,0 +1,192 @@
|
||||||
|
use rand::Rng;
|
||||||
|
use std::{borrow::Cow, vec::Vec};
|
||||||
|
|
||||||
|
use pallas_applying::{
|
||||||
|
types::{ByronProtParams, MultiEraProtParams},
|
||||||
|
validate, UTxOs, ValidationResult,
|
||||||
|
};
|
||||||
|
use pallas_codec::{
|
||||||
|
minicbor::{
|
||||||
|
bytes::ByteVec,
|
||||||
|
decode::{Decode, Decoder},
|
||||||
|
encode,
|
||||||
|
},
|
||||||
|
utils::{CborWrap, EmptyMap, KeepRaw, MaybeIndefArray, TagWrap},
|
||||||
|
};
|
||||||
|
use pallas_crypto::hash::Hash;
|
||||||
|
use pallas_primitives::byron::{
|
||||||
|
Address, Attributes, MintedTxPayload as ByronTxPayload, Tx as ByronTx, TxId as ByronTxId,
|
||||||
|
TxIn as ByronTxIn, TxOut as ByronTxOut, Witnesses as ByronWitnesses,
|
||||||
|
};
|
||||||
|
use pallas_traverse::{MultiEraInput, MultiEraOutput, MultiEraTx};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod byron_tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Note that:
|
||||||
|
// i) the transaction input contains 100000 lovelace,
|
||||||
|
// ii) the minimum_fee_constant protocol parameter is 7,
|
||||||
|
// iii) the minimum_fee_factor protocol parameter is 11, and
|
||||||
|
// iv) the size of the transaction is 82 bytes—it is easy to verify that
|
||||||
|
// 82 == pallas_applying::get_byron_tx_size(tx)
|
||||||
|
// The expected fees are therefore 7 + 11 * 82 = 909 lovelace, which is why the output contains
|
||||||
|
// 100000 - 909 = 99091 lovelace.
|
||||||
|
fn successful_case() {
|
||||||
|
let protocol_params: ByronProtParams = ByronProtParams;
|
||||||
|
let mut tx_ins: ByronTxIns = empty_byron_tx_ins();
|
||||||
|
let tx_in: ByronTxIn = new_tx_in(random_tx_id(), 3);
|
||||||
|
add_byron_tx_in(&mut tx_ins, &tx_in);
|
||||||
|
let mut tx_outs: ByronTxOuts = new_byron_tx_outs();
|
||||||
|
let tx_out: ByronTxOut = new_byron_tx_out(new_address(random_address_payload(), 0), 99091);
|
||||||
|
add_byron_tx_out(&mut tx_outs, &tx_out);
|
||||||
|
let mut utxos: UTxOs = new_utxos();
|
||||||
|
// input_tx_out is the ByronTxOut associated with tx_in.
|
||||||
|
let input_tx_out: ByronTxOut =
|
||||||
|
new_byron_tx_out(new_address(random_address_payload(), 0), 100000);
|
||||||
|
add_to_utxo(&mut utxos, tx_in, input_tx_out);
|
||||||
|
let validation_result = mk_byron_tx_and_validate(
|
||||||
|
&new_byron_tx(tx_ins, tx_outs, empty_byron_attributes()),
|
||||||
|
&empty_byron_witnesses(),
|
||||||
|
&utxos,
|
||||||
|
&protocol_params,
|
||||||
|
);
|
||||||
|
match validation_result {
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(err) => assert!(false, "Unexpected error (sucessful_case - {:?}).", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Types aliases.
|
||||||
|
type ByronTxIns = MaybeIndefArray<ByronTxIn>;
|
||||||
|
type ByronTxOuts = MaybeIndefArray<ByronTxOut>;
|
||||||
|
|
||||||
|
// Helper functions.
|
||||||
|
fn empty_byron_tx_ins() -> ByronTxIns {
|
||||||
|
MaybeIndefArray::Def(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random_tx_id() -> ByronTxId {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let mut bytes = [0u8; 32];
|
||||||
|
for elem in bytes.iter_mut() {
|
||||||
|
*elem = rng.gen();
|
||||||
|
}
|
||||||
|
Hash::new(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_tx_in(tx_id: ByronTxId, index: u32) -> ByronTxIn {
|
||||||
|
ByronTxIn::Variant0(CborWrap((tx_id, index)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_byron_tx_in(ins: &mut ByronTxIns, new_in: &ByronTxIn) {
|
||||||
|
match ins {
|
||||||
|
MaybeIndefArray::Def(vec) | MaybeIndefArray::Indef(vec) => vec.push(new_in.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_byron_tx_outs() -> ByronTxOuts {
|
||||||
|
MaybeIndefArray::Def(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random_address_payload() -> TagWrap<ByteVec, 24> {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let mut bytes = [0u8; 24];
|
||||||
|
for elem in bytes.iter_mut() {
|
||||||
|
*elem = rng.gen();
|
||||||
|
}
|
||||||
|
TagWrap::<ByteVec, 24>::new(ByteVec::from(bytes.to_vec()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_address(payload: TagWrap<ByteVec, 24>, crc: u32) -> Address {
|
||||||
|
Address {
|
||||||
|
payload: payload,
|
||||||
|
crc: crc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_byron_tx_out(address: Address, amount: u64) -> ByronTxOut {
|
||||||
|
ByronTxOut {
|
||||||
|
address: address,
|
||||||
|
amount: amount,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_byron_tx_out(outs: &mut ByronTxOuts, new_out: &ByronTxOut) {
|
||||||
|
match outs {
|
||||||
|
MaybeIndefArray::Def(vec) | MaybeIndefArray::Indef(vec) => vec.push(new_out.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_to_utxo<'a>(utxos: &mut UTxOs<'a>, tx_in: ByronTxIn, tx_out: ByronTxOut) {
|
||||||
|
let multi_era_in: MultiEraInput = MultiEraInput::Byron(Box::new(Cow::Owned(tx_in)));
|
||||||
|
let multi_era_out: MultiEraOutput = MultiEraOutput::Byron(Box::new(Cow::Owned(tx_out)));
|
||||||
|
utxos.insert(multi_era_in, multi_era_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn empty_byron_attributes() -> Attributes {
|
||||||
|
EmptyMap
|
||||||
|
}
|
||||||
|
|
||||||
|
/// pallas_applying::validate takes a MultiEraTx, not a ByronTx and a ByronWitnesses. To be able to
|
||||||
|
/// build a MultiEraTx from a ByronTx and a ByronWitnesses, we need to encode each of them and then
|
||||||
|
/// decode them into KeepRaw<ByronTx> and KeepRaw<ByronWitnesses> values, respectively.
|
||||||
|
fn mk_byron_tx_and_validate(
|
||||||
|
btx: &ByronTx,
|
||||||
|
bwit: &ByronWitnesses,
|
||||||
|
utxos: &UTxOs,
|
||||||
|
prot_pps: &ByronProtParams,
|
||||||
|
) -> ValidationResult {
|
||||||
|
// Encode btx and decode into a KeepRaw<ByronTx> value.
|
||||||
|
let mut btx_buf: Vec<u8> = Vec::new();
|
||||||
|
match encode(btx, &mut btx_buf) {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(err) => assert!(false, "Unable to encode ByronTx ({:?}).", err),
|
||||||
|
};
|
||||||
|
let kpbtx: KeepRaw<ByronTx> =
|
||||||
|
match Decode::decode(&mut Decoder::new(&btx_buf.as_slice()), &mut ()) {
|
||||||
|
Ok(kp) => kp,
|
||||||
|
Err(err) => panic!("Unable to decode ByronTx ({:?}).", err),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Encode bwit and decode into a KeepRaw<ByronWitnesses> value.
|
||||||
|
let mut wit_buf: Vec<u8> = Vec::new();
|
||||||
|
match encode(bwit, &mut wit_buf) {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(err) => assert!(false, "Unable to encode ByronWitnesses ({:?}).", err),
|
||||||
|
};
|
||||||
|
let kpbwit: KeepRaw<ByronWitnesses> =
|
||||||
|
match Decode::decode(&mut Decoder::new(&wit_buf.as_slice()), &mut ()) {
|
||||||
|
Ok(kp) => kp,
|
||||||
|
Err(err) => panic!("Unable to decode ByronWitnesses ({:?}).", err),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mtxp: ByronTxPayload = ByronTxPayload {
|
||||||
|
transaction: kpbtx,
|
||||||
|
witness: kpbwit,
|
||||||
|
};
|
||||||
|
let metx: MultiEraTx = MultiEraTx::from_byron(&mtxp);
|
||||||
|
validate(
|
||||||
|
&metx,
|
||||||
|
utxos,
|
||||||
|
&MultiEraProtParams::Byron(Box::new(Cow::Borrowed(&prot_pps))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_byron_tx(ins: ByronTxIns, outs: ByronTxOuts, attrs: Attributes) -> ByronTx {
|
||||||
|
ByronTx {
|
||||||
|
inputs: ins,
|
||||||
|
outputs: outs,
|
||||||
|
attributes: attrs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn empty_byron_witnesses() -> ByronWitnesses {
|
||||||
|
MaybeIndefArray::Def(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_utxos<'a>() -> UTxOs<'a> {
|
||||||
|
UTxOs::new()
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use minicbor::{data::Tag, Decode, Encode};
|
use minicbor::{data::Tag, Decode, Encode};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{fmt, ops::Deref};
|
use std::{fmt, hash::Hash as StdHash, ops::Deref};
|
||||||
|
|
||||||
/// Utility for skipping parts of the CBOR payload, use only for debugging
|
/// Utility for skipping parts of the CBOR payload, use only for debugging
|
||||||
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
|
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
|
||||||
|
|
@ -292,7 +292,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps a struct so that it is encoded/decoded as a cbor bytes
|
/// Wraps a struct so that it is encoded/decoded as a cbor bytes
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, StdHash)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct CborWrap<T>(pub T);
|
pub struct CborWrap<T>(pub T);
|
||||||
|
|
||||||
|
|
@ -390,7 +390,7 @@ impl<I, const T: u64> Deref for TagWrap<I, T> {
|
||||||
/// An empty map
|
/// An empty map
|
||||||
///
|
///
|
||||||
/// don't ask me why, that's what the CDDL asks for.
|
/// don't ask me why, that's what the CDDL asks for.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct EmptyMap;
|
pub struct EmptyMap;
|
||||||
|
|
||||||
impl<'b, C> minicbor::decode::Decode<'b, C> for EmptyMap {
|
impl<'b, C> minicbor::decode::Decode<'b, C> for EmptyMap {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
use pallas_codec::minicbor::{decode, Decode, Decoder, encode, Encode, Encoder};
|
|
||||||
use pallas_codec::minicbor::data::Tag;
|
use pallas_codec::minicbor::data::Tag;
|
||||||
|
use pallas_codec::minicbor::{decode, encode, Decode, Decoder, Encode, Encoder};
|
||||||
|
|
||||||
use crate::miniprotocols::localtxsubmission::{EraTx, Message, RejectReason};
|
use crate::miniprotocols::localtxsubmission::{EraTx, Message, RejectReason};
|
||||||
|
|
||||||
impl<Tx, Reject> Encode<()> for Message<Tx, Reject>
|
impl<Tx, Reject> Encode<()> for Message<Tx, Reject>
|
||||||
where
|
where
|
||||||
Tx: Encode<()>,
|
Tx: Encode<()>,
|
||||||
Reject: Encode<()>,
|
Reject: Encode<()>,
|
||||||
{
|
{
|
||||||
fn encode<W: encode::Write>(
|
fn encode<W: encode::Write>(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -97,14 +97,14 @@ impl Encode<()> for RejectReason {
|
||||||
) -> Result<(), encode::Error<W::Error>> {
|
) -> Result<(), encode::Error<W::Error>> {
|
||||||
e.writer_mut()
|
e.writer_mut()
|
||||||
.write_all(&self.0)
|
.write_all(&self.0)
|
||||||
.map_err(|w_err| encode::Error::write(w_err))?;
|
.map_err(encode::Error::write)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use pallas_codec::{Fragment, minicbor};
|
use pallas_codec::{minicbor, Fragment};
|
||||||
|
|
||||||
use crate::miniprotocols::localtxsubmission::{EraTx, Message, RejectReason};
|
use crate::miniprotocols::localtxsubmission::{EraTx, Message, RejectReason};
|
||||||
use crate::multiplexer::Error;
|
use crate::multiplexer::Error;
|
||||||
|
|
@ -117,8 +117,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_decode_message<M>(buffer: &mut Vec<u8>) -> Result<Option<M>, Error>
|
fn try_decode_message<M>(buffer: &mut Vec<u8>) -> Result<Option<M>, Error>
|
||||||
where
|
where
|
||||||
M: Fragment,
|
M: Fragment,
|
||||||
{
|
{
|
||||||
let mut decoder = minicbor::Decoder::new(buffer);
|
let mut decoder = minicbor::Decoder::new(buffer);
|
||||||
let maybe_msg = decoder.decode();
|
let maybe_msg = decoder.decode();
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
//! Handcrafted, idiomatic rust artifacts based on based on the [Alonzo CDDL](https://github.com/input-output-hk/cardano-ledger/blob/master/eras/alonzo/test-suite/cddl-files/alonzo.cddl) file in IOHK repo.
|
//! Handcrafted, idiomatic rust artifacts based on based on the [Alonzo CDDL](https://github.com/input-output-hk/cardano-ledger/blob/master/eras/alonzo/test-suite/cddl-files/alonzo.cddl) file in IOHK repo.
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{fmt, ops::Deref};
|
use std::{fmt, hash::Hash as StdHash, ops::Deref};
|
||||||
|
|
||||||
use pallas_codec::minicbor::{data::Tag, Decode, Encode};
|
use pallas_codec::minicbor::{data::Tag, Decode, Encode};
|
||||||
use pallas_crypto::hash::Hash;
|
use pallas_crypto::hash::Hash;
|
||||||
|
|
@ -78,7 +78,9 @@ pub struct Header {
|
||||||
pub body_signature: Bytes,
|
pub body_signature: Bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
|
#[derive(
|
||||||
|
Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, StdHash,
|
||||||
|
)]
|
||||||
pub struct TransactionInput {
|
pub struct TransactionInput {
|
||||||
#[n(0)]
|
#[n(0)]
|
||||||
pub transaction_id: Hash<32>,
|
pub transaction_id: Hash<32>,
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ use pallas_codec::utils::{
|
||||||
// required for derive attrs to work
|
// required for derive attrs to work
|
||||||
use pallas_codec::minicbor;
|
use pallas_codec::minicbor;
|
||||||
|
|
||||||
|
use std::hash::Hash as StdHash;
|
||||||
|
|
||||||
// Basic Cardano Types
|
// Basic Cardano Types
|
||||||
|
|
||||||
pub type Blake2b256 = Hash<32>;
|
pub type Blake2b256 = Hash<32>;
|
||||||
|
|
@ -64,7 +66,7 @@ pub struct Address {
|
||||||
// Transactions
|
// Transactions
|
||||||
|
|
||||||
// txout = [address, u64]
|
// txout = [address, u64]
|
||||||
#[derive(Debug, Encode, Decode, Clone)]
|
#[derive(Debug, Encode, Decode, Clone, PartialEq, Eq)]
|
||||||
pub struct TxOut {
|
pub struct TxOut {
|
||||||
#[n(0)]
|
#[n(0)]
|
||||||
pub address: Address,
|
pub address: Address,
|
||||||
|
|
@ -73,7 +75,7 @@ pub struct TxOut {
|
||||||
pub amount: u64,
|
pub amount: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq, StdHash)]
|
||||||
pub enum TxIn {
|
pub enum TxIn {
|
||||||
// [0, #6.24(bytes .cbor ([txid, u32]))]
|
// [0, #6.24(bytes .cbor ([txid, u32]))]
|
||||||
Variant0(CborWrap<(TxId, u32)>),
|
Variant0(CborWrap<(TxId, u32)>),
|
||||||
|
|
@ -121,7 +123,7 @@ impl<C> minicbor::Encode<C> for TxIn {
|
||||||
}
|
}
|
||||||
|
|
||||||
// tx = [[+ txin], [+ txout], attributes]
|
// tx = [[+ txin], [+ txout], attributes]
|
||||||
#[derive(Debug, Encode, Decode, Clone)]
|
#[derive(Debug, Encode, Decode, Clone, PartialEq, Eq)]
|
||||||
pub struct Tx {
|
pub struct Tx {
|
||||||
#[n(0)]
|
#[n(0)]
|
||||||
pub inputs: MaybeIndefArray<TxIn>,
|
pub inputs: MaybeIndefArray<TxIn>,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
//! Utilities to traverse over multi-era block data
|
//! Utilities to traverse over multi-era block data
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::{borrow::Cow, fmt::Display, hash::Hash as StdHash};
|
||||||
use std::fmt::Display;
|
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
|
@ -89,7 +88,7 @@ pub enum MultiEraOutput<'b> {
|
||||||
Byron(Box<Cow<'b, byron::TxOut>>),
|
Byron(Box<Cow<'b, byron::TxOut>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq, StdHash)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum MultiEraInput<'b> {
|
pub enum MultiEraInput<'b> {
|
||||||
Byron(Box<Cow<'b, byron::TxIn>>),
|
Byron(Box<Cow<'b, byron::TxIn>>),
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ readme = "../README.md"
|
||||||
authors = ["Santiago Carmuega <santiago@carmuega.me>"]
|
authors = ["Santiago Carmuega <santiago@carmuega.me>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
pallas-applying = { version = "=0.19.1", path = "../pallas-applying/" }
|
||||||
pallas-network = { version = "=0.19.1", path = "../pallas-network/" }
|
pallas-network = { version = "=0.19.1", path = "../pallas-network/" }
|
||||||
pallas-primitives = { version = "=0.19.1", path = "../pallas-primitives/" }
|
pallas-primitives = { version = "=0.19.1", path = "../pallas-primitives/" }
|
||||||
pallas-traverse = { version = "=0.19.1", path = "../pallas-traverse/" }
|
pallas-traverse = { version = "=0.19.1", path = "../pallas-traverse/" }
|
||||||
|
|
|
||||||
|
|
@ -40,3 +40,5 @@ pub mod interop {
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use pallas_utxorpc as utxorpc;
|
pub use pallas_utxorpc as utxorpc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use pallas_applying as applying;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue