Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 22 additions & 18 deletions codec/src/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,36 @@ use crate::{
};
use acropolis_common::{validation::Phase1ValidationError, *};
use pallas_primitives::Metadatum as PallasMetadatum;
use pallas_traverse::{Era as PallasEra, MultiEraTx};
use pallas_traverse::{Era as PallasEra, MultiEraInput, MultiEraTx};

/// Parse transaction inputs and outputs, and return the parsed inputs, outputs, total output lovelace, and errors
pub fn map_transaction_inputs_outputs(
pub fn map_transaction_inputs(inputs: &[MultiEraInput]) -> Vec<UTxOIdentifier> {
inputs
.iter()
.map(|input| {
let oref = input.output_ref();
UTxOIdentifier::new(TxHash::from(**oref.hash()), oref.index() as u16)
})
.collect()
}

/// Parse transaction consumes and produces, and return the parsed consumes, produces, total output lovelace, and errors
pub fn map_transaction_consumes_produces(
tx: &MultiEraTx,
) -> (Vec<UTxOIdentifier>, Vec<TxOutput>, u128, Vec<String>) {
let mut parsed_inputs = Vec::new();
let mut parsed_outputs = Vec::new();
let parsed_consumes = map_transaction_inputs(&tx.consumes());
let mut parsed_produces = Vec::new();
let mut total_output = 0;
let mut errors = Vec::new();

let tx_hash = TxHash::from(*tx.hash());

for input in tx.consumes() {
let oref = input.output_ref();
let utxo = UTxOIdentifier::new(TxHash::from(**oref.hash()), oref.index() as u16);

parsed_inputs.push(utxo);
}

for (index, output) in tx.outputs().iter().enumerate() {
for (index, output) in tx.produces() {
let utxo = UTxOIdentifier::new(tx_hash, index as u16);
match output.address() {
Ok(pallas_address) => match map_address(&pallas_address) {
Ok(address) => {
// Add TxOutput to utxo_deltas
parsed_outputs.push(TxOutput {
parsed_produces.push(TxOutput {
utxo_identifier: utxo,
address,
value: map_value(&output.value()),
Expand All @@ -52,7 +55,7 @@ pub fn map_transaction_inputs_outputs(
}
}

(parsed_inputs, parsed_outputs, total_output, errors)
(parsed_consumes, parsed_produces, total_output, errors)
}

pub fn map_metadata(metadata: &PallasMetadatum) -> Metadata {
Expand All @@ -75,7 +78,8 @@ pub fn map_transaction(
network_id: NetworkId,
era: Era,
) -> Transaction {
let (inputs, outputs, total_output, input_output_errors) = map_transaction_inputs_outputs(tx);
let (consumes, produces, total_output, input_output_errors) =
map_transaction_consumes_produces(tx);

let mut errors = input_output_errors;
let mut certs = Vec::new();
Expand Down Expand Up @@ -141,8 +145,8 @@ pub fn map_transaction(
errors.extend(vkey_witness_errors);

Transaction {
inputs,
outputs,
consumes,
produces,
total_output,
certs,
withdrawals,
Expand Down
4 changes: 2 additions & 2 deletions common/src/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use crate::{
};

pub struct Transaction {
pub inputs: Vec<UTxOIdentifier>,
pub outputs: Vec<TxOutput>,
pub consumes: Vec<UTxOIdentifier>,
pub produces: Vec<TxOutput>,
pub total_output: u128,
pub certs: Vec<TxCertificateWithPos>,
pub withdrawals: Vec<Withdrawal>,
Expand Down
66 changes: 58 additions & 8 deletions common/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use std::{
ops::{AddAssign, Neg},
str::FromStr,
};
use tracing::error;

/// Network identifier
#[derive(
Expand Down Expand Up @@ -288,8 +289,8 @@ pub struct TxUTxODeltas {
pub tx_identifier: TxIdentifier,

// Created and spent UTxOs
pub inputs: Vec<UTxOIdentifier>,
pub outputs: Vec<TxOutput>,
pub consumes: Vec<UTxOIdentifier>,
pub produces: Vec<TxOutput>,

// State needed for validation
// This is missing UTxO Authors
Expand Down Expand Up @@ -890,6 +891,17 @@ pub struct TxOutput {
pub reference_script: Option<ReferenceScript>,
}

impl TxOutput {
pub fn utxo_value(&self) -> UTXOValue {
UTXOValue {
address: self.address.clone(),
value: self.value.clone(),
datum: self.datum.clone(),
reference_script: self.reference_script.clone(),
}
}
}

/// Key hash
pub type KeyHash = Hash<28>;

Expand Down Expand Up @@ -1149,6 +1161,22 @@ pub struct Withdrawal {
pub tx_identifier: TxIdentifier,
}

impl Withdrawal {
pub fn get_withdrawal_authors(
&self,
vkey_hashes: &mut HashSet<KeyHash>,
script_hashes: &mut HashSet<ScriptHash>,
) {
match self.address.credential {
StakeCredential::AddrKeyHash(vkey_hash) => {
vkey_hashes.insert(vkey_hash);
}
StakeCredential::ScriptHash(script_hash) => {
script_hashes.insert(script_hash);
}
}
}
}
/// Treasury pot account
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum Pot {
Expand Down Expand Up @@ -1880,6 +1908,12 @@ impl AsRef<BTreeMap<GenesisKeyhash, GenesisDelegate>> for GenesisDelegates {
}
}

impl From<HashMap<PoolId, GenesisDelegate>> for GenesisDelegates {
fn from(map: HashMap<PoolId, GenesisDelegate>) -> Self {
GenesisDelegates(map.into_iter().map(|(k, v)| (*k, v)).collect())
}
}

#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct ProtocolConsts {
pub k: usize,
Expand Down Expand Up @@ -2081,6 +2115,23 @@ pub struct AlonzoBabbageUpdateProposal {
pub enactment_epoch: u64,
}

impl AlonzoBabbageUpdateProposal {
pub fn get_governance_authors(
&self,
vkey_hashes: &mut HashSet<KeyHash>,
genesis_delegs: &GenesisDelegates,
) {
for (genesis_key, _) in self.proposals.iter() {
let found_genesis = genesis_delegs.as_ref().get(genesis_key);
if let Some(genesis) = found_genesis {
vkey_hashes.insert(genesis.delegate);
} else {
error!("Genesis delegate not found: {genesis_key}");
}
}
}
}

#[derive(Serialize, PartialEq, Eq, Deserialize, Debug, Clone)]
pub struct Constitution {
pub anchor: Anchor,
Expand Down Expand Up @@ -2518,10 +2569,11 @@ impl TxCertificate {
/// Reference: https://github.com/IntersectMBO/cardano-ledger/blob/24ef1741c5e0109e4d73685a24d8e753e225656d/eras/shelley/impl/src/Cardano/Ledger/Shelley/TxCert.hs#L583
///
/// returns (vkey_hashes, script_hashes)
pub fn get_cert_authors(&self) -> (HashSet<KeyHash>, HashSet<ScriptHash>) {
let mut vkey_hashes = HashSet::new();
let mut script_hashes = HashSet::new();

pub fn get_cert_authors(
&self,
vkey_hashes: &mut HashSet<KeyHash>,
script_hashes: &mut HashSet<ScriptHash>,
) {
let mut parse_cred = |cred: &StakeCredential| match cred {
StakeCredential::AddrKeyHash(vkey_hash) => {
vkey_hashes.insert(*vkey_hash);
Expand Down Expand Up @@ -2557,8 +2609,6 @@ impl TxCertificate {
}
_ => {}
}

(vkey_hashes, script_hashes)
}
}

Expand Down
25 changes: 17 additions & 8 deletions common/src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub enum ValidationError {
BadKES(#[from] KesValidationError),

#[error(
"Invalid Transactions: {}",
"bad_transactions: {}",
bad_transactions
.iter()
.map(|(tx_index, error)| format!("tx-index={tx_index}, error={error}"))
Expand All @@ -72,11 +72,15 @@ pub enum ValidationError {
bad_transactions: Vec<(u16, TransactionValidationError)>,
},

#[error("CBOR Decoding error")]
CborDecodeError(usize, String),

#[error("Governance failure: {0}")]
BadGovernance(#[from] GovernanceValidationError),

#[error("CBOR Decoding error")]
CborDecodeError {
era: Era,
slot: Slot,
reason: String,
},
}

/// Transaction Validation Error
Expand Down Expand Up @@ -195,10 +199,6 @@ pub enum UTxOValidationError {
required_lovelace: Lovelace,
},

/// **Cause:** The transaction size is too big.
#[error("Max tx size: supplied={supplied}, max={max}")]
MaxTxSizeUTxO { supplied: u32, max: u32 },

/// **Cause:** Malformed UTxO
#[error("Malformed UTxO: era={era}, reason={reason}")]
MalformedUTxO { era: Era, reason: String },
Expand Down Expand Up @@ -285,37 +285,46 @@ pub enum VrfValidationError {
/// **Cause:** Block issuer's pool ID is not registered in current stake distribution
#[error("Unknown Pool: {}", hex::encode(pool_id))]
UnknownPool { pool_id: PoolId },

/// **Cause:** The VRF key hash in the block header doesn't match the VRF key
/// registered with this stake pool in the ledger state for Overlay slot
#[error("{0}")]
WrongGenesisLeaderVrfKey(#[from] WrongGenesisLeaderVrfKeyError),

/// **Cause:** The VRF key hash in the block header doesn't match the VRF key
/// registered with this stake pool in the ledger state
#[error("{0}")]
WrongLeaderVrfKey(#[from] WrongLeaderVrfKeyError),

/// VRF nonce proof verification failed (TPraos rho - nonce proof)
/// **Cause:** The (rho - nonce) VRF proof failed verification
#[error("{0}")]
TPraosBadNonceVrfProof(#[from] TPraosBadNonceVrfProofError),

/// VRF leader proof verification failed (TPraos y - leader proof)
/// **Cause:** The (y - leader) VRF proof failed verification
#[error("{0}")]
TPraosBadLeaderVrfProof(#[from] TPraosBadLeaderVrfProofError),

/// VRF proof cryptographic verification failed (Praos single proof)
/// **Cause:** The cryptographic VRF proof is invalid
#[error("{0}")]
PraosBadVrfProof(#[from] PraosBadVrfProofError),

/// **Cause:** The VRF output is too large for this pool's stake.
/// The pool lost the slot lottery
#[error("{0}")]
VrfLeaderValueTooBig(#[from] VrfLeaderValueTooBigError),

/// **Cause:** This slot is in the overlay schedule but marked as non-active.
/// It's an intentional gap slot where no blocks should be produced.
#[error("Not Active slot in overlay schedule: {slot}")]
NotActiveSlotInOverlaySchedule { slot: Slot },

/// **Cause:** Some data has incorrect bytes
#[error("TryFromSlice: {0}")]
TryFromSlice(String),

/// **Cause:** Other errors (e.g. Invalid shelley params, praos params, missing data)
#[error("{0}")]
Other(String),
Expand Down
12 changes: 6 additions & 6 deletions modules/assets_state/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ impl State {

for tx in deltas {
let mut tx_asset_ids = HashSet::new();
for output in &tx.outputs {
for output in &tx.produces {
for (policy_id, assets) in &output.value.assets {
for asset in assets {
if let Some(asset_id) = registry.lookup_id(policy_id, &asset.name) {
Expand Down Expand Up @@ -589,7 +589,7 @@ impl State {
let mut new_info = self.info.clone();

for tx in deltas {
for output in &tx.outputs {
for output in &tx.produces {
let Some(Datum::Inline(blob)) = &output.datum else {
continue;
};
Expand Down Expand Up @@ -864,13 +864,13 @@ mod tests {

fn make_tx_utxo_deltas(
tx_identifier: TxIdentifier,
inputs: Vec<UTxOIdentifier>,
outputs: Vec<TxOutput>,
consumes: Vec<UTxOIdentifier>,
produces: Vec<TxOutput>,
) -> TxUTxODeltas {
TxUTxODeltas {
tx_identifier,
inputs,
outputs,
consumes,
produces,
vkey_hashes_needed: None,
script_hashes_needed: None,
vkey_hashes_provided: None,
Expand Down
Loading