Skip to content

Commit

Permalink
chore: scaffold tx validation UI (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikarasv authored Apr 10, 2024
1 parent e38a9c9 commit ccfcfca
Show file tree
Hide file tree
Showing 15 changed files with 451 additions and 362 deletions.
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 = "0.21.0"
pallas = { git = "https://github.com/alegadea/pallas.git", rev = "54ffc77" , features = ["unstable"]}

[build-dependencies]
napi-build = "2.0.1"
Expand Down
14 changes: 13 additions & 1 deletion napi-pallas/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,17 @@ export interface Section {
children: Array<Section>
}
export function parseAddress(raw: string): Output
export function safeParseTx(raw: string): Section
export interface SectionValidation {
section: Section
validations: Validations
}
export function safeParseTx(raw: string): SectionValidation
export function safeParseBlock(raw: string): Section
export interface Validation {
name: string
value: boolean
description: string
}
export interface Validations {
validations: Array<Validation>
}
73 changes: 70 additions & 3 deletions napi-pallas/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ extern crate napi_derive;
mod address;
mod block;
mod tx;
mod validations;

#[derive(Default)]
#[napi(object)]
Expand Down Expand Up @@ -143,11 +144,27 @@ pub fn parse_address(raw: String) -> address::Output {
}
}

#[derive(Default)]
#[napi(object)]
pub struct SectionValidation {
pub section: Section,
pub validations: Validations,
}

#[napi]
pub fn safe_parse_tx(raw: String) -> Section {
pub fn safe_parse_tx(raw: String) -> SectionValidation {
match tx::parse(raw) {
Ok(x) => x,
Err(x) => x,
Ok(x) => {
let (section, validations) = x;
SectionValidation {
section,
validations: validations,
}
}
Err(x) => SectionValidation {
section: x,
validations: Validations::new(),
},
}
}

Expand All @@ -158,3 +175,53 @@ pub fn safe_parse_block(raw: String) -> Section {
Err(x) => x,
}
}

#[derive(Default, Debug)]
#[napi(object)]
pub struct Validation {
pub name: String,
pub value: bool,
pub description: String,
}

impl Validation {
fn new() -> Self {
Default::default()
}

pub fn with_description(self, description: impl ToString) -> Self {
Self {
description: description.to_string(),
..self
}
}

pub fn with_value(self, value: bool) -> Self {
Self { value, ..self }
}

pub fn with_name(self, name: impl ToString) -> Self {
Self {
name: name.to_string(),
..self
}
}
}

#[derive(Debug, Default)]
#[napi(object)]
pub struct Validations {
pub validations: Vec<Validation>,
}

impl Validations {
pub fn new() -> Self {
Default::default()
}

pub fn add_new_validation(mut self, validation: Validation) -> Self {
self.validations.push(validation);

self
}
}
40 changes: 31 additions & 9 deletions napi-pallas/src/tx.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use crate::validations::validate::validate;
use crate::Validations;

use super::Section;
use pallas::{
codec::utils::KeepRaw,
crypto::hash::Hasher,
ledger::{
primitives::{
babbage::{Redeemer, RedeemerTag},
conway::{Metadatum, PlutusData, PlutusV1Script, VKeyWitness},
conway::{Metadatum, PlutusData, VKeyWitness},
ToCanonicalJson,
},
traverse::{ComputeHash, MultiEraInput, MultiEraOutput, MultiEraTx},
Expand Down Expand Up @@ -98,8 +101,8 @@ fn print_metadatum(datum: &Metadatum) -> String {
Metadatum::Int(x) => x.to_string(),
Metadatum::Bytes(x) => hex::encode(x.as_slice()),
Metadatum::Text(x) => x.to_owned(),
Metadatum::Array(x) => "[Array]".to_string(),
Metadatum::Map(x) => "[Map]".to_string(),
Metadatum::Array(_) => "[Array]".to_string(),
Metadatum::Map(_) => "[Map]".to_string(),
}
}

Expand Down Expand Up @@ -190,7 +193,8 @@ fn tx_witnesses_section(tx: &MultiEraTx<'_>) -> Section {
Section::new()
.with_topic("tx_witnesses")
.append_children(tx.vkey_witnesses().iter().map(tx_vkey_witnesses_section))
.append_children(tx.redeemers().iter().map(tx_redeemer_section))
// TODO: Uncomment when branch with this issue fixed is used
// .append_children(tx.redeemers().iter().map(tx_redeemer_section))
.append_children(tx.plutus_data().iter().map(tx_plutus_datum_section))
.append_children(
tx.plutus_v1_scripts()
Expand All @@ -209,11 +213,8 @@ fn tx_witnesses_section(tx: &MultiEraTx<'_>) -> Section {
)
}

pub fn parse(raw: String) -> Result<Section, Section> {
pub fn create_cbor_structure(tx: &MultiEraTx<'_>) -> Section {
let out = Section::new().with_topic("cbor_parse").try_build_child(|| {
let cbor = hex::decode(raw)?;
let tx = MultiEraTx::decode(&cbor)?;

let child = Section::new()
.with_topic("tx")
.with_attr("era", tx.era())
Expand All @@ -231,6 +232,27 @@ pub fn parse(raw: String) -> Result<Section, Section> {

Ok(child)
});
out
}

Ok(out)
pub fn parse(raw: String) -> Result<(Section, Validations), Section> {
let res_cbor = hex::decode(raw);
match res_cbor {
Ok(cbor) => {
let res_mtx = MultiEraTx::decode(&cbor);
match res_mtx {
Ok(mtx) => Ok((create_cbor_structure(&mtx), validate(&mtx))),
Err(e) => {
let mut err = Section::new();
err.error = Some(e.to_string());
Err(err)
}
}
}
Err(e) => {
let mut err = Section::new();
err.error = Some(e.to_string());
Err(err)
}
}
}
8 changes: 8 additions & 0 deletions napi-pallas/src/validations/alonzo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use pallas::ledger::primitives::alonzo::MintedTx;

use crate::Validations;

pub fn validate_alonzo(mtx_a: &MintedTx) -> Validations {
let out = Validations::new();
out
}
22 changes: 22 additions & 0 deletions napi-pallas/src/validations/babbage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use crate::{Validation, Validations};
use pallas::{
applying::babbage::check_ins_not_empty,
ledger::primitives::babbage::{MintedTransactionBody, MintedTx as BabbageMintedTx},
};

use super::validate::set_description;

fn validate_babbage_ins_not_empty(mtx: &BabbageMintedTx) -> Validation {
let tx_body: &MintedTransactionBody = &mtx.transaction_body.clone();
let res = check_ins_not_empty(tx_body);
let description = set_description(&res, "Inputs are not empty".to_string());
return Validation::new()
.with_name("Non empty inputs".to_string())
.with_value(res.is_ok())
.with_description(description);
}

pub fn validate_babbage(mtx_b: &BabbageMintedTx) -> Validations {
let out = Validations::new().add_new_validation(validate_babbage_ins_not_empty(&mtx_b));
out
}
6 changes: 6 additions & 0 deletions napi-pallas/src/validations/byron.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use crate::Validations;
use pallas::ledger::primitives::byron::MintedTxPayload;
pub fn validate_byron(mtxp: &MintedTxPayload) -> Validations {
let out = Validations::new();
out
}
7 changes: 7 additions & 0 deletions napi-pallas/src/validations/conway.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use pallas::ledger::primitives::conway::MintedTx;

use crate::Validations;
pub fn validate_conway(mtx_c: &MintedTx) -> Validations {
let out = Validations::new();
out
}
6 changes: 6 additions & 0 deletions napi-pallas/src/validations/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pub mod alonzo;
pub mod babbage;
pub mod byron;
pub mod conway;
pub mod shelley_ma;
pub mod validate;
8 changes: 8 additions & 0 deletions napi-pallas/src/validations/shelley_ma.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use pallas::ledger::primitives::alonzo::MintedTx;

use crate::Validations;

pub fn validate_shelley_ma(mtx_sma: &MintedTx) -> Validations {
let out = Validations::new();
out
}
31 changes: 31 additions & 0 deletions napi-pallas/src/validations/validate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use crate::validations::babbage::validate_babbage;
use crate::Validations;

use pallas::applying::utils::ValidationError;
use pallas::ledger::traverse::{Era, MultiEraTx};

use super::alonzo::validate_alonzo;
use super::byron::validate_byron;
use super::conway::validate_conway;
use super::shelley_ma::validate_shelley_ma;

pub fn set_description(res: &Result<(), ValidationError>, success: String) -> String {
match res {
Ok(_) => success,
Err(e) => format!("Error {:?}", e),
}
}

pub fn validate(mtx: &MultiEraTx<'_>) -> Validations {
match &mtx {
MultiEraTx::Byron(mtxp) => validate_byron(&mtxp),
MultiEraTx::AlonzoCompatible(mtx_sma, Era::Shelley)
| MultiEraTx::AlonzoCompatible(mtx_sma, Era::Allegra)
| MultiEraTx::AlonzoCompatible(mtx_sma, Era::Mary) => validate_shelley_ma(&mtx_sma),
MultiEraTx::AlonzoCompatible(mtx_a, Era::Alonzo) => validate_alonzo(&mtx_a),
MultiEraTx::Babbage(mtx_b) => validate_babbage(&mtx_b),
MultiEraTx::Conway(mtx_c) => validate_conway(&mtx_c),
// This case is impossible. TODO: Handle error
_ => Validations::new(),
}
}
39 changes: 29 additions & 10 deletions web/app/components.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Attribute, type Section } from "napi-pallas";
import { PropsWithChildren, useState } from "react";
import { IValidation } from "./routes/tx";
import { DataProps, IValidation } from "./routes/tx";

export type TopicMeta = {
title: string;
Expand Down Expand Up @@ -53,18 +53,37 @@ export const P1 = Paragraph;
export function RootSection(props: {
data: Section;
topics: Record<string, TopicMeta>;
validations: IValidation[];
}) {
const [open, setOpen] = useState(false);
const handleClick = () => setOpen(!open);
const topic = getTopicMeta(props.data.topic, props.topics);

if (props.data.error)
return (
<div className="block mt-8 p-4 border-2 bg-red-200 border-red-700 shadow shadow-black rounded-lg text-2xl">
<h4 className="text-3xl">{topic.description}</h4>
{props.data.error}
</div>
);

return (
<>
<div className="flex flex-col">
<div className="mb-14">
<button
className={`flex items-center w-full text-left select-none duration-300`}
onClick={handleClick}
>
<div
className={`h-8 w-8 inline-flex items-center justify-center duration-300 `}
>
{open ? "▼" : "▶"}
</div>
<h4 className="text-3xl ">Tx Validations</h4>
</button>
{open && <ValidationAccordion validations={props.validations} />}
</div>
<h4 className="text-3xl">{topic.title}</h4>
{!props.data.error && topic.description}
{!!props.data.error && (
<div className="block mt-8 p-4 border-2 bg-red-200 border-red-700 shadow shadow-black rounded-lg text-2xl">
{props.data.error}
</div>
)}
{!!props.data.bytes && (
<HexBlock name="bytes (hex)" value={props.data.bytes} />
)}
Expand All @@ -74,7 +93,7 @@ export function RootSection(props: {
{props.data.children?.map((c) => (
<DataSection key={c.identity} data={c} topics={props.topics} />
))}
</>
</div>
);
}

Expand Down Expand Up @@ -159,7 +178,7 @@ export function TextArea(props: { name: string; placeholder?: string }) {
);
}

export function logCuriosity(data: any) {
export function logCuriosity(data: DataProps) {
if (data) {
console.group("CURIOUS FELLOW, EH?");
console.log("hello there! want to learn how we parse the data?");
Expand Down
2 changes: 1 addition & 1 deletion web/app/routes/tx.server.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { type Section, safeParseTx } from "napi-pallas";
export { safeParseTx, type Section } from "napi-pallas";
Loading

0 comments on commit ccfcfca

Please sign in to comment.