Skip to content

Commit

Permalink
Refactor a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
Rigidity committed Aug 30, 2024
1 parent c3566d1 commit b261936
Show file tree
Hide file tree
Showing 4 changed files with 404 additions and 389 deletions.
247 changes: 247 additions & 0 deletions src/conversions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
use chia::{
bls::{PublicKey, SecretKey, Signature},
protocol::{Bytes, Bytes32, Program},
};
use napi::bindgen_prelude::*;
use napi::Result;
use thiserror::Error;

use crate::{js, rust};

#[derive(Error, Debug)]
pub enum ConversionError {
#[error("Expected different byte length {0}")]
DifferentLength(u32),

#[error("Invalid public key")]
InvalidPublicKey,

#[error("Invalid private key")]
InvalidPrivateKey,

#[error("Invalid signature")]
InvalidSignature,

#[error("Missing proof")]
MissingProof,

#[error("Missing delegated puzzle info")]
MissingDelegatedPuzzleInfo,

#[error("Invalid URI: {0}")]
InvalidUri(String),
}

pub trait FromJs<T> {
fn from_js(value: T) -> Result<Self>
where
Self: Sized;
}

pub trait ToJs<T> {
fn to_js(&self) -> Result<T>;
}

impl FromJs<Buffer> for Bytes32 {
fn from_js(value: Buffer) -> Result<Self> {
Self::try_from(value.as_ref().to_vec())
.map_err(|_| js::err(ConversionError::DifferentLength(32)))
}
}

impl ToJs<Buffer> for Bytes32 {
fn to_js(&self) -> Result<Buffer> {
Ok(Buffer::from(self.to_vec()))
}
}

impl FromJs<Buffer> for Program {
fn from_js(value: Buffer) -> Result<Self> {
Ok(Self::from(value.to_vec()))
}
}

impl ToJs<Buffer> for Program {
fn to_js(&self) -> Result<Buffer> {
Ok(Buffer::from(self.to_vec()))
}
}

impl FromJs<Buffer> for Bytes {
fn from_js(value: Buffer) -> Result<Self> {
Ok(Self::new(value.to_vec()))
}
}

impl ToJs<Buffer> for Bytes {
fn to_js(&self) -> Result<Buffer> {
Ok(Buffer::from(self.to_vec()))
}
}

impl FromJs<Buffer> for PublicKey {
fn from_js(value: Buffer) -> Result<Self> {
Self::from_bytes(
&<[u8; 48]>::try_from(value.to_vec())
.map_err(|_| js::err(ConversionError::DifferentLength(48)))?,
)
.map_err(|_| js::err(ConversionError::InvalidPublicKey))
}
}

impl ToJs<Buffer> for PublicKey {
fn to_js(&self) -> Result<Buffer> {
Ok(Buffer::from(self.to_bytes().to_vec()))
}
}

impl FromJs<Buffer> for SecretKey {
fn from_js(value: Buffer) -> Result<Self> {
Self::from_bytes(
&<[u8; 32]>::try_from(value.to_vec())
.map_err(|_| js::err(ConversionError::DifferentLength(32)))?,
)
.map_err(|_| js::err(ConversionError::InvalidPrivateKey))
}
}

impl ToJs<Buffer> for SecretKey {
fn to_js(&self) -> Result<Buffer> {
Ok(Buffer::from(self.to_bytes().to_vec()))
}
}

impl FromJs<Buffer> for Signature {
fn from_js(value: Buffer) -> Result<Self> {
Self::from_bytes(
&<[u8; 96]>::try_from(value.to_vec())
.map_err(|_| js::err(ConversionError::DifferentLength(96)))?,
)
.map_err(|_| js::err(ConversionError::InvalidSignature))
}
}

impl ToJs<Buffer> for Signature {
fn to_js(&self) -> Result<Buffer> {
Ok(Buffer::from(self.to_bytes().to_vec()))
}
}

impl FromJs<BigInt> for u64 {
fn from_js(value: BigInt) -> Result<Self> {
Ok(value.get_u64().1)
}
}

impl ToJs<BigInt> for u64 {
fn to_js(&self) -> Result<BigInt> {
Ok(BigInt::from(*self))
}
}

impl FromJs<js::Coin> for rust::Coin {
fn from_js(value: js::Coin) -> Result<Self> {
Ok(Self {
parent_coin_info: Bytes32::from_js(value.parent_coin_info)?,
puzzle_hash: Bytes32::from_js(value.puzzle_hash)?,
amount: u64::from_js(value.amount)?,
})
}
}

impl ToJs<js::Coin> for rust::Coin {
fn to_js(&self) -> Result<js::Coin> {
Ok(js::Coin {
parent_coin_info: self.parent_coin_info.to_js()?,
puzzle_hash: self.puzzle_hash.to_js()?,
amount: self.amount.to_js()?,
})
}
}

impl FromJs<js::CoinSpend> for rust::CoinSpend {
fn from_js(value: js::CoinSpend) -> Result<Self> {
Ok(Self {
coin: rust::Coin::from_js(value.coin)?,
puzzle_reveal: Program::from_js(value.puzzle_reveal)?,
solution: Program::from_js(value.solution)?,
})
}
}

impl ToJs<js::CoinSpend> for rust::CoinSpend {
fn to_js(&self) -> Result<js::CoinSpend> {
Ok(js::CoinSpend {
coin: self.coin.to_js()?,
puzzle_reveal: self.puzzle_reveal.to_js()?,
solution: self.solution.to_js()?,
})
}
}

impl FromJs<js::LineageProof> for rust::LineageProof {
fn from_js(value: js::LineageProof) -> Result<Self> {
Ok(Self {
parent_parent_coin_info: Bytes32::from_js(value.parent_parent_coin_info)?,
parent_inner_puzzle_hash: Bytes32::from_js(value.parent_inner_puzzle_hash)?,
parent_amount: u64::from_js(value.parent_amount)?,
})
}
}

impl ToJs<js::LineageProof> for rust::LineageProof {
fn to_js(&self) -> Result<js::LineageProof> {
Ok(js::LineageProof {
parent_parent_coin_info: self.parent_parent_coin_info.to_js()?,
parent_inner_puzzle_hash: self.parent_inner_puzzle_hash.to_js()?,
parent_amount: self.parent_amount.to_js()?,
})
}
}

impl FromJs<js::EveProof> for rust::EveProof {
fn from_js(value: js::EveProof) -> Result<Self> {
Ok(rust::EveProof {
parent_parent_coin_info: Bytes32::from_js(value.parent_parent_coin_info)?,
parent_amount: u64::from_js(value.parent_amount)?,
})
}
}

impl ToJs<js::EveProof> for rust::EveProof {
fn to_js(&self) -> Result<js::EveProof> {
Ok(js::EveProof {
parent_parent_coin_info: self.parent_parent_coin_info.to_js()?,
parent_amount: self.parent_amount.to_js()?,
})
}
}

impl FromJs<js::Proof> for rust::Proof {
fn from_js(value: js::Proof) -> Result<Self> {
if let Some(lineage_proof) = value.lineage_proof {
Ok(rust::Proof::Lineage(rust::LineageProof::from_js(
lineage_proof,
)?))
} else if let Some(eve_proof) = value.eve_proof {
Ok(rust::Proof::Eve(rust::EveProof::from_js(eve_proof)?))
} else {
Err(js::err(ConversionError::MissingProof))
}
}
}

impl ToJs<js::Proof> for rust::Proof {
fn to_js(&self) -> Result<js::Proof> {
Ok(match self {
rust::Proof::Lineage(lineage_proof) => js::Proof {
lineage_proof: Some(lineage_proof.to_js()?),
eve_proof: None,
},
rust::Proof::Eve(eve_proof) => js::Proof {
lineage_proof: None,
eve_proof: Some(eve_proof.to_js()?),
},
})
}
}
69 changes: 69 additions & 0 deletions src/js.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use napi::bindgen_prelude::*;

#[napi(object)]
#[derive(Clone)]
/// Represents a coin on the Chia blockchain.
///
/// @property {Buffer} parentCoinInfo - Parent coin name/id.
/// @property {Buffer} puzzleHash - Puzzle hash.
/// @property {BigInt} amount - Coin amount.
pub struct Coin {
pub parent_coin_info: Buffer,
pub puzzle_hash: Buffer,
pub amount: BigInt,
}

#[napi(object)]
#[derive(Clone)]
/// Represents a coin spend on the Chia blockchain.
///
/// @property {Coin} coin - The coin being spent.
/// @property {Buffer} puzzleReveal - The puzzle of the coin being spent.
/// @property {Buffer} solution - The solution.
pub struct CoinSpend {
pub coin: Coin,
pub puzzle_reveal: Buffer,
pub solution: Buffer,
}

#[napi(object)]
#[derive(Clone)]
/// Represents a lineage proof that can be used to spend a singleton.
///
/// @property {Buffer} parentParentCoinInfo - Parent coin's parent coin info/name/ID.
/// @property {Buffer} parentInnerPuzzleHash - Parent coin's inner puzzle hash.
/// @property {BigInt} parentAmount - Parent coin's amount.
pub struct LineageProof {
pub parent_parent_coin_info: Buffer,
pub parent_inner_puzzle_hash: Buffer,
pub parent_amount: BigInt,
}

#[napi(object)]
#[derive(Clone)]
/// Represents an eve proof that can be used to spend a singleton. Parent coin is the singleton launcher.
///
/// @property {Buffer} parentParentCoinInfo - Parent coin's name.
/// @property {BigInt} parentAmount - Parent coin's amount.
pub struct EveProof {
pub parent_parent_coin_info: Buffer,
pub parent_amount: BigInt,
}

#[napi(object)]
#[derive(Clone)]
/// Represents a proof (either eve or lineage) that can be used to spend a singleton. Use `new_lineage_proof` or `new_eve_proof` to create a new proof.
///
/// @property {Option<LineageProof>} lineageProof - The lineage proof, if this is a lineage proof.
/// @property {Option<EveProof>} eveProof - The eve proof, if this is an eve proof.
pub struct Proof {
pub lineage_proof: Option<LineageProof>,
pub eve_proof: Option<EveProof>,
}

pub fn err<T>(error: T) -> napi::Error
where
T: ToString,
{
napi::Error::from_reason(error.to_string())
}
Loading

0 comments on commit b261936

Please sign in to comment.