Compare commits
22 commits
58b74a4c9a
...
93a04c09d3
Author | SHA1 | Date | |
---|---|---|---|
93a04c09d3 | |||
4b064af4de | |||
52950885c1 | |||
899b79f155 | |||
0fb02b2514 | |||
1674f9b592 | |||
bb9d336dc3 | |||
f593fefd7f | |||
ee27860299 | |||
4e86a2f5a4 | |||
921d34383a | |||
b0df0480c5 | |||
03d53aa303 | |||
07fa36ed7d | |||
5b6ce3f29b | |||
d659368cff | |||
9c8a851ead | |||
69bce58345 | |||
adc7150b81 | |||
517b736c9a | |||
d1eaf1de4d | |||
e7050f03c0 |
10 changed files with 354 additions and 29 deletions
|
@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [0.5.2.0]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Functionality to parse transparent bundles from Zebra
|
||||||
|
- Types for transparent `TxIn`, `TxOut`, `OutPoint`
|
||||||
|
|
||||||
## [0.5.1.0]
|
## [0.5.1.0]
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -31,9 +31,18 @@ use zcash_primitives::{
|
||||||
sapling::DiversifierKey
|
sapling::DiversifierKey
|
||||||
},
|
},
|
||||||
zip339::{Count, Mnemonic},
|
zip339::{Count, Mnemonic},
|
||||||
transaction::components::sapling::{
|
transaction::components::{
|
||||||
|
transparent::{
|
||||||
|
Bundle as TransparentBundle,
|
||||||
|
TxIn,
|
||||||
|
TxOut,
|
||||||
|
OutPoint,
|
||||||
|
Authorized
|
||||||
|
},
|
||||||
|
sapling::{
|
||||||
GrothProofBytes,
|
GrothProofBytes,
|
||||||
OutputDescription
|
OutputDescription
|
||||||
|
}
|
||||||
},
|
},
|
||||||
sapling::{
|
sapling::{
|
||||||
PaymentAddress,
|
PaymentAddress,
|
||||||
|
@ -221,6 +230,101 @@ impl Hua {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct Htx {
|
||||||
|
txid: Vec<u8>,
|
||||||
|
locktime: u32,
|
||||||
|
expiry: u32,
|
||||||
|
t_bundle: HTBundle
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<RW> ToHaskell<RW> for Htx {
|
||||||
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
||||||
|
self.serialize(writer)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct HTBundle {
|
||||||
|
empty: bool,
|
||||||
|
vin: Vec<HTxIn>,
|
||||||
|
vout: Vec<HTxOut>,
|
||||||
|
coinbase: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<RW> ToHaskell<RW> for HTBundle {
|
||||||
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
||||||
|
self.serialize(writer)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HTBundle {
|
||||||
|
pub fn from_bundle(b: &TransparentBundle<Authorized>) -> HTBundle {
|
||||||
|
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)]
|
||||||
|
pub struct HTxIn {
|
||||||
|
outpoint: Houtpoint,
|
||||||
|
script: Vec<u8>,
|
||||||
|
sequence: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<RW> ToHaskell<RW> for HTxIn {
|
||||||
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
||||||
|
self.serialize(writer)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HTxIn {
|
||||||
|
pub fn pack(t: &TxIn<Authorized>) -> HTxIn {
|
||||||
|
return HTxIn { outpoint: Houtpoint::pack(&t.prevout), script: t.script_sig.0.clone(), sequence: t.sequence}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct HTxOut {
|
||||||
|
amt: i64,
|
||||||
|
script: Vec<u8>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<RW> ToHaskell<RW> for HTxOut {
|
||||||
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
||||||
|
self.serialize(writer)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HTxOut {
|
||||||
|
pub fn pack(t: &TxOut) -> HTxOut {
|
||||||
|
return HTxOut { amt: i64::from_le_bytes(t.value.to_i64_le_bytes()) , script: t.script_pubkey.0.clone() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
@ -556,6 +660,38 @@ pub extern "C" fn rust_wrapper_orchard_note_decrypt(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn rust_wrapper_tx_read(
|
||||||
|
tx: *const u8,
|
||||||
|
tx_len: usize,
|
||||||
|
out: *mut u8,
|
||||||
|
out_len: &mut usize
|
||||||
|
){
|
||||||
|
let tx_input: Vec<u8> = marshall_from_haskell_var(tx, tx_len, RW);
|
||||||
|
let mut tx_reader = Cursor::new(tx_input);
|
||||||
|
let parsed_tx = Transaction::read(&mut tx_reader, Nu5);
|
||||||
|
match parsed_tx {
|
||||||
|
Ok(t) => {
|
||||||
|
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);
|
||||||
|
},
|
||||||
|
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) => {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn rust_wrapper_tx_parse(
|
pub extern "C" fn rust_wrapper_tx_parse(
|
||||||
tx: *const u8,
|
tx: *const u8,
|
||||||
|
|
|
@ -123,6 +123,13 @@ import ZcashHaskell.Types
|
||||||
-> `()'
|
-> `()'
|
||||||
#}
|
#}
|
||||||
|
|
||||||
|
{# fun unsafe rust_wrapper_tx_read as rustWrapperTxRead
|
||||||
|
{ toBorshVar* `BS.ByteString'&
|
||||||
|
, getVarBuffer `Buffer RawZebraTx'&
|
||||||
|
}
|
||||||
|
-> `()'
|
||||||
|
#}
|
||||||
|
|
||||||
{# fun unsafe rust_wrapper_gen_seed_phrase as rustWrapperGenSeedPhrase
|
{# fun unsafe rust_wrapper_gen_seed_phrase as rustWrapperGenSeedPhrase
|
||||||
{ getVarBuffer `Buffer Phrase'& } -> `()'
|
{ getVarBuffer `Buffer Phrase'& } -> `()'
|
||||||
#}
|
#}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
{-# LANGUAGE DeriveGeneric #-}
|
{-# LANGUAGE DeriveGeneric #-}
|
||||||
{-# LANGUAGE DuplicateRecordFields #-}
|
{-# LANGUAGE DuplicateRecordFields #-}
|
||||||
{-# LANGUAGE GeneralisedNewtypeDeriving #-}
|
{-# LANGUAGE GeneralisedNewtypeDeriving #-}
|
||||||
|
{-# LANGUAGE StandaloneDeriving #-}
|
||||||
{-# LANGUAGE DeriveAnyClass #-}
|
{-# LANGUAGE DeriveAnyClass #-}
|
||||||
{-# LANGUAGE DerivingVia #-}
|
{-# LANGUAGE DerivingVia #-}
|
||||||
{-# LANGUAGE UndecidableInstances #-}
|
{-# LANGUAGE UndecidableInstances #-}
|
||||||
|
@ -29,9 +30,11 @@ 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 qualified Data.ByteString.Short as BS (ShortByteString, toShort)
|
||||||
import Data.HexString
|
import Data.HexString
|
||||||
import Data.Int
|
import Data.Int
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromJust, fromMaybe)
|
||||||
import Data.Structured
|
import Data.Structured
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.Encoding as E
|
import qualified Data.Text.Encoding as E
|
||||||
|
@ -39,7 +42,9 @@ import Data.Word
|
||||||
import qualified GHC.Generics as GHC
|
import qualified GHC.Generics as GHC
|
||||||
import qualified Generics.SOP as SOP
|
import qualified Generics.SOP as SOP
|
||||||
import Haskoin.Address (Address)
|
import Haskoin.Address (Address)
|
||||||
|
import qualified Haskoin.Crypto.Hash as H (Hash256(..))
|
||||||
import Haskoin.Crypto.Keys.Extended (XPrvKey)
|
import Haskoin.Crypto.Keys.Extended (XPrvKey)
|
||||||
|
import qualified Haskoin.Transaction.Common as H
|
||||||
|
|
||||||
-- * General
|
-- * General
|
||||||
--
|
--
|
||||||
|
@ -89,6 +94,19 @@ data ZcashNet
|
||||||
|
|
||||||
type AccountId = Int
|
type AccountId = Int
|
||||||
|
|
||||||
|
-- | Function to get the Base58 prefix for encoding a 'TransparentAddress'
|
||||||
|
getTransparentPrefix :: ZcashNet -> TransparentType -> (Word8, Word8)
|
||||||
|
getTransparentPrefix n t =
|
||||||
|
case t of
|
||||||
|
P2SH ->
|
||||||
|
case n of
|
||||||
|
MainNet -> (0x1c, 0xbd)
|
||||||
|
_ -> (0x1c, 0xba)
|
||||||
|
P2PKH ->
|
||||||
|
case n of
|
||||||
|
MainNet -> (0x1c, 0xb8)
|
||||||
|
_ -> (0x1d, 0x25)
|
||||||
|
|
||||||
-- ** Constants
|
-- ** Constants
|
||||||
-- | Type for coin types on the different networks
|
-- | Type for coin types on the different networks
|
||||||
data CoinType
|
data CoinType
|
||||||
|
@ -104,7 +122,50 @@ getValue c =
|
||||||
TestNetCoin -> 1
|
TestNetCoin -> 1
|
||||||
RegTestNetCoin -> 1
|
RegTestNetCoin -> 1
|
||||||
|
|
||||||
-- | Constants for Sapling Human-readable part
|
-- | A Zcash transaction
|
||||||
|
data Transaction = Transaction
|
||||||
|
{ tx_id :: !HexString
|
||||||
|
, tx_height :: !Int
|
||||||
|
, tx_conf :: !Int
|
||||||
|
, tx_expiry :: !Int
|
||||||
|
, tx_transpBundle :: !(Maybe TransparentBundle)
|
||||||
|
} deriving (Prelude.Show, Eq, Read)
|
||||||
|
|
||||||
|
-- | The transparent portion of a Zcash transaction
|
||||||
|
data TransparentBundle = TransparentBundle
|
||||||
|
{ tb_vin :: ![H.TxIn]
|
||||||
|
, tb_vout :: ![H.TxOut]
|
||||||
|
, tb_coinbase :: !Bool
|
||||||
|
} 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 op (rti_script t) (rti_seq t)
|
||||||
|
where
|
||||||
|
op =
|
||||||
|
if rop_hash (rti_outpoint t) ==
|
||||||
|
"\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL"
|
||||||
|
then H.nullOutPoint
|
||||||
|
else H.OutPoint
|
||||||
|
((fromJust .
|
||||||
|
H.hexToTxHash . E.decodeUtf8Lenient . rop_hash . rti_outpoint)
|
||||||
|
t)
|
||||||
|
(rop_n $ rti_outpoint t)
|
||||||
|
|
||||||
|
fromRawTxOut :: RawTxOut -> H.TxOut
|
||||||
|
fromRawTxOut t = H.TxOut (rto_amt t) (rto_script t)
|
||||||
|
|
||||||
|
-- *** Constants for Sapling Human-readable part
|
||||||
sapExtSpendingKeyHrp = "secret-extended-key-main" :: String
|
sapExtSpendingKeyHrp = "secret-extended-key-main" :: String
|
||||||
|
|
||||||
sapExtFullViewingKeyHrp = "zxviews" :: String
|
sapExtFullViewingKeyHrp = "zxviews" :: String
|
||||||
|
@ -117,7 +178,7 @@ sapTestExtFullViewingKeyHrp = "zxviewtestsapling" :: String
|
||||||
|
|
||||||
sapTestPaymentAddressHrp = "ztestsapling" :: String
|
sapTestPaymentAddressHrp = "ztestsapling" :: String
|
||||||
|
|
||||||
-- | Constants for Unified Human-readable part
|
-- *** Constants for Unified Human-readable part
|
||||||
uniPaymentAddressHrp = "u" :: T.Text
|
uniPaymentAddressHrp = "u" :: T.Text
|
||||||
|
|
||||||
uniFullViewingKeyHrp = "uview" :: T.Text
|
uniFullViewingKeyHrp = "uview" :: T.Text
|
||||||
|
@ -130,19 +191,6 @@ uniTestFullViewingKeyHrp = "uviewtest" :: T.Text
|
||||||
|
|
||||||
uniTestIncomingViewingKeyHrp = "uivktest" :: T.Text
|
uniTestIncomingViewingKeyHrp = "uivktest" :: T.Text
|
||||||
|
|
||||||
-- | Function to get the Base58 prefix for encoding a 'TransparentAddress'
|
|
||||||
getTransparentPrefix :: ZcashNet -> TransparentType -> (Word8, Word8)
|
|
||||||
getTransparentPrefix n t =
|
|
||||||
case t of
|
|
||||||
P2SH ->
|
|
||||||
case n of
|
|
||||||
MainNet -> (0x1c, 0xbd)
|
|
||||||
_ -> (0x1c, 0xba)
|
|
||||||
P2PKH ->
|
|
||||||
case n of
|
|
||||||
MainNet -> (0x1c, 0xb8)
|
|
||||||
_ -> (0x1d, 0x25)
|
|
||||||
|
|
||||||
-- * RPC
|
-- * RPC
|
||||||
-- | A type to model Zcash RPC calls
|
-- | A type to model Zcash RPC calls
|
||||||
data RpcCall = RpcCall
|
data RpcCall = RpcCall
|
||||||
|
@ -217,6 +265,42 @@ data RawTxResponse = RawTxResponse
|
||||||
} deriving (Prelude.Show, Eq, Read)
|
} deriving (Prelude.Show, Eq, Read)
|
||||||
|
|
||||||
-- ** `zebrad`
|
-- ** `zebrad`
|
||||||
|
data ZebraTxResponse = ZebraTxResponse
|
||||||
|
{ ztr_blockheight :: !Int
|
||||||
|
, ztr_conf :: !Int
|
||||||
|
, ztr_hex :: !HexString
|
||||||
|
} deriving (Prelude.Show, Eq, Read)
|
||||||
|
|
||||||
|
instance FromJSON ZebraTxResponse where
|
||||||
|
parseJSON =
|
||||||
|
withObject "ZebraTxResponse" $ \obj -> do
|
||||||
|
hex <- obj .: "hex"
|
||||||
|
height <- obj .: "height"
|
||||||
|
c <- obj .: "confirmations"
|
||||||
|
pure $ ZebraTxResponse height c hex
|
||||||
|
|
||||||
|
-- | Type to represent a raw deserialized Zebra transaction
|
||||||
|
data RawZebraTx = RawZebraTx
|
||||||
|
{ zt_id :: !HexString
|
||||||
|
, zt_locktime :: !Word32
|
||||||
|
, zt_expiry :: !Word32
|
||||||
|
, zt_tBundle :: !RawTBundle
|
||||||
|
} deriving stock (Eq, Prelude.Show, GHC.Generic)
|
||||||
|
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
|
||||||
|
deriving anyclass (Data.Structured.Show)
|
||||||
|
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawZebraTx
|
||||||
|
|
||||||
|
-- | Type for a raw deserialized Zebra transparent bundle
|
||||||
|
data RawTBundle = RawTBundle
|
||||||
|
{ ztb_empty :: !Bool
|
||||||
|
, ztb_vin :: ![RawTxIn]
|
||||||
|
, ztb_vout :: ![RawTxOut]
|
||||||
|
, ztb_coinbase :: !Bool
|
||||||
|
} deriving stock (Eq, Prelude.Show, GHC.Generic)
|
||||||
|
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
|
||||||
|
deriving anyclass (Data.Structured.Show)
|
||||||
|
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawTBundle
|
||||||
|
|
||||||
-- | Type for the response from the `zebrad` RPC method `getinfo`
|
-- | Type for the response from the `zebrad` RPC method `getinfo`
|
||||||
data ZebraGetInfo = ZebraGetInfo
|
data ZebraGetInfo = ZebraGetInfo
|
||||||
{ zgi_build :: !T.Text
|
{ zgi_build :: !T.Text
|
||||||
|
@ -268,6 +352,32 @@ data TransparentAddress = TransparentAddress
|
||||||
, ta_bytes :: !HexString
|
, ta_bytes :: !HexString
|
||||||
} deriving (Eq, Prelude.Show, Read)
|
} deriving (Eq, Prelude.Show, Read)
|
||||||
|
|
||||||
|
-- | Wrapper types for transparent elements
|
||||||
|
data RawTxIn = RawTxIn
|
||||||
|
{ rti_outpoint :: !RawOutPoint
|
||||||
|
, rti_script :: !BS.ByteString
|
||||||
|
, rti_seq :: !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 RawTxIn
|
||||||
|
|
||||||
|
data RawTxOut = RawTxOut
|
||||||
|
{ rto_amt :: !Word64
|
||||||
|
, rto_script :: !BS.ByteString
|
||||||
|
} deriving stock (Eq, Prelude.Show, GHC.Generic)
|
||||||
|
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
|
||||||
|
deriving anyclass (Data.Structured.Show)
|
||||||
|
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 =
|
||||||
|
|
|
@ -22,15 +22,15 @@ import C.Zcash
|
||||||
, rustWrapperBech32Encode
|
, rustWrapperBech32Encode
|
||||||
, rustWrapperF4Jumble
|
, rustWrapperF4Jumble
|
||||||
, rustWrapperF4UnJumble
|
, rustWrapperF4UnJumble
|
||||||
|
, rustWrapperTxRead
|
||||||
)
|
)
|
||||||
import Control.Exception (SomeException(..), try)
|
import Control.Exception (SomeException(..), try)
|
||||||
import Control.Monad.IO.Class
|
import Control.Monad.IO.Class
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.Binary.Get
|
import Data.Binary.Get
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import qualified Data.ByteString.Char8 as C
|
|
||||||
import qualified Data.ByteString.Lazy as LBS
|
import qualified Data.ByteString.Lazy as LBS
|
||||||
import Data.HexString
|
import Data.HexString (HexString(..))
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.Encoding as E
|
import qualified Data.Text.Encoding as E
|
||||||
import Foreign.Rust.Marshall.Variable
|
import Foreign.Rust.Marshall.Variable
|
||||||
|
@ -38,13 +38,7 @@ import Network.HTTP.Client (HttpException(..))
|
||||||
import Network.HTTP.Simple
|
import Network.HTTP.Simple
|
||||||
import ZcashHaskell.Types
|
import ZcashHaskell.Types
|
||||||
|
|
||||||
import Foreign.C.Types
|
-- * Utility functions
|
||||||
import Foreign.Marshal.Array (allocaArray, peekArray)
|
|
||||||
import Foreign.Ptr (Ptr)
|
|
||||||
|
|
||||||
import Data.Word
|
|
||||||
|
|
||||||
-- |
|
|
||||||
-- | Decode the given bytestring using Bech32
|
-- | Decode the given bytestring using Bech32
|
||||||
decodeBech32 :: BS.ByteString -> RawData
|
decodeBech32 :: BS.ByteString -> RawData
|
||||||
decodeBech32 = withPureBorshVarBuffer . rustWrapperBech32Decode
|
decodeBech32 = withPureBorshVarBuffer . rustWrapperBech32Decode
|
||||||
|
@ -61,6 +55,7 @@ f4Jumble = withPureBorshVarBuffer . rustWrapperF4Jumble
|
||||||
f4UnJumble :: BS.ByteString -> BS.ByteString
|
f4UnJumble :: BS.ByteString -> BS.ByteString
|
||||||
f4UnJumble = withPureBorshVarBuffer . rustWrapperF4UnJumble
|
f4UnJumble = withPureBorshVarBuffer . rustWrapperF4UnJumble
|
||||||
|
|
||||||
|
-- * Node interaction
|
||||||
-- | Make a Zcash RPC call
|
-- | Make a Zcash RPC call
|
||||||
makeZcashCall ::
|
makeZcashCall ::
|
||||||
(MonadIO m, FromJSON a)
|
(MonadIO m, FromJSON a)
|
||||||
|
@ -112,3 +107,11 @@ getBlockTime hex_block =
|
||||||
fromIntegral $
|
fromIntegral $
|
||||||
runGet getInt32le $
|
runGet getInt32le $
|
||||||
LBS.fromStrict $ BS.take 4 (BS.drop 100 $ hexBytes hex_block)
|
LBS.fromStrict $ BS.take 4 (BS.drop 100 $ hexBytes hex_block)
|
||||||
|
|
||||||
|
readZebraTransaction :: HexString -> Maybe RawZebraTx
|
||||||
|
readZebraTransaction hex =
|
||||||
|
if BS.length (hexBytes $ zt_id rawTx) < 1
|
||||||
|
then Nothing
|
||||||
|
else Just rawTx
|
||||||
|
where
|
||||||
|
rawTx = (withPureBorshVarBuffer . rustWrapperTxRead) $ hexBytes hex
|
||||||
|
|
28
test/Spec.hs
28
test/Spec.hs
|
@ -34,6 +34,7 @@ import qualified Data.Text.Encoding as E
|
||||||
import qualified Data.Text.Lazy.Encoding as LE
|
import qualified Data.Text.Lazy.Encoding as LE
|
||||||
import qualified Data.Text.Lazy.IO as LTIO
|
import qualified Data.Text.Lazy.IO as LTIO
|
||||||
import GHC.Float.RealFracMethods (properFractionDoubleInteger)
|
import GHC.Float.RealFracMethods (properFractionDoubleInteger)
|
||||||
|
import Test.HUnit
|
||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
import Test.Hspec.QuickCheck
|
import Test.Hspec.QuickCheck
|
||||||
import Test.QuickCheck
|
import Test.QuickCheck
|
||||||
|
@ -59,7 +60,12 @@ import ZcashHaskell.Types
|
||||||
, OrchardSpendingKey(..)
|
, OrchardSpendingKey(..)
|
||||||
, Phrase(..)
|
, Phrase(..)
|
||||||
, RawData(..)
|
, RawData(..)
|
||||||
|
, RawOutPoint(..)
|
||||||
|
, RawTBundle(..)
|
||||||
|
, RawTxIn(..)
|
||||||
|
, RawTxOut(..)
|
||||||
, RawTxResponse(..)
|
, RawTxResponse(..)
|
||||||
|
, RawZebraTx(..)
|
||||||
, SaplingReceiver(..)
|
, SaplingReceiver(..)
|
||||||
, SaplingSpendingKey(..)
|
, SaplingSpendingKey(..)
|
||||||
, Scope(..)
|
, Scope(..)
|
||||||
|
@ -71,7 +77,9 @@ import ZcashHaskell.Types
|
||||||
, UnifiedAddress(..)
|
, UnifiedAddress(..)
|
||||||
, UnifiedFullViewingKey(..)
|
, UnifiedFullViewingKey(..)
|
||||||
, ZcashNet(..)
|
, ZcashNet(..)
|
||||||
|
, ZebraTxResponse(..)
|
||||||
, decodeHexText
|
, decodeHexText
|
||||||
|
, fromRawTBundle
|
||||||
, getValue
|
, getValue
|
||||||
)
|
)
|
||||||
import ZcashHaskell.Utils
|
import ZcashHaskell.Utils
|
||||||
|
@ -770,6 +778,26 @@ main = do
|
||||||
let blkdata =
|
let blkdata =
|
||||||
"04000000c732575a3e94b7464c84b35935c2fca26e40d37b6f3278bda3d941877b192a0048cb59da8eeaf9f622d4537ec2a27918415f444d0bb143e8091b470a18a438c117fd96323fd1a9c775ed793154de0e8a2023b551431e89b5ce6f30ef047388f0bdbb0266fe81481f2c006046a8be3bca5b8819209d053a88184bb48753171accb807c38f46d00000fd400500b6a304cbc4e6caecc9b3a29ce42d71752bf5396944e28465e29d1bd7e7f3c680db3c4b85a1488d7c4e21a70c1cf50cfe4e7f70a4f1abb638f144afb90dfa69adfc7c981fd8792df19926da695356699ab76213094431bf6491b80572c310ab8e51c27cda39c771371dbf7adc60089ff5f9614577a92ce3a1e452d5d8280e3d970322e1fc5937c53369623d5e58e57672b48c2edc7a86f7d7de62e06668097547b782a01d3794a50f131695f7de3e4bf038b12abffd29b8eba618820e143ba0be57ccaa67f64511460027efb065c6ddff501376744c6b68ca01d884025e7f939521d230b1a46016d66ad3ab2262dbd477b38bbec234a19425b939dc0f1d868035c3ef99eee635c9dfd62235ede6d62f652fec499127a152e7be4f959a9bb7fcca9b335de98d14aee1330fe37f1ba28be26902a1cddbc3f67f2f6317093d3f278c1c0156e5319a0b35360e38719911b8012a8cc34893f05dc28a22787f3e0461836aef602110e621c8b9d78e991ccc0160deb8c8921f6fd13bd00d47a170b9d0b09ffd57e37467400c138823dce7c12027eb9f919b8d5f4072b331a042f6f5ebb814c6a903110cc97161787d1eb2716c8fb98d747abf321a0b079f3b6a1a0329337b4922a0d739886a03f0d475d41005733f26c675dd9694712d6ee07772a5e8f6b5871789ac14159beced65d3b2196725baa4ce04f059a7034ff0d7ce081e94d23e0115b9d8f0d99fa5b4f9771b4feaac881ac80f178c3575cc70858e40f53f1d0406253edba75e2bb6f40eb2ef4ece3df2b8dadbd3ac168b1743a0cfb68ba81ca4c838435002587852e81e0a0c3c77e11218df892ac0c2f343967b127fbb822712ceabc459ded7f3ca3e95ed5ddfe6cdfe5657da1b12ee47eb63af7a839cdbc1f52f51e349dbf2bd7d8529f814108723d97fcfda7563c4fbe3a24118352e4706f9f91406f11acde3a570e10a258fa6a5415f57a26988249a87e57f192d0408b6f56c2ef65d5e37597d144e8fe1014a4f552dc8c213b0a70b2ccff6747f6f1e0d598715d8cb0da37e0331c01da1f9e0505e9d1907628427d5d032a29fa0e14b75289b10c7d3109b590aec2a4debda9eabcbd3163f6df67efd92687d0c492a71d48b2995a658b34e96814e5674a62e3738efe53e0daf4bfe9d1031e45a246bd3b32c6d581b71c0b60ad711570bca3848c38ba5aed74d977a185d199db721c2677d4868e5afaa6cc2c7369898f58f93738681118d529194d41f0cb6103915d2e99422db387fb90046eae764a79dfe8733a7f68439d0f37e773d16ac7f0ba3a8ce0fd6746d038704b2a0a979659a859682581fee0be3fc50eed13e85e6b52f398d16b59f5f738c1eb289b3861d636b961d9220c1f76bf8a8be3ffd1e2472461202285aa1c5b7eac58564aaab0beedb65e1078517e031888aa3cb8843876aaf19311d5150529a10c9d9bce1538f7533aff126e518ef1ebd919f26aa3869ed1ced167cb1de6075897ad2dc461b9156922c4ee387f8e1635e95564d3964e47d39e6e82079e0220df00614ecd4fd31a5f3d13c9191fc65037ad3cd651f055cc795260f21bb0ba8acd7e3b65b5ff81d5a1b187a777c826f96637e00f8147c4bd43753fe9e0cd73564b53a0e9eab27745505ccd2e4a1a217307c66030ca115580ce6ecb9a8b043ca41bd2de15abd13838d130d3cfecd8d0e3bb6c982bf1f9cdc799c3256e2d722d3f13cd7acdb9d75d7e36483b2ae01e5dcb70db824eadd9c3955d79557d612a879fa6da1da479807640e37bf25a22091f1cf6fb5293e60e5616416fb2adb1d9892258e8ac6859978159338d3b6e2063b9d842a24d61d0616506d5088fe76025df35619febd57f92e30699a0df8731bdbad0775922bb12fb1697d9da833010400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0603204c2a010cffffffff0480b2e60e000000001976a914278aff0c0f8734638ce81aaef4ab0afddd36552888ac286bee000000000017a9140c0bcca02f3cba01a5d7423ac3903d40586399eb8740787d010000000017a91471e1df05024288a00802de81e08c437859586c878738c94d010000000017a91493916098d2a161a91f3ddebab69dd5db9587b6248700000000204c2a000000000000000000000000"
|
"04000000c732575a3e94b7464c84b35935c2fca26e40d37b6f3278bda3d941877b192a0048cb59da8eeaf9f622d4537ec2a27918415f444d0bb143e8091b470a18a438c117fd96323fd1a9c775ed793154de0e8a2023b551431e89b5ce6f30ef047388f0bdbb0266fe81481f2c006046a8be3bca5b8819209d053a88184bb48753171accb807c38f46d00000fd400500b6a304cbc4e6caecc9b3a29ce42d71752bf5396944e28465e29d1bd7e7f3c680db3c4b85a1488d7c4e21a70c1cf50cfe4e7f70a4f1abb638f144afb90dfa69adfc7c981fd8792df19926da695356699ab76213094431bf6491b80572c310ab8e51c27cda39c771371dbf7adc60089ff5f9614577a92ce3a1e452d5d8280e3d970322e1fc5937c53369623d5e58e57672b48c2edc7a86f7d7de62e06668097547b782a01d3794a50f131695f7de3e4bf038b12abffd29b8eba618820e143ba0be57ccaa67f64511460027efb065c6ddff501376744c6b68ca01d884025e7f939521d230b1a46016d66ad3ab2262dbd477b38bbec234a19425b939dc0f1d868035c3ef99eee635c9dfd62235ede6d62f652fec499127a152e7be4f959a9bb7fcca9b335de98d14aee1330fe37f1ba28be26902a1cddbc3f67f2f6317093d3f278c1c0156e5319a0b35360e38719911b8012a8cc34893f05dc28a22787f3e0461836aef602110e621c8b9d78e991ccc0160deb8c8921f6fd13bd00d47a170b9d0b09ffd57e37467400c138823dce7c12027eb9f919b8d5f4072b331a042f6f5ebb814c6a903110cc97161787d1eb2716c8fb98d747abf321a0b079f3b6a1a0329337b4922a0d739886a03f0d475d41005733f26c675dd9694712d6ee07772a5e8f6b5871789ac14159beced65d3b2196725baa4ce04f059a7034ff0d7ce081e94d23e0115b9d8f0d99fa5b4f9771b4feaac881ac80f178c3575cc70858e40f53f1d0406253edba75e2bb6f40eb2ef4ece3df2b8dadbd3ac168b1743a0cfb68ba81ca4c838435002587852e81e0a0c3c77e11218df892ac0c2f343967b127fbb822712ceabc459ded7f3ca3e95ed5ddfe6cdfe5657da1b12ee47eb63af7a839cdbc1f52f51e349dbf2bd7d8529f814108723d97fcfda7563c4fbe3a24118352e4706f9f91406f11acde3a570e10a258fa6a5415f57a26988249a87e57f192d0408b6f56c2ef65d5e37597d144e8fe1014a4f552dc8c213b0a70b2ccff6747f6f1e0d598715d8cb0da37e0331c01da1f9e0505e9d1907628427d5d032a29fa0e14b75289b10c7d3109b590aec2a4debda9eabcbd3163f6df67efd92687d0c492a71d48b2995a658b34e96814e5674a62e3738efe53e0daf4bfe9d1031e45a246bd3b32c6d581b71c0b60ad711570bca3848c38ba5aed74d977a185d199db721c2677d4868e5afaa6cc2c7369898f58f93738681118d529194d41f0cb6103915d2e99422db387fb90046eae764a79dfe8733a7f68439d0f37e773d16ac7f0ba3a8ce0fd6746d038704b2a0a979659a859682581fee0be3fc50eed13e85e6b52f398d16b59f5f738c1eb289b3861d636b961d9220c1f76bf8a8be3ffd1e2472461202285aa1c5b7eac58564aaab0beedb65e1078517e031888aa3cb8843876aaf19311d5150529a10c9d9bce1538f7533aff126e518ef1ebd919f26aa3869ed1ced167cb1de6075897ad2dc461b9156922c4ee387f8e1635e95564d3964e47d39e6e82079e0220df00614ecd4fd31a5f3d13c9191fc65037ad3cd651f055cc795260f21bb0ba8acd7e3b65b5ff81d5a1b187a777c826f96637e00f8147c4bd43753fe9e0cd73564b53a0e9eab27745505ccd2e4a1a217307c66030ca115580ce6ecb9a8b043ca41bd2de15abd13838d130d3cfecd8d0e3bb6c982bf1f9cdc799c3256e2d722d3f13cd7acdb9d75d7e36483b2ae01e5dcb70db824eadd9c3955d79557d612a879fa6da1da479807640e37bf25a22091f1cf6fb5293e60e5616416fb2adb1d9892258e8ac6859978159338d3b6e2063b9d842a24d61d0616506d5088fe76025df35619febd57f92e30699a0df8731bdbad0775922bb12fb1697d9da833010400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0603204c2a010cffffffff0480b2e60e000000001976a914278aff0c0f8734638ce81aaef4ab0afddd36552888ac286bee000000000017a9140c0bcca02f3cba01a5d7423ac3903d40586399eb8740787d010000000017a91471e1df05024288a00802de81e08c437859586c878738c94d010000000017a91493916098d2a161a91f3ddebab69dd5db9587b6248700000000204c2a000000000000000000000000"
|
||||||
getBlockTime (hexString blkdata) `shouldBe` 1711455165
|
getBlockTime (hexString blkdata) `shouldBe` 1711455165
|
||||||
|
it "Raw transaction from faucet" $ do
|
||||||
|
let h =
|
||||||
|
hexString
|
||||||
|
"0400008085202f8900010829d200000000001976a91484ae5002305847e7176362d7c12c19c5bdbbaf8088ac0000000023392a00f02cd200000000000192331caef004cc758fb666bed1908e61daa82d5c9835c0544afd8369589d350b04a7488a9870983860779ca2e0079a286fe71f60d5c583c3427d24ff968bad3246c1c838b90f465becc1ddfea5839b730ec219d577ed182f6da8f493350b422c86943b7c8ff42de8aee0fe01f4b91c8bb204008f06f85c3dffdb622632d2d4e8b8f0c7457cfa0f4238c7ef4c8903a89559e9307c26e844747ccb9b8dd5e7e83637983746b2fec3de051312306eb8b15db4766b3ef5fe3086d53d388cf2b3b209389ff3644e47d6bfdbe2fafef1bc2311093ad0b49f4600925f55328da337e73f01f83097acd8f2aca7a85f28e75fb4efec6551e026a1ebb35c25efde455cc44002bb8cc79288ed738423432558ebb583874aa5c356abe5be794e1bfaeaf6a7eccf67e5d938751a3a351bc21d4422d2ff0f36f5b30759d79b1ef2d83618d9c1769694454002d2f2be74de3ac10d39829369c87a70e1e9769e7d5ae7c865282a04487a8ae4cf5beeecaea6a3be1c864bdd8d61df88f08a76ac49d28a3a069d2c0d02068a10e88674b39c9d03da49256d914319d267c0d1db08ee7777668e90a94c50a065977222ee620f2291f6ca3fa464fafe8fc3fedf64a836eef5a2ca16aaae5573ee082a77f046d388750fa4ce3853c846ae3f338741c7976f72db4ade4abd4211e8d335ec8c83309bc7d7140a99dfb64a29839b9acc74de4ac0949bcbec4e76be9096a45ab6ca19b165f4097e24ab92d7b58694b0897789c3cdcca2b3d4b0a9da153fafe68f940031b6548d3c37c1301faa9adcfc41c417e613c0838340e28801f72610289d7435910fd276ca243d119541e0a121d263fdda149ac40f293e6fee6d5ddc32532ad947548eb5d20a5bfea97543965fe09313f1a5a78ce51ecac9c36b54cb573780da15d197f5ffacf1fa0d2b5495057a29104d610936c1898d1058f6f7b90e614bc2e3ff56b1e75aa4708128e3782f602dbdd29ece268311965592ddd536ea63841ea953b20677e0dd911852d23b85a3382420d22cd276b216e81638540b04966210a9308e8f9fb46958c967e3c2e36ae081a95cec8865a87d85d5689f660fe6c616ebfc2dab0f6e41d3e8c2906405fb98a506d90a8e8c6201d520a0deaa65e92e91f965288128101427d58e0b1e3ad8a49526feed27f3bcc6d505591483e2e4cc4a9b678d63f3abc905f26f91083bc595b89ff0b6cc3caa9d93013127ab7b30fbe18fad6f7f380fd6d5668fb6c3fdea3771fdd3004994e5752275ff7b186f9ad95f9d7ff01263f1165de34c1ae867e8954d66186880a90d73eace4dc1b8b17c76815242342821b4fab93755c3dc24e60aafd1cd3e283a7414de3af18c61328d92e9141916b8bb816de024a5a047a66508340a3287f698a41804e297916ff04f2921a0eeb8fcc5690c7fc024f57ab1fb6c6bc9a0caf9bf9e0e9aad64ceb2634bedbda6716235e4b93b67cd07ae06fde6abd2893143b55628be83fd4b347ce407dabf28e288f99d23b031376bfc1b1552cac1557e4730b03be581a92feae7d39fa2cf1c565a6cbe59a83b64b90ef8fc73ff6f8b9562d77fae1221df8f5ddb029f12ae80c3f128b87e56f78224b875af54a2fa1434749bb2e1c7ad9331497a71015ae0fc63903f36023e7f34b97c6ec5976ba3740845e5870c85f1b2042cdca86620881e08595215332de7d5828844e9e44124e42e1c60f6821cb71640c6643b01681553c932d310632a8b21154445176eb1a9a3c87dff22508bdbe4f1500e19131a072c42ff1d106ade135722a9e37e95e7e93917378e7907aae4be92dab78b1cd5a771d6064f6e3afc26ff84943a84de7f6ca6b0ab5993d1013b061da4053d77398cbeb329a6ae16f76493f85df1164b4f1fdff69bf113c8f18274a4ce6a05dd4c1ccbacb8d2c3760210e312c3a344294b43b23d06b7ce7263d3178e4fd530ba5838dc0e517b7d6fff2a0d9c4d69105a8fdab3f0c51a219c1ec10337b7cf05f8f3b1fb0a09f600308e5c21ae6ae06d6f87a6766d29e3a34f331f520d80524d580bd54b25716b6b937534233b856e022d20e53779b3a4a3615a3d62d1824c2bfa906e7804d629cc6712a3aee8c3703e99ec807cdb2d381acf126d63b83a2ce1d8f5cb768270bf41ae5637976acbaad8a1fa52cfb7a2f012966f3d29867cf2c28e504043a09eeff91917f6e96dc35a7df124074da73a20b87c7c8e2196f344cc08bd4c2406daaf6064488b5f9983131d90141fba82b13b0b1ff60565be66d53c36df3a9b4c772bffd428b34f94060ad32c59c9c029eba5fabd7a01b4e7252406c0ce7bb93c831034b100cc71090b37a436f96ce902973e2dca9594886b602ed6142697413aa448652529fe688a2e62fa96f8031ade066bb2bdc682f0ae3a526c7ad3c5d01e243b999a58aa5f6816dcd7a0cdd49202e128b99436f71e7fb7033bf96d8e3930e39e024530ec4b7932d334e54a66bfc3630b472336b6719d5a38e6e9bed938f71fe49e0af0b20c5db5408cabb3227b1690e904ea3116ee568330f56a5a698b914570962da4d831f5f5acde9acb257d272d0cd14e3133c89307f2d1575e32b8cc1582d1e4a680d35a1a2cace6233dfb4b0a7fea26f41785e1ac6007dd20d8b6dc3bd6857fa487c52b39f86647a67931b33910b746331305199d20ecd2e4d3b454226a134240831ea5a35c1e2d603c48eea209868b839c79a9318b6fd1078bc0f2bb9b0e931b64d63fbbcbf22b41e3cf7bee5cecb3c0e7b3ae39cf736fce8645ab33becbc9586a9154e29dd88f42ec7deecb2a4c08ac020ce54607f8006d2aa05a689ea688419215f0a10043820d85965a0001f102915fa6b2edfc4d6db7011a725db79b3974e9c1fc1636781bc9609359cfb0c5c921b83fc1115f7ed2568e49991ef93f8b8ff93a0d778251f0bcaa00ad64de8438d40aa05adbd1d1d1d2bca05ea9471a2c1a3733e92bcdf896d47dbe41b9f0d8b8b75de1ccd7cd7b7802fc01c4536a1a7b52ce70736e2cdfc547b58401023e34a608c1b09d0f13ab83d7b3fcde0e050c8cb4635508ddc143a9e6edb1e5a489a48ae0f4d5b0cede7d1b0ed8177709edbd61d859f6d9bad93a4c640684b7b8d994d8f5c0c8773da2b7a5b57d28b58d3f00c53430671d4af1537a262e8ea44a1b943c9bfc5082ad86d6690de32bb6527c815da065061bf79562d292e3d4799aa0df968fb939f64203f541dd4d006e5bd0b34b39215a972c36b229fc2f8e7f10e154b369d7b8f85f89daaaba6ec9836ad748dd79be4a58210341a458202a16e152ca2b0338a116a8490a7fa52c02"
|
||||||
|
let t = readZebraTransaction h
|
||||||
|
case t of
|
||||||
|
Nothing -> assertFailure "Couldn't decode"
|
||||||
|
Just t' -> do
|
||||||
|
let tb = zt_tBundle t'
|
||||||
|
fromRawTBundle tb `shouldNotBe` Nothing
|
||||||
|
it "Raw transaction" $ do
|
||||||
|
let h =
|
||||||
|
hexString
|
||||||
|
"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0603204c2a010cffffffff0480b2e60e000000001976a914278aff0c0f8734638ce81aaef4ab0afddd36552888ac286bee000000000017a9140c0bcca02f3cba01a5d7423ac3903d40586399eb8740787d010000000017a91471e1df05024288a00802de81e08c437859586c878738c94d010000000017a91493916098d2a161a91f3ddebab69dd5db9587b6248700000000204c2a000000000000000000000000"
|
||||||
|
let t = readZebraTransaction h
|
||||||
|
case t of
|
||||||
|
Nothing -> assertFailure "Couldn't decode"
|
||||||
|
Just t' -> do
|
||||||
|
let tb = zt_tBundle t'
|
||||||
|
fromRawTBundle tb `shouldNotBe` Nothing
|
||||||
|
|
||||||
-- | Properties
|
-- | Properties
|
||||||
prop_PhraseLength :: Property
|
prop_PhraseLength :: Property
|
||||||
|
|
|
@ -5,7 +5,7 @@ cabal-version: 3.0
|
||||||
-- see: https://github.com/sol/hpack
|
-- see: https://github.com/sol/hpack
|
||||||
|
|
||||||
name: zcash-haskell
|
name: zcash-haskell
|
||||||
version: 0.5.1.0
|
version: 0.5.2.0
|
||||||
synopsis: Utilities to interact with the Zcash blockchain
|
synopsis: Utilities to interact with the Zcash blockchain
|
||||||
description: Please see the README on the repo at <https://git.vergara.tech/Vergara_Tech/zcash-haskell#readme>
|
description: Please see the README on the repo at <https://git.vergara.tech/Vergara_Tech/zcash-haskell#readme>
|
||||||
category: Blockchain
|
category: Blockchain
|
||||||
|
@ -59,6 +59,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
|
||||||
|
@ -76,6 +77,7 @@ test-suite zcash-haskell-test
|
||||||
, haskoin-core
|
, haskoin-core
|
||||||
, hexstring >= 0.12.1
|
, hexstring >= 0.12.1
|
||||||
, hspec
|
, hspec
|
||||||
|
, HUnit
|
||||||
, QuickCheck
|
, QuickCheck
|
||||||
, quickcheck-transformer
|
, quickcheck-transformer
|
||||||
, text
|
, text
|
||||||
|
|
20
zebrablock.json
Normal file
20
zebrablock.json
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"result": {
|
||||||
|
"hash": "0041ee9cb0e256a73c92bb72d830143c402ea350152f56f19f74d23cf51418fb",
|
||||||
|
"confirmations": 3583,
|
||||||
|
"height": 2767099,
|
||||||
|
"tx": [
|
||||||
|
"d169ec3eda57dc750edfc1aa6b8ffb4ed2065780bfd5964de34b529503ec372f",
|
||||||
|
"987fcdb9bd37cbb5b205a8336de60d043f7028bebaa372828d81f3da296c7ef9"
|
||||||
|
],
|
||||||
|
"trees": {
|
||||||
|
"sapling": {
|
||||||
|
"size": 129349
|
||||||
|
},
|
||||||
|
"orchard": {
|
||||||
|
"size": 39382
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": 123
|
||||||
|
}
|
4
zebrahexblock.json
Normal file
4
zebrahexblock.json
Normal file
File diff suppressed because one or more lines are too long
8
zebratx.json
Normal file
8
zebratx.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"result": {
|
||||||
|
"hex": "0400008085202f8900010829d200000000001976a91484ae5002305847e7176362d7c12c19c5bdbbaf8088ac0000000023392a00f02cd200000000000192331caef004cc758fb666bed1908e61daa82d5c9835c0544afd8369589d350b04a7488a9870983860779ca2e0079a286fe71f60d5c583c3427d24ff968bad3246c1c838b90f465becc1ddfea5839b730ec219d577ed182f6da8f493350b422c86943b7c8ff42de8aee0fe01f4b91c8bb204008f06f85c3dffdb622632d2d4e8b8f0c7457cfa0f4238c7ef4c8903a89559e9307c26e844747ccb9b8dd5e7e83637983746b2fec3de051312306eb8b15db4766b3ef5fe3086d53d388cf2b3b209389ff3644e47d6bfdbe2fafef1bc2311093ad0b49f4600925f55328da337e73f01f83097acd8f2aca7a85f28e75fb4efec6551e026a1ebb35c25efde455cc44002bb8cc79288ed738423432558ebb583874aa5c356abe5be794e1bfaeaf6a7eccf67e5d938751a3a351bc21d4422d2ff0f36f5b30759d79b1ef2d83618d9c1769694454002d2f2be74de3ac10d39829369c87a70e1e9769e7d5ae7c865282a04487a8ae4cf5beeecaea6a3be1c864bdd8d61df88f08a76ac49d28a3a069d2c0d02068a10e88674b39c9d03da49256d914319d267c0d1db08ee7777668e90a94c50a065977222ee620f2291f6ca3fa464fafe8fc3fedf64a836eef5a2ca16aaae5573ee082a77f046d388750fa4ce3853c846ae3f338741c7976f72db4ade4abd4211e8d335ec8c83309bc7d7140a99dfb64a29839b9acc74de4ac0949bcbec4e76be9096a45ab6ca19b165f4097e24ab92d7b58694b0897789c3cdcca2b3d4b0a9da153fafe68f940031b6548d3c37c1301faa9adcfc41c417e613c0838340e28801f72610289d7435910fd276ca243d119541e0a121d263fdda149ac40f293e6fee6d5ddc32532ad947548eb5d20a5bfea97543965fe09313f1a5a78ce51ecac9c36b54cb573780da15d197f5ffacf1fa0d2b5495057a29104d610936c1898d1058f6f7b90e614bc2e3ff56b1e75aa4708128e3782f602dbdd29ece268311965592ddd536ea63841ea953b20677e0dd911852d23b85a3382420d22cd276b216e81638540b04966210a9308e8f9fb46958c967e3c2e36ae081a95cec8865a87d85d5689f660fe6c616ebfc2dab0f6e41d3e8c2906405fb98a506d90a8e8c6201d520a0deaa65e92e91f965288128101427d58e0b1e3ad8a49526feed27f3bcc6d505591483e2e4cc4a9b678d63f3abc905f26f91083bc595b89ff0b6cc3caa9d93013127ab7b30fbe18fad6f7f380fd6d5668fb6c3fdea3771fdd3004994e5752275ff7b186f9ad95f9d7ff01263f1165de34c1ae867e8954d66186880a90d73eace4dc1b8b17c76815242342821b4fab93755c3dc24e60aafd1cd3e283a7414de3af18c61328d92e9141916b8bb816de024a5a047a66508340a3287f698a41804e297916ff04f2921a0eeb8fcc5690c7fc024f57ab1fb6c6bc9a0caf9bf9e0e9aad64ceb2634bedbda6716235e4b93b67cd07ae06fde6abd2893143b55628be83fd4b347ce407dabf28e288f99d23b031376bfc1b1552cac1557e4730b03be581a92feae7d39fa2cf1c565a6cbe59a83b64b90ef8fc73ff6f8b9562d77fae1221df8f5ddb029f12ae80c3f128b87e56f78224b875af54a2fa1434749bb2e1c7ad9331497a71015ae0fc63903f36023e7f34b97c6ec5976ba3740845e5870c85f1b2042cdca86620881e08595215332de7d5828844e9e44124e42e1c60f6821cb71640c6643b01681553c932d310632a8b21154445176eb1a9a3c87dff22508bdbe4f1500e19131a072c42ff1d106ade135722a9e37e95e7e93917378e7907aae4be92dab78b1cd5a771d6064f6e3afc26ff84943a84de7f6ca6b0ab5993d1013b061da4053d77398cbeb329a6ae16f76493f85df1164b4f1fdff69bf113c8f18274a4ce6a05dd4c1ccbacb8d2c3760210e312c3a344294b43b23d06b7ce7263d3178e4fd530ba5838dc0e517b7d6fff2a0d9c4d69105a8fdab3f0c51a219c1ec10337b7cf05f8f3b1fb0a09f600308e5c21ae6ae06d6f87a6766d29e3a34f331f520d80524d580bd54b25716b6b937534233b856e022d20e53779b3a4a3615a3d62d1824c2bfa906e7804d629cc6712a3aee8c3703e99ec807cdb2d381acf126d63b83a2ce1d8f5cb768270bf41ae5637976acbaad8a1fa52cfb7a2f012966f3d29867cf2c28e504043a09eeff91917f6e96dc35a7df124074da73a20b87c7c8e2196f344cc08bd4c2406daaf6064488b5f9983131d90141fba82b13b0b1ff60565be66d53c36df3a9b4c772bffd428b34f94060ad32c59c9c029eba5fabd7a01b4e7252406c0ce7bb93c831034b100cc71090b37a436f96ce902973e2dca9594886b602ed6142697413aa448652529fe688a2e62fa96f8031ade066bb2bdc682f0ae3a526c7ad3c5d01e243b999a58aa5f6816dcd7a0cdd49202e128b99436f71e7fb7033bf96d8e3930e39e024530ec4b7932d334e54a66bfc3630b472336b6719d5a38e6e9bed938f71fe49e0af0b20c5db5408cabb3227b1690e904ea3116ee568330f56a5a698b914570962da4d831f5f5acde9acb257d272d0cd14e3133c89307f2d1575e32b8cc1582d1e4a680d35a1a2cace6233dfb4b0a7fea26f41785e1ac6007dd20d8b6dc3bd6857fa487c52b39f86647a67931b33910b746331305199d20ecd2e4d3b454226a134240831ea5a35c1e2d603c48eea209868b839c79a9318b6fd1078bc0f2bb9b0e931b64d63fbbcbf22b41e3cf7bee5cecb3c0e7b3ae39cf736fce8645ab33becbc9586a9154e29dd88f42ec7deecb2a4c08ac020ce54607f8006d2aa05a689ea688419215f0a10043820d85965a0001f102915fa6b2edfc4d6db7011a725db79b3974e9c1fc1636781bc9609359cfb0c5c921b83fc1115f7ed2568e49991ef93f8b8ff93a0d778251f0bcaa00ad64de8438d40aa05adbd1d1d1d2bca05ea9471a2c1a3733e92bcdf896d47dbe41b9f0d8b8b75de1ccd7cd7b7802fc01c4536a1a7b52ce70736e2cdfc547b58401023e34a608c1b09d0f13ab83d7b3fcde0e050c8cb4635508ddc143a9e6edb1e5a489a48ae0f4d5b0cede7d1b0ed8177709edbd61d859f6d9bad93a4c640684b7b8d994d8f5c0c8773da2b7a5b57d28b58d3f00c53430671d4af1537a262e8ea44a1b943c9bfc5082ad86d6690de32bb6527c815da065061bf79562d292e3d4799aa0df968fb939f64203f541dd4d006e5bd0b34b39215a972c36b229fc2f8e7f10e154b369d7b8f85f89daaaba6ec9836ad748dd79be4a58210341a458202a16e152ca2b0338a116a8490a7fa52c02",
|
||||||
|
"height": 2767099,
|
||||||
|
"confirmations": 3582
|
||||||
|
},
|
||||||
|
"id": 123
|
||||||
|
}
|
Loading…
Reference in a new issue