Skip to content
Open
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
2 changes: 1 addition & 1 deletion napi-pallas/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ hex = "0.4.3"
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
napi = { version = "2.12.2", default-features = false, features = ["napi4"] }
napi-derive = "2.12.2"
pallas = { git = "https://github.com/alegadea/pallas.git", rev = "54ffc77" , features = ["unstable"]}
pallas = { git = "https://github.com/txpipe/pallas.git", rev = "2f97cbe" , features = ["unstable"]}

[build-dependencies]
napi-build = "2.0.1"
Expand Down
59 changes: 30 additions & 29 deletions napi-pallas/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,47 @@
/* auto-generated by NAPI-RS */

export interface ShelleyPart {
isScript: boolean
hash?: string
pointer?: string
isScript: boolean;
hash?: string;
pointer?: string;
}
export interface AddressDiagnostic {
kind: string
network?: string
paymentPart?: ShelleyPart
delegationPart?: ShelleyPart
byronCbor?: string
kind: string;
network?: string;
paymentPart?: ShelleyPart;
delegationPart?: ShelleyPart;
byronCbor?: string;
}
export interface Output {
error?: string
bytes?: string
address?: AddressDiagnostic
error?: string;
bytes?: string;
address?: AddressDiagnostic;
}
export interface Attribute {
topic?: string
value?: string
topic?: string;
value?: string;
}
export interface Section {
topic?: string
identity?: string
error?: string
attributes: Array<Attribute>
bytes?: string
children: Array<Section>
}
export function parseAddress(raw: string): Output
topic?: string;
identity?: string;
error?: string;
attributes: Array<Attribute>;
bytes?: string;
children: Array<Section>;
}
export function parseAddress(raw: string): Output;
export interface SectionValidation {
section: Section
validations: Validations
section: Section;
validations: Validations;
}
export function safeParseTx(raw: string): SectionValidation
export function safeParseBlock(raw: string): Section
export function safeParseTx(raw: string): SectionValidation;
export function safeParseBlock(raw: string): Section;
export interface Validation {
name: string
value: boolean
description: string
name: string;
value: boolean;
description: string;
}
export interface Validations {
validations: Array<Validation>
validations: Array<Validation>;
era: string;
}
8 changes: 8 additions & 0 deletions napi-pallas/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ impl Validation {
#[napi(object)]
pub struct Validations {
pub validations: Vec<Validation>,
pub era: String,
}

impl Validations {
Expand All @@ -224,4 +225,11 @@ impl Validations {

self
}

pub fn with_era(self, era: impl ToString) -> Self {
Self {
era: era.to_string(),
..self
}
}
}
269 changes: 266 additions & 3 deletions napi-pallas/src/validations/alonzo.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,271 @@
use pallas::ledger::primitives::alonzo::MintedTx;
use pallas::{
applying::{
alonzo::{
check_auxiliary_data, check_fee, check_ins_and_collateral_in_utxos, check_ins_not_empty,
check_languages, check_min_lovelace, check_minting, check_network_id, check_output_val_size,
check_preservation_of_value, check_script_data_hash, check_tx_ex_units, check_tx_size,
check_tx_validity_interval, check_witness_set,
},
utils::{get_alonzo_comp_tx_size, AlonzoProtParams, FeePolicy},
Environment, MultiEraProtParams, UTxOs,
},
ledger::primitives::alonzo::{MintedTx, TransactionBody},
};

use crate::Validations;
use crate::{Validation, Validations};

use super::validate::set_description;

// & The following validation requires the size and the protocol params
fn validate_alonzo_tx_size(size: &Option<u64>, prot_pps: &AlonzoProtParams) -> Validation {
match size {
Some(size_value) => {
let res = check_tx_size(&size_value, &prot_pps);
let description = set_description(
&res,
"The transaction size does not exceed the protocol limit.".to_string(),
);
return Validation::new()
.with_name("Transaction size".to_string())
.with_value(res.is_ok())
.with_description(description);
}
None => {
return Validation::new()
.with_name("Transaction size".to_string())
.with_value(false)
.with_description("The transaction size could not be obtained.".to_string());
}
}
}

// & The following validations require the transaction
fn validate_alonzo_ins_not_empty(mtx_a: &MintedTx) -> Validation {
let res = check_ins_not_empty(&mtx_a.transaction_body);
let description = set_description(
&res,
"The set of transaction inputs is not empty.".to_string(),
);
return Validation::new()
.with_name("Non empty inputs".to_string())
.with_value(res.is_ok())
.with_description(description);
}

fn validate_alonzo_auxiliary_data(mtx_a: &MintedTx) -> Validation {
let tx_body: &TransactionBody = &mtx_a.transaction_body;
let res = check_auxiliary_data(&tx_body, mtx_a);
let description = set_description(
&res,
"The auxiliary data of the transaction is valid.".to_string(),
);
return Validation::new()
.with_name("Auxiliary data".to_string())
.with_value(res.is_ok())
.with_description(description);
}

fn validate_alonzo_script_data_hash(mtx_a: &MintedTx) -> Validation {
let tx_body: &TransactionBody = &mtx_a.transaction_body;
let res = check_script_data_hash(&tx_body, mtx_a);
let description = set_description(
&res,
"The script data integrity hash matches the hash of the redeemers, languages and datums of the transaction witness set.".to_string(),
);
return Validation::new()
.with_name("Script data hash".to_string())
.with_value(res.is_ok())
.with_description(description);
}

fn validate_alonzo_minting(mtx_a: &MintedTx) -> Validation {
let tx_body: &TransactionBody = &mtx_a.transaction_body;
let res = check_minting(&tx_body, mtx_a);
let description = set_description(
&res,
"Each minted / burned asset is paired with an appropriate native script or Plutus script."
.to_string(),
);
return Validation::new()
.with_name("Minting".to_string())
.with_value(res.is_ok())
.with_description(description);
}

// & The following validations require the transaction and the protocol params
fn validate_alonzo_min_lovelace(mtx_a: &MintedTx, prot_pps: &AlonzoProtParams) -> Validation {
let tx_body: &TransactionBody = &mtx_a.transaction_body;
let res = check_min_lovelace(&tx_body, &prot_pps);
let description = set_description(
&res,
"All transaction outputs (regular outputs and collateral outputs) should contain at least the minimum lovelace".to_string(),
);
return Validation::new()
.with_name("Minimum lovelace".to_string())
.with_value(res.is_ok())
.with_description(description);
}

fn validate_alonzo_output_val_size(mtx_a: &MintedTx, prot_pps: &AlonzoProtParams) -> Validation {
let tx_body: &TransactionBody = &mtx_a.transaction_body;
let res = check_output_val_size(&tx_body, &prot_pps);
let description = set_description(
&res,
"The size of the value in each of the transaction outputs (regular outputs and collateral outputs) is not greater than the maximum allowed".to_string(),
);
return Validation::new()
.with_name("Minimum lovelace".to_string())
.with_value(res.is_ok())
.with_description(description);
}

fn validate_alonzo_tx_ex_units(mtx_a: &MintedTx, prot_pps: &AlonzoProtParams) -> Validation {
let res = check_tx_ex_units(mtx_a, &prot_pps);
let description = set_description(
&res,
"The size of the value in each of the transaction outputs (regular outputs and collateral outputs) is not greater than the maximum allowed".to_string(),
);
return Validation::new()
.with_name("Minimum lovelace".to_string())
.with_value(res.is_ok())
.with_description(description);
}

fn validate_alonzo_languages(mtx_a: &MintedTx, prot_pps: &AlonzoProtParams) -> Validation {
let res = check_languages(mtx_a, &prot_pps);
let description = set_description(
&res,
"The required script languages are included in the protocol parameters.".to_string(),
);
return Validation::new()
.with_name("Minimum lovelace".to_string())
.with_value(res.is_ok())
.with_description(description);
}

// & The following validation requires the transaction and the network id
fn validate_alonzo_network_id(mtx_a: &MintedTx, network_id: &u8) -> Validation {
let res = check_network_id(&mtx_a.transaction_body, network_id);
let description = set_description(
&res,
"The network ID of each output matches the global network ID.".to_string(),
);
return Validation::new()
.with_name("Network ID".to_string())
.with_value(res.is_ok())
.with_description(description);
}

// & The following validations require the transaction and the block slot
fn validate_alonzo_tx_validity_interval(mtx_a: &MintedTx, block_slot: &u64) -> Validation {
let res = check_tx_validity_interval(&mtx_a.transaction_body, mtx_a, block_slot);
let description = set_description(
&res,
"The upper bound of the validity time interval is suitable for script execution: if there are minting policies, native scripts or Plutus scripts involved in the transaction, and if the upper bound of its validity interval is a finite number, then it can be translated to system time.".to_string(),
);
return Validation::new()
.with_name("Transaction validity interval".to_string())
.with_value(res.is_ok())
.with_description(description);
}

// & The following validations require the transaction and its utxos
fn validate_alonzo_ins_and_collateral_in_utxos(mtx_a: &MintedTx, utxos: &UTxOs) -> Validation {
let res = check_ins_and_collateral_in_utxos(&mtx_a.transaction_body, utxos);
let description = set_description(
&res,
"All transaction inputs and collateral inputs are in the set of (yet) unspent transaction outputs.".to_string(),
);
return Validation::new()
.with_name("Inputs and collateral in UTxOs".to_string())
.with_value(res.is_ok())
.with_description(description);
}

fn validate_alonzo_preservation_of_value(mtx_a: &MintedTx, utxos: &UTxOs) -> Validation {
let res = check_preservation_of_value(&mtx_a.transaction_body, utxos);
let description = set_description(
&res,
"The preservation of value property holds.".to_string(),
);
return Validation::new()
.with_name("Preservation of value".to_string())
.with_value(res.is_ok())
.with_description(description);
}

fn validate_alonzo_witness_set(mtx_a: &MintedTx, utxos: &UTxOs) -> Validation {
let res = check_witness_set(mtx_a, utxos);
let description = set_description(&res, "The transaction witness set is valid.".to_string());
return Validation::new()
.with_name("Witness set".to_string())
.with_value(res.is_ok())
.with_description(description);
}

// & The following validation requires the transaction, its utxos and the protocol params
fn validate_alonzo_fee(mtx_a: &MintedTx, utxos: &UTxOs, prot_pps: &AlonzoProtParams) -> Validation {
let tx_body: &TransactionBody = &mtx_a.transaction_body;
let size: &Option<u64> = &get_alonzo_comp_tx_size(tx_body);
match size {
Some(size_value) => {
let res = check_fee(tx_body, size_value, mtx_a, utxos, prot_pps);
let description = set_description(
&res,
"The fee paid by the transaction should be greater than or equal to the minimum fee."
.to_string(),
);
return Validation::new()
.with_name("Fee".to_string())
.with_value(res.is_ok())
.with_description(description);
}
None => {
return Validation::new()
.with_name("Fee".to_string())
.with_value(false)
.with_description("The size could not be obtained.".to_string());
}
}
}

pub fn validate_alonzo(mtx_a: &MintedTx) -> Validations {
let out = Validations::new();
let tx_body: &TransactionBody = &mtx_a.transaction_body;
let size: &Option<u64> = &get_alonzo_comp_tx_size(tx_body);
let prot_params = AlonzoProtParams {
fee_policy: FeePolicy {
summand: 155381,
multiplier: 44,
},
max_tx_size: 16384,
max_block_ex_mem: 62000000,
max_block_ex_steps: 20000000000,
max_tx_ex_mem: 14000000,
max_tx_ex_steps: 10000000000,
max_val_size: 5000,
collateral_percent: 150,
max_collateral_inputs: 3,
coins_per_utxo_word: 4310,
};

let env: Environment = Environment {
prot_params: MultiEraProtParams::Alonzo(prot_params.clone()),
prot_magic: 764824073, // Mainnet. For preprod: 1. For preview: 2
block_slot: 72316896, // TODO: Must be an input
network_id: 1, // Mainnet. For preprod: 0. For preview: 0
};
let out = Validations::new()
.with_era("Alonzo".to_string())
.add_new_validation(validate_alonzo_tx_size(size, &prot_params))
.add_new_validation(validate_alonzo_ins_not_empty(mtx_a))
.add_new_validation(validate_alonzo_auxiliary_data(mtx_a))
.add_new_validation(validate_alonzo_script_data_hash(mtx_a))
.add_new_validation(validate_alonzo_minting(mtx_a))
.add_new_validation(validate_alonzo_min_lovelace(mtx_a, &prot_params))
.add_new_validation(validate_alonzo_output_val_size(mtx_a, &prot_params))
.add_new_validation(validate_alonzo_tx_ex_units(mtx_a, &prot_params))
.add_new_validation(validate_alonzo_languages(mtx_a, &prot_params))
.add_new_validation(validate_alonzo_network_id(mtx_a, &env.network_id))
.add_new_validation(validate_alonzo_tx_validity_interval(mtx_a, &env.block_slot));
out
}
Loading