diff --git a/src/framework/legacy_v1.rs b/src/framework/legacy_v1.rs index 43df8cb4..7ba82a44 100644 --- a/src/framework/legacy_v1.rs +++ b/src/framework/legacy_v1.rs @@ -1,4 +1,3 @@ - use std::fmt::Display; use merge::Merge; @@ -120,12 +119,13 @@ impl From for EventData { } } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub struct TxOutputRecord { pub address: String, pub amount: u64, pub assets: Option>, pub datum_hash: Option, + pub inline_datum: Option, } impl From for EventData { @@ -161,6 +161,8 @@ pub struct TransactionRecord { pub validity_interval_start: Option, pub network_id: Option, pub input_count: usize, + pub collateral_input_count: usize, + pub has_collateral_output: bool, pub output_count: usize, pub mint_count: usize, pub total_output: u64, @@ -169,6 +171,8 @@ pub struct TransactionRecord { pub metadata: Option>, pub inputs: Option>, pub outputs: Option>, + pub collateral_inputs: Option>, + pub collateral_output: Option, pub mint: Option>, pub vkey_witnesses: Option>, pub native_witnesses: Option>, @@ -261,7 +265,6 @@ impl From for EventData { EventData::PlutusDatum(x) } } - #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub struct BlockRecord { pub era: Era, @@ -269,6 +272,7 @@ pub struct BlockRecord { pub epoch_slot: Option, pub body_size: usize, pub issuer_vkey: String, + pub vrf_vkey: String, pub tx_count: usize, pub slot: u64, pub hash: String, diff --git a/src/lib.rs b/src/lib.rs index f60c570a..3d5a47cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +use thiserror::Error; + pub mod filters; pub mod framework; pub mod mapper; @@ -5,4 +7,14 @@ pub mod sinks; pub mod sources; pub mod utils; -pub type Error = Box; +#[derive(Debug, Error)] +pub enum Error { + #[error("parse error {0}")] + Parse(String), +} + +impl Error { + pub fn parse(error: impl ToString) -> Self { + Error::Parse(error) + } +} diff --git a/src/mapper/legacy_v1/babbage.rs b/src/mapper/legacy_v1/babbage.rs index 1e84ae72..a5eec1f3 100644 --- a/src/mapper/legacy_v1/babbage.rs +++ b/src/mapper/legacy_v1/babbage.rs @@ -1,74 +1,71 @@ -use pallas::codec::utils::KeepRaw; - -use pallas::ledger::primitives::babbage::{ - AuxiliaryData, MintedBlock, MintedDatumOption, MintedPostAlonzoTransactionOutput, - MintedTransactionBody, MintedTransactionOutput, MintedWitnessSet, NetworkId, +use pallas::ledger::primitives::babbage::{MintedDatumOption, MintedTransactionOutput, NetworkId}; +use pallas::ledger::traverse::{ + MultiEraAsset, MultiEraBlock, MultiEraInput, MultiEraOutput, MultiEraTx, OriginalHash, }; -use pallas::crypto::hash::Hash; -use pallas::ledger::traverse::{MultiEraBlock, OriginalHash}; - -use crate::model::{BlockRecord, Era, TransactionRecord}; +use crate::framework::legacy_v1::*; use crate::utils::time::TimeProvider; -use crate::{ - model::{EventContext, EventData}, - Error, -}; +use crate::Error; use super::{map::ToHex, EventWriter}; impl EventWriter { - pub fn to_babbage_tx_size( - &self, - body: &KeepRaw, - aux_data: Option<&KeepRaw>, - witness_set: Option<&KeepRaw>, - ) -> usize { - body.raw_cbor().len() - + aux_data.map(|ax| ax.raw_cbor().len()).unwrap_or(2) - + witness_set.map(|ws| ws.raw_cbor().len()).unwrap_or(1) + pub fn to_withdrawal_record(&self, withdrawal: (&[u8], u64)) -> WithdrawalRecord { + WithdrawalRecord { + reward_account: { + let hex = withdrawal.0.to_hex(); + hex.strip_prefix("e1").map(|x| x.to_string()).unwrap_or(hex) + }, + coin: withdrawal.1, + } } - pub fn to_babbage_transaction_record( - &self, - body: &KeepRaw, - tx_hash: &str, - aux_data: Option<&KeepRaw>, - witness_set: Option<&KeepRaw>, - ) -> Result { + pub fn to_transaction_record(&self, tx: &MultiEraTx) -> Result { let mut record = TransactionRecord { - hash: tx_hash.to_owned(), - size: self.to_babbage_tx_size(body, aux_data, witness_set) as u32, - fee: body.fee, - ttl: body.ttl, - validity_interval_start: body.validity_interval_start, - network_id: body.network_id.as_ref().map(|x| match x { + hash: tx.hash().to_string(), + size: tx.size() as u32, + fee: tx.fee().unwrap_or_default(), + ttl: tx.ttl(), + validity_interval_start: tx.validity_start(), + network_id: tx.network_id().map(|x| match x { NetworkId::One => 1, NetworkId::Two => 2, }), ..Default::default() }; - let outputs = self.collect_any_output_records(&body.outputs)?; + let outputs: Vec<_> = tx + .outputs() + .iter() + .map(|x| self.to_transaction_output_record(x)) + .collect::>()?; + record.output_count = outputs.len(); record.total_output = outputs.iter().map(|o| o.amount).sum(); - let inputs = self.collect_input_records(&body.inputs); + let inputs: Vec<_> = tx + .inputs() + .iter() + .map(|x| self.to_transaction_input_record(x)) + .collect(); + record.input_count = inputs.len(); - if let Some(mint) = &body.mint { - let mints = self.collect_mint_records(mint); - record.mint_count = mints.len(); + let mints: Vec<_> = tx.mints().iter().map(|x| self.to_mint_record(x)).collect(); - if self.config.include_transaction_details { - record.mint = mints.into(); - } - } + record.mint_count = mints.len(); + + let collateral_inputs: Vec<_> = tx + .collateral() + .iter() + .map(|x| self.to_transaction_input_record(x)) + .collect(); - // Add Collateral Stuff - let collateral_inputs = &body.collateral.as_deref(); - record.collateral_input_count = collateral_inputs.iter().count(); - record.has_collateral_output = body.collateral_return.is_some(); + record.collateral_input_count = collateral_inputs.len(); + + let collateral_return = tx.collateral_return(); + + record.has_collateral_output = collateral_return.is_some(); // TODO // TransactionBodyComponent::ScriptDataHash(_) @@ -76,50 +73,73 @@ impl EventWriter { // TransactionBodyComponent::AuxiliaryDataHash(_) if self.config.include_transaction_details { - record.outputs = outputs.into(); - record.inputs = inputs.into(); - - // transaction_details collateral stuff - record.collateral_inputs = - collateral_inputs.map(|inputs| self.collect_input_records(inputs)); - - record.collateral_output = body.collateral_return.as_ref().map(|output| match output { - MintedTransactionOutput::Legacy(x) => self.to_legacy_output_record(x).unwrap(), - MintedTransactionOutput::PostAlonzo(x) => { - self.to_post_alonzo_output_record(x).unwrap() - } - }); + record.outputs = Some(outputs); + record.inputs = Some(inputs); + record.mint = Some(mints); - record.metadata = match aux_data { - Some(aux_data) => self.collect_metadata_records(aux_data)?.into(), - None => None, - }; + record.collateral_inputs = Some(collateral_inputs); - if let Some(witnesses) = witness_set { - record.vkey_witnesses = self - .collect_vkey_witness_records(&witnesses.vkeywitness)? - .into(); + record.collateral_output = collateral_return + .map(|x| self.to_transaction_output_record(&x)) + .map_or(Ok(None), |x| x.map(Some))?; - record.native_witnesses = self - .collect_native_witness_records(&witnesses.native_script)? - .into(); + record.metadata = tx + .metadata() + .collect::>() + .iter() + .map(|(l, v)| self.to_metadata_record(l, v)) + .collect::, _>>()? + .into(); - record.plutus_witnesses = self - .collect_plutus_v1_witness_records(&witnesses.plutus_v1_script)? - .into(); + record.vkey_witnesses = tx + .vkey_witnesses() + .iter() + .map(|x| self.to_vkey_witness_record(x)) + .collect::, _>>()? + .into(); - record.plutus_redeemers = self - .collect_plutus_redeemer_records(&witnesses.redeemer)? - .into(); + record.native_witnesses = tx + .native_scripts() + .iter() + .map(|x| self.to_native_witness_record(x)) + .collect::, _>>()? + .into(); - record.plutus_data = self - .collect_witness_plutus_datum_records(&witnesses.plutus_data)? - .into(); - } + let v1_scripts = tx + .plutus_v1_scripts() + .iter() + .map(|x| self.to_plutus_v1_witness_record(x)) + .collect::, _>>()?; - if let Some(withdrawals) = &body.withdrawals { - record.withdrawals = self.collect_withdrawal_records(withdrawals).into(); - } + let v2_scripts = tx + .plutus_v2_scripts() + .iter() + .map(|x| self.to_plutus_v2_witness_record(x)) + .collect::, _>>()?; + + record.plutus_witnesses = Some([v1_scripts, v2_scripts].concat()); + + record.plutus_redeemers = tx + .redeemers() + .iter() + .map(|x| self.to_plutus_redeemer_record(x)) + .collect::, _>>()? + .into(); + + record.plutus_data = tx + .plutus_data() + .iter() + .map(|x| self.to_plutus_datum_record(x)) + .collect::, _>>()? + .into(); + + record.withdrawals = tx + .withdrawals() + .collect::>() + .iter() + .map(|x| self.to_withdrawal_record(*x)) + .collect::>() + .into(); } Ok(record) @@ -136,78 +156,134 @@ impl EventWriter { .as_ref() .map(|time| time.absolute_slot_to_relative(source.slot())); + let header = source.header(); + let mut record = BlockRecord { - era: source.era(), - body_size: source.body_size(), - issuer_vkey: source.source.header.header_body.issuer_vkey.to_hex(), - vrf_vkey: source.header.header_body.vrf_vkey.to_hex(), + era: source.era().into(), + body_size: source.body_size().unwrap_or_default(), + issuer_vkey: header.issuer_vkey().map(hex::encode).unwrap_or_default(), + vrf_vkey: header.vrf_vkey().map(hex::encode).unwrap_or_default(), tx_count: source.tx_count(), hash: source.hash().to_string(), number: source.number(), slot: source.slot(), epoch: relative_epoch.map(|(epoch, _)| epoch), epoch_slot: relative_epoch.map(|(_, epoch_slot)| epoch_slot), - previous_hash: source - .header - .header_body - .prev_hash - .map(hex::encode) + previous_hash: header + .previous_hash() + .map(|x| x.to_string()) .unwrap_or_default(), cbor_hex: match self.config.include_block_cbor { - true => source.encode(), + true => Some(hex::encode(cbor)), false => None, }, transactions: None, }; if self.config.include_block_details { - record.transactions = Some(self.collect_babbage_tx_records(source)?); + let txs = source + .txs() + .iter() + .map(|x| self.to_transaction_record(x)) + .collect::>()?; + + record.transactions = Some(txs); } Ok(record) } - pub fn collect_babbage_tx_records( - &self, - block: &MintedBlock, - ) -> Result, Error> { - block - .transaction_bodies - .iter() - .enumerate() - .map(|(idx, tx)| { - let aux_data = block - .auxiliary_data_set - .iter() - .find(|(k, _)| *k == (idx as u32)) - .map(|(_, v)| v); + fn crawl_collateral(&self, collateral: &MultiEraInput) -> Result<(), Error> { + self.append(self.to_collateral_event(collateral)) + + // TODO: should we have a collateral idx in context? + // more complex event goes here (eg: ???) + } + + pub fn to_mint_record(&self, asset: &MultiEraAsset) -> MintRecord { + MintRecord { + policy: asset.policy().map(|x| x.to_string()).unwrap_or_default(), + asset: asset.name().map(|x| hex::encode(x)).unwrap_or_default(), + quantity: asset.coin(), + } + } + + fn crawl_metadata(&self, tx: &MultiEraTx) -> Result<(), Error> { + let metadata = tx.metadata().collect::>(); - let witness_set = block.transaction_witness_sets.get(idx); + for (label, content) in metadata.iter() { + let record = self.to_metadata_record(label, content)?; + self.append_from(record)?; + + match label { + 721u64 => self.crawl_metadata_label_721(content)?, + 61284u64 => self.crawl_metadata_label_61284(content)?, + _ => (), + } + } + + Ok(()) + } - let tx_hash = tx.original_hash().to_hex(); + pub fn to_transaction_input_record(&self, input: &MultiEraInput) -> TxInputRecord { + TxInputRecord { + tx_id: input.hash().to_string(), + index: input.index(), + } + } - self.to_babbage_transaction_record(tx, &tx_hash, aux_data, witness_set) - }) - .collect() + pub fn to_transaction_output_asset_record(&self, asset: &MultiEraAsset) -> OutputAssetRecord { + OutputAssetRecord { + policy: asset.policy().map(ToString::to_string).unwrap_or_default(), + asset: asset.name().map(|x| x.to_hex()).unwrap_or_default(), + asset_ascii: asset.to_ascii_name(), + amount: asset.coin() as u64, + } } - fn crawl_post_alonzo_output( + pub fn to_transaction_output_record( &self, - output: &MintedPostAlonzoTransactionOutput, - ) -> Result<(), Error> { - let record = self.to_post_alonzo_output_record(output)?; + output: &MultiEraOutput, + ) -> Result { + let address = output.address().map_err(Error::parse)?; + + Ok(TxOutputRecord { + address: address.to_string(), + amount: output.lovelace_amount(), + assets: output + .non_ada_assets() + .iter() + .map(|x| self.to_transaction_output_asset_record(x)) + .collect::>() + .into(), + datum_hash: match &output.datum() { + Some(MintedDatumOption::Hash(x)) => Some(x.to_string()), + Some(MintedDatumOption::Data(x)) => Some(x.original_hash().to_hex()), + None => None, + }, + inline_datum: match &output.datum() { + Some(MintedDatumOption::Data(x)) => Some(self.to_plutus_datum_record(x)?), + _ => None, + }, + }) + } + + fn crawl_transaction_output(&self, output: &MultiEraOutput) -> Result<(), Error> { + let record = self.to_transaction_output_record(output)?; self.append(record.into())?; - let address = pallas::ledger::addresses::Address::from_bytes(&output.address)?; + let address = output.address().map_err(Error::parse)?; let child = &self.child_writer(EventContext { output_address: address.to_string().into(), ..EventContext::default() }); - child.crawl_transaction_output_amount(&output.value)?; + for asset in output.assets() { + self.append_from(self.to_transaction_output_asset_record(&asset))?; + } - if let Some(MintedDatumOption::Data(datum)) = &output.datum_option { + if let Some(MintedDatumOption::Data(datum)) = &output.datum() { let record = self.to_plutus_datum_record(datum)?; child.append(record.into())?; } @@ -215,107 +291,89 @@ impl EventWriter { Ok(()) } - fn crawl_babbage_transaction_output( - &self, - output: &MintedTransactionOutput, - ) -> Result<(), Error> { - match output { - MintedTransactionOutput::Legacy(x) => self.crawl_legacy_output(x), - MintedTransactionOutput::PostAlonzo(x) => self.crawl_post_alonzo_output(x), + fn crawl_witnesses(&self, tx: &MultiEraTx) -> Result<(), Error> { + for script in tx.native_scripts() { + self.append_from(self.to_native_witness_record(script)?)?; } - } - fn crawl_babbage_witness_set( - &self, - witness_set: &KeepRaw, - ) -> Result<(), Error> { - if let Some(native) = &witness_set.native_script { - for script in native.iter() { - self.append_from(self.to_native_witness_record(script)?)?; - } + for script in tx.plutus_v1_scripts() { + self.append_from(self.to_plutus_v1_witness_record(script)?)?; } - if let Some(plutus) = &witness_set.plutus_v1_script { - for script in plutus.iter() { - self.append_from(self.to_plutus_v1_witness_record(script)?)?; - } + for script in tx.plutus_v2_scripts() { + self.append_from(self.to_plutus_v2_witness_record(script)?)?; } - if let Some(redeemers) = &witness_set.redeemer { - for redeemer in redeemers.iter() { - self.append_from(self.to_plutus_redeemer_record(redeemer)?)?; - } + for redeemer in tx.redeemers() { + self.append_from(self.to_plutus_redeemer_record(redeemer)?)?; } - if let Some(datums) = &witness_set.plutus_data { - for datum in datums.iter() { - self.append_from(self.to_plutus_datum_record(datum)?)?; - } + for datum in tx.plutus_data() { + self.append_from(self.to_plutus_datum_record(datum)?)?; } Ok(()) } - fn crawl_babbage_transaction( - &self, - tx: &KeepRaw, - tx_hash: &str, - aux_data: Option<&KeepRaw>, - witness_set: Option<&KeepRaw>, - ) -> Result<(), Error> { - let record = self.to_babbage_transaction_record(tx, tx_hash, aux_data, witness_set)?; - + fn crawl_transaction(&self, tx: &MultiEraTx) -> Result<(), Error> { + let record = self.to_transaction_record(tx)?; self.append_from(record.clone())?; - for (idx, input) in tx.inputs.iter().enumerate() { + // crawl inputs + for (idx, input) in tx.inputs().iter().enumerate() { let child = self.child_writer(EventContext { input_idx: Some(idx), ..EventContext::default() }); - child.crawl_transaction_input(input)?; + self.append_from(self.to_transaction_input_record(input))?; } - for (idx, output) in tx.outputs.iter().enumerate() { + for (idx, output) in tx.outputs().iter().enumerate() { let child = self.child_writer(EventContext { output_idx: Some(idx), ..EventContext::default() }); - child.crawl_babbage_transaction_output(output)?; + child.crawl_transaction_output(output)?; } - if let Some(certs) = &tx.certificates { - for (idx, cert) in certs.iter().enumerate() { + //crawl certs + for (idx, cert) in tx.certs().iter().enumerate() { + if let Some(evt) = self.to_certificate_event(cert) { let child = self.child_writer(EventContext { certificate_idx: Some(idx), ..EventContext::default() }); - child.crawl_certificate(cert)?; + self.append(evt); } } - if let Some(collateral) = &tx.collateral { - for (_idx, collateral) in collateral.iter().enumerate() { - // TODO: collateral context? - - self.crawl_collateral(collateral)?; - } + for collateral in tx.collateral().iter() { + // TODO: collateral context? + self.crawl_collateral(collateral)?; } - if let Some(mint) = &tx.mint { - self.crawl_mints(mint)?; + // crawl mints + for asset in tx.mints() { + self.append_from(self.to_mint_record(&asset))?; } - if let Some(aux_data) = aux_data { - self.crawl_auxdata(aux_data)?; + self.crawl_metadata(tx); + + // crawl aux native scripts + for script in tx.aux_native_scripts() { + self.append(self.to_aux_native_script_event(script))?; } - if let Some(witness_set) = witness_set { - self.crawl_babbage_witness_set(witness_set)?; + // crawl aux plutus v1 scripts + for script in tx.aux_plutus_v1_scripts() { + self.append(self.to_aux_plutus_script_event(script))?; } + self.crawl_witnesses(tx)?; + if self.config.include_transaction_end_events { self.append(EventData::TransactionEnd(record))?; } @@ -325,27 +383,16 @@ impl EventWriter { fn crawl_block(&self, block: &MultiEraBlock, cbor: &[u8]) -> Result<(), Error> { let record = self.to_block_record(block, cbor)?; - self.append(EventData::Block(record.clone()))?; - for (idx, tx) in block.transaction_bodies.iter().enumerate() { - let aux_data = block - .auxiliary_data_set - .iter() - .find(|(k, _)| *k == (idx as u32)) - .map(|(_, v)| v); - - let witness_set = block.transaction_witness_sets.get(idx); - - let tx_hash = tx.original_hash().to_hex(); - + for (idx, tx) in block.txs().iter().enumerate() { let child = self.child_writer(EventContext { tx_idx: Some(idx), - tx_hash: Some(tx_hash.to_owned()), + tx_hash: Some(tx.hash().to_string()), ..EventContext::default() }); - child.crawl_babbage_transaction(tx, &tx_hash, aux_data, witness_set)?; + child.crawl_transaction(tx)?; } if self.config.include_block_end_events { @@ -355,10 +402,7 @@ impl EventWriter { Ok(()) } - /// Mapper entry-point for raw Babbage cbor blocks - /// - /// Entry-point to start crawling a blocks for events. Meant to be used when - /// we haven't decoded the CBOR yet (for example, N2N). + /// Mapper entry-point for raw cbor blocks pub fn crawl_cbor(&self, cbor: &[u8]) -> Result<(), Error> { let block = pallas::ledger::traverse::MultiEraBlock::decode(cbor).map_err(Error::parse)?; diff --git a/src/mapper/legacy_v1/byron.rs b/src/mapper/legacy_v1/byron.rs deleted file mode 100644 index 65d05504..00000000 --- a/src/mapper/legacy_v1/byron.rs +++ /dev/null @@ -1,358 +0,0 @@ -use std::ops::Deref; - -use super::map::ToHex; -use super::EventWriter; -use crate::model::{BlockRecord, Era, EventData, TransactionRecord, TxInputRecord, TxOutputRecord}; -use crate::{model::EventContext, Error}; - -use pallas::crypto::hash::Hash; -use pallas::ledger::primitives::byron; -use pallas::ledger::traverse::OriginalHash; - -impl EventWriter { - fn to_byron_input_record(&self, source: &byron::TxIn) -> Option { - match source { - byron::TxIn::Variant0(x) => { - let (hash, index) = x.deref(); - - Some(TxInputRecord { - tx_id: hash.to_hex(), - index: *index as u64, - }) - } - byron::TxIn::Other(a, b) => { - log::warn!( - "don't know how to handle byron input: ({}, {})", - a, - b.to_hex() - ); - - None - } - } - } - - fn collect_byron_input_records(&self, source: &byron::Tx) -> Vec { - source - .inputs - .iter() - .filter_map(|x| self.to_byron_input_record(x)) - .collect() - } - - fn to_byron_output_record(&self, source: &byron::TxOut) -> Result { - let address: pallas::ledger::addresses::Address = - pallas::ledger::addresses::ByronAddress::new( - &source.address.payload.0, - source.address.crc, - ) - .into(); - - Ok(TxOutputRecord { - address: address.to_string(), - amount: source.amount, - assets: None, - datum_hash: None, - inline_datum: None, - }) - } - - fn collect_byron_output_records( - &self, - source: &byron::Tx, - ) -> Result, Error> { - source - .outputs - .iter() - .map(|x| self.to_byron_output_record(x)) - .collect() - } - - fn to_byron_transaction_record( - &self, - source: &byron::MintedTxPayload, - tx_hash: &str, - ) -> Result { - let input_records = self.collect_byron_input_records(&source.transaction); - let output_records = self.collect_byron_output_records(&source.transaction)?; - - let mut record = TransactionRecord { - hash: tx_hash.to_owned(), - // TODO: we have a problem here. AFAIK, there's no reference to the tx fee in the - // block contents. This leaves us with the two alternative: a) compute the value, b) - // omit the value. - // - // Computing the value is not trivial, the linear policy is easy to - // implement, but tracking the parameters for each epoch means hardcoding values or - // doing some extra queries. - // - // Ommiting the value elegantly would require turning the property data type into an - // option, which is a breaking change. - // - // Chossing the lesser evil, going to send a `0` in the field and add a comment to the - // docs notifying about this as a known issue to be fixed in v2. - - //fee: source.compute_fee_with_defaults()?, - fee: 0, - size: (source.transaction.raw_cbor().len() + source.witness.raw_cbor().len()) as u32, - input_count: input_records.len(), - output_count: output_records.len(), - total_output: output_records.iter().map(|o| o.amount).sum(), - ..Default::default() - }; - - if self.config.include_transaction_details { - record.inputs = input_records.into(); - record.outputs = output_records.into(); - } - - Ok(record) - } - - pub fn collect_byron_tx_records( - &self, - block: &byron::MintedBlock, - ) -> Result, Error> { - block - .body - .tx_payload - .iter() - .map(|tx| { - let tx_hash = tx.transaction.original_hash().to_hex(); - self.to_byron_transaction_record(tx, &tx_hash) - }) - .collect() - } - - fn crawl_byron_transaction( - &self, - source: &byron::MintedTxPayload, - tx_hash: &str, - ) -> Result<(), Error> { - let record = self.to_byron_transaction_record(source, tx_hash)?; - - self.append_from(record.clone())?; - - for (idx, input) in source.transaction.inputs.iter().enumerate() { - let child = self.child_writer(EventContext { - input_idx: Some(idx), - ..EventContext::default() - }); - - if let Some(record) = self.to_byron_input_record(input) { - child.append_from(record)?; - } - } - - for (idx, output) in source.transaction.outputs.iter().enumerate() { - let child = self.child_writer(EventContext { - output_idx: Some(idx), - ..EventContext::default() - }); - - if let Ok(record) = self.to_byron_output_record(output) { - child.append_from(record)?; - } - } - - if self.config.include_transaction_end_events { - self.append(EventData::TransactionEnd(record))?; - } - - Ok(()) - } - - pub fn to_byron_block_record( - &self, - source: &byron::MintedBlock, - hash: &Hash<32>, - cbor: &[u8], - ) -> Result { - let abs_slot = pallas::ledger::traverse::time::byron_epoch_slot_to_absolute( - source.header.consensus_data.0.epoch, - source.header.consensus_data.0.slot, - ); - - let mut record = BlockRecord { - era: Era::Byron, - body_size: cbor.len(), - issuer_vkey: source.header.consensus_data.1.to_hex(), - vrf_vkey: Default::default(), - tx_count: source.body.tx_payload.len(), - hash: hash.to_hex(), - number: source.header.consensus_data.2[0], - slot: abs_slot, - epoch: Some(source.header.consensus_data.0.epoch), - epoch_slot: Some(source.header.consensus_data.0.slot), - previous_hash: source.header.prev_block.to_hex(), - cbor_hex: match self.config.include_block_cbor { - true => hex::encode(cbor).into(), - false => None, - }, - transactions: None, - }; - - if self.config.include_block_details { - record.transactions = Some(self.collect_byron_tx_records(source)?); - } - - Ok(record) - } - - fn crawl_byron_main_block( - &self, - block: &byron::MintedBlock, - hash: &Hash<32>, - cbor: &[u8], - ) -> Result<(), Error> { - let record = self.to_byron_block_record(block, hash, cbor)?; - - self.append(EventData::Block(record.clone()))?; - - for (idx, tx) in block.body.tx_payload.iter().enumerate() { - let tx_hash = tx.transaction.original_hash().to_hex(); - - let child = self.child_writer(EventContext { - tx_idx: Some(idx), - tx_hash: Some(tx_hash.to_owned()), - ..EventContext::default() - }); - - child.crawl_byron_transaction(tx, &tx_hash)?; - } - - if self.config.include_block_end_events { - self.append(EventData::BlockEnd(record))?; - } - - Ok(()) - } - - pub fn to_byron_epoch_boundary_record( - &self, - source: &byron::MintedEbBlock, - hash: &Hash<32>, - cbor: &[u8], - ) -> Result { - let abs_slot = pallas::ledger::traverse::time::byron_epoch_slot_to_absolute( - source.header.consensus_data.epoch_id, - 0, - ); - - Ok(BlockRecord { - era: Era::Byron, - body_size: cbor.len(), - hash: hash.to_hex(), - issuer_vkey: Default::default(), - vrf_vkey: Default::default(), - tx_count: 0, - number: source.header.consensus_data.difficulty[0], - slot: abs_slot, - epoch: Some(source.header.consensus_data.epoch_id), - epoch_slot: Some(0), - previous_hash: source.header.prev_block.to_hex(), - cbor_hex: match self.config.include_block_cbor { - true => hex::encode(cbor).into(), - false => None, - }, - transactions: None, - }) - } - - fn crawl_byron_ebb_block( - &self, - block: &byron::MintedEbBlock, - hash: &Hash<32>, - cbor: &[u8], - ) -> Result<(), Error> { - let record = self.to_byron_epoch_boundary_record(block, hash, cbor)?; - - self.append_from(record.clone())?; - - if self.config.include_block_end_events { - self.append(EventData::BlockEnd(record))?; - } - - Ok(()) - } - - /// Mapper entry-point for decoded Byron blocks - /// - /// Entry-point to start crawling a blocks for events. Meant to be used when - /// we already have a decoded block (for example, N2C). The raw CBOR is also - /// passed through in case we need to attach it to outbound events. - pub fn crawl_byron_with_cbor( - &self, - block: &byron::MintedBlock, - cbor: &[u8], - ) -> Result<(), Error> { - let hash = block.header.original_hash(); - - let abs_slot = pallas::ledger::traverse::time::byron_epoch_slot_to_absolute( - block.header.consensus_data.0.epoch, - block.header.consensus_data.0.slot, - ); - - let child = self.child_writer(EventContext { - block_hash: Some(hex::encode(hash)), - block_number: Some(block.header.consensus_data.2[0]), - slot: Some(abs_slot), - timestamp: self.compute_timestamp(abs_slot), - ..EventContext::default() - }); - - child.crawl_byron_main_block(block, &hash, cbor)?; - - Ok(()) - } - - /// Mapper entry-point for raw Byron cbor blocks - /// - /// Entry-point to start crawling a blocks for events. Meant to be used when - /// we haven't decoded the CBOR yet (for example, N2N). - pub fn crawl_from_byron_cbor(&self, cbor: &[u8]) -> Result<(), Error> { - let (_, block): (u16, byron::MintedBlock) = pallas::codec::minicbor::decode(cbor)?; - self.crawl_byron_with_cbor(&block, cbor) - } - - /// Mapper entry-point for decoded Byron Epoch-Boundary blocks - /// - /// Entry-point to start crawling a blocks for events. Meant to be used when - /// we already have a decoded block (for example, N2C). The raw CBOR is also - /// passed through in case we need to attach it to outbound events. - pub fn crawl_ebb_with_cbor( - &self, - block: &byron::MintedEbBlock, - cbor: &[u8], - ) -> Result<(), Error> { - if self.config.include_byron_ebb { - let hash = block.header.original_hash(); - - let abs_slot = pallas::ledger::traverse::time::byron_epoch_slot_to_absolute( - block.header.consensus_data.epoch_id, - 0, - ); - - let child = self.child_writer(EventContext { - block_hash: Some(hex::encode(hash)), - block_number: Some(block.header.consensus_data.difficulty[0]), - slot: Some(abs_slot), - timestamp: self.compute_timestamp(abs_slot), - ..EventContext::default() - }); - - child.crawl_byron_ebb_block(block, &hash, cbor)?; - } - - Ok(()) - } - - /// Mapper entry-point for raw EBB cbor blocks - /// - /// Entry-point to start crawling a blocks for events. Meant to be used when - /// we haven't decoded the CBOR yet (for example, N2N). - pub fn crawl_from_ebb_cbor(&self, cbor: &[u8]) -> Result<(), Error> { - let (_, block): (u16, byron::MintedEbBlock) = pallas::codec::minicbor::decode(cbor)?; - self.crawl_ebb_with_cbor(&block, cbor) - } -} diff --git a/src/mapper/legacy_v1/collect.rs b/src/mapper/legacy_v1/collect.rs deleted file mode 100644 index 515e11b5..00000000 --- a/src/mapper/legacy_v1/collect.rs +++ /dev/null @@ -1,224 +0,0 @@ -use pallas::{ - codec::utils::{KeepRaw, KeyValuePairs, MaybeIndefArray}, - ledger::{ - primitives::{ - alonzo::{ - AuxiliaryData, Coin, MintedBlock, Multiasset, NativeScript, PlutusData, - PlutusScript, Redeemer, RewardAccount, TransactionInput, VKeyWitness, Value, - }, - babbage::{ - LegacyTransactionOutput, MintedPostAlonzoTransactionOutput, - MintedTransactionOutput, PlutusV2Script, - }, - }, - traverse::OriginalHash, - }, -}; - -use crate::{ - model::{ - MetadataRecord, MintRecord, NativeWitnessRecord, OutputAssetRecord, PlutusDatumRecord, - PlutusRedeemerRecord, PlutusWitnessRecord, TransactionRecord, TxInputRecord, - TxOutputRecord, VKeyWitnessRecord, WithdrawalRecord, - }, - Error, -}; - -use super::{map::ToHex, EventWriter}; - -impl EventWriter { - pub fn collect_input_records(&self, source: &[TransactionInput]) -> Vec { - source - .iter() - .map(|i| self.to_transaction_input_record(i)) - .collect() - } - - pub fn collect_legacy_output_records( - &self, - source: &[LegacyTransactionOutput], - ) -> Result, Error> { - source - .iter() - .map(|i| self.to_legacy_output_record(i)) - .collect() - } - - pub fn collect_post_alonzo_output_records( - &self, - source: &[MintedPostAlonzoTransactionOutput], - ) -> Result, Error> { - source - .iter() - .map(|i| self.to_post_alonzo_output_record(i)) - .collect() - } - - pub fn collect_any_output_records( - &self, - source: &[MintedTransactionOutput], - ) -> Result, Error> { - source - .iter() - .map(|x| match x { - MintedTransactionOutput::Legacy(x) => self.to_legacy_output_record(x), - MintedTransactionOutput::PostAlonzo(x) => self.to_post_alonzo_output_record(x), - }) - .collect() - } - - pub fn collect_asset_records(&self, amount: &Value) -> Vec { - match amount { - Value::Coin(_) => vec![], - Value::Multiasset(_, policies) => policies - .iter() - .flat_map(|(policy, assets)| { - assets.iter().map(|(asset, amount)| { - self.to_transaction_output_asset_record(policy, asset, *amount) - }) - }) - .collect(), - } - } - - pub fn collect_mint_records(&self, mint: &Multiasset) -> Vec { - mint.iter() - .flat_map(|(policy, assets)| { - assets - .iter() - .map(|(asset, amount)| self.to_mint_record(policy, asset, *amount)) - }) - .collect() - } - - pub fn collect_withdrawal_records( - &self, - withdrawls: &KeyValuePairs, - ) -> Vec { - withdrawls - .iter() - .map(|(reward_account, coin)| WithdrawalRecord { - reward_account: { - let hex = reward_account.to_hex(); - hex.strip_prefix("e1").map(|x| x.to_string()).unwrap_or(hex) - }, - coin: *coin, - }) - .collect() - } - - pub fn collect_metadata_records( - &self, - aux_data: &AuxiliaryData, - ) -> Result, Error> { - let metadata = match aux_data { - AuxiliaryData::PostAlonzo(data) => data.metadata.as_deref(), - AuxiliaryData::Shelley(data) => Some(data.as_ref()), - AuxiliaryData::ShelleyMa(data) => Some(data.transaction_metadata.as_ref()), - }; - - match metadata { - Some(x) => x - .iter() - .map(|(label, content)| self.to_metadata_record(label, content)) - .collect(), - None => Ok(vec![]), - } - } - - pub fn collect_vkey_witness_records( - &self, - witness_set: &Option>, - ) -> Result, Error> { - match witness_set { - Some(all) => all.iter().map(|i| self.to_vkey_witness_record(i)).collect(), - None => Ok(vec![]), - } - } - - pub fn collect_native_witness_records( - &self, - witness_set: &Option>, - ) -> Result, Error> { - match witness_set { - Some(all) => all - .iter() - .map(|i| self.to_native_witness_record(i)) - .collect(), - None => Ok(vec![]), - } - } - - pub fn collect_plutus_v1_witness_records( - &self, - witness_set: &Option>, - ) -> Result, Error> { - match &witness_set { - Some(all) => all - .iter() - .map(|i| self.to_plutus_v1_witness_record(i)) - .collect(), - None => Ok(vec![]), - } - } - - pub fn collect_plutus_v2_witness_records( - &self, - witness_set: &Option>, - ) -> Result, Error> { - match &witness_set { - Some(all) => all - .iter() - .map(|i| self.to_plutus_v2_witness_record(i)) - .collect(), - None => Ok(vec![]), - } - } - - pub fn collect_plutus_redeemer_records( - &self, - witness_set: &Option>, - ) -> Result, Error> { - match &witness_set { - Some(all) => all - .iter() - .map(|i| self.to_plutus_redeemer_record(i)) - .collect(), - None => Ok(vec![]), - } - } - - pub fn collect_witness_plutus_datum_records( - &self, - witness_set: &Option>>, - ) -> Result, Error> { - match &witness_set { - Some(all) => all.iter().map(|i| self.to_plutus_datum_record(i)).collect(), - None => Ok(vec![]), - } - } - - pub fn collect_shelley_tx_records( - &self, - block: &MintedBlock, - ) -> Result, Error> { - block - .transaction_bodies - .iter() - .enumerate() - .map(|(idx, tx)| { - let aux_data = block - .auxiliary_data_set - .iter() - .find(|(k, _)| *k == (idx as u32)) - .map(|(_, v)| v); - - let witness_set = block.transaction_witness_sets.get(idx); - - let tx_hash = tx.original_hash().to_hex(); - - self.to_transaction_record(tx, &tx_hash, aux_data, witness_set) - }) - .collect() - } -} diff --git a/src/mapper/legacy_v1/map.rs b/src/mapper/legacy_v1/map.rs index 9ac3a5a3..a2d507b1 100644 --- a/src/mapper/legacy_v1/map.rs +++ b/src/mapper/legacy_v1/map.rs @@ -1,15 +1,11 @@ -use std::collections::HashMap; - -use pallas::ledger::primitives::alonzo::MintedWitnessSet; -use pallas::ledger::primitives::babbage::MintedDatumOption; -use pallas::ledger::traverse::{ComputeHash, OriginalHash}; +use pallas::ledger::traverse::{ComputeHash, MultiEraCert, MultiEraInput, OriginalHash}; use pallas::{codec::utils::KeepRaw, crypto::hash::Hash}; +use std::collections::HashMap; use pallas::ledger::primitives::{ alonzo::{ - self as alonzo, AuxiliaryData, Certificate, InstantaneousRewardSource, - InstantaneousRewardTarget, Metadatum, MetadatumLabel, MintedBlock, NetworkId, Relay, - TransactionBody, TransactionInput, Value, + self as alonzo, Certificate, InstantaneousRewardSource, InstantaneousRewardTarget, + Metadatum, MetadatumLabel, Relay, Value, }, babbage, ToCanonicalJson, }; @@ -17,14 +13,7 @@ use pallas::ledger::primitives::{ use pallas::network::miniprotocols::Point; use serde_json::{json, Value as JsonValue}; -use crate::model::{ - BlockRecord, Era, EventData, MetadataRecord, MetadatumRendition, MintRecord, - NativeWitnessRecord, OutputAssetRecord, PlutusDatumRecord, PlutusRedeemerRecord, - PlutusWitnessRecord, StakeCredential, TransactionRecord, TxInputRecord, TxOutputRecord, - VKeyWitnessRecord, -}; - -use crate::utils::time::TimeProvider; +use crate::framework::legacy_v1::*; use crate::Error; use super::EventWriter; @@ -158,77 +147,6 @@ impl EventWriter { Ok(data) } - pub fn to_transaction_input_record(&self, input: &TransactionInput) -> TxInputRecord { - TxInputRecord { - tx_id: input.transaction_id.to_hex(), - index: input.index, - } - } - - pub fn to_legacy_output_record( - &self, - output: &alonzo::TransactionOutput, - ) -> Result { - let address = pallas::ledger::addresses::Address::from_bytes(&output.address)?; - - Ok(TxOutputRecord { - address: address.to_string(), - amount: get_tx_output_coin_value(&output.amount), - assets: self.collect_asset_records(&output.amount).into(), - datum_hash: output.datum_hash.map(|hash| hash.to_string()), - inline_datum: None, - }) - } - - pub fn to_post_alonzo_output_record( - &self, - output: &babbage::MintedPostAlonzoTransactionOutput, - ) -> Result { - let address = pallas::ledger::addresses::Address::from_bytes(&output.address)?; - - Ok(TxOutputRecord { - address: address.to_string(), - amount: get_tx_output_coin_value(&output.value), - assets: self.collect_asset_records(&output.value).into(), - datum_hash: match &output.datum_option { - Some(MintedDatumOption::Hash(x)) => Some(x.to_string()), - Some(MintedDatumOption::Data(x)) => Some(x.original_hash().to_hex()), - None => None, - }, - inline_datum: match &output.datum_option { - Some(MintedDatumOption::Data(x)) => Some(self.to_plutus_datum_record(x)?), - _ => None, - }, - }) - } - - pub fn to_transaction_output_asset_record( - &self, - policy: &Hash<28>, - asset: &pallas::codec::utils::Bytes, - amount: u64, - ) -> OutputAssetRecord { - OutputAssetRecord { - policy: policy.to_hex(), - asset: asset.to_hex(), - asset_ascii: String::from_utf8(asset.to_vec()).ok(), - amount, - } - } - - pub fn to_mint_record( - &self, - policy: &Hash<28>, - asset: &pallas::codec::utils::Bytes, - quantity: i64, - ) -> MintRecord { - MintRecord { - policy: policy.to_hex(), - asset: asset.to_hex(), - quantity, - } - } - pub fn to_aux_native_script_event(&self, script: &alonzo::NativeScript) -> EventData { EventData::NativeScript { policy_id: script.compute_hash().to_hex(), @@ -311,8 +229,12 @@ impl EventWriter { }) } - pub fn to_certificate_event(&self, certificate: &Certificate) -> EventData { - match certificate { + pub fn to_certificate_event(&self, cert: &MultiEraCert) -> Option { + if !cert.as_alonzo().is_some() { + return None; + } + + let evt = match cert.as_alonzo().unwrap() { Certificate::StakeRegistration(credential) => EventData::StakeRegistration { credential: credential.into(), }, @@ -368,105 +290,16 @@ impl EventWriter { } // TODO: not likely, leaving for later Certificate::GenesisKeyDelegation(..) => EventData::GenesisKeyDelegation {}, - } - } - - pub fn to_collateral_event(&self, collateral: &TransactionInput) -> EventData { - EventData::Collateral { - tx_id: collateral.transaction_id.to_hex(), - index: collateral.index, - } - } - - pub fn to_tx_size( - &self, - body: &KeepRaw, - aux_data: Option<&KeepRaw>, - witness_set: Option<&KeepRaw>, - ) -> usize { - body.raw_cbor().len() - + aux_data.map(|ax| ax.raw_cbor().len()).unwrap_or(2) - + witness_set.map(|ws| ws.raw_cbor().len()).unwrap_or(1) - } - - pub fn to_transaction_record( - &self, - body: &KeepRaw, - tx_hash: &str, - aux_data: Option<&KeepRaw>, - witness_set: Option<&KeepRaw>, - ) -> Result { - let mut record = TransactionRecord { - hash: tx_hash.to_owned(), - size: self.to_tx_size(body, aux_data, witness_set) as u32, - fee: body.fee, - ttl: body.ttl, - validity_interval_start: body.validity_interval_start, - network_id: body.network_id.as_ref().map(|x| match x { - NetworkId::One => 1, - NetworkId::Two => 2, - }), - ..TransactionRecord::default() }; - let outputs = self.collect_legacy_output_records(&body.outputs)?; - record.output_count = outputs.len(); - record.total_output = outputs.iter().map(|o| o.amount).sum(); - - let inputs = self.collect_input_records(&body.inputs); - record.input_count = inputs.len(); - - if let Some(mint) = &body.mint { - let mints = self.collect_mint_records(mint); - record.mint_count = mints.len(); - - if self.config.include_transaction_details { - record.mint = mints.into(); - } - } - - // TODO - // TransactionBodyComponent::ScriptDataHash(_) - // TransactionBodyComponent::RequiredSigners(_) - // TransactionBodyComponent::AuxiliaryDataHash(_) - - if self.config.include_transaction_details { - record.outputs = outputs.into(); - record.inputs = inputs.into(); - - record.metadata = match aux_data { - Some(aux_data) => self.collect_metadata_records(aux_data)?.into(), - None => None, - }; - - if let Some(witnesses) = witness_set { - record.vkey_witnesses = self - .collect_vkey_witness_records(&witnesses.vkeywitness)? - .into(); - - record.native_witnesses = self - .collect_native_witness_records(&witnesses.native_script)? - .into(); - - record.plutus_witnesses = self - .collect_plutus_v1_witness_records(&witnesses.plutus_script)? - .into(); - - record.plutus_redeemers = self - .collect_plutus_redeemer_records(&witnesses.redeemer)? - .into(); - - record.plutus_data = self - .collect_witness_plutus_datum_records(&witnesses.plutus_data)? - .into(); - } + Some(evt) + } - if let Some(withdrawals) = &body.withdrawals { - record.withdrawals = self.collect_withdrawal_records(withdrawals).into(); - } + pub fn to_collateral_event(&self, collateral: &MultiEraInput) -> EventData { + EventData::Collateral { + tx_id: collateral.hash().to_string(), + index: collateral.index(), } - - Ok(record) } pub(crate) fn append_rollback_event(&self, point: &Point) -> Result<(), Error> { diff --git a/src/mapper/legacy_v1/mod.rs b/src/mapper/legacy_v1/mod.rs index 6b349abb..ab6f63a5 100644 --- a/src/mapper/legacy_v1/mod.rs +++ b/src/mapper/legacy_v1/mod.rs @@ -1,13 +1,10 @@ //! A mapper that maintains schema-compatibility with Oura v1 mod babbage; -mod byron; mod cip15; mod cip25; -mod collect; mod map; mod prelude; -mod shelley; pub use prelude::*; use serde::Deserialize; @@ -55,15 +52,33 @@ impl Bootstrapper { let worker_tether = gasket::runtime::spawn_stage( self.0, gasket::runtime::Policy::default(), - Some("mapper_noop"), + Some("mapper_legacy_v1"), ); Ok(Runtime { worker_tether }) } } -#[derive(Deserialize)] -pub struct Config {} +#[derive(Deserialize, Clone, Debug, Default)] +pub struct Config { + #[serde(default)] + pub include_block_end_events: bool, + + #[serde(default)] + pub include_transaction_details: bool, + + #[serde(default)] + pub include_transaction_end_events: bool, + + #[serde(default)] + pub include_block_details: bool, + + #[serde(default)] + pub include_block_cbor: bool, + + #[serde(default)] + pub include_byron_ebb: bool, +} impl Config { pub fn bootstrapper(self, ctx: &Context) -> Result { diff --git a/src/mapper/legacy_v1/prelude.rs b/src/mapper/legacy_v1/prelude.rs index 5b30339a..509ce314 100644 --- a/src/mapper/legacy_v1/prelude.rs +++ b/src/mapper/legacy_v1/prelude.rs @@ -1,50 +1,28 @@ use std::sync::Arc; use crate::{ - framework::StageSender, - model::{Era, Event, EventContext, EventData}, + framework::{legacy_v1::*, MapperOutputPort}, utils::{time::TimeProvider, Utils}, }; use merge::Merge; -use serde::Deserialize; +use super::Config; use crate::Error; #[deprecated] pub use crate::utils::ChainWellKnownInfo; -#[derive(Deserialize, Clone, Debug, Default)] -pub struct Config { - #[serde(default)] - pub include_block_end_events: bool, - - #[serde(default)] - pub include_transaction_details: bool, - - #[serde(default)] - pub include_transaction_end_events: bool, - - #[serde(default)] - pub include_block_details: bool, - - #[serde(default)] - pub include_block_cbor: bool, - - #[serde(default)] - pub include_byron_ebb: bool, -} - #[derive(Clone)] pub struct EventWriter { context: EventContext, - output: StageSender, + output: MapperOutputPort, pub(crate) config: Config, pub(crate) utils: Arc, } impl EventWriter { - pub fn new(output: StageSender, utils: Arc, config: Config) -> Self { + pub fn new(output: MapperOutputPort, utils: Arc, config: Config) -> Self { EventWriter { context: EventContext::default(), output, @@ -55,7 +33,7 @@ impl EventWriter { #[allow(unused)] pub fn standalone( - output: StageSender, + output: MapperOutputPort, well_known: Option, config: Config, ) -> Self { @@ -71,8 +49,6 @@ impl EventWriter { fingerprint: None, }; - self.utils.track_source_progress(&evt); - self.output .send(evt) .expect("error sending event through output stage, pipeline must have crashed."); diff --git a/src/mapper/legacy_v1/shelley.rs b/src/mapper/legacy_v1/shelley.rs deleted file mode 100644 index 57464eb1..00000000 --- a/src/mapper/legacy_v1/shelley.rs +++ /dev/null @@ -1,331 +0,0 @@ -use pallas::codec::utils::KeepRaw; - -use pallas::ledger::primitives::alonzo::{ - AuxiliaryData, Certificate, Metadata, MintedBlock, MintedWitnessSet, Multiasset, - TransactionBody, TransactionInput, TransactionOutput, Value, -}; - -use pallas::crypto::hash::Hash; -use pallas::ledger::traverse::OriginalHash; - -use crate::{ - model::{Era, EventContext, EventData}, - Error, -}; - -use super::{map::ToHex, EventWriter}; - -impl EventWriter { - pub(crate) fn crawl_metadata(&self, metadata: &Metadata) -> Result<(), Error> { - for (label, content) in metadata.iter() { - let record = self.to_metadata_record(label, content)?; - self.append_from(record)?; - - match label { - 721u64 => self.crawl_metadata_label_721(content)?, - 61284u64 => self.crawl_metadata_label_61284(content)?, - _ => (), - } - } - - Ok(()) - } - - pub(crate) fn crawl_auxdata(&self, aux_data: &AuxiliaryData) -> Result<(), Error> { - match aux_data { - AuxiliaryData::PostAlonzo(data) => { - if let Some(metadata) = &data.metadata { - self.crawl_metadata(metadata)?; - } - - if let Some(native) = &data.native_scripts { - for script in native.iter() { - self.append(self.to_aux_native_script_event(script))?; - } - } - - if let Some(plutus) = &data.plutus_scripts { - for script in plutus.iter() { - self.append(self.to_aux_plutus_script_event(script))?; - } - } - } - AuxiliaryData::Shelley(data) => { - self.crawl_metadata(data)?; - } - AuxiliaryData::ShelleyMa(data) => { - self.crawl_metadata(&data.transaction_metadata)?; - - if let Some(native) = &data.auxiliary_scripts { - for script in native.iter() { - self.append(self.to_aux_native_script_event(script))?; - } - } - } - } - - Ok(()) - } - - pub(crate) fn crawl_transaction_input(&self, input: &TransactionInput) -> Result<(), Error> { - self.append_from(self.to_transaction_input_record(input)) - } - - pub(crate) fn crawl_transaction_output_amount(&self, amount: &Value) -> Result<(), Error> { - if let Value::Multiasset(_, policies) = amount { - for (policy, assets) in policies.iter() { - for (asset, amount) in assets.iter() { - self.append_from( - self.to_transaction_output_asset_record(policy, asset, *amount), - )?; - } - } - } - - Ok(()) - } - - pub(crate) fn crawl_legacy_output(&self, output: &TransactionOutput) -> Result<(), Error> { - let record = self.to_legacy_output_record(output)?; - self.append(record.into())?; - - let address = pallas::ledger::addresses::Address::from_bytes(&output.address)?; - - let child = &self.child_writer(EventContext { - output_address: address.to_string().into(), - ..EventContext::default() - }); - - child.crawl_transaction_output_amount(&output.amount)?; - - Ok(()) - } - - pub(crate) fn crawl_certificate(&self, certificate: &Certificate) -> Result<(), Error> { - self.append(self.to_certificate_event(certificate)) - - // more complex event goes here (eg: pool metadata?) - } - - pub(crate) fn crawl_collateral(&self, collateral: &TransactionInput) -> Result<(), Error> { - self.append(self.to_collateral_event(collateral)) - - // TODO: should we have a collateral idx in context? - // more complex event goes here (eg: ???) - } - - pub(crate) fn crawl_mints(&self, mints: &Multiasset) -> Result<(), Error> { - // should we have a policy context? - - for (policy, assets) in mints.iter() { - for (asset, quantity) in assets.iter() { - self.append_from(self.to_mint_record(policy, asset, *quantity))?; - } - } - - Ok(()) - } - - pub(crate) fn crawl_witness_set( - &self, - witness_set: &KeepRaw, - ) -> Result<(), Error> { - if let Some(native) = &witness_set.native_script { - for script in native.iter() { - self.append_from(self.to_native_witness_record(script)?)?; - } - } - - if let Some(plutus) = &witness_set.plutus_script { - for script in plutus.iter() { - self.append_from(self.to_plutus_v1_witness_record(script)?)?; - } - } - - if let Some(redeemers) = &witness_set.redeemer { - for redeemer in redeemers.iter() { - self.append_from(self.to_plutus_redeemer_record(redeemer)?)?; - } - } - - if let Some(datums) = &witness_set.plutus_data { - for datum in datums.iter() { - self.append_from(self.to_plutus_datum_record(datum)?)?; - } - } - - Ok(()) - } - - fn crawl_shelley_transaction( - &self, - tx: &KeepRaw, - tx_hash: &str, - aux_data: Option<&KeepRaw>, - witness_set: Option<&KeepRaw>, - ) -> Result<(), Error> { - let record = self.to_transaction_record(tx, tx_hash, aux_data, witness_set)?; - - self.append_from(record.clone())?; - - for (idx, input) in tx.inputs.iter().enumerate() { - let child = self.child_writer(EventContext { - input_idx: Some(idx), - ..EventContext::default() - }); - - child.crawl_transaction_input(input)?; - } - - for (idx, output) in tx.outputs.iter().enumerate() { - let child = self.child_writer(EventContext { - output_idx: Some(idx), - ..EventContext::default() - }); - - child.crawl_legacy_output(output)?; - } - - if let Some(certs) = &tx.certificates { - for (idx, cert) in certs.iter().enumerate() { - let child = self.child_writer(EventContext { - certificate_idx: Some(idx), - ..EventContext::default() - }); - - child.crawl_certificate(cert)?; - } - } - - if let Some(collateral) = &tx.collateral { - for (_idx, collateral) in collateral.iter().enumerate() { - // TODO: collateral context? - - self.crawl_collateral(collateral)?; - } - } - - if let Some(mint) = &tx.mint { - self.crawl_mints(mint)?; - } - - if let Some(aux_data) = aux_data { - self.crawl_auxdata(aux_data)?; - } - - if let Some(witness_set) = witness_set { - self.crawl_witness_set(witness_set)?; - } - - if self.config.include_transaction_end_events { - self.append(EventData::TransactionEnd(record))?; - } - - Ok(()) - } - - fn crawl_shelley_block( - &self, - block: &MintedBlock, - hash: &Hash<32>, - cbor: &[u8], - era: Era, - ) -> Result<(), Error> { - let record = self.to_block_record(block, hash, cbor, era)?; - - self.append(EventData::Block(record.clone()))?; - - for (idx, tx) in block.transaction_bodies.iter().enumerate() { - let aux_data = block - .auxiliary_data_set - .iter() - .find(|(k, _)| *k == (idx as u32)) - .map(|(_, v)| v); - - let witness_set = block.transaction_witness_sets.get(idx); - - let tx_hash = tx.original_hash().to_hex(); - - let child = self.child_writer(EventContext { - tx_idx: Some(idx), - tx_hash: Some(tx_hash.to_owned()), - ..EventContext::default() - }); - - child.crawl_shelley_transaction(tx, &tx_hash, aux_data, witness_set)?; - } - - if self.config.include_block_end_events { - self.append(EventData::BlockEnd(record))?; - } - - Ok(()) - } - - #[deprecated(note = "use crawl_from_shelley_cbor instead")] - pub fn crawl_with_cbor(&self, block: &MintedBlock, cbor: &[u8]) -> Result<(), Error> { - let hash = block.header.original_hash(); - - let child = self.child_writer(EventContext { - block_hash: Some(hex::encode(hash)), - block_number: Some(block.header.header_body.block_number), - slot: Some(block.header.header_body.slot), - timestamp: self.compute_timestamp(block.header.header_body.slot), - ..EventContext::default() - }); - - child.crawl_shelley_block(block, &hash, cbor, Era::Undefined) - } - - #[deprecated(note = "use crawl_from_shelley_cbor instead")] - pub fn crawl(&self, block: &MintedBlock) -> Result<(), Error> { - let hash = block.header.original_hash(); - - let child = self.child_writer(EventContext { - block_hash: Some(hex::encode(hash)), - block_number: Some(block.header.header_body.block_number), - slot: Some(block.header.header_body.slot), - timestamp: self.compute_timestamp(block.header.header_body.slot), - ..EventContext::default() - }); - - child.crawl_shelley_block(block, &hash, &[], Era::Undefined) - } - - /// Mapper entry-point for decoded Shelley blocks - /// - /// Entry-point to start crawling a blocks for events. Meant to be used when - /// we already have a decoded block (for example, N2C). The raw CBOR is also - /// passed through in case we need to attach it to outbound events. - pub fn crawl_shelley_with_cbor<'b>( - &self, - block: &'b MintedBlock<'b>, - cbor: &'b [u8], - era: Era, - ) -> Result<(), Error> { - let hash = block.header.original_hash(); - - let child = self.child_writer(EventContext { - block_hash: Some(hex::encode(hash)), - block_number: Some(block.header.header_body.block_number), - slot: Some(block.header.header_body.slot), - timestamp: self.compute_timestamp(block.header.header_body.slot), - ..EventContext::default() - }); - - child.crawl_shelley_block(block, &hash, cbor, era) - } - - /// Mapper entry-point for raw Shelley cbor blocks - /// - /// Entry-point to start crawling a blocks for events. Meant to be used when - /// we haven't decoded the CBOR yet (for example, N2N). - /// - /// We use Alonzo primitives since they are backward compatible with - /// Shelley. In this way, we can avoid having to fork the crawling procedure - /// for each different hard-fork. - pub fn crawl_from_shelley_cbor(&self, cbor: &[u8], era: Era) -> Result<(), Error> { - let (_, block): (u16, MintedBlock) = pallas::codec::minicbor::decode(cbor)?; - self.crawl_shelley_with_cbor(&block, cbor, era) - } -} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index fe841b7f..5bba4db9 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -21,7 +21,6 @@ use crate::Error; pub mod cursor; pub mod metrics; -pub mod throttle; pub(crate) mod retry; pub(crate) mod time;