Implements low-level transparent components (#45)

This PR includes components for the deserialization of low-level part of transparent components.

Reviewed-on: #45
Co-authored-by: Rene Vergara <rene@vergara.network>
Co-committed-by: Rene Vergara <rene@vergara.network>
This commit is contained in:
Rene Vergara 2024-03-26 20:39:31 +00:00 committed by Vergara Technologies LLC
parent 4e86a2f5a4
commit bb9d336dc3
Signed by: Vergara Technologies LLC
GPG key ID: 99DB473BB4715618
3 changed files with 72 additions and 8 deletions

View file

@ -36,6 +36,7 @@ use zcash_primitives::{
Bundle as TransparentBundle, Bundle as TransparentBundle,
TxIn, TxIn,
TxOut, TxOut,
OutPoint,
Authorized Authorized
}, },
sapling::{ sapling::{
@ -246,6 +247,7 @@ impl<RW> ToHaskell<RW> for Htx {
#[derive(BorshSerialize, BorshDeserialize)] #[derive(BorshSerialize, BorshDeserialize)]
pub struct HTBundle { pub struct HTBundle {
empty: bool,
vin: Vec<HTxIn>, vin: Vec<HTxIn>,
vout: Vec<HTxOut>, vout: Vec<HTxOut>,
coinbase: bool coinbase: bool
@ -260,13 +262,13 @@ impl<RW> ToHaskell<RW> for HTBundle {
impl HTBundle { impl HTBundle {
pub fn from_bundle(b: &TransparentBundle<Authorized>) -> HTBundle { pub fn from_bundle(b: &TransparentBundle<Authorized>) -> HTBundle {
HTBundle { vin: b.vin.iter().map(HTxIn::pack).collect() , vout: b.vout.iter().map(HTxOut::pack).collect(), coinbase: b.is_coinbase()} HTBundle {empty: false, vin: b.vin.iter().map(HTxIn::pack).collect() , vout: b.vout.iter().map(HTxOut::pack).collect(), coinbase: b.is_coinbase()}
} }
} }
#[derive(BorshSerialize, BorshDeserialize)] #[derive(BorshSerialize, BorshDeserialize)]
pub struct HTxIn { pub struct HTxIn {
outpoint: u32, outpoint: Houtpoint,
script: Vec<u8>, script: Vec<u8>,
sequence: u32 sequence: u32
} }
@ -280,7 +282,7 @@ impl<RW> ToHaskell<RW> for HTxIn {
impl HTxIn { impl HTxIn {
pub fn pack(t: &TxIn<Authorized>) -> HTxIn { pub fn pack(t: &TxIn<Authorized>) -> HTxIn {
return HTxIn { outpoint: t.prevout.n(), script: t.script_sig.0.clone(), sequence: t.sequence} return HTxIn { outpoint: Houtpoint::pack(&t.prevout), script: t.script_sig.0.clone(), sequence: t.sequence}
} }
} }
@ -303,6 +305,25 @@ impl HTxOut {
} }
} }
#[derive(BorshSerialize, BorshDeserialize)]
pub struct Houtpoint {
hash: Vec<u8>,
index: u32
}
impl<RW> ToHaskell<RW> for Houtpoint {
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
self.serialize(writer)?;
Ok(())
}
}
impl Houtpoint {
pub fn pack(o: &OutPoint) -> Houtpoint {
return Houtpoint {hash: o.hash().to_vec() , index: o.n() }
}
}
#[derive(BorshSerialize, BorshDeserialize)] #[derive(BorshSerialize, BorshDeserialize)]
pub struct Hufvk { pub struct Hufvk {
net: u8, net: u8,
@ -651,11 +672,20 @@ pub extern "C" fn rust_wrapper_tx_read(
let parsed_tx = Transaction::read(&mut tx_reader, Nu5); let parsed_tx = Transaction::read(&mut tx_reader, Nu5);
match parsed_tx { match parsed_tx {
Ok(t) => { Ok(t) => {
let h = Htx {txid: t.txid().as_ref().to_vec(), locktime: t.lock_time(), expiry: u32::from(t.expiry_height()), t_bundle: HTBundle::from_bundle(t.transparent_bundle().unwrap()) }; let tb = t.transparent_bundle();
match tb {
Some(my_tb) => {
let h = Htx {txid: t.txid().as_ref().to_vec(), locktime: t.lock_time(), expiry: u32::from(t.expiry_height()), t_bundle: HTBundle::from_bundle(my_tb) };
marshall_to_haskell_var(&h, out, out_len, RW); marshall_to_haskell_var(&h, out, out_len, RW);
}, },
None => {
let h0 = Htx {txid: t.txid().as_ref().to_vec(), locktime: t.lock_time(), expiry: u32::from(t.expiry_height()), t_bundle: HTBundle {empty: true, vin: vec![HTxIn {outpoint: Houtpoint {hash: vec![0], index: 0}, script: vec![0], sequence: 0}], vout: vec![HTxOut {amt: 0, script: vec![0]}], coinbase: true} };
marshall_to_haskell_var(&h0, out, out_len, RW);
}
}
},
Err(_e) => { Err(_e) => {
let h0 = Htx {txid: vec![0], locktime: 0, expiry: 0, t_bundle: HTBundle {vin: vec![HTxIn {outpoint: 0, script: vec![0], sequence: 0}], vout: vec![HTxOut {amt: 0, script: vec![0]}], coinbase: true} }; let h0 = Htx {txid: vec![0], locktime: 0, expiry: 0, t_bundle: HTBundle {empty: true, vin: vec![HTxIn {outpoint: Houtpoint {hash: vec![0], index: 0}, script: vec![0], sequence: 0}], vout: vec![HTxOut {amt: 0, script: vec![0]}], coinbase: true} };
marshall_to_haskell_var(&h0, out, out_len, RW); marshall_to_haskell_var(&h0, out, out_len, RW);
} }
} }

View file

@ -30,6 +30,7 @@ import Data.Aeson
import qualified Data.ByteArray as BA import qualified Data.ByteArray as BA
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as C import qualified Data.ByteString.Char8 as C
import qualified Data.ByteString.Lazy.UTF8 as US
import Data.HexString import Data.HexString
import Data.Int import Data.Int
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
@ -135,6 +136,29 @@ data TransparentBundle = TransparentBundle
, tb_coinbase :: !Bool , tb_coinbase :: !Bool
} deriving (Eq, Prelude.Show, Read) } deriving (Eq, Prelude.Show, Read)
-- | Read a raw transparent bundle into the Haskell type
fromRawTBundle :: RawTBundle -> Maybe TransparentBundle
fromRawTBundle rtb =
if ztb_empty rtb
then Nothing
else Just $
TransparentBundle
(map fromRawTxIn $ ztb_vin rtb)
(map fromRawTxOut $ ztb_vout rtb)
(ztb_coinbase rtb)
fromRawTxIn :: RawTxIn -> H.TxIn
fromRawTxIn t =
H.TxIn
(H.OutPoint
(read $ US.toString $ C.fromStrict $ rop_hash $ rti_outpoint t)
(rop_n $ rti_outpoint t))
(rti_script t)
(rti_seq t)
fromRawTxOut :: RawTxOut -> H.TxOut
fromRawTxOut t = H.TxOut (rto_amt t) (rto_script t)
-- *** Constants for Sapling Human-readable part -- *** Constants for Sapling Human-readable part
sapExtSpendingKeyHrp = "secret-extended-key-main" :: String sapExtSpendingKeyHrp = "secret-extended-key-main" :: String
@ -262,7 +286,8 @@ data RawZebraTx = RawZebraTx
-- | Type for a raw deserialized Zebra transparent bundle -- | Type for a raw deserialized Zebra transparent bundle
data RawTBundle = RawTBundle data RawTBundle = RawTBundle
{ ztb_vin :: ![RawTxIn] { ztb_empty :: !Bool
, ztb_vin :: ![RawTxIn]
, ztb_vout :: ![RawTxOut] , ztb_vout :: ![RawTxOut]
, ztb_coinbase :: !Bool , ztb_coinbase :: !Bool
} deriving stock (Eq, Prelude.Show, GHC.Generic) } deriving stock (Eq, Prelude.Show, GHC.Generic)
@ -323,7 +348,7 @@ data TransparentAddress = TransparentAddress
-- | Wrapper types for transparent elements -- | Wrapper types for transparent elements
data RawTxIn = RawTxIn data RawTxIn = RawTxIn
{ rti_outpoint :: !Word32 { rti_outpoint :: !RawOutPoint
, rti_script :: !BS.ByteString , rti_script :: !BS.ByteString
, rti_seq :: !Word32 , rti_seq :: !Word32
} deriving stock (Eq, Prelude.Show, GHC.Generic) } deriving stock (Eq, Prelude.Show, GHC.Generic)
@ -339,6 +364,14 @@ data RawTxOut = RawTxOut
deriving anyclass (Data.Structured.Show) deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawTxOut deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawTxOut
data RawOutPoint = RawOutPoint
{ rop_hash :: !BS.ByteString
, rop_n :: !Word32
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawOutPoint
-- * Sapling -- * Sapling
-- | A spending key for Sapling -- | A spending key for Sapling
newtype SaplingSpendingKey = newtype SaplingSpendingKey =

View file

@ -58,6 +58,7 @@ library
, text , text
, haskoin-core , haskoin-core
, secp256k1-haskell , secp256k1-haskell
, utf8-string
build-tool-depends: build-tool-depends:
c2hs:c2hs c2hs:c2hs
default-language: Haskell2010 default-language: Haskell2010