feat(applying): add cert and native script validation for ShelleyMA (#510)
BREAKING CHANGE: the `validate` fn signature has changed to support these changes --------- Co-authored-by: Ale Gadea <ale.gadea@txpipe.io>
This commit is contained in:
parent
1bec8be109
commit
07b74515a4
15 changed files with 1881 additions and 134 deletions
|
|
@ -9,41 +9,78 @@ pub mod utils;
|
|||
use alonzo::validate_alonzo_tx;
|
||||
use babbage::validate_babbage_tx;
|
||||
use byron::validate_byron_tx;
|
||||
use pallas_primitives::alonzo::TransactionIndex;
|
||||
use pallas_traverse::{Era, MultiEraTx};
|
||||
use shelley_ma::validate_shelley_ma_tx;
|
||||
|
||||
pub use utils::{
|
||||
Environment, MultiEraProtocolParameters, UTxOs,
|
||||
ValidationError::{TxAndProtParamsDiffer, UnknownProtParams},
|
||||
CertState, Environment, MultiEraProtocolParameters, UTxOs,
|
||||
ValidationError::{
|
||||
EnvMissingAccountState, PParamsByronDoesntNeedAccountState, TxAndProtParamsDiffer,
|
||||
UnknownProtParams,
|
||||
},
|
||||
ValidationResult,
|
||||
};
|
||||
|
||||
pub fn validate(metx: &MultiEraTx, utxos: &UTxOs, env: &Environment) -> ValidationResult {
|
||||
match env.prot_params() {
|
||||
MultiEraProtocolParameters::Byron(bpp) => match metx {
|
||||
/// Ledger sequence rule: LEDGERS
|
||||
pub fn validate_txs(
|
||||
metxs: &[MultiEraTx],
|
||||
env: &Environment,
|
||||
utxos: &UTxOs,
|
||||
cert_state: &mut CertState,
|
||||
) -> ValidationResult {
|
||||
let mut delta_state: CertState = cert_state.clone();
|
||||
for (txix, metx) in metxs.iter().enumerate() {
|
||||
validate_tx(
|
||||
&metx,
|
||||
txix.try_into().unwrap(),
|
||||
env,
|
||||
utxos,
|
||||
&mut delta_state,
|
||||
)?;
|
||||
}
|
||||
*cert_state = delta_state;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Ledger inference rule: LEDGER
|
||||
pub fn validate_tx(
|
||||
metx: &MultiEraTx,
|
||||
txix: TransactionIndex,
|
||||
env: &Environment,
|
||||
utxos: &UTxOs,
|
||||
cert_state: &mut CertState,
|
||||
) -> ValidationResult {
|
||||
let pp_acnt = (env.prot_params(), env.acnt());
|
||||
match pp_acnt {
|
||||
(MultiEraProtocolParameters::Byron(bpp), None) => match metx {
|
||||
MultiEraTx::Byron(mtxp) => validate_byron_tx(mtxp, utxos, bpp, env.prot_magic()),
|
||||
_ => Err(TxAndProtParamsDiffer),
|
||||
},
|
||||
MultiEraProtocolParameters::Shelley(spp) => match metx {
|
||||
(MultiEraProtocolParameters::Byron(_), Some(_)) => Err(PParamsByronDoesntNeedAccountState),
|
||||
(MultiEraProtocolParameters::Shelley(spp), Some(acnt)) => match metx {
|
||||
MultiEraTx::AlonzoCompatible(mtx, Era::Shelley)
|
||||
| MultiEraTx::AlonzoCompatible(mtx, Era::Allegra)
|
||||
| MultiEraTx::AlonzoCompatible(mtx, Era::Mary) => validate_shelley_ma_tx(
|
||||
mtx,
|
||||
txix,
|
||||
utxos,
|
||||
cert_state,
|
||||
spp,
|
||||
&acnt,
|
||||
env.block_slot(),
|
||||
env.network_id(),
|
||||
&metx.era(),
|
||||
),
|
||||
_ => Err(TxAndProtParamsDiffer),
|
||||
},
|
||||
MultiEraProtocolParameters::Alonzo(app) => match metx {
|
||||
(MultiEraProtocolParameters::Alonzo(app), _) => match metx {
|
||||
MultiEraTx::AlonzoCompatible(mtx, Era::Alonzo) => {
|
||||
validate_alonzo_tx(mtx, utxos, app, env.block_slot(), env.network_id())
|
||||
}
|
||||
_ => Err(TxAndProtParamsDiffer),
|
||||
},
|
||||
MultiEraProtocolParameters::Babbage(bpp) => match metx {
|
||||
(MultiEraProtocolParameters::Babbage(bpp), _) => match metx {
|
||||
MultiEraTx::Babbage(mtx) => validate_babbage_tx(
|
||||
mtx,
|
||||
utxos,
|
||||
|
|
@ -54,8 +91,9 @@ pub fn validate(metx: &MultiEraTx, utxos: &UTxOs, env: &Environment) -> Validati
|
|||
),
|
||||
_ => Err(TxAndProtParamsDiffer),
|
||||
},
|
||||
MultiEraProtocolParameters::Conway(_) => {
|
||||
(MultiEraProtocolParameters::Conway(_), _) => {
|
||||
todo!("conway phase-1 validation not yet implemented");
|
||||
}
|
||||
(_, None) => Err(EnvMissingAccountState),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use crate::utils::{
|
|||
add_minted_value, add_values, aux_data_from_alonzo_minted_tx, empty_value,
|
||||
get_alonzo_comp_tx_size, get_lovelace_from_alonzo_val, get_payment_part, get_shelley_address,
|
||||
get_val_size_in_words, mk_alonzo_vk_wits_check_list, values_are_equal, verify_signature,
|
||||
AccountState, CertPointer, CertState, DState, PState, PoolParam,
|
||||
ShelleyMAError::*,
|
||||
ShelleyProtParams, UTxOs,
|
||||
ValidationError::{self, *},
|
||||
|
|
@ -11,20 +12,32 @@ use crate::utils::{
|
|||
};
|
||||
use pallas_addresses::{PaymentKeyHash, ScriptHash, ShelleyAddress, ShelleyPaymentPart};
|
||||
use pallas_codec::minicbor::encode;
|
||||
use pallas_crypto::hash::Hasher as PallasHasher;
|
||||
use pallas_primitives::{
|
||||
alonzo::{
|
||||
MintedTx, MintedWitnessSet, NativeScript, PolicyId, TransactionBody, TransactionOutput,
|
||||
VKeyWitness, Value,
|
||||
Certificate::{self, *},
|
||||
Coin, Epoch, GenesisDelegateHash, Genesishash,
|
||||
InstantaneousRewardSource::*,
|
||||
InstantaneousRewardTarget::*,
|
||||
MintedTx, MintedWitnessSet, MoveInstantaneousReward, NativeScript, PolicyId, PoolKeyhash,
|
||||
StakeCredential::{self},
|
||||
TransactionBody, TransactionIndex, TransactionOutput, VKeyWitness, Value, VrfKeyhash,
|
||||
},
|
||||
byron::TxOut,
|
||||
};
|
||||
use pallas_traverse::{ComputeHash, Era, MultiEraInput, MultiEraOutput};
|
||||
use std::{cmp::max, ops::Deref};
|
||||
use pallas_traverse::{
|
||||
time::Slot, wellknown::GenesisValues, ComputeHash, Era, MultiEraInput, MultiEraOutput,
|
||||
};
|
||||
|
||||
use std::{cmp::max, collections::HashMap, ops::Deref}; // TODO: remove when fixed missing args
|
||||
|
||||
pub fn validate_shelley_ma_tx(
|
||||
mtx: &MintedTx,
|
||||
txix: TransactionIndex,
|
||||
utxos: &UTxOs,
|
||||
cert_state: &mut CertState,
|
||||
prot_pps: &ShelleyProtParams,
|
||||
acnt: &AccountState,
|
||||
block_slot: &u64,
|
||||
network_id: &u8,
|
||||
era: &Era,
|
||||
|
|
@ -32,12 +45,38 @@ pub fn validate_shelley_ma_tx(
|
|||
let tx_body: &TransactionBody = &mtx.transaction_body;
|
||||
let tx_wits: &MintedWitnessSet = &mtx.transaction_witness_set;
|
||||
let size: u32 = get_alonzo_comp_tx_size(mtx);
|
||||
let stk_dep_count: &mut u64 = &mut 0; // count of key registrations (for deposits)
|
||||
let stk_refund_count: &mut u64 = &mut 0; // count of key deregs (for refunds)
|
||||
let pool_count: &mut u64 = &mut 0; // count of pool regs (for deposits)
|
||||
|
||||
let stab_win = 129600; // FIXME: Found as "1.5 days" in unreliable sources.
|
||||
|
||||
check_ins_not_empty(tx_body)?;
|
||||
check_ins_in_utxos(tx_body, utxos)?;
|
||||
check_ttl(tx_body, block_slot)?;
|
||||
check_tx_size(&size, prot_pps)?;
|
||||
check_min_lovelace(tx_body, prot_pps, era)?;
|
||||
check_preservation_of_value(tx_body, utxos, era)?;
|
||||
check_certificates(
|
||||
&tx_body.certificates,
|
||||
txix,
|
||||
cert_state,
|
||||
stk_dep_count,
|
||||
stk_refund_count,
|
||||
pool_count,
|
||||
&acnt,
|
||||
block_slot,
|
||||
&stab_win,
|
||||
prot_pps,
|
||||
)?;
|
||||
check_preservation_of_value(
|
||||
tx_body,
|
||||
utxos,
|
||||
stk_dep_count,
|
||||
stk_refund_count,
|
||||
pool_count,
|
||||
era,
|
||||
prot_pps,
|
||||
)?;
|
||||
check_fees(tx_body, &size, prot_pps)?;
|
||||
check_network_id(tx_body, network_id)?;
|
||||
check_metadata(tx_body, mtx)?;
|
||||
|
|
@ -115,25 +154,27 @@ fn compute_min_lovelace(output: &TransactionOutput, prot_pps: &ShelleyProtParams
|
|||
fn check_preservation_of_value(
|
||||
tx_body: &TransactionBody,
|
||||
utxos: &UTxOs,
|
||||
stk_dep_count: &u64,
|
||||
stk_refund_count: &u64,
|
||||
pool_count: &u64,
|
||||
era: &Era,
|
||||
prot_pps: &ShelleyProtParams,
|
||||
) -> ValidationResult {
|
||||
let neg_val_err: ValidationError = ShelleyMA(NegativeValue);
|
||||
let input: Value = get_consumed(tx_body, utxos, era)?;
|
||||
let produced: Value = get_produced(tx_body, era)?;
|
||||
let output: Value = add_values(&produced, &Value::Coin(tx_body.fee), &neg_val_err)?;
|
||||
if let Some(m) = &tx_body.mint {
|
||||
add_minted_value(&output, m, &neg_val_err)?;
|
||||
let consumed: Value = get_consumed(tx_body, utxos, stk_refund_count, era, prot_pps)?;
|
||||
let produced: Value = get_produced(tx_body, stk_dep_count, pool_count, era, prot_pps)?;
|
||||
if !values_are_equal(&consumed, &produced) {
|
||||
Err(ShelleyMA(PreservationOfValue))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
if !values_are_equal(&input, &output) {
|
||||
return Err(ShelleyMA(PreservationOfValue));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_consumed(
|
||||
tx_body: &TransactionBody,
|
||||
utxos: &UTxOs,
|
||||
stk_refund_count: &u64,
|
||||
era: &Era,
|
||||
prot_pps: &ShelleyProtParams,
|
||||
) -> Result<Value, ValidationError> {
|
||||
let neg_val_err: ValidationError = ShelleyMA(NegativeValue);
|
||||
let mut res: Value = empty_value();
|
||||
|
|
@ -155,10 +196,26 @@ fn get_consumed(
|
|||
},
|
||||
}
|
||||
}
|
||||
// TODO: Set right error message below.
|
||||
// Adding key refunds and minted assets
|
||||
res = add_values(
|
||||
&res,
|
||||
&Value::Coin(prot_pps.key_deposit * *stk_refund_count),
|
||||
&neg_val_err,
|
||||
)?;
|
||||
if let Some(m) = &tx_body.mint {
|
||||
res = add_minted_value(&res, m, &neg_val_err)?;
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn get_produced(tx_body: &TransactionBody, era: &Era) -> Result<Value, ValidationError> {
|
||||
fn get_produced(
|
||||
tx_body: &TransactionBody,
|
||||
stk_dep_count: &u64,
|
||||
pool_count: &u64,
|
||||
era: &Era,
|
||||
prot_pps: &ShelleyProtParams,
|
||||
) -> Result<Value, ValidationError> {
|
||||
let neg_val_err: ValidationError = ShelleyMA(NegativeValue);
|
||||
let mut res: Value = empty_value();
|
||||
for TransactionOutput { amount, .. } in tx_body.outputs.iter() {
|
||||
|
|
@ -168,6 +225,13 @@ fn get_produced(tx_body: &TransactionBody, era: &Era) -> Result<Value, Validatio
|
|||
_ => res = add_values(&res, amount, &neg_val_err)?,
|
||||
}
|
||||
}
|
||||
// TODO: Set right error message below.
|
||||
// Adding fees
|
||||
res = add_values(&res, &Value::Coin(tx_body.fee), &neg_val_err)?;
|
||||
// Pool reg deposits and staking key registrations
|
||||
let total_deposits = prot_pps.pool_deposit * *pool_count +
|
||||
prot_pps.key_deposit * *stk_dep_count;
|
||||
res = add_values(&res, &Value::Coin(total_deposits), &neg_val_err)?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
|
|
@ -220,6 +284,10 @@ fn check_witnesses(
|
|||
let vk_wits: &mut Vec<(bool, VKeyWitness)> =
|
||||
&mut mk_alonzo_vk_wits_check_list(&tx_wits.vkeywitness, ShelleyMA(MissingVKWitness))?;
|
||||
let tx_hash: &Vec<u8> = &Vec::from(tx_body.compute_hash().as_ref());
|
||||
let native_scripts: Vec<NativeScript> = match &tx_wits.native_script {
|
||||
Some(scripts) => scripts.iter().map(|x| x.clone().unwrap()).collect(),
|
||||
None => Vec::new(),
|
||||
};
|
||||
for input in tx_body.inputs.iter() {
|
||||
match utxos.get(&MultiEraInput::from_alonzo_compatible(input)) {
|
||||
Some(multi_era_output) => {
|
||||
|
|
@ -243,6 +311,13 @@ fn check_witnesses(
|
|||
None => return Err(ShelleyMA(InputNotInUTxO)),
|
||||
}
|
||||
}
|
||||
let vkey_wits = &vk_wits.iter().map(|bv| bv.clone().1).collect();
|
||||
check_native_scripts(
|
||||
vkey_wits,
|
||||
&native_scripts,
|
||||
&tx_body.validity_interval_start,
|
||||
&tx_body.ttl,
|
||||
)?;
|
||||
check_remaining_vk_wits(vk_wits, tx_hash)
|
||||
}
|
||||
|
||||
|
|
@ -330,3 +405,339 @@ fn compute_script_hash(script: &NativeScript) -> PolicyId {
|
|||
payload.insert(0, 0);
|
||||
pallas_crypto::hash::Hasher::<224>::hash(&payload)
|
||||
}
|
||||
|
||||
// Checks all certificates in order, and counts the relevant ones for computing deposits.
|
||||
fn check_certificates(
|
||||
cert_opt: &Option<Vec<Certificate>>,
|
||||
tx_ix: TransactionIndex,
|
||||
cert_state: &mut CertState,
|
||||
stk_dep_count: &mut u64,
|
||||
stk_refund_count: &mut u64,
|
||||
pool_count: &mut u64,
|
||||
acnt: &AccountState,
|
||||
slot: &Slot,
|
||||
stab_win: &Slot,
|
||||
prot_pps: &ShelleyProtParams,
|
||||
) -> ValidationResult {
|
||||
if let Some(certs) = cert_opt {
|
||||
let genesis = &GenesisValues::mainnet();
|
||||
let cepoch: Epoch = to_epoch(genesis, slot);
|
||||
let mpc: Coin = prot_pps.min_pool_cost;
|
||||
let mut ptr = CertPointer {
|
||||
slot: *slot,
|
||||
tx_ix,
|
||||
cert_ix: 0,
|
||||
};
|
||||
for (ix, cert) in certs.iter().enumerate() {
|
||||
match cert {
|
||||
StakeRegistration(stc) => {
|
||||
*stk_dep_count += 1;
|
||||
check_stake_registration(stc, &ptr, &mut cert_state.dstate)?;
|
||||
}
|
||||
StakeDeregistration(stc) => {
|
||||
check_stake_deregistration(stc, &mut cert_state.dstate)?;
|
||||
*stk_refund_count += 1;
|
||||
}
|
||||
StakeDelegation(stc, pk) => {
|
||||
check_stake_delegation(stc, pk, &mut cert_state.dstate, &cert_state.pstate)?;
|
||||
}
|
||||
PoolRegistration {
|
||||
operator,
|
||||
vrf_keyhash,
|
||||
pledge,
|
||||
cost,
|
||||
margin,
|
||||
reward_account,
|
||||
pool_owners,
|
||||
relays,
|
||||
pool_metadata,
|
||||
} => {
|
||||
if !cert_state.pstate.pool_params.contains_key(&operator) {
|
||||
*pool_count += 1;
|
||||
}
|
||||
let pool_param = PoolParam {
|
||||
vrf_keyhash: *vrf_keyhash,
|
||||
pledge: *pledge,
|
||||
cost: *cost,
|
||||
margin: margin.clone(),
|
||||
reward_account: reward_account.clone(),
|
||||
pool_owners: pool_owners.clone(),
|
||||
relays: relays.clone(),
|
||||
pool_metadata: pool_metadata.clone(),
|
||||
};
|
||||
check_pool_reg_or_update(operator, &pool_param, &mpc, &mut cert_state.pstate)?;
|
||||
}
|
||||
PoolRetirement(pk, repoch) => {
|
||||
check_pool_retirement(
|
||||
pk,
|
||||
repoch,
|
||||
&cepoch,
|
||||
&prot_pps.maximum_epoch,
|
||||
&mut cert_state.pstate,
|
||||
)?;
|
||||
}
|
||||
GenesisKeyDelegation(gkh, dkh, vrf) => {
|
||||
check_genesis_key_delegation(
|
||||
gkh,
|
||||
dkh,
|
||||
vrf,
|
||||
slot,
|
||||
stab_win,
|
||||
&mut cert_state.dstate,
|
||||
)?;
|
||||
}
|
||||
MoveInstantaneousRewardsCert(mir) => {
|
||||
check_mir(mir, slot, stab_win, &mut cert_state.dstate, acnt)?;
|
||||
}
|
||||
}
|
||||
ptr.cert_ix = ix as u32; // FIXME: Careful here, `ix` is `usize`
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn check_stake_registration(
|
||||
stc: &StakeCredential,
|
||||
ptr: &CertPointer,
|
||||
ds: &mut DState,
|
||||
) -> ValidationResult {
|
||||
insert_or_err(
|
||||
&mut ds.rewards,
|
||||
stc,
|
||||
&0_u64,
|
||||
ShelleyMA(KeyAlreadyRegistered),
|
||||
)?;
|
||||
insert_or_err(&mut ds.ptrs, ptr, stc, ShelleyMA(PointerInUse))
|
||||
}
|
||||
|
||||
fn check_stake_deregistration(stc: &StakeCredential, ds: &mut DState) -> ValidationResult {
|
||||
match ds.rewards.get(stc) {
|
||||
None => Err(ShelleyMA(KeyNotRegistered)),
|
||||
Some(0) => {
|
||||
ds.ptrs.retain(|_, v| v != stc);
|
||||
ds.delegations.remove(stc);
|
||||
ds.rewards.remove(stc);
|
||||
Ok(())
|
||||
}
|
||||
Some(_) => Err(ShelleyMA(RewardsNotNull)),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_stake_delegation(
|
||||
stc: &StakeCredential,
|
||||
pk: &PoolKeyhash,
|
||||
ds: &mut DState,
|
||||
ps: &PState,
|
||||
) -> ValidationResult {
|
||||
if !ps.pool_params.contains_key(pk) {
|
||||
Err(ShelleyMA(PoolNotRegistered))
|
||||
} else if ds.rewards.contains_key(stc) {
|
||||
ds.delegations.insert(stc.clone(), *pk);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ShelleyMA(KeyNotRegistered))
|
||||
}
|
||||
}
|
||||
|
||||
// Inserts a key-value pair if the key is not already in use, otherwise return
|
||||
// the provided error.
|
||||
fn insert_or_err<K, V, E>(map: &mut HashMap<K, V>, key: &K, value: &V, error: E) -> Result<(), E>
|
||||
where
|
||||
K: Eq,
|
||||
K: std::hash::Hash,
|
||||
K: Clone,
|
||||
V: Clone,
|
||||
{
|
||||
if map.contains_key(key) {
|
||||
return Err(error);
|
||||
} else {
|
||||
map.insert(key.clone(), value.clone());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn check_pool_reg_or_update(
|
||||
pool_hash: &PoolKeyhash,
|
||||
pool_param: &PoolParam,
|
||||
min_pool_cost: &Coin,
|
||||
ps: &mut PState,
|
||||
) -> ValidationResult {
|
||||
if pool_param.cost < *min_pool_cost {
|
||||
Err(ShelleyMA(PoolCostBelowMin))
|
||||
} else if ps.pool_params.contains_key(pool_hash) {
|
||||
// Updating
|
||||
ps.fut_pool_params
|
||||
.insert(pool_hash.clone(), (*pool_param).clone());
|
||||
ps.retiring.remove(&pool_hash);
|
||||
Ok(())
|
||||
} else {
|
||||
// Registering
|
||||
ps.pool_params
|
||||
.insert(pool_hash.clone(), (*pool_param).clone());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn check_pool_retirement(
|
||||
pool_hash: &PoolKeyhash,
|
||||
repoch: &Epoch,
|
||||
cepoch: &Epoch,
|
||||
emax: &u32,
|
||||
ps: &mut PState,
|
||||
) -> ValidationResult {
|
||||
if !ps.pool_params.contains_key(&pool_hash) {
|
||||
return Err(ShelleyMA(PoolNotRegistered));
|
||||
}
|
||||
if (*cepoch < *repoch) & (*repoch <= *cepoch + *emax as u64) {
|
||||
ps.retiring.insert(pool_hash.clone(), *repoch);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ShelleyMA(PoolNotRegistered))
|
||||
}
|
||||
}
|
||||
|
||||
fn check_genesis_key_delegation(
|
||||
gkh: &Genesishash,
|
||||
dkh: &GenesisDelegateHash, // called `vkh` in specs
|
||||
vrf: &VrfKeyhash,
|
||||
slot: &Slot,
|
||||
stab_win: &Slot,
|
||||
ds: &mut DState,
|
||||
) -> ValidationResult {
|
||||
let cod = ds
|
||||
.gen_delegs
|
||||
.iter()
|
||||
.filter(|kv| kv.0 != gkh)
|
||||
.map(|kv| kv.1)
|
||||
.collect::<Vec<_>>();
|
||||
let fod = ds
|
||||
.fut_gen_delegs
|
||||
.iter()
|
||||
.filter(|kv| kv.0 .1 != *gkh)
|
||||
.map(|kv| kv.1)
|
||||
.collect::<Vec<_>>();
|
||||
let curr_keyhashes = cod.iter().map(|v| v.0.clone()).collect::<Vec<_>>();
|
||||
let curr_vrfs = cod.iter().map(|v| v.1).collect::<Vec<_>>();
|
||||
let fut_keyhashes = fod.iter().map(|v| v.0.clone()).collect::<Vec<_>>();
|
||||
let fut_vrfs = fod.iter().map(|v| v.1).collect::<Vec<_>>();
|
||||
if curr_keyhashes.contains(dkh)
|
||||
| fut_keyhashes.contains(dkh)
|
||||
| curr_vrfs.contains(vrf)
|
||||
| fut_vrfs.contains(vrf)
|
||||
{
|
||||
Err(ShelleyMA(DuplicateGenesisDelegate))
|
||||
} else if !ds.gen_delegs.contains_key(gkh) {
|
||||
Err(ShelleyMA(GenesisKeyNotInMapping))
|
||||
} else {
|
||||
let gen_slot: Slot = *slot + *stab_win;
|
||||
ds.fut_gen_delegs
|
||||
.insert((gen_slot, gkh.clone()), (dkh.clone(), vrf.clone()));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn check_mir(
|
||||
mir: &MoveInstantaneousReward,
|
||||
slot: &Slot,
|
||||
stab_win: &Slot,
|
||||
ds: &mut DState,
|
||||
acnt: &AccountState,
|
||||
) -> ValidationResult {
|
||||
let genesis = &GenesisValues::mainnet();
|
||||
if !(*slot < first_slot(genesis, &(to_epoch(genesis, slot) + 1)) - *stab_win) {
|
||||
Err(ShelleyMA(MIRCertificateTooLateinEpoch))
|
||||
} else {
|
||||
let (ir_reserves, ir_treasury) = ds.inst_rewards.clone();
|
||||
let (pot, ir_pot) = match mir.source {
|
||||
Reserves => (acnt.reserves, ir_reserves.clone()),
|
||||
Treasury => (acnt.treasury, ir_treasury.clone()),
|
||||
};
|
||||
let mut combined: HashMap<StakeCredential, Coin> = HashMap::new();
|
||||
match &mir.target {
|
||||
StakeCredentials(kvp) => {
|
||||
let mut kvv: Vec<(StakeCredential, u64)> = // TODO: Err if the value is negative
|
||||
kvp.iter().map(|kv| (kv.clone().0, kv.clone().1 as u64)).collect();
|
||||
kvv.extend(ir_pot);
|
||||
for (key, value) in kvv {
|
||||
combined.insert(key, value);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
if combined.iter().map(|kv| kv.1).sum::<u64>() > pot {
|
||||
return Err(ShelleyMA(InsufficientForInstantaneousRewards));
|
||||
} else {
|
||||
ds.inst_rewards = match mir.source {
|
||||
Reserves => (combined, ir_reserves),
|
||||
Treasury => (ir_treasury, combined),
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
// Called just `epoch` in specs
|
||||
fn to_epoch(genesis: &GenesisValues, slot: &Slot) -> Epoch {
|
||||
genesis.absolute_slot_to_relative(*slot).0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
// CamelCase in specs
|
||||
fn first_slot(genesis: &GenesisValues, epoch: &Epoch) -> Slot {
|
||||
genesis.relative_slot_to_absolute(*epoch, 0)
|
||||
}
|
||||
|
||||
fn check_native_scripts(
|
||||
vkey_wits: &Vec<VKeyWitness>, // changed from alonzo
|
||||
native_scripts: &Vec<NativeScript>,
|
||||
low_bnd: &Option<u64>,
|
||||
upp_bnd: &Option<u64>,
|
||||
) -> ValidationResult {
|
||||
for native_script in native_scripts {
|
||||
if !eval_native_script(vkey_wits, native_script, low_bnd, upp_bnd) {
|
||||
return Err(ShelleyMA(ScriptDenial));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn eval_native_script(
|
||||
vkey_wits: &Vec<VKeyWitness>, // changed from alonzo
|
||||
native_script: &NativeScript,
|
||||
low_bnd: &Option<u64>,
|
||||
upp_bnd: &Option<u64>,
|
||||
) -> bool {
|
||||
match native_script {
|
||||
NativeScript::ScriptAll(scripts) => scripts
|
||||
.iter()
|
||||
.all(|scr| eval_native_script(vkey_wits, scr, low_bnd, upp_bnd)),
|
||||
NativeScript::ScriptAny(scripts) => scripts
|
||||
.iter()
|
||||
.any(|scr| eval_native_script(vkey_wits, scr, low_bnd, upp_bnd)),
|
||||
NativeScript::ScriptPubkey(hash) => vkey_wits
|
||||
.iter()
|
||||
.any(|vkey_wit| PallasHasher::<224>::hash(&vkey_wit.vkey.clone()) == *hash),
|
||||
NativeScript::ScriptNOfK(val, scripts) => {
|
||||
let count = scripts
|
||||
.iter()
|
||||
.map(|scr| eval_native_script(vkey_wits, scr, low_bnd, upp_bnd))
|
||||
.fold(0, |x, y| x + y as u32);
|
||||
count >= *val
|
||||
}
|
||||
NativeScript::InvalidBefore(val) => {
|
||||
match low_bnd {
|
||||
Some(time) => val >= time,
|
||||
None => false, // as per mary-ledger.pdf, p.20
|
||||
}
|
||||
}
|
||||
NativeScript::InvalidHereafter(val) => {
|
||||
match upp_bnd {
|
||||
Some(time) => val <= time,
|
||||
None => false, // as per mary-ledger.pdf, p.20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,12 +12,14 @@ use pallas_codec::{
|
|||
use pallas_crypto::key::ed25519::{PublicKey, Signature};
|
||||
use pallas_primitives::{
|
||||
alonzo::{
|
||||
AssetName, AuxiliaryData, Coin, MintedTx as AlonzoMintedTx, Multiasset, NativeScript,
|
||||
NetworkId, PlutusScript, PolicyId, VKeyWitness, Value,
|
||||
AddrKeyhash, AssetName, AuxiliaryData, Coin, Epoch, GenesisDelegateHash, Genesishash,
|
||||
MintedTx as AlonzoMintedTx, Multiasset, NativeScript, NetworkId, PlutusScript, PolicyId,
|
||||
PoolKeyhash, PoolMetadata, Relay, RewardAccount, StakeCredential, TransactionIndex,
|
||||
UnitInterval, VKeyWitness, Value, VrfKeyhash,
|
||||
},
|
||||
babbage::{MintedTx as BabbageMintedTx, PlutusV2Script},
|
||||
};
|
||||
use pallas_traverse::{MultiEraInput, MultiEraOutput};
|
||||
use pallas_traverse::{time::Slot, MultiEraInput, MultiEraOutput};
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Deref;
|
||||
pub use validation::*;
|
||||
|
|
@ -101,6 +103,10 @@ pub fn lovelace_diff_or_fail(
|
|||
}
|
||||
|
||||
pub fn multi_assets_are_equal(fma: &Multiasset<Coin>, sma: &Multiasset<Coin>) -> bool {
|
||||
multi_asset_included(fma, sma) && multi_asset_included(sma, fma)
|
||||
}
|
||||
|
||||
pub fn multi_asset_included(fma: &Multiasset<Coin>, sma: &Multiasset<Coin>) -> bool {
|
||||
for (fpolicy, fassets) in fma.iter() {
|
||||
match find_policy(sma, fpolicy) {
|
||||
Some(sassets) => {
|
||||
|
|
@ -158,7 +164,7 @@ fn coerce_to_coin(
|
|||
err: &ValidationError,
|
||||
) -> Result<Multiasset<Coin>, ValidationError> {
|
||||
let mut res: Vec<(PolicyId, KeyValuePairs<AssetName, Coin>)> = Vec::new();
|
||||
for (policy, assets) in value.clone().to_vec().iter() {
|
||||
for (policy, assets) in value.iter() {
|
||||
let mut aa: Vec<(AssetName, Coin)> = Vec::new();
|
||||
for (asset_name, amount) in assets.clone().to_vec().iter() {
|
||||
if *amount < 0 {
|
||||
|
|
@ -342,3 +348,58 @@ pub fn compute_plutus_v2_script_hash(script: &PlutusV2Script) -> PolicyId {
|
|||
payload.insert(0, 2);
|
||||
pallas_crypto::hash::Hasher::<224>::hash(&payload)
|
||||
}
|
||||
|
||||
pub type CertificateIndex = u32;
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Clone)]
|
||||
pub struct CertPointer {
|
||||
pub slot: Slot,
|
||||
pub tx_ix: TransactionIndex,
|
||||
pub cert_ix: CertificateIndex,
|
||||
}
|
||||
|
||||
pub type GenesisDelegation = HashMap<Genesishash, (GenesisDelegateHash, VrfKeyhash)>;
|
||||
pub type FutGenesisDelegation = HashMap<(Slot, Genesishash), (GenesisDelegateHash, VrfKeyhash)>;
|
||||
pub type InstantaneousRewards = (
|
||||
HashMap<StakeCredential, Coin>,
|
||||
HashMap<StakeCredential, Coin>,
|
||||
);
|
||||
|
||||
#[derive(Default, Clone)] // for testing
|
||||
pub struct DState {
|
||||
pub rewards: HashMap<StakeCredential, Coin>,
|
||||
pub delegations: HashMap<StakeCredential, PoolKeyhash>,
|
||||
pub ptrs: HashMap<CertPointer, StakeCredential>,
|
||||
pub fut_gen_delegs: FutGenesisDelegation,
|
||||
pub gen_delegs: GenesisDelegation,
|
||||
pub inst_rewards: InstantaneousRewards,
|
||||
}
|
||||
|
||||
// Essentially part of the `PoolRegistration` component of `Certificate` at alonzo/src/model.rs
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PoolParam {
|
||||
pub vrf_keyhash: VrfKeyhash,
|
||||
pub pledge: Coin,
|
||||
pub cost: Coin,
|
||||
pub margin: UnitInterval,
|
||||
pub reward_account: RewardAccount, // FIXME: Should be a `StakeCredential`, or `Hash<_>`???
|
||||
pub pool_owners: Vec<AddrKeyhash>,
|
||||
pub relays: Vec<Relay>,
|
||||
pub pool_metadata: Nullable<PoolMetadata>,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)] // for testing
|
||||
pub struct PState {
|
||||
pub pool_params: HashMap<PoolKeyhash, PoolParam>,
|
||||
pub fut_pool_params: HashMap<PoolKeyhash, PoolParam>,
|
||||
pub retiring: HashMap<PoolKeyhash, Epoch>,
|
||||
}
|
||||
|
||||
// Originally `DPState` in ShelleyMA specs, then updated to
|
||||
// `CertState` in Haskell sources at Intersect (#3369).
|
||||
#[non_exhaustive]
|
||||
#[derive(Default, Clone)] // for testing
|
||||
pub struct CertState {
|
||||
pub pstate: PState,
|
||||
pub dstate: DState,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -178,12 +178,19 @@ pub struct ConwayProtParams {
|
|||
pub minfee_refscript_cost_per_byte: UnitInterval,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct AccountState {
|
||||
pub treasury: Coin,
|
||||
pub reserves: Coin,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Environment {
|
||||
pub prot_params: MultiEraProtocolParameters,
|
||||
pub prot_magic: u32,
|
||||
pub block_slot: u64,
|
||||
pub network_id: u8,
|
||||
pub acnt: Option<AccountState>,
|
||||
}
|
||||
|
||||
impl Environment {
|
||||
|
|
@ -202,4 +209,8 @@ impl Environment {
|
|||
pub fn network_id(&self) -> &u8 {
|
||||
&self.network_id
|
||||
}
|
||||
|
||||
pub fn acnt(&self) -> &Option<AccountState> {
|
||||
&self.acnt
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
#[non_exhaustive]
|
||||
pub enum ValidationError {
|
||||
TxAndProtParamsDiffer,
|
||||
PParamsByronDoesntNeedAccountState,
|
||||
EnvMissingAccountState,
|
||||
UnknownProtParams,
|
||||
Byron(ByronError),
|
||||
ShelleyMA(ShelleyMAError),
|
||||
|
|
@ -49,6 +51,19 @@ pub enum ShelleyMAError {
|
|||
MissingScriptWitness,
|
||||
WrongSignature,
|
||||
MintingLacksPolicy,
|
||||
KeyAlreadyRegistered,
|
||||
KeyNotRegistered,
|
||||
PointerInUse,
|
||||
RewardsNotNull,
|
||||
PoolAlreadyRegistered,
|
||||
PoolNotRegistered,
|
||||
PoolCostBelowMin,
|
||||
DuplicateGenesisDelegate,
|
||||
DuplicateGenesisVRF,
|
||||
GenesisKeyNotInMapping,
|
||||
InsufficientForInstantaneousRewards,
|
||||
MIRCertificateTooLateinEpoch,
|
||||
ScriptDenial,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
|||
|
|
@ -28,9 +28,23 @@ Note that, since phase-1 validations do not include the execution of native scri
|
|||
List of positive unit tests:
|
||||
- **successful_mainnet_shelley_tx** ([here](https://cexplorer.io/tx/50eba65e73c8c5f7b09f4ea28cf15dce169f3d1c322ca3deff03725f51518bb2) to see on Cardano explorer) is a simple Shelley transaction, with no native scripts or metadata.
|
||||
- **successful_mainnet_shelley_tx_with_script** ([here](https://cexplorer.io/tx/4a3f86762383f1d228542d383ae7ac89cf75cf7ff84dec8148558ea92b0b92d0) to see on Cardano explorer) is a Shelley transaction with a native script and no metadata.
|
||||
- **successful_mainnet_shelley_tx_with_changed_script** is the same as the
|
||||
previous transaction but the script is modified from requiring all signatures
|
||||
to requiring only one of them, and with one key-witness pair removed.
|
||||
- **successful_mainnet_shelley_tx_with_metadata** ([here](https://cexplorer.io/tx/c220e20cc480df9ce7cd871df491d7390c6a004b9252cf20f45fc3c968535b4a) to see on Cardano Explorer) is a Shelley transaction with metadata and no native scripts.
|
||||
- **successful_mainnet_mary_tx_with_minting** ([here](https://cexplorer.io/tx/b7b1046d1787ac6917f5bb5841e73b3f4bef8f0a6bf692d05ef18e1db9c3f519) to see on Cardano Explorer) is a Mary transaction that mints assets and has, therefore, a native script. It has no metadata.
|
||||
|
||||
- **successful_mainnet_mary_tx_with_pool_reg**
|
||||
([here](https://cexplorer.io/tx/ce8ba608357e31695ce7be1a4a9875f43b3fd264f106e455e870714f149af925)
|
||||
to see on Cardano explorer) is a Mary transaction with a pool registration.
|
||||
- **successful_mainnet_mary_tx_with_stk_deleg**
|
||||
([here](https://cexplorer.io/tx/cc6a92cc0f4ea326439bac6b18bc7b424470c508a99b9aebc8fafc027d906465)
|
||||
to see on Cardano explorer) is a Mary transaction with a staking key
|
||||
registration and delegation to the pool above.
|
||||
- **successful_mainnet_allegra_tx_with_mir**
|
||||
([here](https://cexplorer.io/tx/99f621beaacefc14ad8912b777422600e707f75bf619b2af20e918b0fe53f882)
|
||||
to see on Cardano explorer) is a Mary transaction moving instantaneous
|
||||
rewards, drawn from the Treasury.
|
||||
|
||||
List of negative unit tests:
|
||||
- **empty_ins** takes successful_mainnet_shelley_tx and removes its input.
|
||||
- **unfound_utxo** takes successful_mainnet_shelley_tx and calls validation on it without a proper UTxO set containing the transaction input information.
|
||||
|
|
@ -45,6 +59,16 @@ List of negative unit tests:
|
|||
- **missing_vk_witness** takes successful_mainnet_shelley_tx and removes the verification-key witness associated to one of its inputs.
|
||||
- **vk_witness_changed** takes successful_mainnet_shelley_tx and modifies the verification-key witness associated to one of its inputs.
|
||||
- **missing_native_script_witness** takes successful_mainnet_shelley_tx_with_script and removes the native script associated to one of its inputs.
|
||||
- **missing_signature_native_script** takes successful_mainnet_shelley_tx but
|
||||
one verification-key witness is removed (the same one of
|
||||
successful_mainnet_shelley_tx_with_changed_script).
|
||||
- **unregistered_pool** takes successful_mainnet_mary_tx_with_stk_deleg,
|
||||
but the pool to which the delegation occurs is not registered.
|
||||
- **delegation_before_registration** takes
|
||||
successful_mainnet_mary_tx_with_stk_deleg and flips the order of the
|
||||
certificates (stake registration and delegation).
|
||||
- **too_late_for_mir** takes successful_mainnet_allegra_tx_with_mir but the slot
|
||||
is advanced to a later moment.
|
||||
|
||||
### Alonzo
|
||||
*pallas-applying/tests/alonzo.rs* contains multiple unit tests for validation in the Alonzo era.
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@ use common::*;
|
|||
use pallas_addresses::{Address, Network, ShelleyAddress, ShelleyPaymentPart};
|
||||
use pallas_applying::{
|
||||
utils::{
|
||||
AlonzoError, AlonzoProtParams, Environment, MultiEraProtocolParameters, ValidationError::*,
|
||||
AccountState, AlonzoError, AlonzoProtParams, Environment, MultiEraProtocolParameters,
|
||||
ValidationError::*,
|
||||
},
|
||||
validate, UTxOs,
|
||||
validate_txs, CertState, UTxOs,
|
||||
};
|
||||
use pallas_codec::{
|
||||
minicbor::{
|
||||
|
|
@ -43,13 +44,21 @@ mod alonzo_tests {
|
|||
None,
|
||||
)],
|
||||
);
|
||||
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_334()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 44237276,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => (),
|
||||
Err(err) => panic!("Unexpected error ({:?})", err),
|
||||
}
|
||||
|
|
@ -143,13 +152,21 @@ mod alonzo_tests {
|
|||
None,
|
||||
)],
|
||||
);
|
||||
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_300()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 58924928,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => (),
|
||||
Err(err) => panic!("Unexpected error ({:?})", err),
|
||||
}
|
||||
|
|
@ -170,13 +187,21 @@ mod alonzo_tests {
|
|||
None,
|
||||
)],
|
||||
);
|
||||
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_300()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 6447035,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => (),
|
||||
Err(err) => panic!("Unexpected error ({:?})", err),
|
||||
}
|
||||
|
|
@ -197,13 +222,21 @@ mod alonzo_tests {
|
|||
None,
|
||||
)],
|
||||
);
|
||||
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_300()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 6447038,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => (),
|
||||
Err(err) => panic!("Unexpected error ({:?})", err),
|
||||
}
|
||||
|
|
@ -229,13 +262,21 @@ mod alonzo_tests {
|
|||
mtx.transaction_body =
|
||||
Decode::decode(&mut Decoder::new(tx_buf.as_slice()), &mut ()).unwrap();
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_334()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 44237276,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Inputs set should not be empty"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::TxInsEmpty) => (),
|
||||
|
|
@ -252,13 +293,21 @@ mod alonzo_tests {
|
|||
let mtx: MintedTx = minted_tx_from_cbor(&cbor_bytes);
|
||||
let utxos: UTxOs = UTxOs::new();
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_334()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 44237276,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("All inputs should be within the UTxO set"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::InputNotInUTxO) => (),
|
||||
|
|
@ -288,13 +337,21 @@ mod alonzo_tests {
|
|||
mtx.transaction_body =
|
||||
Decode::decode(&mut Decoder::new(tx_buf.as_slice()), &mut ()).unwrap();
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_334()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 44237276,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Validity interval lower bound should have been reached"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::BlockPrecedesValInt) => (),
|
||||
|
|
@ -324,13 +381,21 @@ mod alonzo_tests {
|
|||
mtx.transaction_body =
|
||||
Decode::decode(&mut Decoder::new(tx_buf.as_slice()), &mut ()).unwrap();
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_334()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 44237276,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Validity interval upper bound should not have been surpassed"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::BlockExceedsValInt) => (),
|
||||
|
|
@ -356,13 +421,21 @@ mod alonzo_tests {
|
|||
);
|
||||
let mut alonzo_prot_params: AlonzoProtParams = mk_params_epoch_334();
|
||||
alonzo_prot_params.minfee_a = 79; // This value was 44 during Alonzo on mainnet
|
||||
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(alonzo_prot_params),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 44237276,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Fee should not be below minimum"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::FeeBelowMin) => (),
|
||||
|
|
@ -465,13 +538,21 @@ mod alonzo_tests {
|
|||
mtx.transaction_body =
|
||||
Decode::decode(&mut Decoder::new(tx_buf.as_slice()), &mut ()).unwrap();
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_300()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 58924928,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("No collateral inputs"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::CollateralMissing) => (),
|
||||
|
|
@ -571,13 +652,20 @@ mod alonzo_tests {
|
|||
);
|
||||
let mut alonzo_prot_params: AlonzoProtParams = mk_params_epoch_300();
|
||||
alonzo_prot_params.max_collateral_inputs = 0; // This value was 3 during Alonzo on mainnet
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(alonzo_prot_params),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 58924928,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Number of collateral inputs should be within limits"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::TooManyCollaterals) => (),
|
||||
|
|
@ -696,13 +784,20 @@ mod alonzo_tests {
|
|||
);
|
||||
utxos.insert(multi_era_in, multi_era_out);
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_300()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 58924928,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Collateral inputs should be verification-key locked"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::CollateralNotVKeyLocked) => (),
|
||||
|
|
@ -810,13 +905,20 @@ mod alonzo_tests {
|
|||
None,
|
||||
)],
|
||||
);
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_300()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 58924928,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Collateral inputs should contain only lovelace"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::NonLovelaceCollateral) => (),
|
||||
|
|
@ -915,13 +1017,20 @@ mod alonzo_tests {
|
|||
);
|
||||
let mut alonzo_prot_params: AlonzoProtParams = mk_params_epoch_300();
|
||||
alonzo_prot_params.collateral_percentage = 700; // This was 150 during Alonzo on mainnet.
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(alonzo_prot_params),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 58924928,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Collateral inputs should contain the minimum lovelace"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::CollateralMinLovelace) => (),
|
||||
|
|
@ -951,13 +1060,20 @@ mod alonzo_tests {
|
|||
mtx.transaction_body =
|
||||
Decode::decode(&mut Decoder::new(tx_buf.as_slice()), &mut ()).unwrap();
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_334()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 44237276,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Preservation of value does not hold"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::PreservationOfValue) => (),
|
||||
|
|
@ -1007,13 +1123,20 @@ mod alonzo_tests {
|
|||
None,
|
||||
)],
|
||||
);
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_334()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 44237276,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Output network ID should match environment network ID"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::OutputWrongNetworkID) => (),
|
||||
|
|
@ -1045,13 +1168,20 @@ mod alonzo_tests {
|
|||
None,
|
||||
)],
|
||||
);
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_334()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 44237276,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Transaction network ID should match environment network ID"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::TxWrongNetworkID) => (),
|
||||
|
|
@ -1151,13 +1281,20 @@ mod alonzo_tests {
|
|||
let mut alonzo_prot_params: AlonzoProtParams = mk_params_epoch_300();
|
||||
alonzo_prot_params.max_tx_ex_units.mem = 4649575; // This is 1 lower than that of the transaction
|
||||
alonzo_prot_params.max_tx_ex_units.steps = 1765246503; // This is 1 lower than that of the transaction
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(alonzo_prot_params),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 58924928,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Transaction ex units should be below maximum"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::TxExUnitsExceeded) => (),
|
||||
|
|
@ -1184,13 +1321,20 @@ mod alonzo_tests {
|
|||
);
|
||||
let mut alonzo_prot_params: AlonzoProtParams = mk_params_epoch_334();
|
||||
alonzo_prot_params.max_transaction_size = 158; // 1 byte less than the size of the tx
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(alonzo_prot_params),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 44237276,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!(
|
||||
"Transaction size should not exceed the maximum allowed by the protocol parameter"
|
||||
),
|
||||
|
|
@ -1301,13 +1445,20 @@ mod alonzo_tests {
|
|||
mtx.transaction_body =
|
||||
Decode::decode(&mut Decoder::new(tx_buf.as_slice()), &mut ()).unwrap();
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_300()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 58924928,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("All required signers should have signed the transaction"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::ReqSignerMissing) => (),
|
||||
|
|
@ -1337,13 +1488,20 @@ mod alonzo_tests {
|
|||
mtx.transaction_witness_set =
|
||||
Decode::decode(&mut Decoder::new(tx_buf.as_slice()), &mut ()).unwrap();
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_334()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 44237276,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Missing verification key witness"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::VKWitnessMissing) => (),
|
||||
|
|
@ -1380,13 +1538,20 @@ mod alonzo_tests {
|
|||
mtx.transaction_witness_set =
|
||||
Decode::decode(&mut Decoder::new(tx_buf.as_slice()), &mut ()).unwrap();
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_334()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 44237276,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Witness signature should verify the transaction"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::VKWrongSignature) => (),
|
||||
|
|
@ -1489,13 +1654,20 @@ mod alonzo_tests {
|
|||
mtx.transaction_witness_set =
|
||||
Decode::decode(&mut Decoder::new(tx_buf.as_slice()), &mut ()).unwrap();
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_300()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 58924928,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Missing Plutus script"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::ScriptWitnessMissing) => (),
|
||||
|
|
@ -1606,13 +1778,20 @@ mod alonzo_tests {
|
|||
mtx.transaction_witness_set =
|
||||
Decode::decode(&mut Decoder::new(tx_buf.as_slice()), &mut ()).unwrap();
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_300()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 58924928,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Unneeded Plutus script"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::UnneededNativeScript) => (),
|
||||
|
|
@ -1642,13 +1821,20 @@ mod alonzo_tests {
|
|||
mtx.transaction_witness_set =
|
||||
Decode::decode(&mut Decoder::new(tx_buf.as_slice()), &mut ()).unwrap();
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_300()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 6447035,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Minting policy is not supported by a matching native script"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::MintingLacksPolicy) => (),
|
||||
|
|
@ -1751,13 +1937,20 @@ mod alonzo_tests {
|
|||
mtx.transaction_witness_set =
|
||||
Decode::decode(&mut Decoder::new(tx_buf.as_slice()), &mut ()).unwrap();
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_300()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 58924928,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Missing datum"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::DatumMissing) => (),
|
||||
|
|
@ -1866,13 +2059,20 @@ mod alonzo_tests {
|
|||
mtx.transaction_witness_set =
|
||||
Decode::decode(&mut Decoder::new(tx_buf.as_slice()), &mut ()).unwrap();
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_300()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 58924928,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Unneeded datum"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::UnneededDatum) => (),
|
||||
|
|
@ -1982,13 +2182,20 @@ mod alonzo_tests {
|
|||
mtx.transaction_witness_set =
|
||||
Decode::decode(&mut Decoder::new(tx_buf.as_slice()), &mut ()).unwrap();
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_300()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 58924928,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Unneeded redeemer"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::UnneededRedeemer) => (),
|
||||
|
|
@ -2091,13 +2298,20 @@ mod alonzo_tests {
|
|||
mtx.transaction_witness_set =
|
||||
Decode::decode(&mut Decoder::new(tx_buf.as_slice()), &mut ()).unwrap();
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_300()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 58924928,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Redeemer missing"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::RedeemerMissing) => (),
|
||||
|
|
@ -2122,13 +2336,20 @@ mod alonzo_tests {
|
|||
None,
|
||||
)],
|
||||
);
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_300()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 6447038,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Transaction auxiliary data removed"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::MetadataHash) => (),
|
||||
|
|
@ -2154,13 +2375,20 @@ mod alonzo_tests {
|
|||
);
|
||||
let mut alonzo_prot_params: AlonzoProtParams = mk_params_epoch_334();
|
||||
alonzo_prot_params.ada_per_utxo_byte = 10000000; // This was 34482 during Alonzo on mainnet.
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(alonzo_prot_params),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 44237276,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Output minimum lovelace is unreached"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::MinLovelaceUnreached) => (),
|
||||
|
|
@ -2186,13 +2414,20 @@ mod alonzo_tests {
|
|||
);
|
||||
let mut alonzo_prot_params: AlonzoProtParams = mk_params_epoch_334();
|
||||
alonzo_prot_params.max_value_size = 0; // This was 5000 during Alonzo on mainnet
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(alonzo_prot_params),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 44237276,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Max value size exceeded"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::MaxValSizeExceeded) => (),
|
||||
|
|
@ -2299,13 +2534,20 @@ mod alonzo_tests {
|
|||
mtx.transaction_witness_set =
|
||||
Decode::decode(&mut Decoder::new(tx_witness_set_buf.as_slice()), &mut ()).unwrap();
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
let acnt = AccountState {
|
||||
treasury: 261_254_564_000_000,
|
||||
reserves: 0,
|
||||
};
|
||||
|
||||
let env: Environment = Environment {
|
||||
prot_params: MultiEraProtocolParameters::Alonzo(mk_params_epoch_300()),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 58924928,
|
||||
network_id: 1,
|
||||
acnt: Some(acnt),
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Wrong script integrity hash"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::ScriptIntegrityHash) => (),
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -3,9 +3,10 @@ pub mod common;
|
|||
use common::{cbor_to_bytes, minted_tx_payload_from_cbor, mk_utxo_for_byron_tx};
|
||||
use pallas_applying::{
|
||||
utils::{
|
||||
ByronError, ByronProtParams, Environment, MultiEraProtocolParameters, ValidationError::*,
|
||||
ByronError, ByronProtParams, CertState, Environment, MultiEraProtocolParameters,
|
||||
ValidationError::*,
|
||||
},
|
||||
validate, UTxOs,
|
||||
validate_txs, UTxOs,
|
||||
};
|
||||
|
||||
use pallas_codec::{
|
||||
|
|
@ -59,8 +60,10 @@ mod byron_tests {
|
|||
prot_magic: 764824073,
|
||||
block_slot: 6341,
|
||||
network_id: 1,
|
||||
acnt: None,
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => (),
|
||||
Err(err) => panic!("Unexpected error ({:?})", err),
|
||||
}
|
||||
|
|
@ -102,8 +105,10 @@ mod byron_tests {
|
|||
prot_magic: 764824073,
|
||||
block_slot: 3241381,
|
||||
network_id: 1,
|
||||
acnt: None,
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => (),
|
||||
Err(err) => panic!("Unexpected error ({:?})", err),
|
||||
}
|
||||
|
|
@ -153,8 +158,10 @@ mod byron_tests {
|
|||
prot_magic: 764824073,
|
||||
block_slot: 3241381,
|
||||
network_id: 1,
|
||||
acnt: None,
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Inputs set should not be empty"),
|
||||
Err(err) => match err {
|
||||
Byron(ByronError::TxInsEmpty) => (),
|
||||
|
|
@ -207,8 +214,10 @@ mod byron_tests {
|
|||
prot_magic: 764824073,
|
||||
block_slot: 3241381,
|
||||
network_id: 1,
|
||||
acnt: None,
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Outputs set should not be empty"),
|
||||
Err(err) => match err {
|
||||
Byron(ByronError::TxOutsEmpty) => (),
|
||||
|
|
@ -246,8 +255,10 @@ mod byron_tests {
|
|||
prot_magic: 764824073,
|
||||
block_slot: 3241381,
|
||||
network_id: 1,
|
||||
acnt: None,
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("All inputs must be within the UTxO set"),
|
||||
Err(err) => match err {
|
||||
Byron(ByronError::InputNotInUTxO) => (),
|
||||
|
|
@ -306,8 +317,10 @@ mod byron_tests {
|
|||
prot_magic: 764824073,
|
||||
block_slot: 3241381,
|
||||
network_id: 1,
|
||||
acnt: None,
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("All outputs must contain lovelace"),
|
||||
Err(err) => match err {
|
||||
Byron(ByronError::OutputWithoutLovelace) => (),
|
||||
|
|
@ -351,8 +364,10 @@ mod byron_tests {
|
|||
prot_magic: 764824073,
|
||||
block_slot: 3241381,
|
||||
network_id: 1,
|
||||
acnt: None,
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Fees should not be below minimum"),
|
||||
Err(err) => match err {
|
||||
Byron(ByronError::FeesBelowMin) => (),
|
||||
|
|
@ -396,8 +411,10 @@ mod byron_tests {
|
|||
prot_magic: 764824073,
|
||||
block_slot: 3241381,
|
||||
network_id: 1,
|
||||
acnt: None,
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Transaction size cannot exceed protocol limit"),
|
||||
Err(err) => match err {
|
||||
Byron(ByronError::MaxTxSizeExceeded) => (),
|
||||
|
|
@ -449,8 +466,10 @@ mod byron_tests {
|
|||
prot_magic: 764824073,
|
||||
block_slot: 3241381,
|
||||
network_id: 1,
|
||||
acnt: None,
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("All inputs must have a witness signature"),
|
||||
Err(err) => match err {
|
||||
Byron(ByronError::MissingWitness) => (),
|
||||
|
|
@ -511,8 +530,10 @@ mod byron_tests {
|
|||
prot_magic: 764824073,
|
||||
block_slot: 3241381,
|
||||
network_id: 1,
|
||||
acnt: None,
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
let mut cert_state: CertState = CertState::default();
|
||||
match validate_txs(&[metx], &env, &utxos, &mut cert_state) {
|
||||
Ok(()) => panic!("Witness signature should verify the transaction"),
|
||||
Err(err) => match err {
|
||||
Byron(ByronError::WrongSignature) => (),
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -413,7 +413,7 @@ pub type UnitInterval = RationalNumber;
|
|||
|
||||
pub type PositiveInterval = RationalNumber;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Eq, Ord, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Hash)]
|
||||
pub enum StakeCredential {
|
||||
AddrKeyhash(AddrKeyhash),
|
||||
Scripthash(Scripthash),
|
||||
|
|
|
|||
1
test_data/allegra1.tx
Normal file
1
test_data/allegra1.tx
Normal file
File diff suppressed because one or more lines are too long
1
test_data/mary2.tx
Normal file
1
test_data/mary2.tx
Normal file
|
|
@ -0,0 +1 @@
|
|||
84a500818258201dd22b2976374f9b8e6aa045ded141742fa5adc5184a505410fb9f343d14e407000181825839018e8f7a7073b8a95a4c1f1cf412b1042fca4945b89eb11754b3481b29fb2b631db76384f64dd94b47f97fc8c2a206764c17a1de7da2f70e831a3c0f17fa021a0002fce9031a0191f62f04828a03581c59ebe72ae96462018fbe04633100f90b3066688d85f00f3bd254707f58201efb798f239b9b02deb4636a3ab1962af43512595fcb82276e11971e684e49b71a3b9aca001a1443fd00d81e82011864581de1fb2b631db76384f64dd94b47f97fc8c2a206764c17a1de7da2f70e8381581cfb2b631db76384f64dd94b47f97fc8c2a206764c17a1de7da2f70e83818400190bb944c22614bbf682781c68747470733a2f2f6361726461706f6f6c2e636f6d2f612e6a736f6e582001f708549816c9a075ff96e9682c11a5f5c7f4e147862a663bdeece0716ab76e83028200581cfb2b631db76384f64dd94b47f97fc8c2a206764c17a1de7da2f70e83581c59ebe72ae96462018fbe04633100f90b3066688d85f00f3bd254707fa100838258205ac72fb72ac603eb4aa1be5b98af76f193e24924b4a7c877f9e9c401fb9cda385840bdbd394d90106cd033224caffbba57fc071a0e00087bc26aa07174ec42d26060259cb865cbd8ce0981897c1fb0ebc38678420b52731827e9cb00f5209649850b825820af5d32c73a976fcd7abed9fa9c85e128862bd870c8ebc51f602a053343fab8dc584032bb6013443435846521d42e6cf076f0769766ed366661d286fda0788622f603339afa20649123a04cc4266581e328a5f02f9eca866fa44e971a6d8ab7bb5c04825820bc08576470a74179757177311dd8bdae9e56a637d58ed5d50a737d2b03dd9e685840cf586f9bc2ef1684c396e047d9923ab94fa616aed013d5f7c7d3c730ec75f0cd6021a51bd9bdb6f91711d92e332b21fef2221809659b56d538debaaf0bc02b0ef5f6
|
||||
1
test_data/mary3.tx
Normal file
1
test_data/mary3.tx
Normal file
|
|
@ -0,0 +1 @@
|
|||
84a50081825820f8cad2b3e5a3744e096cbb3040ff6057560d3ec8d5444fda1efc669f9c2c7d30060181825839015d74deb638695cc12d11b7dfa50b2023b626287371674fecaa569b8039cf0461807b986a6477205e376dac280d7f150eb497025f67c497571a2549ae4f021a0002a8b1031a01bb2735048282008200581c39cf0461807b986a6477205e376dac280d7f150eb497025f67c4975783028200581c39cf0461807b986a6477205e376dac280d7f150eb497025f67c49757581c59ebe72ae96462018fbe04633100f90b3066688d85f00f3bd254707fa100828258208f9010e31a25735302c168f71416bae8d5cc8333067e06cc5d3c3e0b9d1d262058403719305623d25de0648e17cf041a30f28483d4e0354cdd1d12a3e9c13210327c736754049686e6f7315bb9c4b5bcc50cf140290452362e8a2beb66efcd1b2a02825820e7101958033ebca48dc8d71dee85d1a10c1e94460ec43275b1e82e2638a096b05840b6c16dadb85ae630aa0376b6fd26d103b33085a8b12011e515fa265d548431e65a8eb2c8091ed0bc3b364551eaba47ced495bdce4de758509539481ec123d70af5f6
|
||||
1
test_data/shelley4.tx
Normal file
1
test_data/shelley4.tx
Normal file
|
|
@ -0,0 +1 @@
|
|||
84a40081825820e7db1f809fcc21d3dd108ced6218bf0f0cbb6a0f679f848ff1790b68d3a35872000181825839010c57a4aa08aaa7c42b45e4e9490151e2665dbb7d374e795ad5be5e4960562a0d213c675c2b84ee0e34eb377d4abbe82a4c256a0708baac251a0016e360021a0007a120031a010c59f8a200838258205df1be8b0071123c982a94c19c0c06485dbe9271e4381e8cf4fc2ed554ac133f5840c271a9d652ae95e6a8a5117c5026369235182da7e4fe040b02465089e5e2caf05063cf8b61601e6f6074c03f700bacaadcd62483c48d66a5f8d418a7c27c4b01825820403171966fadb1ce9b26852cb74018a04bc031a4aee92be39702b18efd75e058584039395858906ec9ab7540e79022b25a1f3bdfece09f9e2f36254eb5abe625b72dbd8179ece4c9fc1d537afce95b67d8095d29e1f3c50de4ecc30fd67e1ba440048258206311da054c5dfa3ac53c9fc3be859bd322f0712f7e093596fa5f6de031d95acd58403d7deba60f80a03f5bf172c1699f07ecef557d9509551cbe8d2b9000e903c3e3f60bb127c9c0b4cd5df84c01791b98e10fe19209088d0b085c74702b25914a0d01818202838200581ca96da581c39549aeda81f539ac3940ac0cb53657e774ca7e68f15ed98200581cccfcb3fed004562be1354c837a4a4b9f4b1c2b6705229efeedd12d4d8200581c74fcd61aecebe36aa6b6cd4314027282fa4b41c3ce8af17d9b77d0d1f5f6
|
||||
Loading…
Add table
Add a link
Reference in a new issue