feat: Add Vasil / Babbage compatibility (#126)

* feat: Bump n2n protocol versions for Babbage (#125)
* feat: Allow a specified timeout on tcp connection (#127)
* feat: Add Babbage primitives (#128)
* fix: Inaccurate header-body CDDL (#129)
* fix: Babbage CBOR codec issues (#130)
* feat: Include Babbage in traverse lib
* Parse Babbage headers (#131)
* Add Babbage nonce/leader vrf extension (#132)

Co-authored-by: Andrew Westberg <andrewwestberg@gmail.com>
This commit is contained in:
Santiago Carmuega 2022-06-20 22:09:42 -03:00 committed by GitHub
parent 879d70285b
commit f67d36e7fa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 1826 additions and 90 deletions

3
.gitignore vendored
View file

@ -3,4 +3,5 @@ Cargo.lock
scratchpad
.DS_Store
RELEASE.md
RELEASE.md
.idea

View file

@ -229,7 +229,7 @@ where
}
/// Wraps a struct so that it is encoded/decoded as a cbor bytes
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct CborWrap<T>(pub T);
impl<'b, C, T> minicbor::Decode<'b, C> for CborWrap<T>

View file

@ -8,6 +8,9 @@ const PROTOCOL_V4: u64 = 4;
const PROTOCOL_V5: u64 = 5;
const PROTOCOL_V6: u64 = 6;
const PROTOCOL_V7: u64 = 7;
const PROTOCOL_V8: u64 = 8;
const PROTOCOL_V9: u64 = 9;
const PROTOCOL_V10: u64 = 10;
impl VersionTable {
pub fn v4_and_above(network_magic: u64) -> VersionTable {
@ -16,6 +19,9 @@ impl VersionTable {
(PROTOCOL_V5, VersionData::new(network_magic, false)),
(PROTOCOL_V6, VersionData::new(network_magic, false)),
(PROTOCOL_V7, VersionData::new(network_magic, false)),
(PROTOCOL_V8, VersionData::new(network_magic, false)),
(PROTOCOL_V9, VersionData::new(network_magic, false)),
(PROTOCOL_V10, VersionData::new(network_magic, false)),
]
.into_iter()
.collect::<HashMap<u64, VersionData>>();
@ -27,6 +33,22 @@ impl VersionTable {
let values = vec![
(PROTOCOL_V6, VersionData::new(network_magic, false)),
(PROTOCOL_V7, VersionData::new(network_magic, false)),
(PROTOCOL_V8, VersionData::new(network_magic, false)),
(PROTOCOL_V9, VersionData::new(network_magic, false)),
(PROTOCOL_V10, VersionData::new(network_magic, false)),
]
.into_iter()
.collect::<HashMap<u64, VersionData>>();
VersionTable { values }
}
pub fn v7_and_above(network_magic: u64) -> VersionTable {
let values = vec![
(PROTOCOL_V7, VersionData::new(network_magic, false)),
(PROTOCOL_V8, VersionData::new(network_magic, false)),
(PROTOCOL_V9, VersionData::new(network_magic, false)),
(PROTOCOL_V10, VersionData::new(network_magic, false)),
]
.into_iter()
.collect::<HashMap<u64, VersionData>>();

View file

@ -1,13 +1,14 @@
use byteorder::{ByteOrder, NetworkEndian, WriteBytesExt};
use log::{debug, log_enabled, trace};
use std::io::{Read, Write};
use std::net::{TcpListener, ToSocketAddrs};
use std::net::{SocketAddr, TcpListener, ToSocketAddrs};
use std::{net::TcpStream, time::Instant};
use crate::Payload;
#[cfg(target_family = "unix")]
use std::os::unix::net::UnixStream;
use std::time::Duration;
pub struct Segment {
pub protocol: u16,
@ -110,6 +111,16 @@ impl Bearer {
Ok(Bearer::Tcp(bearer))
}
pub fn connect_tcp_timeout(
addr: &SocketAddr,
timeout: Duration,
) -> Result<Self, std::io::Error> {
let bearer = TcpStream::connect_timeout(addr, timeout)?;
bearer.set_nodelay(true)?;
Ok(Bearer::Tcp(bearer))
}
pub fn accept_tcp(server: TcpListener) -> Result<Self, std::io::Error> {
let (bearer, _) = server.accept().unwrap();
bearer.set_nodelay(true)?;

View file

@ -0,0 +1,394 @@
block =
[ header
, transaction_bodies : [* transaction_body]
, transaction_witness_sets : [* transaction_witness_set]
, auxiliary_data_set : {* transaction_index => auxiliary_data }
, invalid_transactions : [* transaction_index ]
]; Valid blocks must also satisfy the following two constraints:
; 1) the length of transaction_bodies and transaction_witness_sets
; must be the same
; 2) every transaction_index must be strictly smaller than the
; length of transaction_bodies
transaction =
[ transaction_body
, transaction_witness_set
, bool
, auxiliary_data / null
]
transaction_index = uint .size 2
header =
[ header_body
, body_signature : $kes_signature
]
header_body =
[ block_number : uint
, slot : uint
, prev_hash : $hash32 / null
, issuer_vkey : $vkey
, vrf_vkey : $vrf_vkey
, nonce_vrf : $vrf_cert
, leader_vrf : $vrf_cert
, block_body_size : uint
, block_body_hash : $hash32 ; merkle triple root
, operational_cert
, protocol_version
]
operational_cert =
( hot_vkey : $kes_vkey
, sequence_number : uint
, kes_period : uint
, sigma : $signature
)
protocol_version = (uint, uint)
transaction_body =
{ 0 : set<transaction_input> ; inputs
, 1 : [* transaction_output]
, 2 : coin ; fee
, ? 3 : uint ; time to live
, ? 4 : [* certificate]
, ? 5 : withdrawals
, ? 6 : update
, ? 7 : auxiliary_data_hash
, ? 8 : uint ; validity interval start
, ? 9 : mint
, ? 11 : script_data_hash
, ? 13 : set<transaction_input> ; collateral inputs
, ? 14 : required_signers
, ? 15 : network_id
}
required_signers = set<$addr_keyhash>
transaction_input = [ transaction_id : $hash32
, index : uint
]
transaction_output =
[ address
, amount : value
, ? datum_hash : $hash32
]
script_data_hash = $hash32
; This is a hash of data which may affect evaluation of a script.
; This data consists of:
; - The redeemers from the transaction_witness_set (the value of field 5).
; - The datums from the transaction_witness_set (the value of field 4).
; - The value in the costmdls map corresponding to the script's language
; (in field 18 of protocol_param_update.)
; (In the future it may contain additional protocol parameters.)
;
; Since this data does not exist in contiguous form inside a transaction, it needs
; to be independently constructed by each recipient.
;
; script data format:
; [ redeemers | datums | language views ]
; The redeemers are exactly the data present in the transaction witness set.
; Similarly for the datums, if present. If no datums are provided, the middle
; field is an empty string.
;
; language views CDDL:
; { * language => script_integrity_data }
;
; This must be encoded canonically, using the same scheme as in
; RFC7049 section 3.9:
; - Maps, strings, and bytestrings must use a definite-length encoding
; - Integers must be as small as possible.
; - The expressions for map length, string length, and bytestring length
; must be as short as possible.
; - The keys in the map must be sorted as follows:
; - If two keys have different lengths, the shorter one sorts earlier.
; - If two keys have the same length, the one with the lower value
; in (byte-wise) lexical order sorts earlier.
;
; For PlutusV1 (language id 0), the language view is the following:
; - the value of costmdls map at key 0 is encoded as an indefinite length
; list and the result is encoded as a bytestring. (our apologies)
; - the language ID tag is also encoded twice. first as a uint then as
; a bytestring. (our apologies)
;
; If there is no value for key 0, then the corresponding scripts cannot execute.
; Regardless of what the script integrity data is.
;
; Finally, note that in the case that a transaction includes datums but does not
; include any redeemers, the script data format becomes (in hex):
; [ 80 | datums | A0 ]
; corresponding to a CBOR empty list and an empty map.
; address = bytes
; reward_account = bytes
; address format:
; [ 8 bit header | payload ];
;
; shelley payment addresses:
; bit 7: 0
; bit 6: base/other
; bit 5: pointer/enterprise [for base: stake cred is keyhash/scripthash]
; bit 4: payment cred is keyhash/scripthash
; bits 3-0: network id
;
; reward addresses:
; bits 7-5: 111
; bit 4: credential is keyhash/scripthash
; bits 3-0: network id
;
; byron addresses:
; bits 7-4: 1000
; 0000: base address: keyhash28,keyhash28
; 0001: base address: scripthash28,keyhash28
; 0010: base address: keyhash28,scripthash28
; 0011: base address: scripthash28,scripthash28
; 0100: pointer address: keyhash28, 3 variable length uint
; 0101: pointer address: scripthash28, 3 variable length uint
; 0110: enterprise address: keyhash28
; 0111: enterprise address: scripthash28
; 1000: byron address
; 1110: reward account: keyhash28
; 1111: reward account: scripthash28
; 1001 - 1101: future formats
certificate =
[ stake_registration
// stake_deregistration
// stake_delegation
// pool_registration
// pool_retirement
// genesis_key_delegation
// move_instantaneous_rewards_cert
]
stake_registration = (0, stake_credential)
stake_deregistration = (1, stake_credential)
stake_delegation = (2, stake_credential, pool_keyhash)
pool_registration = (3, pool_params)
pool_retirement = (4, pool_keyhash, epoch)
genesis_key_delegation = (5, genesishash, genesis_delegate_hash, vrf_keyhash)
move_instantaneous_rewards_cert = (6, move_instantaneous_reward)
move_instantaneous_reward = [ 0 / 1, { * stake_credential => delta_coin } / coin ]
; The first field determines where the funds are drawn from.
; 0 denotes the reserves, 1 denotes the treasury.
; If the second field is a map, funds are moved to stake credentials,
; otherwise the funds are given to the other accounting pot.
delta_coin = int
stake_credential =
[ 0, addr_keyhash
// 1, scripthash
]
pool_params = ( operator: pool_keyhash
, vrf_keyhash: vrf_keyhash
, pledge: coin
, cost: coin
, margin: unit_interval
, reward_account: reward_account
, pool_owners: set<addr_keyhash>
, relays: [* relay]
, pool_metadata: pool_metadata / null
)
port = uint .le 65535
ipv4 = bytes .size 4
ipv6 = bytes .size 16
dns_name = tstr .size (0..64)
single_host_addr = ( 0
, port / null
, ipv4 / null
, ipv6 / null
)
single_host_name = ( 1
, port / null
, dns_name ; An A or AAAA DNS record
)
multi_host_name = ( 2
, dns_name ; A SRV DNS record
)
relay =
[ single_host_addr
// single_host_name
// multi_host_name
]
pool_metadata = [url, pool_metadata_hash]
url = tstr .size (0..64)
withdrawals = { * reward_account => coin }
update = [ proposed_protocol_parameter_updates
, epoch
]
proposed_protocol_parameter_updates =
{ * genesishash => protocol_param_update }
protocol_param_update =
{ ? 0: uint ; minfee A
, ? 1: uint ; minfee B
, ? 2: uint ; max block body size
, ? 3: uint ; max transaction size
, ? 4: uint ; max block header size
, ? 5: coin ; key deposit
, ? 6: coin ; pool deposit
, ? 7: epoch ; maximum epoch
, ? 8: uint ; n_opt: desired number of stake pools
, ? 9: rational ; pool pledge influence
, ? 10: unit_interval ; expansion rate
, ? 11: unit_interval ; treasury growth rate
, ? 12: unit_interval ; d. decentralization constant
, ? 13: $nonce ; extra entropy
, ? 14: [protocol_version] ; protocol version
, ? 16: coin ; min pool cost
, ? 17: coin ; ada per utxo byte
, ? 18: costmdls ; cost models for script languages
, ? 19: ex_unit_prices ; execution costs
, ? 20: ex_units ; max tx ex units
, ? 21: ex_units ; max block ex units
, ? 22: uint ; max value size
, ? 23: uint ; collateral percentage
, ? 24: uint ; max collateral inputs
}
transaction_witness_set =
{ ? 0: [* vkeywitness ]
, ? 1: [* native_script ]
, ? 2: [* bootstrap_witness ]
, ? 3: [* plutus_script ]
, ? 4: [* plutus_data ]
, ? 5: [* redeemer ]
}
plutus_script = bytes
plutus_data =
constr<plutus_data>
/ { * plutus_data => plutus_data }
/ [ * plutus_data ]
/ big_int
/ bounded_bytes
big_int = int / big_uint / big_nint
big_uint = #6.2(bounded_bytes)
big_nint = #6.3(bounded_bytes)
constr<a> =
#6.121([* a])
/ #6.122([* a])
/ #6.123([* a])
/ #6.124([* a])
/ #6.125([* a])
/ #6.126([* a])
/ #6.127([* a])
; similarly for tag range: 6.1280 .. 6.1400 inclusive
/ #6.102([uint, [* a]])
redeemer = [ tag: redeemer_tag, index: uint, data: plutus_data, ex_units: ex_units ]
redeemer_tag =
0 ; inputTag "Spend"
/ 1 ; mintTag "Mint"
/ 2 ; certTag "Cert"
/ 3 ; wdrlTag "Reward"
ex_units = [mem: uint, steps: uint]
ex_unit_prices =
[ mem_price: sub_coin, step_price: sub_coin ]
; This is an enumeration. for now there's only one value ; New
language = 0 ; Plutus v1
costmdls = { * language => cost_model } ; New
; The keys to the cost model map are not present in the serialization.
; The values in the serialization are assumed to be ordered
; lexicographically by their correpsonding key value.
; The key values are listed in sorted_cost_model_keys.txt.
cost_model = [ 166*166 int ] ; New
transaction_metadatum =
{ * transaction_metadatum => transaction_metadatum }
/ [ * transaction_metadatum ]
/ int
/ bytes .size (0..64)
/ text .size (0..64)
transaction_metadatum_label = uint
metadata = { * transaction_metadatum_label => transaction_metadatum }
auxiliary_data =
metadata ; Shelley
/ [ transaction_metadata: metadata ; Shelley-ma
, auxiliary_scripts: [ * native_script ]
]
/ #6.259({ ? 0 => metadata ; Alonzo and beyond
, ? 1 => [ * native_script ]
, ? 2 => [ * plutus_script ]
})
vkeywitness = [ $vkey, $signature ]
bootstrap_witness =
[ public_key : $vkey
, signature : $signature
, chain_code : bytes .size 32
, attributes : bytes
]
native_script =
[ script_pubkey
// script_all
// script_any
// script_n_of_k
// invalid_before
; Timelock validity intervals are half-open intervals [a, b).
; This field specifies the left (included) endpoint a.
// invalid_hereafter
; Timelock validity intervals are half-open intervals [a, b).
; This field specifies the right (excluded) endpoint b.
]
script_pubkey = (0, addr_keyhash)
script_all = (1, [ * native_script ])
script_any = (2, [ * native_script ])
script_n_of_k = (3, n: uint, [ * native_script ])
invalid_before = (4, uint)
invalid_hereafter = (5, uint)
coin = uint
sub_coin = positive_interval
multiasset<a> = { * policy_id => { * asset_name => a } }
policy_id = scripthash
asset_name = bytes .size (0..32)
value = coin / [coin,multiasset<uint>]
mint = multiasset<int64>
int64 = -9223372036854775808 .. 9223372036854775807
network_id = 0 / 1
epoch = uint
addr_keyhash = $hash28
scripthash = $hash28
genesis_delegate_hash = $hash28
pool_keyhash = $hash28
genesishash = $hash28
vrf_keyhash = $hash32
auxiliary_data_hash = $hash32
pool_metadata_hash = $hash32

View file

@ -43,24 +43,26 @@ pub struct HeaderBody {
pub block_body_hash: Hash<32>,
#[n(9)]
pub operational_cert: ByteVec,
pub operational_cert_hot_vkey: ByteVec,
#[n(10)]
pub unknown_0: u64,
pub operational_cert_sequence_number: u64,
#[n(11)]
pub unknown_1: u64,
pub operational_cert_kes_period: u64,
#[n(12)]
pub unknown_2: ByteVec,
pub operational_cert_sigma: ByteVec,
#[n(13)]
pub protocol_version_major: u64,
pub protocol_major: u64,
#[n(14)]
pub protocol_version_minor: u64,
pub protocol_minor: u64,
}
pub type ProtocolVersion = (u64, u64);
#[derive(Encode, Decode, Debug, PartialEq)]
pub struct KesSignature {}
@ -634,8 +636,6 @@ pub type CostModel = MaybeIndefArray<i32>;
pub type CostMdls = KeyValuePairs<Language, CostModel>;
pub type ProtocolVersion = (u32, u32);
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)]
pub struct ProtocolParamUpdate {
@ -1146,11 +1146,13 @@ pub struct TransactionWitnessSet {
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)]
pub struct AlonzoAuxiliaryData {
pub struct PostAlonzoAuxiliaryData {
#[n(0)]
pub metadata: Option<Metadata>,
#[n(1)]
pub native_scripts: Option<MaybeIndefArray<NativeScript>>,
#[n(2)]
pub plutus_scripts: Option<MaybeIndefArray<PlutusScript>>,
}
@ -1246,14 +1248,20 @@ pub type MetadatumLabel = AnyUInt;
pub type Metadata = KeyValuePairs<MetadatumLabel, Metadatum>;
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct ShelleyMaAuxiliaryDAta {
#[n(0)]
transaction_metadata: Metadata,
#[n(1)]
auxiliary_scripts: Option<MaybeIndefArray<NativeScript>>,
}
#[derive(Debug, PartialEq, Clone)]
pub enum AuxiliaryData {
Shelley(Metadata),
ShelleyMa {
transaction_metadata: Metadata,
auxiliary_scripts: Option<MaybeIndefArray<NativeScript>>,
},
Alonzo(AlonzoAuxiliaryData),
ShelleyMa(ShelleyMaAuxiliaryDAta),
PostAlonzo(PostAlonzoAuxiliaryData),
}
impl<'b, C> minicbor::Decode<'b, C> for AuxiliaryData {
@ -1262,18 +1270,10 @@ impl<'b, C> minicbor::Decode<'b, C> for AuxiliaryData {
minicbor::data::Type::Map | minicbor::data::Type::MapIndef => {
Ok(AuxiliaryData::Shelley(d.decode_with(ctx)?))
}
minicbor::data::Type::Array => {
d.array()?;
let transaction_metadata = d.decode_with(ctx)?;
let auxiliary_scripts = d.decode_with(ctx)?;
Ok(AuxiliaryData::ShelleyMa {
transaction_metadata,
auxiliary_scripts,
})
}
minicbor::data::Type::Array => Ok(AuxiliaryData::ShelleyMa(d.decode_with(ctx)?)),
minicbor::data::Type::Tag => {
d.tag()?;
Ok(AuxiliaryData::Alonzo(d.decode_with(ctx)?))
Ok(AuxiliaryData::PostAlonzo(d.decode_with(ctx)?))
}
_ => Err(minicbor::decode::Error::message(
"Can't infer variant from data type for AuxiliaryData",
@ -1292,15 +1292,10 @@ impl<C> minicbor::Encode<C> for AuxiliaryData {
AuxiliaryData::Shelley(m) => {
e.encode_with(m, ctx)?;
}
AuxiliaryData::ShelleyMa {
transaction_metadata,
auxiliary_scripts,
} => {
e.array(2)?;
e.encode_with(transaction_metadata, ctx)?;
e.encode_with(auxiliary_scripts, ctx)?;
AuxiliaryData::ShelleyMa(m) => {
e.encode_with(m, ctx)?;
}
AuxiliaryData::Alonzo(v) => {
AuxiliaryData::PostAlonzo(v) => {
// TODO: check if this is the correct tag
e.tag(Tag::Unassigned(259))?;
e.encode_with(v, ctx)?;

View file

@ -0,0 +1,57 @@
use crate::Error;
use super::TransactionOutput;
use bech32::{self, ToBase32};
pub fn encode_bech32_address(data: &[u8], hrp: &str) -> Result<String, Error> {
bech32::encode(hrp, data.to_base32(), bech32::Variant::Bech32).map_err(|e| e.into())
}
impl TransactionOutput {
pub fn to_bech32_address(&self, hrp: &str) -> Result<String, Error> {
let address = match self {
TransactionOutput::Legacy(x) => &x.address,
TransactionOutput::PostAlonzo(x) => &x.address,
};
encode_bech32_address(address.as_slice(), hrp)
}
}
#[cfg(test)]
mod tests {
use pallas_codec::minicbor;
use crate::babbage::Block;
type BlockWrapper = (u16, Block);
const KNOWN_ADDRESSES: &[&str] =
&["addr_test1vpfwv0ezc5g8a4mkku8hhy3y3vp92t7s3ul8g778g5yegsgalc6gc"];
#[test]
fn known_address_matches() {
// TODO: expand this test to include more test blocks
let block_idx = 1;
let block_str = include_str!("../../../test_data/babbage1.block");
let block_bytes = hex::decode(block_str).expect(&format!("bad block file {}", block_idx));
let (_, block): BlockWrapper = minicbor::decode(&block_bytes[..])
.expect(&format!("error decoding cbor for file {}", block_idx));
// don't want to pass if we don't have tx in the block
assert!(block.transaction_bodies.len() > 0);
for tx in block.transaction_bodies.iter() {
for output in tx.outputs.iter() {
let addr_str = output.to_bech32_address("addr_test").unwrap();
assert!(
KNOWN_ADDRESSES.contains(&addr_str.as_str()),
"address {} not in known list",
addr_str
);
}
}
}
}

View file

@ -0,0 +1,58 @@
use crate::ToHash;
use super::{Header, PlutusV2Script, TransactionBody};
use pallas_codec::utils::KeepRaw;
use pallas_crypto::hash::{Hash, Hasher};
impl ToHash<32> for Header {
fn to_hash(&self) -> pallas_crypto::hash::Hash<32> {
Hasher::<256>::hash_cbor(self)
}
}
impl ToHash<28> for PlutusV2Script {
fn to_hash(&self) -> Hash<28> {
Hasher::<224>::hash_tagged_cbor(self, 1)
}
}
impl ToHash<32> for TransactionBody {
fn to_hash(&self) -> Hash<32> {
Hasher::<256>::hash_cbor(self)
}
}
impl ToHash<32> for KeepRaw<'_, TransactionBody> {
fn to_hash(&self) -> pallas_crypto::hash::Hash<32> {
Hasher::<256>::hash(self.raw_cbor())
}
}
#[cfg(test)]
mod tests {
use pallas_codec::minicbor;
use crate::babbage::MintedBlock;
use crate::ToHash;
type BlockWrapper<'b> = (u16, MintedBlock<'b>);
#[test]
fn transaction_hash_works() {
// TODO: expand this test to include more test blocks
let block_idx = 1;
let block_str = include_str!("../../../test_data/babbage1.block");
let block_bytes = hex::decode(block_str).expect(&format!("bad block file {}", block_idx));
let (_, block_model): BlockWrapper = minicbor::decode(&block_bytes[..])
.expect(&format!("error decoding cbor for file {}", block_idx));
let valid_hashes = vec!["3fad302595665b004971a6b76909854a39a0a7ecdbff3692f37b77ae37dbe882"];
for (tx_idx, tx) in block_model.transaction_bodies.iter().enumerate() {
let computed_hash = tx.to_hash();
let known_hash = valid_hashes[tx_idx];
assert_eq!(hex::encode(computed_hash), known_hash)
}
}
}

View file

@ -0,0 +1,412 @@
block =
[ header
, transaction_bodies : [* transaction_body]
, transaction_witness_sets : [* transaction_witness_set]
, auxiliary_data_set : {* transaction_index => auxiliary_data }
, invalid_transactions : [* transaction_index ]
]; Valid blocks must also satisfy the following two constraints:
; 1) the length of transaction_bodies and transaction_witness_sets
; must be the same
; 2) every transaction_index must be strictly smaller than the
; length of transaction_bodies
transaction =
[ transaction_body
, transaction_witness_set
, bool
, auxiliary_data / null
]
transaction_index = uint .size 2
header =
[ header_body
, body_signature : $kes_signature
]
header_body =
[ block_number : uint
, slot : uint
, prev_hash : $hash32 / null
, issuer_vkey : $vkey
, vrf_vkey : $vrf_vkey
, vrf_result : $vrf_cert ; New, replaces nonce_vrf and leader_vrf
, block_body_size : uint
, block_body_hash : $hash32 ; merkle triple root
, operational_cert
, protocol_version
]
operational_cert =
( hot_vkey : $kes_vkey
, sequence_number : uint
, kes_period : uint
, sigma : $signature
)
protocol_version = (uint, uint)
transaction_body =
{ 0 : set<transaction_input> ; inputs
, 1 : [* transaction_output]
, 2 : coin ; fee
, ? 3 : uint ; time to live
, ? 4 : [* certificate]
, ? 5 : withdrawals
, ? 6 : update
, ? 7 : auxiliary_data_hash
, ? 8 : uint ; validity interval start
, ? 9 : mint
, ? 11 : script_data_hash
, ? 13 : set<transaction_input> ; collateral inputs
, ? 14 : required_signers
, ? 15 : network_id
, ? 16 : transaction_output ; collateral return; New
, ? 17 : coin ; total collateral; New
, ? 18 : set<transaction_input> ; reference inputs; New
}
required_signers = set<$addr_keyhash>
transaction_input = [ transaction_id : $hash32
, index : uint
]
transaction_output = legacy_transaction_output / post_alonzo_transaction_output ; New
legacy_transaction_output =
[ address
, amount : value
, ? datum_hash : $hash32
]
post_alonzo_transaction_output =
{ 0 : address
, 1 : value
, ? 2 : datum_option ; New; datum option
, ? 3 : script_ref ; New; script reference
}
script_data_hash = $hash32
; This is a hash of data which may affect evaluation of a script.
; This data consists of:
; - The redeemers from the transaction_witness_set (the value of field 5).
; - The datums from the transaction_witness_set (the value of field 4).
; - The value in the costmdls map corresponding to the script's language
; (in field 18 of protocol_param_update.)
; (In the future it may contain additional protocol parameters.)
;
; Since this data does not exist in contiguous form inside a transaction, it needs
; to be independently constructed by each recipient.
;
; script data format:
; [ redeemers | datums | language views ]
; The redeemers are exactly the data present in the transaction witness set.
; Similarly for the datums, if present. If no datums are provided, the middle
; field is an empty string.
;
; language views CDDL:
; { * language => script_integrity_data }
;
; This must be encoded canonically, using the same scheme as in
; RFC7049 section 3.9:
; - Maps, strings, and bytestrings must use a definite-length encoding
; - Integers must be as small as possible.
; - The expressions for map length, string length, and bytestring length
; must be as short as possible.
; - The keys in the map must be sorted as follows:
; - If two keys have different lengths, the shorter one sorts earlier.
; - If two keys have the same length, the one with the lower value
; in (byte-wise) lexical order sorts earlier.
;
; For PlutusV1 (language id 0), the language view is the following:
; - the value of costmdls map at key 0 is encoded as an indefinite length
; list and the result is encoded as a bytestring. (our apologies)
; - the language ID tag is also encoded twice. first as a uint then as
; a bytestring. (our apologies)
; For PlutusV2 (language id 1), the language view is the following:
; - the value of costmdls map at key 1 is encoded as an definite length list.
;
; If there is no value for key 0, then the corresponding scripts cannot execute.
; Regardless of what the script integrity data is.
;
; Finally, note that in the case that a transaction includes datums but does not
; include any redeemers, the script data format becomes (in hex):
; [ 80 | datums | A0 ]
; corresponding to a CBOR empty list and an empty map.
; address = bytes
; reward_account = bytes
; address format:
; [ 8 bit header | payload ];
;
; shelley payment addresses:
; bit 7: 0
; bit 6: base/other
; bit 5: pointer/enterprise [for base: stake cred is keyhash/scripthash]
; bit 4: payment cred is keyhash/scripthash
; bits 3-0: network id
;
; reward addresses:
; bits 7-5: 111
; bit 4: credential is keyhash/scripthash
; bits 3-0: network id
;
; byron addresses:
; bits 7-4: 1000
; 0000: base address: keyhash28,keyhash28
; 0001: base address: scripthash28,keyhash28
; 0010: base address: keyhash28,scripthash28
; 0011: base address: scripthash28,scripthash28
; 0100: pointer address: keyhash28, 3 variable length uint
; 0101: pointer address: scripthash28, 3 variable length uint
; 0110: enterprise address: keyhash28
; 0111: enterprise address: scripthash28
; 1000: byron address
; 1110: reward account: keyhash28
; 1111: reward account: scripthash28
; 1001 - 1101: future formats
certificate =
[ stake_registration
// stake_deregistration
// stake_delegation
// pool_registration
// pool_retirement
// genesis_key_delegation
// move_instantaneous_rewards_cert
]
stake_registration = (0, stake_credential)
stake_deregistration = (1, stake_credential)
stake_delegation = (2, stake_credential, pool_keyhash)
pool_registration = (3, pool_params)
pool_retirement = (4, pool_keyhash, epoch)
genesis_key_delegation = (5, genesishash, genesis_delegate_hash, vrf_keyhash)
move_instantaneous_rewards_cert = (6, move_instantaneous_reward)
move_instantaneous_reward = [ 0 / 1, { * stake_credential => delta_coin } / coin ]
; The first field determines where the funds are drawn from.
; 0 denotes the reserves, 1 denotes the treasury.
; If the second field is a map, funds are moved to stake credentials,
; otherwise the funds are given to the other accounting pot.
delta_coin = int
stake_credential =
[ 0, addr_keyhash
// 1, scripthash
]
pool_params = ( operator: pool_keyhash
, vrf_keyhash: vrf_keyhash
, pledge: coin
, cost: coin
, margin: unit_interval
, reward_account: reward_account
, pool_owners: set<addr_keyhash>
, relays: [* relay]
, pool_metadata: pool_metadata / null
)
port = uint .le 65535
ipv4 = bytes .size 4
ipv6 = bytes .size 16
dns_name = tstr .size (0..64)
single_host_addr = ( 0
, port / null
, ipv4 / null
, ipv6 / null
)
single_host_name = ( 1
, port / null
, dns_name ; An A or AAAA DNS record
)
multi_host_name = ( 2
, dns_name ; A SRV DNS record
)
relay =
[ single_host_addr
// single_host_name
// multi_host_name
]
pool_metadata = [url, pool_metadata_hash]
url = tstr .size (0..64)
withdrawals = { * reward_account => coin }
update = [ proposed_protocol_parameter_updates
, epoch
]
proposed_protocol_parameter_updates =
{ * genesishash => protocol_param_update }
protocol_param_update =
{ ? 0: uint ; minfee A
, ? 1: uint ; minfee B
, ? 2: uint ; max block body size
, ? 3: uint ; max transaction size
, ? 4: uint ; max block header size
, ? 5: coin ; key deposit
, ? 6: coin ; pool deposit
, ? 7: epoch ; maximum epoch
, ? 8: uint ; n_opt: desired number of stake pools
, ? 9: rational ; pool pledge influence
, ? 10: unit_interval ; expansion rate
, ? 11: unit_interval ; treasury growth rate
, ? 14: [protocol_version] ; protocol version
, ? 16: coin ; min pool cost
, ? 17: coin ; ada per utxo byte
, ? 18: costmdls ; cost models for script languages
, ? 19: ex_unit_prices ; execution costs
, ? 20: ex_units ; max tx ex units
, ? 21: ex_units ; max block ex units
, ? 22: uint ; max value size
, ? 23: uint ; collateral percentage
, ? 24: uint ; max collateral inputs
}
transaction_witness_set =
{ ? 0: [* vkeywitness ]
, ? 1: [* native_script ]
, ? 2: [* bootstrap_witness ]
, ? 3: [* plutus_v1_script ]
, ? 4: [* plutus_data ]
, ? 5: [* redeemer ]
, ? 6: [* plutus_v2_script ] ; New
}
plutus_v1_script = bytes
plutus_v2_script = bytes
plutus_data =
constr<plutus_data>
/ { * plutus_data => plutus_data }
/ [ * plutus_data ]
/ big_int
/ bounded_bytes
big_int = int / big_uint / big_nint
big_uint = #6.2(bounded_bytes)
big_nint = #6.3(bounded_bytes)
constr<a> =
#6.121([* a])
/ #6.122([* a])
/ #6.123([* a])
/ #6.124([* a])
/ #6.125([* a])
/ #6.126([* a])
/ #6.127([* a])
; similarly for tag range: 6.1280 .. 6.1400 inclusive
/ #6.102([uint, [* a]])
redeemer = [ tag: redeemer_tag, index: uint, data: plutus_data, ex_units: ex_units ]
redeemer_tag =
0 ; inputTag "Spend"
/ 1 ; mintTag "Mint"
/ 2 ; certTag "Cert"
/ 3 ; wdrlTag "Reward"
ex_units = [mem: uint, steps: uint]
ex_unit_prices =
[ mem_price: sub_coin, step_price: sub_coin ]
language = 0 ; Plutus v1
/ 1 ; Plutus v2
costmdls =
{ ? 0 : [ 166*166 int ] ; Plutus v1
, ? 1 : [ 175*175 int ] ; Plutus v2
}
transaction_metadatum =
{ * transaction_metadatum => transaction_metadatum }
/ [ * transaction_metadatum ]
/ int
/ bytes .size (0..64)
/ text .size (0..64)
transaction_metadatum_label = uint
metadata = { * transaction_metadatum_label => transaction_metadatum }
auxiliary_data =
metadata ; Shelley
/ [ transaction_metadata: metadata ; Shelley-ma
, auxiliary_scripts: [ * native_script ]
]
/ #6.259({ ? 0 => metadata ; Alonzo and beyond
, ? 1 => [ * native_script ]
, ? 2 => [ * plutus_v1_script ]
, ? 3 => [ * plutus_v2_script ]
})
vkeywitness = [ $vkey, $signature ]
bootstrap_witness =
[ public_key : $vkey
, signature : $signature
, chain_code : bytes .size 32
, attributes : bytes
]
native_script =
[ script_pubkey
// script_all
// script_any
// script_n_of_k
// invalid_before
; Timelock validity intervals are half-open intervals [a, b).
; This field specifies the left (included) endpoint a.
// invalid_hereafter
; Timelock validity intervals are half-open intervals [a, b).
; This field specifies the right (excluded) endpoint b.
]
script_pubkey = (0, addr_keyhash)
script_all = (1, [ * native_script ])
script_any = (2, [ * native_script ])
script_n_of_k = (3, n: uint, [ * native_script ])
invalid_before = (4, uint)
invalid_hereafter = (5, uint)
coin = uint
sub_coin = positive_interval
multiasset<a> = { * policy_id => { * asset_name => a } }
policy_id = scripthash
asset_name = bytes .size (0..32)
value = coin / [coin,multiasset<uint>]
mint = multiasset<int64>
int64 = -9223372036854775808 .. 9223372036854775807
network_id = 0 / 1
epoch = uint
addr_keyhash = $hash28
scripthash = $hash28
genesis_delegate_hash = $hash28
pool_keyhash = $hash28
genesishash = $hash28
vrf_keyhash = $hash32
auxiliary_data_hash = $hash32
pool_metadata_hash = $hash32
datum_hash = $hash32
data = #6.24(bytes .cbor plutus_data)
datum_option = [ 0, $hash32 // 1, data ]
script_ref = #6.24(bytes .cbor script)
script = [ 0, native_script // 1, plutus_v1_script // 2, plutus_v2_script ]

View file

@ -0,0 +1,5 @@
mod address;
mod crypto;
mod model;
pub use model::*;

View file

@ -0,0 +1,607 @@
//! Ledger primitives and cbor codec for the Alonzo era
//!
//! Handcrafted, idiomatic rust artifacts based on based on the [Babbage CDDL](https://github.com/input-output-hk/cardano-ledger/blob/master/eras/babbage/test-suite/cddl-files/babbage.cddl) file in IOHK repo.
use pallas_codec::minicbor::{bytes::ByteVec, Decode, Encode};
use pallas_crypto::hash::Hash;
use pallas_codec::utils::{CborWrap, KeepRaw, KeyValuePairs, MaybeIndefArray};
// required for derive attrs to work
use pallas_codec::minicbor;
pub use crate::alonzo::VrfCert;
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct HeaderBody {
#[n(0)]
pub block_number: u64,
#[n(1)]
pub slot: u64,
#[n(2)]
pub prev_hash: Hash<32>,
#[n(3)]
pub issuer_vkey: ByteVec,
#[n(4)]
pub vrf_vkey: ByteVec,
#[n(5)]
pub vrf_result: VrfCert,
#[n(6)]
pub block_body_size: u64,
#[n(7)]
pub block_body_hash: Hash<32>,
#[n(8)]
pub operational_cert: OperationalCert,
#[n(9)]
pub protocol_version: ProtocolVersion,
}
#[derive(Encode, Decode, Debug, Clone, PartialEq, PartialOrd)]
pub struct OperationalCert {
#[n(0)]
pub operational_cert_hot_vkey: ByteVec,
#[n(1)]
pub operational_cert_sequence_number: u64,
#[n(2)]
pub operational_cert_kes_period: u64,
#[n(3)]
pub operational_cert_sigma: ByteVec,
}
pub use crate::alonzo::ProtocolVersion;
pub use crate::alonzo::KesSignature;
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct Header {
#[n(0)]
pub header_body: HeaderBody,
#[n(1)]
pub body_signature: ByteVec,
}
pub use crate::alonzo::TransactionInput;
pub use crate::alonzo::NonceVariant;
pub use crate::alonzo::Nonce;
pub use crate::alonzo::ScriptHash;
pub use crate::alonzo::PolicyId;
pub use crate::alonzo::AssetName;
pub use crate::alonzo::Multiasset;
pub use crate::alonzo::Mint;
pub use crate::alonzo::Coin;
pub use crate::alonzo::Value;
pub use crate::alonzo::TransactionOutput as LegacyTransacionOutput;
pub use crate::alonzo::PoolKeyhash;
pub use crate::alonzo::Epoch;
pub use crate::alonzo::Genesishash;
pub use crate::alonzo::GenesisDelegateHash;
pub use crate::alonzo::VrfKeyhash;
pub use crate::alonzo::InstantaneousRewardSource;
pub use crate::alonzo::InstantaneousRewardTarget;
pub use crate::alonzo::MoveInstantaneousReward;
pub use crate::alonzo::RewardAccount;
pub use crate::alonzo::Port;
pub use crate::alonzo::IPv4;
pub use crate::alonzo::IPv6;
pub use crate::alonzo::DnsName;
pub use crate::alonzo::Relay;
pub use crate::alonzo::PoolMetadataHash;
pub use crate::alonzo::PoolMetadata;
pub use crate::alonzo::AddrKeyhash;
pub use crate::alonzo::Scripthash;
pub use crate::alonzo::RationalNumber;
pub use crate::alonzo::UnitInterval;
pub use crate::alonzo::PositiveInterval;
pub use crate::alonzo::StakeCredential;
pub use crate::alonzo::Certificate;
pub use crate::alonzo::NetworkId;
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(index_only)]
pub enum Language {
#[n(0)]
PlutusV1,
#[n(1)]
PlutusV2,
}
pub use crate::alonzo::CostModel;
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)]
pub struct CostMdls {
#[n(0)]
pub plutus_v1: CostModel,
#[n(1)]
pub plutus_v2: CostModel,
}
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)]
pub struct ProtocolParamUpdate {
#[n(0)]
pub minfee_a: Option<u32>,
#[n(1)]
pub minfee_b: Option<u32>,
#[n(2)]
pub max_block_body_size: Option<u32>,
#[n(3)]
pub max_transaction_size: Option<u32>,
#[n(4)]
pub max_block_header_size: Option<u32>,
#[n(5)]
pub key_deposit: Option<Coin>,
#[n(6)]
pub pool_deposit: Option<Coin>,
#[n(7)]
pub maximum_epoch: Option<Epoch>,
#[n(8)]
pub desired_number_of_stake_pools: Option<u32>,
#[n(9)]
pub pool_pledge_influence: Option<RationalNumber>,
#[n(10)]
pub expansion_rate: Option<UnitInterval>,
#[n(11)]
pub treasury_growth_rate: Option<UnitInterval>,
#[n(14)]
pub protocol_version: Option<ProtocolVersion>,
#[n(16)]
pub min_pool_cost: Option<Coin>,
#[n(17)]
pub ada_per_utxo_byte: Option<Coin>,
#[n(18)]
pub cost_models_for_script_languages: Option<CostMdls>,
#[n(19)]
pub execution_costs: Option<ExUnitPrices>,
#[n(20)]
pub max_tx_ex_units: Option<ExUnits>,
#[n(21)]
pub max_block_ex_units: Option<ExUnits>,
#[n(22)]
pub max_value_size: Option<u32>,
#[n(23)]
pub collateral_percentage: Option<u32>,
#[n(24)]
pub max_collateral_inputs: Option<u32>,
}
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct Update {
#[n(0)]
pub proposed_protocol_parameter_updates: KeyValuePairs<Genesishash, ProtocolParamUpdate>,
#[n(1)]
pub epoch: Epoch,
}
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)]
pub struct TransactionBody {
#[n(0)]
pub inputs: MaybeIndefArray<TransactionInput>,
#[n(1)]
pub outputs: MaybeIndefArray<TransactionOutput>,
#[n(2)]
pub fee: u64,
#[n(3)]
pub ttl: Option<u64>,
#[n(4)]
pub certificates: Option<MaybeIndefArray<Certificate>>,
#[n(5)]
pub withdrawals: Option<KeyValuePairs<RewardAccount, Coin>>,
#[n(6)]
pub update: Option<Update>,
#[n(7)]
pub auxiliary_data_hash: Option<ByteVec>,
#[n(8)]
pub validity_interval_start: Option<u64>,
#[n(9)]
pub mint: Option<Multiasset<i64>>,
#[n(11)]
pub script_data_hash: Option<Hash<32>>,
#[n(13)]
pub collateral: Option<MaybeIndefArray<TransactionInput>>,
#[n(14)]
pub required_signers: Option<MaybeIndefArray<AddrKeyhash>>,
#[n(15)]
pub network_id: Option<NetworkId>,
#[n(16)]
pub collateral_return: Option<TransactionOutput>,
#[n(17)]
pub total_collateral: Option<Coin>,
#[n(18)]
pub reference_inputs: Option<MaybeIndefArray<TransactionInput>>,
}
#[derive(Debug, PartialEq, Clone)]
pub enum TransactionOutput {
Legacy(LegacyTransacionOutput),
PostAlonzo(PostAlonzoTransactionOutput),
}
impl<'b, C> minicbor::Decode<'b, C> for TransactionOutput {
fn decode(
d: &mut minicbor::Decoder<'b>,
_ctx: &mut C,
) -> Result<Self, minicbor::decode::Error> {
match d.datatype()? {
minicbor::data::Type::Array | minicbor::data::Type::ArrayIndef => {
Ok(TransactionOutput::Legacy(d.decode()?))
}
minicbor::data::Type::Map | minicbor::data::Type::MapIndef => {
Ok(TransactionOutput::PostAlonzo(d.decode()?))
}
_ => Err(minicbor::decode::Error::message(
"invalid type for transaction output struct",
)),
}
}
}
impl<C> minicbor::Encode<C> for TransactionOutput {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
TransactionOutput::Legacy(x) => x.encode(e, ctx),
TransactionOutput::PostAlonzo(x) => x.encode(e, ctx),
}
}
}
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)]
pub struct PostAlonzoTransactionOutput {
#[n(0)]
pub address: ByteVec,
#[n(1)]
pub value: Value,
#[n(2)]
pub datum_option: Option<DatumOption>,
#[n(3)]
pub script_ref: Option<ScriptRef>,
}
pub use crate::alonzo::VKeyWitness;
pub use crate::alonzo::NativeScript;
pub use crate::alonzo::PlutusScript as PlutusV1Script;
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(transparent)]
pub struct PlutusV2Script(#[n(0)] pub ByteVec);
impl AsRef<[u8]> for PlutusV2Script {
fn as_ref(&self) -> &[u8] {
self.0.as_slice()
}
}
pub use crate::alonzo::BigInt;
pub use crate::alonzo::PlutusData;
pub use crate::alonzo::Constr;
pub use crate::alonzo::ExUnits;
pub use crate::alonzo::ExUnitPrices;
pub use crate::alonzo::RedeemerTag;
pub use crate::alonzo::Redeemer;
pub use crate::alonzo::BootstrapWitness;
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)]
pub struct TransactionWitnessSet {
#[n(0)]
pub vkeywitness: Option<MaybeIndefArray<VKeyWitness>>,
#[n(1)]
pub native_script: Option<MaybeIndefArray<NativeScript>>,
#[n(2)]
pub bootstrap_witness: Option<MaybeIndefArray<BootstrapWitness>>,
#[n(3)]
pub plutus_v1_script: Option<MaybeIndefArray<PlutusV1Script>>,
#[n(4)]
pub plutus_data: Option<MaybeIndefArray<PlutusData>>,
#[n(5)]
pub redeemer: Option<MaybeIndefArray<Redeemer>>,
#[n(6)]
pub plutus_v2_script: Option<MaybeIndefArray<PlutusV2Script>>,
}
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)]
pub struct PostAlonzoAuxiliaryData {
#[n(0)]
pub metadata: Option<Metadata>,
#[n(1)]
pub native_scripts: Option<MaybeIndefArray<NativeScript>>,
#[n(2)]
pub plutus_v1_scripts: Option<MaybeIndefArray<PlutusV1Script>>,
#[n(3)]
pub plutus_v2_scripts: Option<MaybeIndefArray<PlutusV2Script>>,
}
pub type DatumHash = Hash<32>;
pub type Data = CborWrap<PlutusData>;
// datum_option = [ 0, $hash32 // 1, data ]
#[derive(Debug, PartialEq, Clone)]
pub enum DatumOption {
Hash(Hash<32>),
Data(Data),
}
impl<'b, C> minicbor::Decode<'b, C> for DatumOption {
fn decode(
d: &mut minicbor::Decoder<'b>,
_ctx: &mut C,
) -> Result<Self, minicbor::decode::Error> {
d.array()?;
match d.u8()? {
0 => Ok(Self::Hash(d.decode()?)),
1 => Ok(Self::Data(d.decode()?)),
_ => Err(minicbor::decode::Error::message(
"invalid variant for datum option enum",
)),
}
}
}
impl<C> minicbor::Encode<C> for DatumOption {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
Self::Hash(x) => e.encode_with((0, x), ctx)?,
Self::Data(x) => e.encode_with((1, x), ctx)?,
};
Ok(())
}
}
// script_ref = #6.24(bytes .cbor script)
pub type ScriptRef = CborWrap<Script>;
// script = [ 0, native_script // 1, plutus_v1_script // 2, plutus_v2_script ]
#[derive(Debug, PartialEq, Clone)]
pub enum Script {
NativeScript(NativeScript),
PlutusV1Script(PlutusV1Script),
PlutusV2Script(PlutusV2Script),
}
impl<'b, C> minicbor::Decode<'b, C> for Script {
fn decode(
d: &mut minicbor::Decoder<'b>,
_ctx: &mut C,
) -> Result<Self, minicbor::decode::Error> {
d.array()?;
match d.u8()? {
0 => Ok(Self::NativeScript(d.decode()?)),
1 => Ok(Self::PlutusV1Script(d.decode()?)),
2 => Ok(Self::PlutusV2Script(d.decode()?)),
_ => Err(minicbor::decode::Error::message(
"invalid variant for script enum",
)),
}
}
}
impl<C> minicbor::Encode<C> for Script {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
Self::NativeScript(x) => e.encode_with((0, x), ctx)?,
Self::PlutusV1Script(x) => e.encode_with((1, x), ctx)?,
Self::PlutusV2Script(x) => e.encode_with((2, x), ctx)?,
};
Ok(())
}
}
pub use crate::alonzo::Metadatum;
pub use crate::alonzo::MetadatumLabel;
pub use crate::alonzo::Metadata;
pub use crate::alonzo::AuxiliaryData;
pub use crate::alonzo::TransactionIndex;
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct Block {
#[n(0)]
pub header: Header,
#[b(1)]
pub transaction_bodies: MaybeIndefArray<TransactionBody>,
#[n(2)]
pub transaction_witness_sets: MaybeIndefArray<TransactionWitnessSet>,
#[n(3)]
pub auxiliary_data_set: KeyValuePairs<TransactionIndex, AuxiliaryData>,
#[n(4)]
pub invalid_transactions: Option<MaybeIndefArray<TransactionIndex>>,
}
/// A memory representation of an already minted block
///
/// This structure is analogous to [Block], but it allows to retrieve the
/// original CBOR bytes for each structure that might require hashing. In this
/// way, we make sure that the resulting hash matches what exists on-chain.
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
pub struct MintedBlock<'b> {
#[n(0)]
pub header: KeepRaw<'b, Header>,
#[b(1)]
pub transaction_bodies: MaybeIndefArray<KeepRaw<'b, TransactionBody>>,
#[n(2)]
pub transaction_witness_sets: MaybeIndefArray<TransactionWitnessSet>,
#[n(3)]
pub auxiliary_data_set: KeyValuePairs<TransactionIndex, KeepRaw<'b, AuxiliaryData>>,
#[n(4)]
pub invalid_transactions: Option<MaybeIndefArray<TransactionIndex>>,
}
#[derive(Encode, Decode, Debug)]
pub struct Tx {
#[n(0)]
pub transaction_body: TransactionBody,
#[n(1)]
pub transaction_witness_set: TransactionWitnessSet,
#[n(2)]
pub success: bool,
#[n(3)]
pub auxiliary_data: Option<AuxiliaryData>,
}
#[derive(Encode, Decode, Debug, Clone)]
pub struct MintedTx<'b> {
#[b(0)]
pub transaction_body: KeepRaw<'b, TransactionBody>,
#[n(1)]
pub transaction_witness_set: TransactionWitnessSet,
#[n(2)]
pub success: bool,
#[n(3)]
pub auxiliary_data: Option<KeepRaw<'b, AuxiliaryData>>,
}
#[cfg(test)]
mod tests {
use pallas_codec::minicbor;
use super::MintedBlock;
type BlockWrapper<'b> = (u16, MintedBlock<'b>);
#[test]
fn block_isomorphic_decoding_encoding() {
let test_blocks = vec![
include_str!("../../../test_data/babbage1.block"),
include_str!("../../../test_data/babbage2.block"),
include_str!("../../../test_data/babbage3.block"),
];
for (idx, block_str) in test_blocks.iter().enumerate() {
println!("decoding test block {}", idx + 1);
let bytes = hex::decode(block_str).expect(&format!("bad block file {}", idx));
let block: BlockWrapper = minicbor::decode(&bytes[..])
.expect(&format!("error decoding cbor for file {}", idx));
let bytes2 = minicbor::to_vec(block)
.expect(&format!("error encoding block cbor for file {}", idx));
assert!(bytes.eq(&bytes2), "re-encoded bytes didn't match original");
}
}
}

View file

@ -3,6 +3,7 @@
mod framework;
pub mod alonzo;
pub mod babbage;
pub mod byron;
pub use framework::*;

View file

@ -2,7 +2,7 @@ use std::borrow::Cow;
use pallas_codec::minicbor;
use pallas_crypto::hash::Hash;
use pallas_primitives::{alonzo, byron, ToHash};
use pallas_primitives::{alonzo, babbage, byron, ToHash};
use crate::{probe, support, Era, Error, MultiEraBlock, MultiEraTx};
@ -63,6 +63,13 @@ impl<'b> MultiEraBlock<'b> {
))
}
pub fn decode_babbage(cbor: &'b [u8]) -> Result<Self, Error> {
let (_, block): BlockWrapper<babbage::MintedBlock> =
minicbor::decode(cbor).map_err(Error::invalid_cbor)?;
Ok(Self::Babbage(Box::new(Cow::Owned(block))))
}
pub fn decode(cbor: &'b [u8]) -> Result<MultiEraBlock<'b>, Error> {
match probe::block_era(cbor) {
probe::Outcome::EpochBoundary => Self::decode_epoch_boundary(cbor),
@ -72,6 +79,7 @@ impl<'b> MultiEraBlock<'b> {
Era::Allegra => Self::decode_allegra(cbor),
Era::Mary => Self::decode_mary(cbor),
Era::Alonzo => Self::decode_alonzo(cbor),
Era::Babbage => Self::decode_babbage(cbor),
},
probe::Outcome::Inconclusive => Err(Error::unknown_cbor(cbor)),
}
@ -81,6 +89,7 @@ impl<'b> MultiEraBlock<'b> {
match self {
MultiEraBlock::EpochBoundary(_) => Era::Byron,
MultiEraBlock::AlonzoCompatible(_, x) => *x,
MultiEraBlock::Babbage(_) => Era::Babbage,
MultiEraBlock::Byron(_) => Era::Byron,
}
}
@ -89,6 +98,7 @@ impl<'b> MultiEraBlock<'b> {
match self {
MultiEraBlock::EpochBoundary(x) => x.header.to_hash(),
MultiEraBlock::AlonzoCompatible(x, _) => x.header.to_hash(),
MultiEraBlock::Babbage(x) => x.header.to_hash(),
MultiEraBlock::Byron(x) => x.header.to_hash(),
}
}
@ -97,6 +107,7 @@ impl<'b> MultiEraBlock<'b> {
match self {
MultiEraBlock::EpochBoundary(x) => x.header.to_abs_slot(),
MultiEraBlock::AlonzoCompatible(x, _) => x.header.header_body.slot,
MultiEraBlock::Babbage(x) => x.header.header_body.slot,
MultiEraBlock::Byron(x) => x.header.consensus_data.0.to_abs_slot(),
}
}
@ -107,6 +118,10 @@ impl<'b> MultiEraBlock<'b> {
.into_iter()
.map(|x| MultiEraTx::AlonzoCompatible(Box::new(Cow::Owned(x)), *era))
.collect(),
MultiEraBlock::Babbage(x) => support::clone_babbage_txs(x)
.into_iter()
.map(|x| MultiEraTx::Babbage(Box::new(Cow::Owned(x))))
.collect(),
MultiEraBlock::Byron(x) => support::clone_byron_txs(x)
.into_iter()
.map(|x| MultiEraTx::Byron(Box::new(Cow::Owned(x))))
@ -119,6 +134,16 @@ impl<'b> MultiEraBlock<'b> {
match self {
MultiEraBlock::EpochBoundary(_) => None,
MultiEraBlock::AlonzoCompatible(x, _) => Some(x),
MultiEraBlock::Babbage(_) => None,
MultiEraBlock::Byron(_) => None,
}
}
pub fn as_babbage(&self) -> Option<&babbage::MintedBlock> {
match self {
MultiEraBlock::EpochBoundary(_) => None,
MultiEraBlock::AlonzoCompatible(_, _) => None,
MultiEraBlock::Babbage(x) => Some(x),
MultiEraBlock::Byron(_) => None,
}
}
@ -127,6 +152,7 @@ impl<'b> MultiEraBlock<'b> {
match self {
MultiEraBlock::EpochBoundary(_) => None,
MultiEraBlock::AlonzoCompatible(_, _) => None,
MultiEraBlock::Babbage(_) => None,
MultiEraBlock::Byron(x) => Some(x),
}
}

View file

@ -1,17 +1,18 @@
use std::fmt::{Display, Formatter};
use crate::{Era, Feature};
impl Era {
#[allow(clippy::match_like_matches_macro)]
pub fn has_feature(&self, feature: Feature) -> bool {
match (self, feature) {
(Era::Byron, _) => false,
(Era::Shelley, Feature::SmartContracts) => false,
(Era::Shelley, Feature::TimeLocks) => false,
(Era::Shelley, Feature::MultiAssets) => false,
(Era::Allegra, Feature::MultiAssets) => false,
(Era::Allegra, Feature::SmartContracts) => false,
(Era::Mary, Feature::SmartContracts) => false,
_ => true,
match feature {
Feature::Staking => self.ge(&Era::Shelley),
Feature::MultiAssets => self.ge(&Era::Mary),
Feature::TimeLocks => self.ge(&Era::Allegra),
Feature::SmartContracts => self.ge(&Era::Alonzo),
Feature::CIP31 => self.ge(&Era::Babbage),
Feature::CIP32 => self.ge(&Era::Babbage),
Feature::CIP33 => self.ge(&Era::Babbage),
}
}
}
@ -29,7 +30,8 @@ impl TryFrom<u16> for Era {
3 => Ok(Era::Allegra),
4 => Ok(Era::Mary),
5 => Ok(Era::Alonzo),
x => Err(crate::Error::UnkownEra(x)),
6 => Ok(Era::Babbage),
x => Err(crate::Error::UnknownEra(x)),
}
}
}
@ -42,6 +44,20 @@ impl From<Era> for u16 {
Era::Allegra => 3,
Era::Mary => 4,
Era::Alonzo => 5,
Era::Babbage => 6,
}
}
}
impl Display for Era {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Era::Byron => write!(f, "Byron"),
Era::Shelley => write!(f, "Shelley"),
Era::Allegra => write!(f, "Allegra"),
Era::Mary => write!(f, "Mary"),
Era::Alonzo => write!(f, "Alonzo"),
Era::Babbage => write!(f, "Babbage"),
}
}
}

View file

@ -1,7 +1,8 @@
use pallas_codec::minicbor;
use pallas_crypto::hash::Hash;
use pallas_crypto::hash::{Hash, Hasher};
use pallas_primitives::ToHash;
use crate::Era::Byron;
use crate::{Error, MultiEraHeader};
impl<'b> MultiEraHeader<'b> {
@ -17,6 +18,10 @@ impl<'b> MultiEraHeader<'b> {
Ok(MultiEraHeader::Byron(header))
}
},
5 => {
let header = minicbor::decode(cbor).map_err(Error::invalid_cbor)?;
Ok(MultiEraHeader::Babbage(header))
}
_ => {
let header = minicbor::decode(cbor).map_err(Error::invalid_cbor)?;
Ok(MultiEraHeader::AlonzoCompatible(header))
@ -28,6 +33,7 @@ impl<'b> MultiEraHeader<'b> {
match self {
MultiEraHeader::EpochBoundary(x) => x.to_abs_slot(),
MultiEraHeader::AlonzoCompatible(x) => x.header_body.slot,
MultiEraHeader::Babbage(x) => x.header_body.slot,
MultiEraHeader::Byron(x) => x.consensus_data.0.to_abs_slot(),
}
}
@ -36,7 +42,34 @@ impl<'b> MultiEraHeader<'b> {
match self {
MultiEraHeader::EpochBoundary(x) => x.to_hash(),
MultiEraHeader::AlonzoCompatible(x) => x.to_hash(),
MultiEraHeader::Babbage(x) => x.to_hash(),
MultiEraHeader::Byron(x) => x.to_hash(),
}
}
pub fn leader_vrf_output(&self) -> Result<Vec<u8>, Error> {
match self {
MultiEraHeader::EpochBoundary(_) => Err(Error::InvalidEra(Byron)),
MultiEraHeader::AlonzoCompatible(x) => Ok(x.header_body.leader_vrf.0.to_vec()),
MultiEraHeader::Babbage(x) => {
let mut leader_tagged_vrf: Vec<u8> = vec![0x4C_u8]; /* "L" */
leader_tagged_vrf.extend(&*x.header_body.vrf_result.0);
Ok(Hasher::<256>::hash(&leader_tagged_vrf).to_vec())
}
MultiEraHeader::Byron(_) => Err(Error::InvalidEra(Byron)),
}
}
pub fn nonce_vrf_output(&self) -> Result<Vec<u8>, Error> {
match self {
MultiEraHeader::EpochBoundary(_) => Err(Error::InvalidEra(Byron)),
MultiEraHeader::AlonzoCompatible(x) => Ok(x.header_body.nonce_vrf.0.to_vec()),
MultiEraHeader::Babbage(x) => {
let mut nonce_tagged_vrf: Vec<u8> = vec![0x4E_u8]; /* "N" */
nonce_tagged_vrf.extend(&*x.header_body.vrf_result.0);
Ok(Hasher::<256>::hash(&nonce_tagged_vrf).to_vec())
}
MultiEraHeader::Byron(_) => Err(Error::InvalidEra(Byron)),
}
}
}

View file

@ -3,10 +3,11 @@
use std::borrow::Cow;
use std::fmt::Display;
use thiserror::Error;
use pallas_codec::utils::KeepRaw;
use pallas_crypto::hash::Hash;
use pallas_primitives::{alonzo, byron};
use thiserror::Error;
use pallas_primitives::{alonzo, babbage, byron};
pub mod block;
pub mod cert;
@ -26,6 +27,7 @@ pub enum Era {
Allegra, // time-locks
Mary, // multi-assets
Alonzo, // smart-contracts
Babbage, // CIP-31/32/33
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
@ -35,12 +37,16 @@ pub enum Feature {
MultiAssets,
Staking,
SmartContracts,
CIP31,
CIP32,
CIP33,
}
#[derive(Debug)]
pub enum MultiEraHeader<'b> {
EpochBoundary(KeepRaw<'b, byron::EbbHead>),
AlonzoCompatible(KeepRaw<'b, alonzo::Header>),
Babbage(KeepRaw<'b, babbage::Header>),
Byron(KeepRaw<'b, byron::BlockHead>),
}
@ -49,6 +55,7 @@ pub enum MultiEraHeader<'b> {
pub enum MultiEraBlock<'b> {
EpochBoundary(Box<Cow<'b, byron::EbBlock>>),
AlonzoCompatible(Box<Cow<'b, alonzo::MintedBlock<'b>>>, Era),
Babbage(Box<Cow<'b, babbage::MintedBlock<'b>>>),
Byron(Box<Cow<'b, byron::MintedBlock<'b>>>),
}
@ -56,14 +63,16 @@ pub enum MultiEraBlock<'b> {
#[non_exhaustive]
pub enum MultiEraTx<'b> {
AlonzoCompatible(Box<Cow<'b, alonzo::MintedTx<'b>>>, Era),
Babbage(Box<Cow<'b, babbage::MintedTx<'b>>>),
Byron(Box<Cow<'b, byron::MintedTxPayload<'b>>>),
}
#[derive(Debug)]
#[non_exhaustive]
pub enum MultiEraOutput<'b> {
Byron(Box<Cow<'b, byron::TxOut>>),
AlonzoCompatible(Box<Cow<'b, alonzo::TransactionOutput>>),
Babbage(Box<Cow<'b, babbage::TransactionOutput>>),
Byron(Box<Cow<'b, byron::TxOut>>),
}
#[derive(Debug)]
@ -89,7 +98,10 @@ pub enum Error {
UnknownCbor(String),
#[error("Unknown era tag: {0}")]
UnkownEra(u16),
UnknownEra(u16),
#[error("Invalid era for request: {0}")]
InvalidEra(Era),
}
impl Error {

View file

@ -1,6 +1,6 @@
use std::borrow::Cow;
use std::{borrow::Cow, ops::Deref};
use pallas_primitives::{alonzo::{self, Value}, byron};
use pallas_primitives::{alonzo, babbage, byron};
use crate::MultiEraOutput;
@ -13,36 +13,61 @@ impl<'b> MultiEraOutput<'b> {
Self::AlonzoCompatible(Box::new(Cow::Borrowed(output)))
}
pub fn from_babbage(output: &'b babbage::TransactionOutput) -> Self {
Self::Babbage(Box::new(Cow::Borrowed(output)))
}
pub fn address(&self, hrp: &str) -> String {
match self {
MultiEraOutput::Byron(x) => x.address.to_addr_string().expect("invalid address value"),
MultiEraOutput::AlonzoCompatible(x) => {
x.to_bech32_address(hrp).expect("invalid address value")
}
MultiEraOutput::Babbage(x) => x.to_bech32_address(hrp).expect("invalid address value"),
MultiEraOutput::Byron(x) => x.address.to_addr_string().expect("invalid address value"),
}
}
pub fn ada_amount(&self) -> u64 {
match self {
MultiEraOutput::Byron(x) => x.amount,
MultiEraOutput::Babbage(x) => match x.deref().deref() {
babbage::TransactionOutput::Legacy(x) => match x.amount {
babbage::Value::Coin(c) => u64::from(c),
babbage::Value::Multiasset(c, _) => u64::from(c),
},
babbage::TransactionOutput::PostAlonzo(x) => match x.value {
babbage::Value::Coin(c) => u64::from(c),
babbage::Value::Multiasset(c, _) => u64::from(c),
},
},
MultiEraOutput::AlonzoCompatible(x) => match x.amount {
Value::Coin(c) => u64::from(c),
Value::Multiasset(c, _) => u64::from(c)
}
alonzo::Value::Coin(c) => u64::from(c),
alonzo::Value::Multiasset(c, _) => u64::from(c),
},
}
}
pub fn as_babbage(&self) -> Option<&babbage::TransactionOutput> {
match self {
MultiEraOutput::AlonzoCompatible(_) => None,
MultiEraOutput::Babbage(x) => Some(x),
MultiEraOutput::Byron(_) => None,
}
}
pub fn as_alonzo(&self) -> Option<&alonzo::TransactionOutput> {
match self {
MultiEraOutput::Byron(_) => None,
MultiEraOutput::AlonzoCompatible(x) => Some(x),
MultiEraOutput::Babbage(_) => None,
MultiEraOutput::Byron(_) => None,
}
}
pub fn as_byron(&self) -> Option<&byron::TxOut> {
match self {
MultiEraOutput::Byron(x) => Some(x),
MultiEraOutput::AlonzoCompatible(_) => None,
MultiEraOutput::Babbage(_) => None,
MultiEraOutput::Byron(x) => Some(x),
}
}
}

View file

@ -1,44 +1,57 @@
//! Internal supporting utilities
use pallas_primitives::{alonzo, byron};
use pallas_primitives::{alonzo, babbage, byron};
pub fn clone_alonzo_tx_at<'b>(
block: &'b alonzo::MintedBlock,
index: usize,
) -> Option<alonzo::MintedTx<'b>> {
let transaction_body = block.transaction_bodies.get(index).cloned()?;
macro_rules! clone_tx_fn {
($fn_name:ident, $era:tt) => {
fn $fn_name<'b>(block: &'b $era::MintedBlock, index: usize) -> Option<$era::MintedTx<'b>> {
let transaction_body = block.transaction_bodies.get(index).cloned()?;
let transaction_witness_set = block.transaction_witness_sets.get(index).cloned()?;
let transaction_witness_set = block.transaction_witness_sets.get(index).cloned()?;
let success = !block
.invalid_transactions
.as_ref()?
.contains(&(index as u32));
let success = !block
.invalid_transactions
.as_ref()?
.contains(&(index as u32));
let auxiliary_data = block
.auxiliary_data_set
.iter()
.find_map(|(idx, val)| {
if idx.eq(&(index as u32)) {
Some(val)
} else {
None
}
})
.cloned();
let auxiliary_data = block
.auxiliary_data_set
.iter()
.find_map(|(idx, val)| {
if idx.eq(&(index as u32)) {
Some(val)
} else {
None
}
})
.cloned();
Some(alonzo::MintedTx {
transaction_body,
transaction_witness_set,
success,
auxiliary_data,
})
let x = $era::MintedTx {
transaction_body,
transaction_witness_set,
success,
auxiliary_data,
};
Some(x)
}
};
}
clone_tx_fn!(babbage_clone_tx_at, babbage);
clone_tx_fn!(alonzo_clone_tx_at, alonzo);
pub fn clone_alonzo_txs<'b>(block: &'b alonzo::MintedBlock) -> Vec<alonzo::MintedTx<'b>> {
(0..block.transaction_bodies.len())
.step_by(1)
.filter_map(|idx| clone_alonzo_tx_at(block, idx))
.filter_map(|idx| alonzo_clone_tx_at(block, idx))
.collect()
}
pub fn clone_babbage_txs<'b>(block: &'b babbage::MintedBlock) -> Vec<babbage::MintedTx<'b>> {
(0..block.transaction_bodies.len())
.step_by(1)
.filter_map(|idx| babbage_clone_tx_at(block, idx))
.collect()
}

View file

@ -1,6 +1,6 @@
use pallas_codec::minicbor;
use pallas_crypto::hash::Hash;
use pallas_primitives::{alonzo, byron, ToHash};
use pallas_primitives::{alonzo, babbage, byron, ToHash};
use std::borrow::Cow;
use crate::{Era, MultiEraCert, MultiEraInput, MultiEraOutput, MultiEraTx};
@ -14,9 +14,14 @@ impl<'b> MultiEraTx<'b> {
Self::AlonzoCompatible(Box::new(Cow::Borrowed(tx)), era)
}
pub fn from_babbage(tx: &'b babbage::MintedTx<'b>) -> Self {
Self::Babbage(Box::new(Cow::Borrowed(tx)))
}
pub fn encode(&self) -> Result<Vec<u8>, minicbor::encode::Error<std::io::Error>> {
match self {
MultiEraTx::AlonzoCompatible(x, _) => minicbor::to_vec(x),
MultiEraTx::Babbage(x) => minicbor::to_vec(x),
MultiEraTx::Byron(x) => minicbor::to_vec(x),
}
}
@ -33,12 +38,18 @@ impl<'b> MultiEraTx<'b> {
let tx = Box::new(Cow::Owned(tx));
Ok(MultiEraTx::AlonzoCompatible(tx, era))
}
Era::Babbage => {
let tx = minicbor::decode(cbor)?;
let tx = Box::new(Cow::Owned(tx));
Ok(MultiEraTx::Babbage(tx))
}
}
}
pub fn era(&self) -> Era {
match self {
MultiEraTx::AlonzoCompatible(_, era) => *era,
MultiEraTx::Babbage(_) => Era::Babbage,
MultiEraTx::Byron(_) => Era::Byron,
}
}
@ -46,6 +57,7 @@ impl<'b> MultiEraTx<'b> {
pub fn hash(&self) -> Hash<32> {
match self {
MultiEraTx::AlonzoCompatible(x, _) => x.transaction_body.to_hash(),
MultiEraTx::Babbage(x) => x.transaction_body.to_hash(),
MultiEraTx::Byron(x) => x.transaction.to_hash(),
}
}
@ -58,6 +70,12 @@ impl<'b> MultiEraTx<'b> {
.iter()
.map(MultiEraOutput::from_alonzo_compatible)
.collect(),
MultiEraTx::Babbage(x) => x
.transaction_body
.outputs
.iter()
.map(MultiEraOutput::from_babbage)
.collect(),
MultiEraTx::Byron(x) => x
.transaction
.outputs
@ -74,6 +92,11 @@ impl<'b> MultiEraTx<'b> {
.outputs
.get(index)
.map(MultiEraOutput::from_alonzo_compatible),
MultiEraTx::Babbage(x) => x
.transaction_body
.outputs
.get(index)
.map(MultiEraOutput::from_babbage),
MultiEraTx::Byron(x) => x
.transaction
.outputs
@ -90,7 +113,12 @@ impl<'b> MultiEraTx<'b> {
.iter()
.map(MultiEraInput::from_alonzo_compatible)
.collect(),
MultiEraTx::Babbage(x) => x
.transaction_body
.inputs
.iter()
.map(MultiEraInput::from_alonzo_compatible)
.collect(),
MultiEraTx::Byron(x) => x
.transaction
.inputs
@ -109,13 +137,29 @@ impl<'b> MultiEraTx<'b> {
.flat_map(|c| c.iter())
.map(|c| MultiEraCert::AlonzoCompatible(Box::new(Cow::Borrowed(c))))
.collect(),
MultiEraTx::Babbage(x) => x
.transaction_body
.certificates
.iter()
.flat_map(|c| c.iter())
.map(|c| MultiEraCert::AlonzoCompatible(Box::new(Cow::Borrowed(c))))
.collect(),
MultiEraTx::Byron(_) => vec![],
}
}
pub fn as_babbage(&self) -> Option<&babbage::MintedTx> {
match self {
MultiEraTx::AlonzoCompatible(_, _) => None,
MultiEraTx::Babbage(x) => Some(x),
MultiEraTx::Byron(_) => None,
}
}
pub fn as_alonzo(&self) -> Option<&alonzo::MintedTx> {
match self {
MultiEraTx::AlonzoCompatible(x, _) => Some(x),
MultiEraTx::Babbage(_) => None,
MultiEraTx::Byron(_) => None,
}
}
@ -123,6 +167,7 @@ impl<'b> MultiEraTx<'b> {
pub fn as_byron(&self) -> Option<&byron::MintedTxPayload> {
match self {
MultiEraTx::AlonzoCompatible(_, _) => None,
MultiEraTx::Babbage(_) => None,
MultiEraTx::Byron(x) => Some(x),
}
}

1
test_data/babbage1.block Normal file
View file

@ -0,0 +1 @@
820685828a19ae991a000fb73c582068e0b30103cba96819b7f7abbe80f4aae6fb35270c3c77c4a8f82d9ab21a920e582063fc404a8f5635aa133818457a406f62d946dd35362ef78429da4953b5125ab15820a9a971c7cc826c53a9a1690ae9c6a46123d85ac90641c859da408cbc7ce6b3eb825840e5b74253ccd2a78e4e5653499151fb1c01e0c009d3b6e80feb4d15c6ef10abe9683b652ca968a1ae124be7b59eb1f4ebfd882671da49101635b1995e1e42a2ef58500ec054de37747089cd4fd9864b2fe17cdb2567adf9ee89a44c29e81fad88d663bd76d6abd65848ba0df146df1f95a6eb16e7d794332323e359442a9f2830d5b5b052e00bcd147c7e5bed987a70580f021903385820219f8b90967156d6ee02e3507ccb413b5a8d87343706cbd9e8fb1e1285e4b3c0845820840ba03379518ab70200edd70a984cd5fcf4ef8f0994c95cc394d3e7243de3f100005840a352185eb0e2783206e23d0aa25b8d799a228266baf65de832cd2b64d666fbdd5649461d3cd30f721bc04e94bb9f97c31335ee39893247eaf9912cfa688785048207005901c0954157d0a93992a0cda655574074541b92a5d12cba0a94dc8dc7c97de407dc6bbb463810a6fec0ae47c7d4d3cddcb51485616e924448e9850369efdf9f248d0ff052309c26385a7bff045e39d4afdb90cc114b06215ee4c2ba026b9109aecf87e0547eeab8973a3f5903403fea20416357881a2226733dafd3700154992ad454f75383438acab170e4fca6691d40ed986df32b006d9408cb70a1265c52673cb7c361b646b8a1e47b92b015dd82743ce75680caa0b3337dbec280b91d4fcf31e97630d09977f264eb4c4794647734532a36538896e640982f52649f808a26e71782232617c944e8ab2bf62e59772123b68d136b3a06c0d3263fbfc51f4225a18d788b4f45b62741472e72d107be72e63265cf83f389b4ced1b5246e5f4b1c2aeb35d7f60b1e417940b917f0ad9cc7962f28dcd243cac00b7a4c2d233a1e3dc0749d5430d777d41425c9cac7f7232f620f0ed8e5f400b7c2a1508e5e61adcd2d5bf76d9db9576cd1d87ba1912567b493c7e20756e970a731a05ee20ef2db22f8b7959323025072ecdb163adb96878bea9aee92b67556ae38ee764e37ce65d74c5c4255ec86defaf48cd31d9ab7b868606f050c816119d7c00dbbf66c248cbfc4a281a70082825820e8cbbfc1732f91fbd6aa62e6accd144b0e114fadbb1aaa2fba37801fe3b2052400825820e8cbbfc1732f91fbd6aa62e6accd144b0e114fadbb1aaa2fba37801fe3b20524010d80018282581d6052e63f22c5107ed776b70f7b92248b02552fd08f3e747bc7450994411a000f424082581d6052e63f22c5107ed776b70f7b92248b02552fd08f3e747bc7450994411b000000731c54b53b021a000313c5031a00113dd60e8007582067787f4d32b037291080fc828784f70594a465837455a972825939b4945cf74d81a10081825820742d8af3543349b5b18f3cba28f23b2d6e465b9c136c42e1fae6b2390f5654275840056ea09ad43a718039a358f289d4fdc2b720a35f0c8400778bd51db4b97f70d5101c67a729cc4b29fcfd996e5793dc15903ca8eaf19c48cd6b493157a0588806a100d90103a100a11902a2a1636d73678f78264175746f2d4c6f6f702d5472616e73616374696f6e202332363035323020627920415441444160783c4c6976652045706f6368203134332c207765206861766520303030682030306d20313773206c65667420756e74696c20746865206e657874206f6e657831497427732053616d73746167202d203138204a756e692032303232202d2031353a35393a343320696e2041757374726961607838f09f9388205468652063757272656e7420414441205072696365206f6e204b72616b656e2069733a2024302e343634383535202f20414441607820412072616e646f6d205a656e2d51756f746520666f7220796f753a20f09f998f783d48617070696e657373206973207072657474792073696d706c653a20736f6d656f6e6520746f206c6f76652c20736f6d657468696e6720746f20646f2c782e736f6d657468696e6720746f206c6f6f6b20666f727761726420746f2e202d2052697461204d61652042726f776e6078374e6f64652d5265766973696f6e3a203634373163333166386236313739386466353761396633333435353438373033323935636163396560782f566173696c2d4465762d436861696e20697320617765736f6d652c206861766520736f6d652066756e2120f09f988d7819204265737420726567617264732c204d617274696e203a2d2980

1
test_data/babbage2.block Normal file
View file

@ -0,0 +1 @@
820685828a19b3c11a001028995820657dabb20444fec23e9cc8e33b9a3b1d1e4af2b5004a2455a6070f252a071789582033961b097794a23cf32b8501abcededd36f159b95c5bc2f33be6cb392668eb005820c9aaceec29b09ac5e1f862d00be0fe63fab8f4e0f5e80f4767b04ab08541996c825840c4fbd2858d501d36fe08803db0252e025e949a5c7afdb3a0f91abc04368e3b632b3b931b5e68b44486c1104bead7c9f688d6e251d8a96eed729321fc29c9ad7c585085c78927f6e3bd8ea9afe03486fc36d46b6e2f82d4282ea5bd09135126e8e07f8512264d10896208a4f40b958f9f4df1cee2591b605888fc4a3bbbec6a45ec02fe8704199051d0f86933e796a5744d0219033258200def2b0bcd96375513e42457c7499460ad98efd80403cbba48ce301e03b89f12845820e508f9e41092301f5001d5bf7641ae472bde530ed87cbe49eb5eac0054f87aa20000584034ecfdefa26119be45c1bd46acb8bb65cb80d522773cef7d9bc1da85c88c4521dc38c3a7b91789e59350db04e1e237223f9b39b6e6e5a721871acaf524e1cd0f8207005901c0fa7c6af75815aba3193d75c627ec945af2d1df7178cbbc91120e32a2b82c028f22703b4bef220e2080069228020f4593e07bd30491642639c1c07d254b760d028f93531982c1ab043b44753f6cc04142e7ccd66e9de0233eb54f176fdc88ce4c90b455a33f5624c30a93b0d02da76c4bdfa6e2cca8c0aed9a008a02363f8c67811fa131abf8a629c6e41f35a94b0d17e23375c5440a42384058a795f3f13d648a3384f8f0703abfd13b5d5d39ce98419ec2d7a443206623bdf08750e372fdf18347b0d1adef11186294f5949c74360bcdd579dd7ddd12a0baa23c3d8b9a2828821087f80c51049c02522ed0c2431ee32ec28b18d5ace8055be88380efeef3c31e0cfdc350442bf3bf4d4c0670244d79d60a53288db2cde0b964acb11972b89fc269741721c6753a77f7478342b3f9d7bf0e0d156eeb69097738904579151d6d5867fd5260602c2eb1d1575fccfa92dba90645228a10a612250af5ad7e45bb5d893456d2d02d5ac240b57d20a89e74998cf97b09cdc0d9642422f6d7f164a0bc61cebd45091bb401a7f09984d019454e4796089dc5359d9995ef59883729f886637e7491392ded69b2e7ec77f91c1292073bc1bd3b87a68d80768d4851966d81c81a70082825820ad1464531d1078e67004f6837a2a27a2537e850d211e9a7fac66db84fe5c9acc00825820ad1464531d1078e67004f6837a2a27a2537e850d211e9a7fac66db84fe5c9acc010d80018282581d6052e63f22c5107ed776b70f7b92248b02552fd08f3e747bc7450994411a000f424082581d6052e63f22c5107ed776b70f7b92248b02552fd08f3e747bc7450994411b0000007314c79460021a000312bd031a0011af320e8007582034e55bb9354c39ff06e62db4866870c99524d457c25e9f2e77108b3141c3ec4e81a10081825820742d8af3543349b5b18f3cba28f23b2d6e465b9c136c42e1fae6b2390f5654275840fb57c8a405185042ba7d39f8cf01d478f1ece1ab63a5267301e15872010545e838820b0b16b22759d07342419fc49b0b8753ca46a17be35d9f8364d83af00f02a100d90103a100a11902a2a1636d73678f78264175746f2d4c6f6f702d5472616e73616374696f6e202332363131353220627920415441444160783c4c6976652045706f6368203134382c207765206861766520303031682035366d20333873206c65667420756e74696c20746865206e657874206f6e6578314974277320536f6e6e746167202d203139204a756e692032303232202d2030303a30333a323220696e2041757374726961607838f09f9388205468652063757272656e7420414441205072696365206f6e204b72616b656e2069733a2024302e343436353234202f20414441607820412072616e646f6d205a656e2d51756f746520666f7220796f753a20f09f998f783a496620697420656e7465727461696e7320796f75206e6f77206275742077696c6c20626f726520796f7520736f6d656461792c20697427732061782b6469737472616374696f6e2e204b656570206c6f6f6b696e672e202d204e6176616c20526176696b616e746078374e6f64652d5265766973696f6e3a203634373163333166386236313739386466353761396633333435353438373033323935636163396560782f566173696c2d4465762d436861696e20697320617765736f6d652c206861766520736f6d652066756e2120f09f988d7819204265737420726567617264732c204d617274696e203a2d2980

1
test_data/babbage3.block Normal file
View file

@ -0,0 +1 @@
820685828a19b3c51a0010293958208b93e0ca1cfcb6a48cb081bbc4243e159e84609516a7774b31e7d335ead12f455820b66a201280d405518cb91fb6d5c365220dc892ed2bed041b6996c64e2ab570625820e7b493d575baa41450f7c8c82a462d6c7a5179d143536cdd1a50e8200e6db5d58258407b9680406739e12ae5add6e3370ce74e5f3b7206341926e07df855d5cc5b909f4abd904838776db05b82afca6161be8232f3e74ac964a509221638fd2b0454865850c81fa00e09a6bde3266f7794dcbecb2a028f21a5000a61a2d0c602b0beb82e96d64d3742bd0993a826ac50ada337a79a94641aa1c84f0536aceee170cb09810b1b33ad9f39bab744ba364b82b05b6b051903275820410fd782d7c27a1c3f8c163e18755473aac071ae2d0914420028c6a5b1e30626845820137b969e66998a63e73b3617d97571bae5c281df9d9978d9141677e31d5dfbf400025840aac7ad858b702b6f6700b07f64ebefc09ccb7b7d58cd274620537cd4785a4c39c9dcc7fdaa23cff9f6f056ea2b3e588ee550b2866636e8ba5e109c052a6e910a8207005901c053aa57ffd9afa38c4a44251656a81719a49ef0274c6fd90d071037519321f04dfd00c4b4618d92b526f1c0588684916c77fd556c6986d247a7c3d105298c0001d6fed161ba8c43dcc0abd5f1d7575d7cb10b5a3550b81592b815ec2c850cedb751cc735fb787be9f98de17708ce9703e896616cf6a90e91df80506aa82f12fef6913c5c230fc12174a1e02bcc0b9f93868d39324eddd3649bc1727194bd44c7e7c31a1c3c68dfd9e4793af53575ff8f7e967a4ed213cc3af4d721a3da1e3d499c83060a0c28b2487f3dabce5f1e5a7c2004541a95d0331d7a539c9fd43d88494caeec5a82369dc19939530661e754277fce9579006b43e57ea33c15b6a387a072282d6350bae245264cf3d47c2259e53d8e791e1d6f697470929b2388b953645f33654d141984cb10b9bc4419a33cfbffd65b12f9baf311ca8517dbe146f482f6d69772a7ec12f8f321049afd9056ecea37deb16552350c95fdd0ade0fdcad77a80adfac5ae3e402077c88e288b212f5d1e8128b7aa4d5302aeaec9e5c0383e4c66e7c116f61d4228d9b912d30fadee0468dd0ef1eda0e10dd2ff80b188026145ff0276e21c01d2e04c1f1df2ecc9ce13ed80b7641da3d9464c2a1b769610f2c81a70082825820d4e6079fc395d0c5a6c6c029b4233c8694ab62e2b56568678a84c23bb9ff437000825820d4e6079fc395d0c5a6c6c029b4233c8694ab62e2b56568678a84c23bb9ff4370010d80018282581d6052e63f22c5107ed776b70f7b92248b02552fd08f3e747bc7450994411a000f424082581d6052e63f22c5107ed776b70f7b92248b02552fd08f3e747bc7450994411b0000007314c17466021a000310d9031a0011afcd0e80075820def4265b9bc49ae3663bface1b11df4bd3ea49b9c64456c343d3eb47f8ab025981a10081825820742d8af3543349b5b18f3cba28f23b2d6e465b9c136c42e1fae6b2390f565427584014a08f80f4a359f757ec51a67823e11fb33a8365f7fac33341edb30215c57ea0ae2f34231b39c6f618f06828350d079f92fa21c2845012d3c901b9a10f1b0b01a100d90103a100a11902a2a1636d73678f78264175746f2d4c6f6f702d5472616e73616374696f6e202332363131353420627920415441444160783c4c6976652045706f6368203134382c207765206861766520303031682035346d20303273206c65667420756e74696c20746865206e657874206f6e6578314974277320536f6e6e746167202d203139204a756e692032303232202d2030303a30353a353820696e2041757374726961607838f09f9388205468652063757272656e7420414441205072696365206f6e204b72616b656e2069733a2024302e343436353234202f20414441607820412072616e646f6d205a656e2d51756f746520666f7220796f753a20f09f998f783e53756363657373206973206f6674656e2061636869657665642062792074686f73652077686f20646f6e2774206b6e6f772074686174206661696c757265781c697320696e6576697461626c652e202d20436f636f204368616e656c6078374e6f64652d5265766973696f6e3a203634373163333166386236313739386466353761396633333435353438373033323935636163396560782f566173696c2d4465762d436861696e20697320617765736f6d652c206861766520736f6d652066756e2120f09f988d7819204265737420726567617264732c204d617274696e203a2d2980