zcash-haskell/test/Spec.hs

947 lines
85 KiB
Haskell

{- Copyright 2022-2024 Vergara Technologies LLC
This file is part of Zcash-Haskell.
Zcash-Haskell is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.
Zcash-Haskell is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License along with
Zcash-Haskell. If not, see <https://www.gnu.org/licenses/>.
-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeSynonymInstances #-}
import C.Zcash (rustWrapperUADecode)
import Control.Exception (throwIO)
import Control.Monad.IO.Class (liftIO)
import Data.Aeson
import Data.Bool (Bool(True))
import qualified Data.ByteString as BS
import Data.Either (isRight)
import Data.Foldable (sequenceA_)
import Data.HexString
import Data.Maybe
import qualified Data.Text as T
import qualified Data.Text.Encoding as E
import qualified Data.Text.Lazy.Encoding as LE
import qualified Data.Text.Lazy.IO as LTIO
import Data.Word
import Foreign.C.Types
import GHC.Float.RealFracMethods (properFractionDoubleInteger)
import Haskoin.Crypto.Hash (ripemd160)
import Haskoin.Crypto.Keys.Extended
import Haskoin.Transaction.Common
import Test.HUnit
import Test.Hspec
import Test.Hspec.QuickCheck
import Test.QuickCheck
import ZcashHaskell.Keys (generateWalletSeedPhrase, getWalletSeed)
import ZcashHaskell.Orchard
import ZcashHaskell.Sapling
( decodeSaplingOutput
, genSaplingInternalAddress
, genSaplingPaymentAddress
, genSaplingSpendingKey
, getShieldedOutputs
, isValidSaplingViewingKey
, isValidShieldedAddress
, matchSaplingAddress
)
import ZcashHaskell.Transparent
import ZcashHaskell.Types
( AccountId
, BlockResponse(..)
, CoinType(..)
, DecodedNote(..)
, OrchardAction(..)
, OrchardSpendingKey(..)
, Phrase(..)
, RawData(..)
, RawOutPoint(..)
, RawTBundle(..)
, RawTxIn(..)
, RawTxOut(..)
, RawTxResponse(..)
, RawZebraTx(..)
, SaplingReceiver(..)
, SaplingSpendingKey(..)
, Scope(..)
, Seed(..)
, ShieldedOutput(..)
, ToBytes(..)
, TransparentAddress(..)
, TransparentBundle(..)
, TransparentType(..)
, UnifiedAddress(..)
, UnifiedFullViewingKey(..)
, ZcashNet(..)
, ZebraTxResponse(..)
, decodeHexText
, fromRawOBundle
, fromRawSBundle
, fromRawTBundle
, getValue
)
import ZcashHaskell.Utils
m2bs :: Maybe BS.ByteString -> BS.ByteString
m2bs x = fromMaybe "" x
main :: IO ()
main = do
hspec $ do
describe "Bech32" $ do
let s = "abc14w46h2at4w46h2at4w46h2at4w46h2at958ngu"
let decodedString = decodeBech32 s
it "hrp matches" $ do hrp decodedString `shouldBe` "abc"
xit "data matches" $ do
bytes decodedString `shouldBe` BS.pack ([0x00, 0x01, 0x02] :: [Word8])
it "encoding works" $ do
encodeBech32m "abc" (bytes decodedString) `shouldBe`
E.decodeUtf8Lenient s
describe "F4Jumble" $ do
it "jumble a string" $ do
let input =
[ 0x5d
, 0x7a
, 0x8f
, 0x73
, 0x9a
, 0x2d
, 0x9e
, 0x94
, 0x5b
, 0x0c
, 0xe1
, 0x52
, 0xa8
, 0x04
, 0x9e
, 0x29
, 0x4c
, 0x4d
, 0x6e
, 0x66
, 0xb1
, 0x64
, 0x93
, 0x9d
, 0xaf
, 0xfa
, 0x2e
, 0xf6
, 0xee
, 0x69
, 0x21
, 0x48
, 0x1c
, 0xdd
, 0x86
, 0xb3
, 0xcc
, 0x43
, 0x18
, 0xd9
, 0x61
, 0x4f
, 0xc8
, 0x20
, 0x90
, 0x5d
, 0x04
, 0x2b
] :: [Word8]
let out =
[ 0x03
, 0x04
, 0xd0
, 0x29
, 0x14
, 0x1b
, 0x99
, 0x5d
, 0xa5
, 0x38
, 0x7c
, 0x12
, 0x59
, 0x70
, 0x67
, 0x35
, 0x04
, 0xd6
, 0xc7
, 0x64
, 0xd9
, 0x1e
, 0xa6
, 0xc0
, 0x82
, 0x12
, 0x37
, 0x70
, 0xc7
, 0x13
, 0x9c
, 0xcd
, 0x88
, 0xee
, 0x27
, 0x36
, 0x8c
, 0xd0
, 0xc0
, 0x92
, 0x1a
, 0x04
, 0x44
, 0xc8
, 0xe5
, 0x85
, 0x8d
, 0x22
] :: [Word8]
BS.pack out `shouldBe` f4Jumble (BS.pack input)
it "unjumble a string" $ do
let input =
[ 0x5d
, 0x7a
, 0x8f
, 0x73
, 0x9a
, 0x2d
, 0x9e
, 0x94
, 0x5b
, 0x0c
, 0xe1
, 0x52
, 0xa8
, 0x04
, 0x9e
, 0x29
, 0x4c
, 0x4d
, 0x6e
, 0x66
, 0xb1
, 0x64
, 0x93
, 0x9d
, 0xaf
, 0xfa
, 0x2e
, 0xf6
, 0xee
, 0x69
, 0x21
, 0x48
, 0x1c
, 0xdd
, 0x86
, 0xb3
, 0xcc
, 0x43
, 0x18
, 0xd9
, 0x61
, 0x4f
, 0xc8
, 0x20
, 0x90
, 0x5d
, 0x04
, 0x2b
] :: [Word8]
let out =
[ 0x03
, 0x04
, 0xd0
, 0x29
, 0x14
, 0x1b
, 0x99
, 0x5d
, 0xa5
, 0x38
, 0x7c
, 0x12
, 0x59
, 0x70
, 0x67
, 0x35
, 0x04
, 0xd6
, 0xc7
, 0x64
, 0xd9
, 0x1e
, 0xa6
, 0xc0
, 0x82
, 0x12
, 0x37
, 0x70
, 0xc7
, 0x13
, 0x9c
, 0xcd
, 0x88
, 0xee
, 0x27
, 0x36
, 0x8c
, 0xd0
, 0xc0
, 0x92
, 0x1a
, 0x04
, 0x44
, 0xc8
, 0xe5
, 0x85
, 0x8d
, 0x22
] :: [Word8]
f4UnJumble (BS.pack out) `shouldBe` BS.pack input
describe "JSON parsing" $ do
it "block response" $ do
j <- LTIO.readFile "block.json"
let p = eitherDecode $ LE.encodeUtf8 j :: Either String BlockResponse
case p of
Left s -> s `shouldBe` ""
Right x -> bl_height x `shouldBe` 2196277
it "raw transaction response" $ do
j <- LTIO.readFile "tx.json"
let t = eitherDecode $ LE.encodeUtf8 j :: Either String RawTxResponse
case t of
Left s -> s `shouldBe` ""
Right x ->
toText (rt_id x) `shouldBe`
"5242b51f22a7d6fe9dee237137271cde704d306a5fff6a862bffaebb6f0e7e56"
describe "Seeds" $ do
it "generate seed phrase" $ do
s <- generateWalletSeedPhrase
BS.length (getBytes s) `shouldNotBe` 0
it "get seed from phrase" $ do
s <- generateWalletSeedPhrase
let x = getWalletSeed s
let result =
case x of
Nothing -> False
Just s' -> True
result `shouldBe` True
describe "Sapling address" $ do
it "succeeds with valid address" $ do
let sa =
"zs17faa6l5ma55s55exq9rnr32tu0wl8nmqg7xp3e6tz0m5ajn2a6yxlc09t03mqdmvyphavvf3sl8"
isValidShieldedAddress sa `shouldBe` True
it "fails with invalid address" $ do
let sa =
"zs17faa6l5ma55s55exq9rnr32tu0wl8nmqg7xp3e6tz0m5ajn2a6yxlc09t03mqdmvyphavvffake"
isValidShieldedAddress sa `shouldBe` False
describe "Decode Sapling VK" $ do
let vk =
"zxviews1qdjagrrpqqqqpq8es75mlu6rref0qyrstchf8dxzeygtsejwfqu8ckhwl2qj5m8am7lmupxk3vkvdjm8pawjpmesjfapvsqw96pa46c2z0kk7letrxf7mkltwz54fwpxc7kc79mm5kce3rwn5ssl009zwsra2spppwgrx25s9k5hq65f69l4jz2tjmqgy0pl49qmtaj3nudk6wglwe2hpa327hydlchtyq9av6wjd6hu68e04ahwk9a9n2kt0kj3nj99nue65awtu5cwwcpjs"
let sa =
"zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
let sa' =
"zs17faa6l5ma55s55exq9rnr32tu0wl8nmqg7xp3e6tz0m5ajn2a6yxlc09t03mqdmvyphavvf3sl8"
let rawKey = decodeBech32 vk
let rawSa = decodeBech32 sa
let rawSa' = decodeBech32 sa'
it "is mainnet" $ do hrp rawKey `shouldBe` "zxviews"
it "is valid Sapling extended full viewing key" $ do
isValidSaplingViewingKey vk `shouldBe` True
it "matches the right Sapling address" $ do
matchSaplingAddress (bytes rawKey) (bytes rawSa) `shouldBe` True
it "doesn't match the wrong Sapling address" $ do
matchSaplingAddress (bytes rawKey) (bytes rawSa') `shouldBe` False
describe "Decode invalid Sapling VK" $ do
let vk =
"zxviews1qdjagrrpqqqqpq8es75mlu6rref0qyrstchf8dxzeygtsejwfqu8ckhwl2qj5m8am7lmupxk3vkvdjm8pawjpmesjfapvsqw96pa46c2z0kk7letrxf7mkltwz54fwpxc7kc79mm5kce3rwn5ssl009zwsra2spppwgrx25s9k5hq65f69l4jz2tjmqgy0pl49qmtaj3nudk6wglwe2hpa327hydlchtyq9av6wjd6hu68e04ahwk9a9n2kt0kj3nj99nue65awtu5cwwfake"
let rawKey = decodeBech32 vk
it "is not mainnet" $ do hrp rawKey `shouldBe` "fail"
describe "Unified address" $ do
it "succeeds with correct UA" $ do
let ua =
"u1salpdyefywvsg2dlmxg9589yznh0h9v6qjr478k80amtkqkws5pr408lxt2953dpprvu06mahxt99cv65fgsm7sw8hlchplfg5pl89ur"
isJust (isValidUnifiedAddress ua) `shouldBe` True
it "fails with incorrect UA" $ do
let ua =
"u1salpdyefbreakingtheaddressh0h9v6qjr478k80amtkqkws5pr408lxt2953dpprvu06mahxt99cv65fgsm7sw8hlchplfg5pl89ur"
isValidUnifiedAddress ua `shouldBe` Nothing
it "encodes UA correctly" $ do
let ua =
"u1salpdyefywvsg2dlmxg9589yznh0h9v6qjr478k80amtkqkws5pr408lxt2953dpprvu06mahxt99cv65fgsm7sw8hlchplfg5pl89ur"
(encodeUnifiedAddress <$> isValidUnifiedAddress ua) `shouldBe`
Just (E.decodeUtf8Lenient ua)
describe "Decode UVK from YWallet" $ do
let uvk =
"uview1u833rp8yykd7h4druwht6xp6k8krle45fx8hqsw6vzw63n24atxpcatws82z092kryazuu6d7rayyut8m36wm4wpjy2z8r9hj48fx5pf49gw4sjrq8503qpz3vqj5hg0vg9vsqeasg5qjuyh94uyfm7v76udqcm2m0wfc25hcyqswcn56xxduq3xkgxkr0l73cjy88fdvf90eq5fda9g6x7yv7d0uckpevxg6540wc76xrc4axxvlt03ptaa2a0rektglmdy68656f3uzcdgqqyu0t7wk5cvwghyyvgqc0rp3vgu5ye4nd236ml57rjh083a2755qemf6dk6pw0qrnfm7246s8eg2hhzkzpf9h73chhng7xhmyem2sjh8rs2m9nhfcslsgenm"
let res = decodeUfvk uvk
it "is mainnet" $ do maybe 0 net res `shouldBe` 1
it "has Orchard key" $ do BS.length (maybe "" o_key res) `shouldBe` 96
it "has Sapling key" $ do BS.length (maybe "" s_key res) `shouldBe` 128
it "does not have Transparent key" $ do
BS.length (maybe "" t_key res) `shouldBe` 1
describe "Decode bad UVK" $ do
it "should fail" $ do
let fakeUvk =
"uview1u83changinga987bundchofch4ract3r5x8hqsw6vzw63n24atxpcatws82z092kryazuu6d7rayyut8m36wm4wpjy2z8r9hj48fx5pf49gw4sjrq8503qpz3vqj5hg0vg9vsqeasg5qjuyh94uyfm7v76udqcm2m0wfc25hcyqswcn56xxduq3xkgxkr0l73cjy88fdvf90eq5fda9g6x7yv7d0uckpevxg6540wc76xrc4axxvlt03ptaa2a0rektglmdy68656f3uzcdgqqyu0t7wk5cvwghyyvgqc0rp3vgu5ye4nd236ml57rjh083a2755qemf6dk6pw0qrnfm7246s8eg2hhzkzpf9h73chhng7xhmyem2sjh8rs2m9nhfcslsgenm"
decodeUfvk fakeUvk `shouldBe` Nothing
describe "Check if UA and UVK match" $ do
let ua =
"u15hjz9v46azzmdept050heh8795qxzwy2pykg097lg69jpk4qzah90cj2q4amq0c07gta60x8qgw00qewcy3hg9kv9h6zjkh3jc66vr40u6uu2dxmqkqhypud95vm0gq7y5ga7c8psdqgthsrwvgd676a2pavpcd4euwwapgackxa3qhvga0wnl0k6vncskxlq94vqwjd7zepy3qd5jh"
let ua' =
"u17n7hpwaujyq7ux8f9jpyymtnk5urw7pyrf60smp5mawy7jgz325hfvz3jn3zsfya8yxryf9q7ldk8nu8df0emra5wne28zq9d9nm2pu4x6qwjha565av9aze0xgujgslz74ufkj0c0cylqwjyrh9msjfh7jzal6d3qzrnhkkqy3pqm8j63y07jxj7txqeac982778rmt64f32aum94x"
let uvk =
"uview1u833rp8yykd7h4druwht6xp6k8krle45fx8hqsw6vzw63n24atxpcatws82z092kryazuu6d7rayyut8m36wm4wpjy2z8r9hj48fx5pf49gw4sjrq8503qpz3vqj5hg0vg9vsqeasg5qjuyh94uyfm7v76udqcm2m0wfc25hcyqswcn56xxduq3xkgxkr0l73cjy88fdvf90eq5fda9g6x7yv7d0uckpevxg6540wc76xrc4axxvlt03ptaa2a0rektglmdy68656f3uzcdgqqyu0t7wk5cvwghyyvgqc0rp3vgu5ye4nd236ml57rjh083a2755qemf6dk6pw0qrnfm7246s8eg2hhzkzpf9h73chhng7xhmyem2sjh8rs2m9nhfcslsgenm"
it "succeeds with correct address" $ do
matchOrchardAddress uvk ua `shouldBe` True
it "fails with wrong address" $ do
matchOrchardAddress uvk ua' `shouldBe` False
describe "Decode Sapling tx" $ do
let svk =
"zxviews1qvapd723qqqqpqq09ldgykvyusthmkky2w062esx5xg3nz4m29qxcvndyx6grrhrdepu4ns88sjr3u6mfp2hhwj5hfd6y24r0f64uwq65vjrmsh9mr568kenk33fcumag6djcjywkm5v295egjuk3qdd47atprs0j33nhaaqep3uqspzp5kg4mthugvug0sc3gc83atkrgmguw9g7gkvh82tugrntf66lnvyeh6ufh4j2xt0xr2r4zujtm3qvrmd3vvnulycuwqtetg2jk384"
let badvk =
"zxviews1qvapd723ffakeqq09ldgykvyusthmkky2w062esx5xg3nz4m29qxcvndyx6grrhrdepu4ns88sjr3u6mfp2hhwj5hfd6y24r0f64uwq65vjrmsh9mr568kenk33fcumag6djcjywkm5v295egjuk3qdd47atprs0j33nhaaqep3uqspzp5kg4mthugvug0sc3gc83atkrgmguw9g7gkvh82tugrntf66lnvyeh6ufh4j2xt0xr2r4zujtm3qvrmd3vvnulycuwqtetg2jk384"
let rawKey = decodeBech32 svk
let badKey = decodeBech32 badvk
let rawTx =
fromText
"050000800a27a726b4d0d6c200000000ff8e210000000001146cc65bd6d252d09b8eb0a8ab0aab6d7a798325aefc1d3032fc6d31373a85a25a3a16b447a698f720ade1bc290a74d85574b5b20515391035a67f8d5883dc65ea3ba4a17b009d6f325d41072b3ce240270959a7ffd040e5f16c697d8148973c62ffe037fc83aded21e4c91722b52520a2395c23e9c1a896f4b0f12d32ae8e31833d9d95adae40f6ecf7aff52af184efd390a4c1aa76b5fb1cab6003b1a8a004016f385926661f56d38273ec2c3df7775210310a65fff5fa9ac5509f0784eefea28bdcc67b0ff69eef930335f3b9768529e2bfe733024492101f642f989de8cbf04dd66638e9317780bce47085079675b772664c8007e96597dba83ea9af22ddf07ff1c212983d4a902914431245357527294e69ea5616e720ef1e9215bbfa33ba108b8d07efff2bad1850525d7725c681761c9b8c844a5548afabf176863de7b4cde3901defc3e83d31086d3c6e6af9a5fcc3cfb38b52ac7de84f91df5e0587f7603773401a62eeef10cd3ccf4d927ef42402c32f32280abbeaac33e73ceda52089820a186e9a1adfea81453998c6bbaa0deb41bc4f94586bfee80bad25fc71abe7c6dd44bcb1a6929a0112c7e4f8fcadb9745bde9422b954f72954c4d22db48719de61f383d620935b647337f73d119d79fd208e1d5a92f0855447df5782cd4764ba91efa65d9e4ebaa34e2eccb7aac93a5b0efe0c7664f3cd9384b3ff706ad3019c907cdcfa084351c9f6a0bfa8c78c91272ca66ac86dd6e1d0d6ba9704ea7dc54f71a053dce91f844c1ca62b5ddfe6b53834f4a816b1b01460810d9b87517659f4915adf4b84783a60ecf3bd71569259f1ff90a91a0b314bd4c77976d7893bf42e5d6ad0f8df95eb6d6c69d41490be8e39b2452df3bebfc297d5b0fc97f081890390fb0727a96898585f0120a7da9a798f2032590553f724d8756c67c5b0d1c0d23301c4ed60fa283994fd712aab17ca6360256fd5aef0ebc48f0256e3eda5894b53981d0d46768aefdc85b48c1525b7f134dce5d4ec2d76c03c821513f1652d9671219d744bdce5e69b9a74ca0c7c837668f0d8ffffffffffff9534b3d594e1609b3bace18608750b35a066c57f85e291d194400cb351430bbbe212abba32be071e747b7310863bd5fd989855a6567a351b288144b6e9f838c6a517db94673246ef0010b65f9c0be8aca654f6f57b83d893663cfd389ab96ce50e8077fe588c16b1b5989c6cc262e6658efb9b88ac800e49e9e5999e2651b8fff28fa77071d63790df155ed8344e2581ac5205b31d4f17bd748fcf60e35a9d6048d23c94c7aca8d4e541fda497aa268df9c173af5877a5da56d8fa2a42166900c734b62e56792f6c8bed48e4f108a817e83d64d6a59e38cfdb55c0f8a89bc7507c89326266f7ac03a3941f448cb879bd792bb116d0be8876c0856a76ddec0f0c02e16f0338626013ee5f6037fc6a3c69fa291204039d04d17c11295ee3024aea8f5d381e9b7eb3f938b6f9182bf4f889f1e53e30f998b1cdd23f45cfaa20aaef058248cc2e1c487fcdf54a4bc22a68a17cb6fa7b2fbf333b99feb84643d321398b675634929602126b2fb40171e514769bf82f18c267ce9cda0c24300caa9a5a361144d3b7b9ab2243ee9811d9b2e72c8bb1d145cdfcf6b29994a969b41c47208f5dba8d6d871e490e9b970afec4d8bca40ba51825cdc78cc7cde6b6f235a4105b1d1b5e2765efd753095ce770f070b02cce3316721b9345680c146c2f428c0bbca90d5a8cd0a1c4c31cbfa8ec165ea9f9c71d2d05e3cf8bae5e779786f179c45a3cd8087d820cae812aded04f8acda9068af80ea834f79f1bd03bfd66f8a19074649a85ce877df1a621a867debb423ec0d19015b326fcf6f143aba34029c1da2fc7b099378a366c38c9609ef6a9d9e175e21b0c1ab94a84e28ee7f1a00e39cb6fb59f44e4567e9f85f8f98158263c52ec433c042397c784edb07c28d2bca036f59090e819157375d610acb1993a4107b48da13a371f5383429baee209b2c0cc150fcef79a042749668ba1f89ad24a8c746142191ed0e8fd63624a331d98d50daa84ccf9043076947cf5115b9f8787acd36000c5e72c8d783b29bb28a3e46036d0a592ce8a158ee5a7ac210be72d3a6185c13645d96a8446021b64043ab8b589a20091c152e7d5a993ba94770eea988e289e1536d0d81dbc7046ca9c6d918446bf970894f073c920006681ccf6d1a3f138519c68eba0296069e42dc60f2bcd0f17c400efe4f4e87de8606606dc4fdf31494df4d454d14a440b1d9db4265c7aa9bc8683c68cb149f2cc826427575e2af82e842199a9cb9fdc7243b3bc12f1a71c37eac5cf88ba830cb95728897fa4c177a290d6b2b3814173262da14db9b4ef39fc54f888a6ffef4221ae672fb03bc78ebef479360a682ddb12ea0369a428a6c2960ff8327e9a2f5e5d98ce1eae748db8f6a4631c789b4d751d6b99c97c149a813998d44a7b57ba06c8bcb8a6c73c6388cdcfeb1346cec8fee7bdebf2a2388d9722183eb2d2e0e183cdd092152ef640880f4514f3c5e836cc3a8249413500630aa8da85f9e3cd92bdadbb69a2bab8d71f0b3ec5832a7ddbddd67b34c33b2e12a0c8468e852e4a8f7df45657e9632088aa7c6c5048a2686019cfec33b27fc88e23759938dd55a5dff589c1c21a37da617609e9d8be37dbf9bd6e84ee160fe10268171d969e4611afe9d3482ed4b132dcdd11ee516f36d512a333da20266fd984caebf4937fdfd18ed07b4a45771cf5c8c16c6b258b289a07d136a22acc766011f366c420bafb8fc1a10e42219bede5a3d1166c525491ab60bbd1f973fd3fb2e94cea888e24d5fb0adce51faeda75d62de70094d4b36d38d03cd824d284fad577c3ead4d98bcc8ceccd18174a889b22380bfcc12656e764ea0b8fe1409971283008ed02cbef89d6f544c62c3b001bfe96723fda9190deecba534d69cfa358036fdaf16127b89f925c52d4e750919ffb7182b6a8ad13d0a8e00e0b906978dd24ee11869c1a63837a80e46e1216e2e273aba07aa5b0d97558db0ba7f9ac4c89403c65f1719394e479311f5cf84746e6be6f1abcac03194aa8bf1735811198b5df90dd6cac345779c185c24beda0101b932048dc4144af664a63acc0c395052882ee1f18bd0ddf13bb583861923bc00ed5ae815b964698ca097eda1c4281e039139fa3091890244f926cc4ab773ca8a35d5263d3bb48fd6ac53a4bb4d7d60b36446dbc714c35b5e13a17c5b0c70f67207839d1f7404604aff63b2fa83a4da7dac92aac96b3f250412f8d04a9e298004313b02edefd076c67d8a1316355777814e2e1ab03690e426b672d32ff65c03c592ecce6a70e34fea2e15b9a6b4fd092d027199caf27e84e25c09380b38a5eb8985355b3259aa1d94be74269b84f953053b02ba3be9df872ae5fb2d893188575bdfe222ba267b5461a0d0be274a7d9e6ee51490d98e4cd97978804c4f0f8e9f4908fd8c102b01080f5a02b7578591e95d60f3f56d8e48514b1ce7ea6894f55a32c8ac8564985d18c6b82f8dcde5b315624e9321bdd49dd350c87907cc373c0238a79321e6250e38a0ceb2c060ecee6708c11cb30a49687da9923bcdf011f9aca27e6eb5a8477a2bae2dcff9884cc2349b51a66b5179ed2d8f69e4bbba74c694194e83d04a8566228227eb732a95180c6788483d1f259d52c52fe43357656d50a1cf2902c3124d60d15fc85f0447a1203f824c1106452cfec1c92b18de003f82a0000000000001cbd27436a221a53d08c4838831d1bc60ff7e93df41a51412ef6096eec98bb28fd601c53a5371b23a497062635b5cdde715c23840d37f1cf328f0a2ba96260357689ae3f84a80dbdca1520df68513be1285177d3c0da664c64944de78d8b8d5864f5ac15444cd3204adc4fe487503066c18fbbef8d0515248b0a97577f5aea1d255788ed4bb66d4d56303efe135063392c312b4671963daa20e0ade262984e11263a1588eba3cf829e6131ab506e6a850aacce603e8ecfd6e794c90a772603d80fd2aad6027b34854072a0d23079252adb1ba637bbc650ed4afd35d977e1498d998020bc1c814718b48ba7378a92c56827d3c2f20daa231fa51f0a9188520e2a11149e162489f0d6dbd27cf94fd5775311d3dfbcfeb431bafc3515bbb8c4ba4488c320dca0dfec548fe9f46d8810b3f6b16bb3e3eb0ea130747d3d127c5953ca8d561f8d425a35dc3f2cd831743139fbdcada42308b524313782e23b32d5d54a265eae408623e3b2779fe60e13cf47d54dfe520f9f4e57c68aed31f78629a9074d72ab87bea993a38f95ab40df3ef01735e7d44ad365a786e0d3032f1c1dc4e6839c974185dbe63f8725e79831ebe269f94c96705639ab38d5d0700da04c6a9f686e1ea13391885287ba43cf3ccef1c2227918f15ed55441c45adca84153530bbfea3cf37adbf84831a2bfcbf0ca4a4bbd90e623789fe993dc17503ec11b1ef3049f27b27ff778af364d634a46165cda1dd8241cb88740bce74a73e7e3d656df2dee05bb561a85e64671b191ec802c5bfaca49b8168e44271cf13df756395896ff41a99654f55b6951f20d04b2007938a420218db8e37445ef3267130e288e3270b13a92596a26043e1ae84f3934cdb13363bc2843f74a0f6608a36b52c985132aa427c56b7275a864b3c76502c37b8abb8d0286b3199c78492ba8103f5a23c6cdca2292c75d7d6d7080108850807f78af3dc7e418371c6b8951bd89b79fa586af4e16096b08ac1f4dc2b1e4feaa5c040bb002b57311523197b6e2bef5b79ac9c9b4a339be6f6bf7fbe9b5c93862c87be6647949c70bb2c7e268e2ab39cbadd69de628376b3af744eeabc85b599bbdd09defacefa443e05c9b5f259a7783743fecf1a749c57cacc85703269ed67db1d8d475f6fe25d66f84a77379411ba123d98fcb3ae4eec306489a08372893616a91268ea6bf34ddbf0fdef1360ab9e82f4ac80a24e41f439af06fadc223c61f445b7261eda5e1320e269d1277631ee2245cf930244bf8c04050c514e2d59035b80827586cbfeb7da7a59c1208aa86390b9dc7a9b6ef38879ba4deea5eef47c5c98d9167594cd730abdfaf082090efe759d1b13199d739c112ae324ba24b275bf1d89867b81f4580a7ea3a8d3d07b45e2de6c1c7099de3606873b13f3083ecd1e84456c9a1b1d358075c68b1a7cf0b1f26031a2909e226f5da7877d0085b879165ec4b1d9abb7b0732ab4a6f22d9a7bbd0d494ef3f9af4903dc733fe92c6b2f557d1406d223a93e8ad6e579ebcde9c39a5652ad31335df924e5b6a09a0191821b4a0c8f886e2d7860b75ae79ad9dfbebf3500c8b9762dcd131eb5c8b866b5efb4fbfdcc5e31605c2b7d2ff8db5198a6c41bcf880065ff232ff8f84ca3f8022d3428359dc9fb19f57a6ad3f3d174d8a348879a754b37095f01d9a7f6f873798b97dfc5d7c7eaf0383b3fdccdcc11b30dbb3a0fe3186a36c4ddc9674624e38a81cca60a9bbc1b124021b61a383b7547d6af187022c133ba9d6dadf711a3af3b0255b859b214ef6c5dec592248fc94339a64f19196ca0fdad80f7f8e3d78b1f783b1f038008d0d106bd86e23e33ae5728872d42a555bb36d0e3303f0b4ab41180f4251590ee3ee244b77191c31b9f3f990f71c6e237b9dbcf7ca21c9b4c2446b856c67861785bb9edb920b8f530a7a088313ef044419a879f26db137e1557d079315844f9f60bae03d8cffa7a28bd2857a001fd5d2d999fca95ff91df0e228567f6c9ff592b77b7ccdc93a951f7e34910361a8f4fb517e1c9fb956a3bb50ddf37ed37e8d26adfc0f71e059ba95ec77a1e34e1b3420c893f89b79fc72e3a1d864fd35526727f939badc29740f5ef9c0bb9a3f72e1e08b2ef2ab366f80d8e14e03e92162736e2ccb7cde82b2af08de8a6a81c03c63e2396974ec29fb122d818a2d2d5b29d11b704d3ac3b39431099b7b2f6aae04d28a2182b55380503127e4986ee9e8d5c0c2058e09e4592d08d013a4f088e45403720160622236bd56fbd9cc240efceb1b23c19ceafec49e9d5776ca9da5f7810ac979cf6ec5f678c09257abf79c9ab55dea00054e11b62c0a0ed4363d0a96a37ae1a323aa93bb1af253885afb684ed30caf5cf3b37afe6a6463a16f34cc28b4530c6bc6281f597bea476cd9a773205b96d47ed4b0bfeeee39b7ea44ff194911bcddbb161c2c0ce9488978b99e880d8e43624dbb4a567483ed293348d752634b2f46219575175e3c249b8e4e853142b66491aa1c142e7bb558955747cf2bd61ac802a2a4784d9fe080f771dd537d0ff928b3b04029d9ac03175c2d535ad7f3c123eff30c0437b32dd9fa31b2976e369b89b79a2a95e31aee15a462c5fe25fd937ce6b0795808d16163f2cea8f19b7c83913cb4a793576aa5c0ddfb6415326d8f2be0621017616c85ee46aa768b077dbec72311cb8a0f78ba0621a277a79af6607063839a52c6825a20e1c5818b24628862aff5fbbfe87311866b9956eeea7412ef69a3e4da84699b8d8b45c74ac96c3356989fd4962ba79fc26a92488304fd9f42486266b433eeb57368d26ae91ba4e7ed812581f790314cc7f44639aa7f6775618111369e8e2d68a6ab24388824bbbe3c3b0fbfb88635c1fc3216af1af40eba3555c0b0390a18ccba9e68afbcd21ecb212aaf82846f0a55793945902c48cac5d19332e23248a464529f4cca177137c508b6b13637e7df523254f24b8343d19164174202bcb00d5fe618b760c374f69b5065b1f9acf91af95abd7eb271586cae14fc835f633aacb4cd2ecd0f0ac08b688ef4d13b8a7b4c487ad46485bde0e340309672dc38af275e6ab525971409a39eff0ad134b1674db5d1f9725874e36d8730dc034b0a596c6e0a26e521c199d3e3f86815a64d148ffc394290b19f15390934b5d0da27dc8365360511628b93ebc375d2a531e4f4cfa031eeb501afe96d201c7b6078bbceb8e5d8615599f4c613bbb81a88f4eeaa57a9c008125073a30154044c422eaf2a32cecb15aab0774bb44e52b1792d154b8036ff9224af53e023fc011ab251d47d7d76e55c5015db1926d43c56d055feca1259de53ce98a2faecb5843ce17a3e83ccf678f5d13a8321f278a670c684e62b720e1eefd0abb2e9d0a3ddea81d5eb6e380a1c22af5587daac852e93a86f5e4293c18bb26b32035c7e5ca20cd2e3eabd3de0e55092a79a42c7ccc0aef033d6683043c2a29531a2ef1f503595c0e464ac042153c4685b062275f88bab93cc017f1ef9dc6f8aeab7b0b234f1c543420324512554f1786c82b37836238a4dfdf86f97d09ae466eb39d5f3ab159e2060be309d1284be133ab40abd61468c1706f7f9e57a7bc747479693a03edc8863dd196fd7cb2721260e42f4f606389c4972c74d357e7467b61cb7f455562015d29a59c7cafe0df03f26b77bca81c2bbac8cbccf8a65190b0c4e5ca832e82ce4e11044433aa397106cafc05634ad778270d20d8a13068586bc6b582ea24524fd921a5ee22dbae5296ee86d80f12b78bba26f8b42c1401b75d5cfcc4775c5cd1cb0a9248dabc8f82d216787b2a2780f7d13a5ee8c6ab56399a8dd5db3a152677d01eb8ee98d1927ca5069e0d1ba3907971a2199ba3634b48e570dd97d93729a6c43e4f359e2d89795218d52270a338a1f511b1f008cd04553c1a89caf987fd18c329be7ac2282084ef1789615d7eb7afd2261f606d3953b8863abe57796289e7761b01c3ca0faf2291287f9ad7027d7f0876b5f77d2a7f87dfa6ad4db905d4bcad042f403824aee3b4f8d7b5ab027fe1eda9d683db24f56f694b0b10ec72ba0df40bdd6e52b4a7b8d064ad46c7490c4705c14b06ef55222435d2d6316c7dfee83d225eaa431c11a4b85b0bafbe66fda1abadaec8eabcc2f8c688a7b9cb2942597f20cfafd7520892c535bbf6359a6989a84dd89989d95b8e5222c3aca2e8b0f8881d759e450466b75b5f36b7b723b0a212edf52abd591e7e545a3974b8b31b84b523af7b47e3804b5a268c86ae0bd7c80bc6b578b79f749eccdb4a00813925ef40259ac10bbd0fc4f2fc536c30f7c1efe68a52bee22f57021d23f445211b36fee6302202c9b62c6cf9064a2df424563f9f805e51c4092482253e4c258d53b80a2d26eec9fcdc104f7124d876a3ad573a7f419b0d67a41a34dac9d8f28cf9519b9c2677c9d1e720667d5fce26091d64c6df8b46c98b58017de0d055651e8caa3a230f57aef214ae2f27fa85400e34ce7087538fb6b854a6ad534780052210b8b8c90b4de4c2afbad9f58a71770ec186cfa44b61b53876bf904972078673845ec3181caaccf11f71a8e2a502deaf144f16df1df3bd81277dfbf6e1ae5a17363725ec31759b743066fbd4cafb5eda6e09418bc375f42e0dcbd4624dbe26c5fabb77152124f400e677004fcf3c862a9b5576140cbeb800fcde4409caae06286cb643842687bc6b89738374c7c759c911d7bbec8613f1fdd996d4b970fb6f2a9290a84c34d5fea6b8006357c8e6e9d4048d5a8ec476dab0b55e8358ecf7d27c31da86681f3fa74d072b1150223eaa21c4027378a99c8a2dbdc07d4062c401e92eddfff82841292bda2798c4e2ee9e09f618cc181c91a4dbefa44c410dff5cb705ee005e3a0470c13baddf9066109797a3b51e73a0ef229796d330aee0c0160529a4ca3b39e861ee5c4a0f78619007ecdf32266c7c42f0c972b91cccc45f6f8688b2692f298721cb5da39cbca9a5adef6969a2592ba421680241f8a5384bb92e70acf79c2f41d1171dfc6e1939887b9c8ea94429bcbf3532919fdcfcd0f443d3c95515b41e3f9c84bdcd3de1fd481f98482f667f2d017e3579208341e9a225f85516c8ca133cbada77598b6f596e6151eca377fcc8029cc99a879b26d975684173c0874509117ece4136bd2d69848f858c05e8ba3421499d7fb5e3e7645fc135117d8fdd1dc46bebaedfbad4dc7cc23fad6e696fe349712cf7579b4e63b38cc7d02a4c6a33ee4117d7ccdb86ea02cd791756b2a3c516d59d39ed83a8c328823f1934731820c187624219b487ca86edcc2f61a064e4e8d17f58f4a71462f3f0cfef6be95c0eb3737616de5954096d761a51534b36d798c651541acfe2e5bed6e58c45c46e014923a342409d49e782054f2a4877332e0adb0663dce0e84df0ff0d71c4c5ef18d9cacc8b8d47c78d53fc7649bab719334601c79a345d2101e65d4c3f1616741b24fdd9f7d6569fb8de67799648b323856c2ca96ac91823aa12249934c7050505258c43763ac9b174d55fee71c7817d65056c30d7853500656040621eff9f291e9db198772451cd3d58bc9421f6191a863777edf49125543b22ba127ea3063e1989bc4635d50bb22270948ba594b2066d91e1589aa0c1f476af8b170820ae0d2409df83819579621161ba55cc8d020e1ea68cedbccc9a737746d824b06e12cd2e3730260fdc52a68b6e142bdb997d8f93f25d241360285e7372939828fd54c015ba90bb4d553558ffa2558a43098644357860785addc455bf1ef4ffa5aebb8f002eb0f6a8ddd6f45edcc7cfe88d7ae7141b9113a4ab851b5fa8ff39c7024d2b3202841266f256b1f4ce4e4ea8b83d0067555ddd56fb1f8ed6cb5ce7340cdc403fac1dd3b48c373629202c70f1f95c0001b4f94a9b4bad9e1c64429b541ff57a2f2ea0c1fb2af8f0e490fac415cc3bcdd5739f2069e2bfb873206b8c8811619f1db39386cd2dd748c6301239b4e873f3d4618a43c52ef7d8abc0ca127881dc8809dc20a8730718c64c5a132cf638ec1e3b3cedaae55763637b4c6341baeff17e14c1e3c34e5d23befdddec0c7e25f0ebfa90a0bca07a0f5446507b7fb9cf91cb3cb8d24a111f46e7dbe3ea62b384eebecaf8de49b15b17f9cf151c4c3d33220b3adcf9f87222813ff2125120e77c638ab19c1daf9631d53b3efee67c3c40c9c23495848d4c5ecafc0998bf2704bb78ade666f414e9c6bb100b90451d93397d062b741a3ef20e7e6ebebab8238e2adf415775179c866eb4a2f628924674b20f711d2515d3b024e7e0fd3af6e116cfb0030709fb9bed4a441646c03dfa0b11cb460415ccb3c0999b738a0b07d55be741f3d2646a3d9e22bbfeb46b87acb6fcc2d83cdf44b656d2269a0734259a738d83a7429bfc99da7238b9497fbb10e0f623dc1f793e3be2326a7e55677e20ebb152f71794fd70d7698d0cff1334341b3a8eee38d66a021cae6f8dfe67913fdeb8d46efd9b77f28950aee7ce112f8f0dfc04132a99d95dfa923d391e06a578056ec8d15ddfb0fe8cd2790ed55f8254c6351d471c7273c2e61c2694bf6b0a1173cdc2d422246ca5cc51a9b8669dc331fe33bfe330d5167a244cf041f8444775562eaa8ddb92e0623d4c689db0919ece87a7feeb1ddd2d034a0d884d6bc8b5fa5fc7df00cf667dfc82c9e98e9b57fbe07fed391729034c467b46d3d16ed72c8ded069a117ca2d28e71ef4c37f1b1939590af19433ff2a784ff38134aacc59719673c53ed047d79e0c36f3acc03f64458826107853ff8d02de9362ffada79feabc597d019de6afb6577dbbefcaeaee801a49b1718151690b43a4d70b2fcb73ece3e3ea5fe2a9616cc6a9a494b8c6c7121497688652eb854e7bae19af3e5ae1a8df75138ce18621d11f15054ac8971f6ac084bd90e3909b46db321916c9e3c8950f3cc8e0a10dd255bd6b359c73dfde7de6e01538d03609253968177af14d327337bc1bc4e866c75ab5b69125f9e9a758f061418110a615b97f733f899382e2a14fa0ff0d1bda3b7449e1f54362697aef064fc9dd50692ad2b9ec286a1b7c1f845b09f4b1ccd46142f9e272d018eabf76c23c26b1831762a8a2c9152ef0cc843ebba20bf979e851e76141f41e817cca0ac60c1baf239a6c920a244b0be031a3b65d76eebae15bd9d49c53dd3e4303ca379f26840901f1da886d330d8ab4408a25eaa280ddb545b968b4aa59ca6f9cecbf82984264a3232b97498be0729f3d97dbd64823393b42794ec1676244212af382c37d53d66019a5db34c3d8ac156cac852ecb1c57f0f6057815460eb9f666c368acca6dfee0d2b7bdacd2148d74cea3bbac8b528f00809f403b1964b9d199d2db93363a53732efd97c66f28cb51442dbfb1c912dce078944e02889f9395ff2655e2d7118a11848e3ca64efb5eca119240b537b5d4548a744d96962e9b2a99af73bc4d753df16fe75a08005da7773b7bef68a44f56951a3a93995c5d0516a8b2c39abd2057b3d86ba7fe511dc33292596fcc4d3c67df88812e26d3628527752a81c8ce6eba711ae7ea8748229caa2580e18937f45cbfb0041f0a9254eade41c95ef4f390db6174e6b0ba89af344c215393b627348ebf00901e343c1599c832bd2cfb751750808719f18119ab3fee6baf5fd4b8bf7c92a271ff24576984610abaf1b2297c18a2784f57d7aad26f52c0d60fa6cd2484492a1524dd14924eebf53348ee2dca0643ef47381541b91d1843817067a94bb7c79e4e08c4d81c7266afefeda4a0db21b0db629cedf13b4f6ba11e6480116a7c9780009ee0e1e2bd543dbb68bea356a6010a1e3ded4229c4d8035420833fc83337dce4bc483eec76f479f33be2d6a8fb013813952eb66bc247f37f9def7e9bea0f277f380079aeb48c192b9c2c24f909435586bcb994ae6f75eea111c8842b855f90df21e956f839aef89bb1b96899e343cc66814ac08eed4defe5e2a62c54cf83a27f0499224e02bac652aebe6529143372c483edcdbfbdd5a02106fd3651875f23724d2154c0138ace745d038d6cf6b233ae2bbb8313c8ab59dc896844da5a6610845d9147e57518ada61b7debcd66111d609587632cccb936751d099639735f09f77b2b9aa1177e95ac0f8070bcbeb01bbfb3e7a638811d919016ed628865e2405aa17f5129ea43a836a76ec7cbd943e20b1e388d47db2df3394785e27dd7efbe350ccec6057af7483303a6a588d4005c05ff7f3c90dc5b9a0f95c3c541ea40615f6b0ed6cd3787e608e7612b52199062991a63511b3055dfab25b18ab55948d9d529aff91a0d8aa7705afc187e32d1107c07623a309390f32c62e1abb830bb090a7dc4c6817b554720fce354563662d78cc2bcd0483149b304ab86502f0ad36ba2c262fa60b1b84be2499e56fd72129c0fdf1961214df8dd6c9b831109fadc7464df090aac96d221ab387b6eee3080ea0d94e195ca795b5d80c42946c0c353e39075bb1aa4f3fac36a77445cd57b11b3c7ef0e89aca911be35fbb72e1e2fff84b7ece66bb8b3dea52b0aff473475d298f730e79ff77e955856817514908baaec1b53f39f9d5dcbb1cef29536a483a1845d8538e5ec43f634914bae4f2319579adcf3f0fbb151c80b54f02be54be612f9417f916579863dc16da5af07fab05db2094c77612b445b7b9784198abbfc8387486449969118d3a83142022017d69b939d30fd6b1c5ba360c0e37f264b5d604c7ebdaf327874b22d4092dcf35aad93f0f0b3037f90000d4a1892dab827d3c2f1ddede948d330706ef17bf442f8228c168401541ea89a837f81cfffde8480e1b6014f2f5d3132ee740e04622600ad93dba41e39267f17554b29102390f8196094de19e8d966d3c03a9e3348494b54045629224612734a1304ed76d17a465c305675bf99b7aff1950dd2012e6cbe8d15a9e35a7c16081bf647e2766c7b8e9d12ef8a2c94fd7531f6d1a7ac7ce6bac028917a2a71c8eded4f3ce3be8c7d98422094e88414338fc25839a582b5965c71179ce3ddf7a645bb163f3265f4bc4ebe91ff25d86520696d237741ba73084070e23494d6a890e1ae748091a6936a3137d16dd14571f86ee118bcb17c8ecd2ed20c25cbab79a78c53fba1d5db4fdb15e6a124bdb2d41fef080e7318f78c67451beff04b58a182f592fec3feab6011be4663dca8b62ad2a8e40c716b3c8a170e1574517c44e146109d223529b0de480aa168b5a4b0522cea03dd26a684b08c58aa2e1fe41f44ba8837737a74a4681b0508d9604aa7484c5ec68ccb369c056702b03f75722033597ce5b55e5a88f14e3ee23b1c96f5d38604128cf2e901a745996f4a29d412e5ce1b4ee82cf2f248aa80f8c8f2eb7b6951f1b0910857a17edc319bc76b1a59fe05f9394a5b16a91ef15afba9ee2e115c9c9afc51a8d7c4a61cb335724855007f564fec341342d53717023118917304c2dfcf0bd79e456c94718b8388767564d6055aad1d505f36506fd6e8cb1a10f6fe8a67e772030dab78b43ec15fae0322fe991944be86cd0bd78ba00110474dec84dd9597a602c4a6c97a27f13159ff1e32fa63e28f63278b09c9d051cabf8bb49f2780d4c33ca061ff16c6288ff29d46a22e31c719dfaf6087590ea8197c066f9057e0c24b40f5eb205b730985daaf7e7d85fecd7449677c0ec1abd7111d795de6de4a6ab30cf266987dd55569f2a705ae16f51de738fcc4cc218f2cb9dab8af509ba26ed93ddc7a73028d9187527fa6d554b491faade05852eb50847affb81b58d2501989d5b4a9de4237b33bea154c4d016b08f3e1c39ee61382fb500be2123ccfcd30e37c88979a19d636c9dcf5fcec822e5558cb2939e40e1af039aa942b503c9fce95f8ff51a2977f58e4d5032f9099fb4783b7764dd1299a1a89f21c1f5e38038f219e9a4e9d6c6edaef70132ee1f2a580227b256c9139d339183e278277a9dd260bf7d8a9853c4185f9b6509ab9b67a3563ed0b9afca6f2db28258025d8c2036cc4cd9fb4f7007dca96597c26476def29191cb0c77c44df80994ad3c79833820ce2f1108d17a083fa857397d2839c37899ce2e634578b3eee0135f66cfe1aeb7bcb8732fedba16093a6e666321236f56e285058d00c1bba2db3263844e4b0ea013e7a8d370ecae9ac7a9620eaaa244b25be1eb6e71368f550736d3ca13747edfb6254c9a373aadcc30a148907d39e81bdda8a53e8644b39a1625de851fc5d759686c63c76bb162b244415175eb0ccaf3a63d4ad910369e30313bdeb175ace63ad33e400e642dbdcb472a336d82d2f818e6888e5aef472d03fd298a5d14b8da432b72e6c5f5694887a7e4e165bc41055379bd204298d65796d5351a9121f949904bd6c87510649127ef5797d432c6c759939c99026d57076db225d7d0df01ab9b9e3e1221e7e323ff752eb7988cd2b2bbfc8ae7fdd23c3f7cfd2ae2679014e986e3c01b6c66a67fbf69483ad3e89c1f2dd0867f411151e048d81212c0b5e2fbba9d317f283f97c9576180121f41856355b906a22c69869bc27729db5974c5b1257b35d186dcb4e9f7bc51dc331c0ff9baed5955e5052a6ac7743b"
let x = getShieldedOutputs rawTx
describe "extract Shielded Output bytes" $ do
it "should have outputs" $ do null x `shouldBe` False
describe "succeeds with correct key" $ do
let a = decodeSaplingOutput (bytes rawKey) (head x)
it "amount should match" $ do maybe 0 a_value a `shouldBe` 10000
it "memo should match" $ do
maybe "" a_memo a `shouldBe` "Tx with Sapling and Orchard"
describe "fails with incorrect key" $ do
let a = decodeSaplingOutput (bytes badKey) (head x)
it "amount should not match" $ do maybe 0 a_value a `shouldNotBe` 10000
it "memo should not match" $ do
maybe "" a_memo a `shouldNotBe` "Tx with Sapling and Orchard"
describe "Decode Orchard tx" $ do
let uvk =
"uview1u833rp8yykd7h4druwht6xp6k8krle45fx8hqsw6vzw63n24atxpcatws82z092kryazuu6d7rayyut8m36wm4wpjy2z8r9hj48fx5pf49gw4sjrq8503qpz3vqj5hg0vg9vsqeasg5qjuyh94uyfm7v76udqcm2m0wfc25hcyqswcn56xxduq3xkgxkr0l73cjy88fdvf90eq5fda9g6x7yv7d0uckpevxg6540wc76xrc4axxvlt03ptaa2a0rektglmdy68656f3uzcdgqqyu0t7wk5cvwghyyvgqc0rp3vgu5ye4nd236ml57rjh083a2755qemf6dk6pw0qrnfm7246s8eg2hhzkzpf9h73chhng7xhmyem2sjh8rs2m9nhfcslsgenm"
let res = decodeUfvk uvk
let a =
OrchardAction
(fromText
"248b16d98dfa33f7ba69a0610a63b606699da76c288840b81d7691ee42764416")
(fromText
"17fcc27cce560733edaf91439a8020c4a029a4e7d5893ce024d5ff4b40bbd0a9")
(fromText
"34796d541864832acca43f083892e98a46c912802d5643672d3f25bea177c61c")
(fromText
"a6d2ca10e3fc7446e372266ef45ee3dc0ba373bd378e6bf3092519a7f272bd8c")
(fromText
"08beafdf59110b5d045e4acc13731ef1a27bfa3a9cabe1d575640c18f18ee6697fbb132d36e982ae3eadf5f37fd35f42c2bb07def14759deab1fbe2f98dc1d5913e4a6ef388b714e2cfd6d89ba2302800e02ab5f45e0e02e3895448518cd8afd2c37bb48a66d8b988a37de9d0838d92876894a311bb9f314ba842e5c18ff7a3d8c7f0ff1a7209e2d661595db8f4a4aa267b9593258914bf63c09286eeda7c9b27ddbb4646208c0d03a8fbdc5d96633335a5a65316f5b25189bdce735bdea7e900de56d3b475ae51b7c35eb7ae79ba104baeb0a5a09d1cd8bb347ab34fb26d62ddbf024f5394710626ec0a665b9c917e65b00256db635145164a0329db7bc5358f435d573b2662adf8a6128801825ec8fb7d8aeef567d35c875ddd784fceb7620355e3f056a648b39b4b2d29a1f5e7b7c4ec5fd2b1874ff1e832b308f8644e83878d90582b9a6fd6c293e19dd3e24dbe1b4c15c96608169843d46551900a8cb787b15f0f1696b736dd4c8ebacf1e3288b14e469bdc004fa8557d6b1395700eaba59334906bb012f876e4cd7acd2157719ebd2e28bd0cd4ab4ac458f8848e1c30e729803dd47102200fe703932a15c3618862ec83b40d3aa0ec2343641bcb9afbf931ab21aa4afdbe7e51deca24283c2ccab0eef6e07aac5a4bf3a775bf7d2ddfc8d8766c3bf8e35df1435cf515d93c3b9549477bd9f53d133f05dd256fbcc0b13a63e3e7f8cce6301ab4f19c114f5af079f8c581537458e861b553218a890ea3e77fb99781c7088cd43c67c155ec611c1148721cab5fd0168e4a5ec390b506ec44145474c")
(fromText
"1e40d33446d9f0f0fad40f8829c1ffe860c11c3439e2c15d37c6c40282f9e933dc01798c800e6c92edb4d20478b92559510eda67f3855f68f5ab22ca31e1885c7fa9d4c9ebfb62ceb5e73267bcad0ba7")
(fromText
"63d0d6e8e92691f700bf8af246dcd4ae1041b13e3969f7a9d819a06e0f9429bc")
(fromText
"fe362be160accf2794841c244e8d80bbeb80b9bc95bb653d297a98d32bddf5a05dd5f874891d55924a83f722f75f576f63796770c31074067694cffb2cce7a2a")
let b =
OrchardAction
(fromText
"8921446787f1bd28fa0e4cc5c945ea7fc71165a25f40cd2a325dae0c4467d12c")
(fromText
"240b08b7861aa78989c68cbedd0038af9b3e3456bdc7ff582d597df571d54da2")
(fromText
"e1bc8ccba69ab9f429bf735417aa005cf439d27500b0d3086dbf1be764b42a36")
(fromText
"c89c58ef8553e7d09ba4090654edd1a8c98763c44d3dfb9dad18286c7ef363ae")
(fromText
"0eee1ca5a3a4959cd4b8bc277e6e633f950680c4acb978c14ad8d944a784f46771c9d666a203ca3ac693943d79dd23f8b76a734a62e81932cbe98e8c851f47a11aaef50249e53151f38f88262a4bae8cf26f5f8b2db1d165aff9b57b64713a677c167608585c038e34ca7bbe468e5f86475ccec0a4a8b9a43b56e342e77a6bd09415787c9f4a1c6f20599f57545f1ac32c3a338d7a5bb2d35456adb880cb65c1455969e10df5d94b8c74b244e7093b1a88cc10697a7c2f4d34b6eae3296e64b820573b4d52e06b4427af5b8f5d6722d3a93fd85da615fceac732976ad2c1be4150b4821c149521f5419ea0746fb132d47f593cfc8a3aab6b2b4480c12fadf21280ccd3142e7188d9e5aef3fcd8c5dc0c066dc975bead023ef7f89a486b615b146110ae68b703a8349a5fc225b26a08b2adaf36fb44c9ad1be59d7ced134eb84e3f0b4aec19b71b2d26e910628a11446b97c5e6bbf97e1befa4e04b5947f83c65161b92f58088d28e57adc2a2873e27008e29772c5803502842045cb355d1ea5a9d27c2683dcb38cb49d26af39625ba99b1342f700387b939e7ff6c129417ca8836fe1e96331e35c8bc0763879e8c17cd4535fbcb27a2785c0a47294e07cb54837bb997df34882ce0bececc6adca365c76fc7533cf0503458937dcfb6058b016dbbd399b9f0cca44cbc881016f4957b5e10daada3393d5b2a4cb15ed983506d4d264f9855ce2ef87a7d4a1fc03293a22c28a53c4455447d546813fa33008e5d2d81848825fae2f437ab9575ba99c230e78f4b23e575e7647beff0e4c4e2b0a1f7320e9460")
(fromText
"d727aeec27bb0f7463c6ed4f5b3f4085cfd3e7218478db0dcebfca875e025320fb64bc4062251823859e963446cadd9924c559e5f981480df5a4f036daf5a8033d4c8241e128902aa1aeaf6adc149730")
(fromText
"98e72813aeb6ea05347798e35379bc881d9cf2b37d38850496ee956fbecd8eab")
(fromText
"cb9926f519041343c957a74f2f67900ed3d250c4dbcd26b9e2addd5247b841a9fde2219d2ef8c9ae8145fecc7792ca6770830c58c95648087f3c8a0a69369402")
let decryptedNote = (`decryptOrchardAction` a) =<< res
let decryptedNote2 = (`decryptOrchardAction` b) =<< res
describe "First action (sender)" $ do
it "Decryption fails " $ do decryptedNote `shouldBe` Nothing
describe "Second action (recipient)" $ do
it "Decryption succeeds" $ do decryptedNote2 `shouldNotBe` Nothing
it "Tx amount is validated" $ do
(a_value <$> decryptedNote2) `shouldBe` Just 3000
it "Memo is validated" $ do
let msg = maybe "" a_memo decryptedNote2
msg `shouldBe`
"Hello World!\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL"
describe "Wallet seed phrase:" $ do
prop "Generated phrases are valid" $ again prop_PhraseLength
prop "Derived seeds are valid" $ again prop_SeedLength
before getSeed $
describe "Optimized spending key tests:" $ do
it "Transparent spending keys are valid" $ \s ->
property $ prop_TransparentSpendingKey s
it "Transparent receivers are valid" $ \s ->
property $ prop_TransparentReceiver s
it "Sapling spending keys are valid" $ \s ->
property $ prop_SaplingSpendingKey s
it "Sapling receivers are valid" $ \s ->
property $ prop_SaplingReceiver s
it "Sapling receivers are distinct" $ \s ->
property $ prop_SaplingRecRepeated s
it "Orchard spending keys are valid" $ \s ->
property $ prop_OrchardSpendingKey s
it "Orchard receivers are valid" $ \s ->
property $ prop_OrchardReceiver s
it "Orchard receivers are distinct" $ \s ->
property $ prop_OrchardRecRepeated s
describe "Address tests:" $ do
it "Encode transparent" $ do
let ua =
"u17n7hpwaujyq7ux8f9jpyymtnk5urw7pyrf60smp5mawy7jgz325hfvz3jn3zsfya8yxryf9q7ldk8nu8df0emra5wne28zq9d9nm2pu4x6qwjha565av9aze0xgujgslz74ufkj0c0cylqwjyrh9msjfh7jzal6d3qzrnhkkqy3pqm8j63y07jxj7txqeac982778rmt64f32aum94x"
let msg =
case isValidUnifiedAddress ua of
Nothing -> "Bad UA"
Just u ->
maybe "No transparent" (encodeTransparent (ua_net u)) $
t_rec u
msg `shouldBe` "t1LPWuQnjCRH7JAeEErSXKixcUteLJRJjKD"
it "Recover UA from YWallet" $
ioProperty $ do
let p =
Phrase
"security expect junk hour people bind law hub between topic wink cliff spirit scissors auction idle figure option wide useful swift prison cushion round"
let targetUA =
isValidUnifiedAddress
"u1qsylqauvnhw8tsfe3cldcsj3mjrfqzgaf3mt8yzlkjuvsf5wzj223yvrt8q66qukfqcc80x3z0mk6ym6pm2f0hukzkp6t4wj78h85t6kfr2u9mqsfhdd73g3sc7ezy2ut3rtq5jmejatwv4xqqd6l8tt9fycer8kdw0gz6e607nkssqsc7kd7nk2yfz2hpvpqhdg39wxalpjzhe34j7"
let s = getWalletSeed p
case s of
Nothing -> return $ expectationFailure "Failed to generate seed"
Just s' -> do
let oK = genOrchardSpendingKey s' MainNetCoin 0
let sK = genSaplingSpendingKey s' MainNetCoin 0
let tK = genTransparentPrvKey s' MainNetCoin 0
let oR = genOrchardReceiver 0 External =<< oK
let sR = genSaplingPaymentAddress 0 =<< sK
tR <- genTransparentReceiver 0 External =<< tK
let newUA = UnifiedAddress MainNet oR sR $ Just tR
return $ Just newUA `shouldBe` targetUA
it "Recover UA from Zingo:" $
ioProperty $ do
let p =
Phrase
"cloth swing left trap random tornado have great onion element until make shy dad success art tuition canvas thunder apple decade elegant struggle invest"
let targetUA =
isValidUnifiedAddress
"u1trd8cvc6265ywwj4mmvuznsye5ghe2dhhn3zy8kcuyg4vx3svskw9r2dedp5hu6m740vylkqc34t4w9eqkl9fyu5uyzn3af72jg235440ke6tu5cf994eq85n97x69x9824hqejmwz3d8qqthtesrd6gerjupdymldhl9xccejjwfj0dhh9mt4rw4kytp325twlutsxd20rfqhzxu3m"
let s = getWalletSeed p
case s of
Nothing -> return $ expectationFailure "Failed to generate seed"
Just s' -> do
let oK = genOrchardSpendingKey s' MainNetCoin 0
let sK = genSaplingSpendingKey s' MainNetCoin 0
let tK = genTransparentPrvKey s' MainNetCoin 0
let oR = genOrchardReceiver 0 External =<< oK
let sR = genSaplingPaymentAddress 0 =<< sK
tR <- genTransparentReceiver 0 External =<< tK
let newUA = UnifiedAddress MainNet oR sR $ Just tR
return $ Just newUA `shouldBe` targetUA
describe "Sapling Change Payment Address generation test" $ do
it "Call genSaplingInternalAddress" $ do
let sk =
[ 3
, 183
, 26
, 151
, 89
, 0
, 0
, 0
, 128
, 199
, 189
, 33
, 169
, 114
, 194
, 50
, 0
, 139
, 140
, 162
, 100
, 100
, 35
, 58
, 226
, 6
, 47
, 232
, 34
, 214
, 11
, 173
, 142
, 40
, 45
, 163
, 190
, 207
, 49
, 130
, 158
, 113
, 232
, 251
, 79
, 98
, 77
, 195
, 196
, 40
, 42
, 113
, 133
, 35
, 211
, 68
, 146
, 104
, 5
, 56
, 244
, 162
, 55
, 239
, 55
, 112
, 37
, 38
, 189
, 183
, 121
, 201
, 1
, 60
, 158
, 151
, 141
, 123
, 250
, 95
, 169
, 123
, 208
, 56
, 103
, 74
, 85
, 49
, 152
, 207
, 245
, 216
, 58
, 37
, 0
, 127
, 186
, 245
, 234
, 47
, 68
, 11
, 78
, 76
, 12
, 171
, 37
, 63
, 172
, 90
, 111
, 94
, 88
, 152
, 211
, 53
, 243
, 142
, 16
, 195
, 142
, 50
, 14
, 13
, 32
, 91
, 5
, 82
, 182
, 121
, 136
, 109
, 125
, 165
, 125
, 123
, 226
, 54
, 60
, 34
, 62
, 111
, 167
, 88
, 254
, 113
, 204
, 47
, 181
, 97
, 18
, 220
, 46
, 51
, 160
, 62
, 16
, 199
, 143
, 184
, 200
, 209
, 124
, 154
, 175
, 29
, 216
, 48
, 201
] :: [Word8]
let cAdr =
[ 31
, 232
, 31
, 17
, 196
, 178
, 208
, 227
, 206
, 199
, 105
, 55
, 147
, 23
, 151
, 206
, 117
, 59
, 249
, 162
, 218
, 140
, 189
, 17
, 60
, 116
, 106
, 56
, 64
, 203
, 152
, 52
, 155
, 133
, 179
, 118
, 47
, 161
, 70
, 155
, 21
, 22
, 41
] :: [Word8]
let bscAdr = SaplingReceiver $ BS.pack cAdr
let ca = genSaplingInternalAddress (SaplingSpendingKey $ BS.pack sk)
fromMaybe (SaplingReceiver "") ca `shouldBe` bscAdr
describe "Zebra response processing: " $ do
it "Read block time" $ do
let blkdata =
"04000000c732575a3e94b7464c84b35935c2fca26e40d37b6f3278bda3d941877b192a0048cb59da8eeaf9f622d4537ec2a27918415f444d0bb143e8091b470a18a438c117fd96323fd1a9c775ed793154de0e8a2023b551431e89b5ce6f30ef047388f0bdbb0266fe81481f2c006046a8be3bca5b8819209d053a88184bb48753171accb807c38f46d00000fd400500b6a304cbc4e6caecc9b3a29ce42d71752bf5396944e28465e29d1bd7e7f3c680db3c4b85a1488d7c4e21a70c1cf50cfe4e7f70a4f1abb638f144afb90dfa69adfc7c981fd8792df19926da695356699ab76213094431bf6491b80572c310ab8e51c27cda39c771371dbf7adc60089ff5f9614577a92ce3a1e452d5d8280e3d970322e1fc5937c53369623d5e58e57672b48c2edc7a86f7d7de62e06668097547b782a01d3794a50f131695f7de3e4bf038b12abffd29b8eba618820e143ba0be57ccaa67f64511460027efb065c6ddff501376744c6b68ca01d884025e7f939521d230b1a46016d66ad3ab2262dbd477b38bbec234a19425b939dc0f1d868035c3ef99eee635c9dfd62235ede6d62f652fec499127a152e7be4f959a9bb7fcca9b335de98d14aee1330fe37f1ba28be26902a1cddbc3f67f2f6317093d3f278c1c0156e5319a0b35360e38719911b8012a8cc34893f05dc28a22787f3e0461836aef602110e621c8b9d78e991ccc0160deb8c8921f6fd13bd00d47a170b9d0b09ffd57e37467400c138823dce7c12027eb9f919b8d5f4072b331a042f6f5ebb814c6a903110cc97161787d1eb2716c8fb98d747abf321a0b079f3b6a1a0329337b4922a0d739886a03f0d475d41005733f26c675dd9694712d6ee07772a5e8f6b5871789ac14159beced65d3b2196725baa4ce04f059a7034ff0d7ce081e94d23e0115b9d8f0d99fa5b4f9771b4feaac881ac80f178c3575cc70858e40f53f1d0406253edba75e2bb6f40eb2ef4ece3df2b8dadbd3ac168b1743a0cfb68ba81ca4c838435002587852e81e0a0c3c77e11218df892ac0c2f343967b127fbb822712ceabc459ded7f3ca3e95ed5ddfe6cdfe5657da1b12ee47eb63af7a839cdbc1f52f51e349dbf2bd7d8529f814108723d97fcfda7563c4fbe3a24118352e4706f9f91406f11acde3a570e10a258fa6a5415f57a26988249a87e57f192d0408b6f56c2ef65d5e37597d144e8fe1014a4f552dc8c213b0a70b2ccff6747f6f1e0d598715d8cb0da37e0331c01da1f9e0505e9d1907628427d5d032a29fa0e14b75289b10c7d3109b590aec2a4debda9eabcbd3163f6df67efd92687d0c492a71d48b2995a658b34e96814e5674a62e3738efe53e0daf4bfe9d1031e45a246bd3b32c6d581b71c0b60ad711570bca3848c38ba5aed74d977a185d199db721c2677d4868e5afaa6cc2c7369898f58f93738681118d529194d41f0cb6103915d2e99422db387fb90046eae764a79dfe8733a7f68439d0f37e773d16ac7f0ba3a8ce0fd6746d038704b2a0a979659a859682581fee0be3fc50eed13e85e6b52f398d16b59f5f738c1eb289b3861d636b961d9220c1f76bf8a8be3ffd1e2472461202285aa1c5b7eac58564aaab0beedb65e1078517e031888aa3cb8843876aaf19311d5150529a10c9d9bce1538f7533aff126e518ef1ebd919f26aa3869ed1ced167cb1de6075897ad2dc461b9156922c4ee387f8e1635e95564d3964e47d39e6e82079e0220df00614ecd4fd31a5f3d13c9191fc65037ad3cd651f055cc795260f21bb0ba8acd7e3b65b5ff81d5a1b187a777c826f96637e00f8147c4bd43753fe9e0cd73564b53a0e9eab27745505ccd2e4a1a217307c66030ca115580ce6ecb9a8b043ca41bd2de15abd13838d130d3cfecd8d0e3bb6c982bf1f9cdc799c3256e2d722d3f13cd7acdb9d75d7e36483b2ae01e5dcb70db824eadd9c3955d79557d612a879fa6da1da479807640e37bf25a22091f1cf6fb5293e60e5616416fb2adb1d9892258e8ac6859978159338d3b6e2063b9d842a24d61d0616506d5088fe76025df35619febd57f92e30699a0df8731bdbad0775922bb12fb1697d9da833010400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0603204c2a010cffffffff0480b2e60e000000001976a914278aff0c0f8734638ce81aaef4ab0afddd36552888ac286bee000000000017a9140c0bcca02f3cba01a5d7423ac3903d40586399eb8740787d010000000017a91471e1df05024288a00802de81e08c437859586c878738c94d010000000017a91493916098d2a161a91f3ddebab69dd5db9587b6248700000000204c2a000000000000000000000000"
getBlockTime (hexString blkdata) `shouldBe` 1711455165
describe "Raw transaction from faucet" $ do
let h =
hexString
"0400008085202f8900010829d200000000001976a91484ae5002305847e7176362d7c12c19c5bdbbaf8088ac0000000023392a00f02cd200000000000192331caef004cc758fb666bed1908e61daa82d5c9835c0544afd8369589d350b04a7488a9870983860779ca2e0079a286fe71f60d5c583c3427d24ff968bad3246c1c838b90f465becc1ddfea5839b730ec219d577ed182f6da8f493350b422c86943b7c8ff42de8aee0fe01f4b91c8bb204008f06f85c3dffdb622632d2d4e8b8f0c7457cfa0f4238c7ef4c8903a89559e9307c26e844747ccb9b8dd5e7e83637983746b2fec3de051312306eb8b15db4766b3ef5fe3086d53d388cf2b3b209389ff3644e47d6bfdbe2fafef1bc2311093ad0b49f4600925f55328da337e73f01f83097acd8f2aca7a85f28e75fb4efec6551e026a1ebb35c25efde455cc44002bb8cc79288ed738423432558ebb583874aa5c356abe5be794e1bfaeaf6a7eccf67e5d938751a3a351bc21d4422d2ff0f36f5b30759d79b1ef2d83618d9c1769694454002d2f2be74de3ac10d39829369c87a70e1e9769e7d5ae7c865282a04487a8ae4cf5beeecaea6a3be1c864bdd8d61df88f08a76ac49d28a3a069d2c0d02068a10e88674b39c9d03da49256d914319d267c0d1db08ee7777668e90a94c50a065977222ee620f2291f6ca3fa464fafe8fc3fedf64a836eef5a2ca16aaae5573ee082a77f046d388750fa4ce3853c846ae3f338741c7976f72db4ade4abd4211e8d335ec8c83309bc7d7140a99dfb64a29839b9acc74de4ac0949bcbec4e76be9096a45ab6ca19b165f4097e24ab92d7b58694b0897789c3cdcca2b3d4b0a9da153fafe68f940031b6548d3c37c1301faa9adcfc41c417e613c0838340e28801f72610289d7435910fd276ca243d119541e0a121d263fdda149ac40f293e6fee6d5ddc32532ad947548eb5d20a5bfea97543965fe09313f1a5a78ce51ecac9c36b54cb573780da15d197f5ffacf1fa0d2b5495057a29104d610936c1898d1058f6f7b90e614bc2e3ff56b1e75aa4708128e3782f602dbdd29ece268311965592ddd536ea63841ea953b20677e0dd911852d23b85a3382420d22cd276b216e81638540b04966210a9308e8f9fb46958c967e3c2e36ae081a95cec8865a87d85d5689f660fe6c616ebfc2dab0f6e41d3e8c2906405fb98a506d90a8e8c6201d520a0deaa65e92e91f965288128101427d58e0b1e3ad8a49526feed27f3bcc6d505591483e2e4cc4a9b678d63f3abc905f26f91083bc595b89ff0b6cc3caa9d93013127ab7b30fbe18fad6f7f380fd6d5668fb6c3fdea3771fdd3004994e5752275ff7b186f9ad95f9d7ff01263f1165de34c1ae867e8954d66186880a90d73eace4dc1b8b17c76815242342821b4fab93755c3dc24e60aafd1cd3e283a7414de3af18c61328d92e9141916b8bb816de024a5a047a66508340a3287f698a41804e297916ff04f2921a0eeb8fcc5690c7fc024f57ab1fb6c6bc9a0caf9bf9e0e9aad64ceb2634bedbda6716235e4b93b67cd07ae06fde6abd2893143b55628be83fd4b347ce407dabf28e288f99d23b031376bfc1b1552cac1557e4730b03be581a92feae7d39fa2cf1c565a6cbe59a83b64b90ef8fc73ff6f8b9562d77fae1221df8f5ddb029f12ae80c3f128b87e56f78224b875af54a2fa1434749bb2e1c7ad9331497a71015ae0fc63903f36023e7f34b97c6ec5976ba3740845e5870c85f1b2042cdca86620881e08595215332de7d5828844e9e44124e42e1c60f6821cb71640c6643b01681553c932d310632a8b21154445176eb1a9a3c87dff22508bdbe4f1500e19131a072c42ff1d106ade135722a9e37e95e7e93917378e7907aae4be92dab78b1cd5a771d6064f6e3afc26ff84943a84de7f6ca6b0ab5993d1013b061da4053d77398cbeb329a6ae16f76493f85df1164b4f1fdff69bf113c8f18274a4ce6a05dd4c1ccbacb8d2c3760210e312c3a344294b43b23d06b7ce7263d3178e4fd530ba5838dc0e517b7d6fff2a0d9c4d69105a8fdab3f0c51a219c1ec10337b7cf05f8f3b1fb0a09f600308e5c21ae6ae06d6f87a6766d29e3a34f331f520d80524d580bd54b25716b6b937534233b856e022d20e53779b3a4a3615a3d62d1824c2bfa906e7804d629cc6712a3aee8c3703e99ec807cdb2d381acf126d63b83a2ce1d8f5cb768270bf41ae5637976acbaad8a1fa52cfb7a2f012966f3d29867cf2c28e504043a09eeff91917f6e96dc35a7df124074da73a20b87c7c8e2196f344cc08bd4c2406daaf6064488b5f9983131d90141fba82b13b0b1ff60565be66d53c36df3a9b4c772bffd428b34f94060ad32c59c9c029eba5fabd7a01b4e7252406c0ce7bb93c831034b100cc71090b37a436f96ce902973e2dca9594886b602ed6142697413aa448652529fe688a2e62fa96f8031ade066bb2bdc682f0ae3a526c7ad3c5d01e243b999a58aa5f6816dcd7a0cdd49202e128b99436f71e7fb7033bf96d8e3930e39e024530ec4b7932d334e54a66bfc3630b472336b6719d5a38e6e9bed938f71fe49e0af0b20c5db5408cabb3227b1690e904ea3116ee568330f56a5a698b914570962da4d831f5f5acde9acb257d272d0cd14e3133c89307f2d1575e32b8cc1582d1e4a680d35a1a2cace6233dfb4b0a7fea26f41785e1ac6007dd20d8b6dc3bd6857fa487c52b39f86647a67931b33910b746331305199d20ecd2e4d3b454226a134240831ea5a35c1e2d603c48eea209868b839c79a9318b6fd1078bc0f2bb9b0e931b64d63fbbcbf22b41e3cf7bee5cecb3c0e7b3ae39cf736fce8645ab33becbc9586a9154e29dd88f42ec7deecb2a4c08ac020ce54607f8006d2aa05a689ea688419215f0a10043820d85965a0001f102915fa6b2edfc4d6db7011a725db79b3974e9c1fc1636781bc9609359cfb0c5c921b83fc1115f7ed2568e49991ef93f8b8ff93a0d778251f0bcaa00ad64de8438d40aa05adbd1d1d1d2bca05ea9471a2c1a3733e92bcdf896d47dbe41b9f0d8b8b75de1ccd7cd7b7802fc01c4536a1a7b52ce70736e2cdfc547b58401023e34a608c1b09d0f13ab83d7b3fcde0e050c8cb4635508ddc143a9e6edb1e5a489a48ae0f4d5b0cede7d1b0ed8177709edbd61d859f6d9bad93a4c640684b7b8d994d8f5c0c8773da2b7a5b57d28b58d3f00c53430671d4af1537a262e8ea44a1b943c9bfc5082ad86d6690de32bb6527c815da065061bf79562d292e3d4799aa0df968fb939f64203f541dd4d006e5bd0b34b39215a972c36b229fc2f8e7f10e154b369d7b8f85f89daaaba6ec9836ad748dd79be4a58210341a458202a16e152ca2b0338a116a8490a7fa52c02"
let t = readZebraTransaction h
it "Transparent output is identified" $ do
case t of
Nothing -> assertFailure "Couldn't decode"
Just t' -> do
let a =
"utest13dq4u4dnf3yddw8lq2n6zdclshra6xsp8zgkc5ydyu6k20zrsscmuex46qa4vh84rgd78sqnlleapznnz7mnzx9wv0unts8pv32paj8se5ca3kves2u4a89uy6e8cf4hnarxydxh7hq2e9uu39punfmm53k5h45xn9k3dx35la8j7munh9td7774m8gkqgc4mn40t69w20uu2gtks7a"
let a' = isValidUnifiedAddress a
let tb = zt_tBundle t'
let myTb = fromRawTBundle tb
case a' of
Nothing -> assertFailure "Couldn't read address"
Just addr -> do
case myTb of
Nothing -> assertFailure "Couldn't read transparent bundle"
Just myTb' -> do
let pkHash =
BS.take 20 $
BS.drop 3 $
(\(TxOut v s) -> s) (head (tb_vout myTb'))
pkHash `shouldBe`
maybe "" (hexBytes . ta_bytes) (t_rec addr)
myTb `shouldNotBe` Nothing
it "Sapling component is read" $ do
case t of
Nothing -> assertFailure "Couldn't decode"
Just t' -> do
let sb = zt_sBundle t'
fromRawSBundle sb `shouldNotBe` Nothing
describe "Raw transaction with Orchard" $ do
let h =
hexString
"050000800a27a726b4d0d6c200000000ff8e210000000001146cc65bd6d252d09b8eb0a8ab0aab6d7a798325aefc1d3032fc6d31373a85a25a3a16b447a698f720ade1bc290a74d85574b5b20515391035a67f8d5883dc65ea3ba4a17b009d6f325d41072b3ce240270959a7ffd040e5f16c697d8148973c62ffe037fc83aded21e4c91722b52520a2395c23e9c1a896f4b0f12d32ae8e31833d9d95adae40f6ecf7aff52af184efd390a4c1aa76b5fb1cab6003b1a8a004016f385926661f56d38273ec2c3df7775210310a65fff5fa9ac5509f0784eefea28bdcc67b0ff69eef930335f3b9768529e2bfe733024492101f642f989de8cbf04dd66638e9317780bce47085079675b772664c8007e96597dba83ea9af22ddf07ff1c212983d4a902914431245357527294e69ea5616e720ef1e9215bbfa33ba108b8d07efff2bad1850525d7725c681761c9b8c844a5548afabf176863de7b4cde3901defc3e83d31086d3c6e6af9a5fcc3cfb38b52ac7de84f91df5e0587f7603773401a62eeef10cd3ccf4d927ef42402c32f32280abbeaac33e73ceda52089820a186e9a1adfea81453998c6bbaa0deb41bc4f94586bfee80bad25fc71abe7c6dd44bcb1a6929a0112c7e4f8fcadb9745bde9422b954f72954c4d22db48719de61f383d620935b647337f73d119d79fd208e1d5a92f0855447df5782cd4764ba91efa65d9e4ebaa34e2eccb7aac93a5b0efe0c7664f3cd9384b3ff706ad3019c907cdcfa084351c9f6a0bfa8c78c91272ca66ac86dd6e1d0d6ba9704ea7dc54f71a053dce91f844c1ca62b5ddfe6b53834f4a816b1b01460810d9b87517659f4915adf4b84783a60ecf3bd71569259f1ff90a91a0b314bd4c77976d7893bf42e5d6ad0f8df95eb6d6c69d41490be8e39b2452df3bebfc297d5b0fc97f081890390fb0727a96898585f0120a7da9a798f2032590553f724d8756c67c5b0d1c0d23301c4ed60fa283994fd712aab17ca6360256fd5aef0ebc48f0256e3eda5894b53981d0d46768aefdc85b48c1525b7f134dce5d4ec2d76c03c821513f1652d9671219d744bdce5e69b9a74ca0c7c837668f0d8ffffffffffff9534b3d594e1609b3bace18608750b35a066c57f85e291d194400cb351430bbbe212abba32be071e747b7310863bd5fd989855a6567a351b288144b6e9f838c6a517db94673246ef0010b65f9c0be8aca654f6f57b83d893663cfd389ab96ce50e8077fe588c16b1b5989c6cc262e6658efb9b88ac800e49e9e5999e2651b8fff28fa77071d63790df155ed8344e2581ac5205b31d4f17bd748fcf60e35a9d6048d23c94c7aca8d4e541fda497aa268df9c173af5877a5da56d8fa2a42166900c734b62e56792f6c8bed48e4f108a817e83d64d6a59e38cfdb55c0f8a89bc7507c89326266f7ac03a3941f448cb879bd792bb116d0be8876c0856a76ddec0f0c02e16f0338626013ee5f6037fc6a3c69fa291204039d04d17c11295ee3024aea8f5d381e9b7eb3f938b6f9182bf4f889f1e53e30f998b1cdd23f45cfaa20aaef058248cc2e1c487fcdf54a4bc22a68a17cb6fa7b2fbf333b99feb84643d321398b675634929602126b2fb40171e514769bf82f18c267ce9cda0c24300caa9a5a361144d3b7b9ab2243ee9811d9b2e72c8bb1d145cdfcf6b29994a969b41c47208f5dba8d6d871e490e9b970afec4d8bca40ba51825cdc78cc7cde6b6f235a4105b1d1b5e2765efd753095ce770f070b02cce3316721b9345680c146c2f428c0bbca90d5a8cd0a1c4c31cbfa8ec165ea9f9c71d2d05e3cf8bae5e779786f179c45a3cd8087d820cae812aded04f8acda9068af80ea834f79f1bd03bfd66f8a19074649a85ce877df1a621a867debb423ec0d19015b326fcf6f143aba34029c1da2fc7b099378a366c38c9609ef6a9d9e175e21b0c1ab94a84e28ee7f1a00e39cb6fb59f44e4567e9f85f8f98158263c52ec433c042397c784edb07c28d2bca036f59090e819157375d610acb1993a4107b48da13a371f5383429baee209b2c0cc150fcef79a042749668ba1f89ad24a8c746142191ed0e8fd63624a331d98d50daa84ccf9043076947cf5115b9f8787acd36000c5e72c8d783b29bb28a3e46036d0a592ce8a158ee5a7ac210be72d3a6185c13645d96a8446021b64043ab8b589a20091c152e7d5a993ba94770eea988e289e1536d0d81dbc7046ca9c6d918446bf970894f073c920006681ccf6d1a3f138519c68eba0296069e42dc60f2bcd0f17c400efe4f4e87de8606606dc4fdf31494df4d454d14a440b1d9db4265c7aa9bc8683c68cb149f2cc826427575e2af82e842199a9cb9fdc7243b3bc12f1a71c37eac5cf88ba830cb95728897fa4c177a290d6b2b3814173262da14db9b4ef39fc54f888a6ffef4221ae672fb03bc78ebef479360a682ddb12ea0369a428a6c2960ff8327e9a2f5e5d98ce1eae748db8f6a4631c789b4d751d6b99c97c149a813998d44a7b57ba06c8bcb8a6c73c6388cdcfeb1346cec8fee7bdebf2a2388d9722183eb2d2e0e183cdd092152ef640880f4514f3c5e836cc3a8249413500630aa8da85f9e3cd92bdadbb69a2bab8d71f0b3ec5832a7ddbddd67b34c33b2e12a0c8468e852e4a8f7df45657e9632088aa7c6c5048a2686019cfec33b27fc88e23759938dd55a5dff589c1c21a37da617609e9d8be37dbf9bd6e84ee160fe10268171d969e4611afe9d3482ed4b132dcdd11ee516f36d512a333da20266fd984caebf4937fdfd18ed07b4a45771cf5c8c16c6b258b289a07d136a22acc766011f366c420bafb8fc1a10e42219bede5a3d1166c525491ab60bbd1f973fd3fb2e94cea888e24d5fb0adce51faeda75d62de70094d4b36d38d03cd824d284fad577c3ead4d98bcc8ceccd18174a889b22380bfcc12656e764ea0b8fe1409971283008ed02cbef89d6f544c62c3b001bfe96723fda9190deecba534d69cfa358036fdaf16127b89f925c52d4e750919ffb7182b6a8ad13d0a8e00e0b906978dd24ee11869c1a63837a80e46e1216e2e273aba07aa5b0d97558db0ba7f9ac4c89403c65f1719394e479311f5cf84746e6be6f1abcac03194aa8bf1735811198b5df90dd6cac345779c185c24beda0101b932048dc4144af664a63acc0c395052882ee1f18bd0ddf13bb583861923bc00ed5ae815b964698ca097eda1c4281e039139fa3091890244f926cc4ab773ca8a35d5263d3bb48fd6ac53a4bb4d7d60b36446dbc714c35b5e13a17c5b0c70f67207839d1f7404604aff63b2fa83a4da7dac92aac96b3f250412f8d04a9e298004313b02edefd076c67d8a1316355777814e2e1ab03690e426b672d32ff65c03c592ecce6a70e34fea2e15b9a6b4fd092d027199caf27e84e25c09380b38a5eb8985355b3259aa1d94be74269b84f953053b02ba3be9df872ae5fb2d893188575bdfe222ba267b5461a0d0be274a7d9e6ee51490d98e4cd97978804c4f0f8e9f4908fd8c102b01080f5a02b7578591e95d60f3f56d8e48514b1ce7ea6894f55a32c8ac8564985d18c6b82f8dcde5b315624e9321bdd49dd350c87907cc373c0238a79321e6250e38a0ceb2c060ecee6708c11cb30a49687da9923bcdf011f9aca27e6eb5a8477a2bae2dcff9884cc2349b51a66b5179ed2d8f69e4bbba74c694194e83d04a8566228227eb732a95180c6788483d1f259d52c52fe43357656d50a1cf2902c3124d60d15fc85f0447a1203f824c1106452cfec1c92b18de003f82a0000000000001cbd27436a221a53d08c4838831d1bc60ff7e93df41a51412ef6096eec98bb28fd601c53a5371b23a497062635b5cdde715c23840d37f1cf328f0a2ba96260357689ae3f84a80dbdca1520df68513be1285177d3c0da664c64944de78d8b8d5864f5ac15444cd3204adc4fe487503066c18fbbef8d0515248b0a97577f5aea1d255788ed4bb66d4d56303efe135063392c312b4671963daa20e0ade262984e11263a1588eba3cf829e6131ab506e6a850aacce603e8ecfd6e794c90a772603d80fd2aad6027b34854072a0d23079252adb1ba637bbc650ed4afd35d977e1498d998020bc1c814718b48ba7378a92c56827d3c2f20daa231fa51f0a9188520e2a11149e162489f0d6dbd27cf94fd5775311d3dfbcfeb431bafc3515bbb8c4ba4488c320dca0dfec548fe9f46d8810b3f6b16bb3e3eb0ea130747d3d127c5953ca8d561f8d425a35dc3f2cd831743139fbdcada42308b524313782e23b32d5d54a265eae408623e3b2779fe60e13cf47d54dfe520f9f4e57c68aed31f78629a9074d72ab87bea993a38f95ab40df3ef01735e7d44ad365a786e0d3032f1c1dc4e6839c974185dbe63f8725e79831ebe269f94c96705639ab38d5d0700da04c6a9f686e1ea13391885287ba43cf3ccef1c2227918f15ed55441c45adca84153530bbfea3cf37adbf84831a2bfcbf0ca4a4bbd90e623789fe993dc17503ec11b1ef3049f27b27ff778af364d634a46165cda1dd8241cb88740bce74a73e7e3d656df2dee05bb561a85e64671b191ec802c5bfaca49b8168e44271cf13df756395896ff41a99654f55b6951f20d04b2007938a420218db8e37445ef3267130e288e3270b13a92596a26043e1ae84f3934cdb13363bc2843f74a0f6608a36b52c985132aa427c56b7275a864b3c76502c37b8abb8d0286b3199c78492ba8103f5a23c6cdca2292c75d7d6d7080108850807f78af3dc7e418371c6b8951bd89b79fa586af4e16096b08ac1f4dc2b1e4feaa5c040bb002b57311523197b6e2bef5b79ac9c9b4a339be6f6bf7fbe9b5c93862c87be6647949c70bb2c7e268e2ab39cbadd69de628376b3af744eeabc85b599bbdd09defacefa443e05c9b5f259a7783743fecf1a749c57cacc85703269ed67db1d8d475f6fe25d66f84a77379411ba123d98fcb3ae4eec306489a08372893616a91268ea6bf34ddbf0fdef1360ab9e82f4ac80a24e41f439af06fadc223c61f445b7261eda5e1320e269d1277631ee2245cf930244bf8c04050c514e2d59035b80827586cbfeb7da7a59c1208aa86390b9dc7a9b6ef38879ba4deea5eef47c5c98d9167594cd730abdfaf082090efe759d1b13199d739c112ae324ba24b275bf1d89867b81f4580a7ea3a8d3d07b45e2de6c1c7099de3606873b13f3083ecd1e84456c9a1b1d358075c68b1a7cf0b1f26031a2909e226f5da7877d0085b879165ec4b1d9abb7b0732ab4a6f22d9a7bbd0d494ef3f9af4903dc733fe92c6b2f557d1406d223a93e8ad6e579ebcde9c39a5652ad31335df924e5b6a09a0191821b4a0c8f886e2d7860b75ae79ad9dfbebf3500c8b9762dcd131eb5c8b866b5efb4fbfdcc5e31605c2b7d2ff8db5198a6c41bcf880065ff232ff8f84ca3f8022d3428359dc9fb19f57a6ad3f3d174d8a348879a754b37095f01d9a7f6f873798b97dfc5d7c7eaf0383b3fdccdcc11b30dbb3a0fe3186a36c4ddc9674624e38a81cca60a9bbc1b124021b61a383b7547d6af187022c133ba9d6dadf711a3af3b0255b859b214ef6c5dec592248fc94339a64f19196ca0fdad80f7f8e3d78b1f783b1f038008d0d106bd86e23e33ae5728872d42a555bb36d0e3303f0b4ab41180f4251590ee3ee244b77191c31b9f3f990f71c6e237b9dbcf7ca21c9b4c2446b856c67861785bb9edb920b8f530a7a088313ef044419a879f26db137e1557d079315844f9f60bae03d8cffa7a28bd2857a001fd5d2d999fca95ff91df0e228567f6c9ff592b77b7ccdc93a951f7e34910361a8f4fb517e1c9fb956a3bb50ddf37ed37e8d26adfc0f71e059ba95ec77a1e34e1b3420c893f89b79fc72e3a1d864fd35526727f939badc29740f5ef9c0bb9a3f72e1e08b2ef2ab366f80d8e14e03e92162736e2ccb7cde82b2af08de8a6a81c03c63e2396974ec29fb122d818a2d2d5b29d11b704d3ac3b39431099b7b2f6aae04d28a2182b55380503127e4986ee9e8d5c0c2058e09e4592d08d013a4f088e45403720160622236bd56fbd9cc240efceb1b23c19ceafec49e9d5776ca9da5f7810ac979cf6ec5f678c09257abf79c9ab55dea00054e11b62c0a0ed4363d0a96a37ae1a323aa93bb1af253885afb684ed30caf5cf3b37afe6a6463a16f34cc28b4530c6bc6281f597bea476cd9a773205b96d47ed4b0bfeeee39b7ea44ff194911bcddbb161c2c0ce9488978b99e880d8e43624dbb4a567483ed293348d752634b2f46219575175e3c249b8e4e853142b66491aa1c142e7bb558955747cf2bd61ac802a2a4784d9fe080f771dd537d0ff928b3b04029d9ac03175c2d535ad7f3c123eff30c0437b32dd9fa31b2976e369b89b79a2a95e31aee15a462c5fe25fd937ce6b0795808d16163f2cea8f19b7c83913cb4a793576aa5c0ddfb6415326d8f2be0621017616c85ee46aa768b077dbec72311cb8a0f78ba0621a277a79af6607063839a52c6825a20e1c5818b24628862aff5fbbfe87311866b9956eeea7412ef69a3e4da84699b8d8b45c74ac96c3356989fd4962ba79fc26a92488304fd9f42486266b433eeb57368d26ae91ba4e7ed812581f790314cc7f44639aa7f6775618111369e8e2d68a6ab24388824bbbe3c3b0fbfb88635c1fc3216af1af40eba3555c0b0390a18ccba9e68afbcd21ecb212aaf82846f0a55793945902c48cac5d19332e23248a464529f4cca177137c508b6b13637e7df523254f24b8343d19164174202bcb00d5fe618b760c374f69b5065b1f9acf91af95abd7eb271586cae14fc835f633aacb4cd2ecd0f0ac08b688ef4d13b8a7b4c487ad46485bde0e340309672dc38af275e6ab525971409a39eff0ad134b1674db5d1f9725874e36d8730dc034b0a596c6e0a26e521c199d3e3f86815a64d148ffc394290b19f15390934b5d0da27dc8365360511628b93ebc375d2a531e4f4cfa031eeb501afe96d201c7b6078bbceb8e5d8615599f4c613bbb81a88f4eeaa57a9c008125073a30154044c422eaf2a32cecb15aab0774bb44e52b1792d154b8036ff9224af53e023fc011ab251d47d7d76e55c5015db1926d43c56d055feca1259de53ce98a2faecb5843ce17a3e83ccf678f5d13a8321f278a670c684e62b720e1eefd0abb2e9d0a3ddea81d5eb6e380a1c22af5587daac852e93a86f5e4293c18bb26b32035c7e5ca20cd2e3eabd3de0e55092a79a42c7ccc0aef033d6683043c2a29531a2ef1f503595c0e464ac042153c4685b062275f88bab93cc017f1ef9dc6f8aeab7b0b234f1c543420324512554f1786c82b37836238a4dfdf86f97d09ae466eb39d5f3ab159e2060be309d1284be133ab40abd61468c1706f7f9e57a7bc747479693a03edc8863dd196fd7cb2721260e42f4f606389c4972c74d357e7467b61cb7f455562015d29a59c7cafe0df03f26b77bca81c2bbac8cbccf8a65190b0c4e5ca832e82ce4e11044433aa397106cafc05634ad778270d20d8a13068586bc6b582ea24524fd921a5ee22dbae5296ee86d80f12b78bba26f8b42c1401b75d5cfcc4775c5cd1cb0a9248dabc8f82d216787b2a2780f7d13a5ee8c6ab56399a8dd5db3a152677d01eb8ee98d1927ca5069e0d1ba3907971a2199ba3634b48e570dd97d93729a6c43e4f359e2d89795218d52270a338a1f511b1f008cd04553c1a89caf987fd18c329be7ac2282084ef1789615d7eb7afd2261f606d3953b8863abe57796289e7761b01c3ca0faf2291287f9ad7027d7f0876b5f77d2a7f87dfa6ad4db905d4bcad042f403824aee3b4f8d7b5ab027fe1eda9d683db24f56f694b0b10ec72ba0df40bdd6e52b4a7b8d064ad46c7490c4705c14b06ef55222435d2d6316c7dfee83d225eaa431c11a4b85b0bafbe66fda1abadaec8eabcc2f8c688a7b9cb2942597f20cfafd7520892c535bbf6359a6989a84dd89989d95b8e5222c3aca2e8b0f8881d759e450466b75b5f36b7b723b0a212edf52abd591e7e545a3974b8b31b84b523af7b47e3804b5a268c86ae0bd7c80bc6b578b79f749eccdb4a00813925ef40259ac10bbd0fc4f2fc536c30f7c1efe68a52bee22f57021d23f445211b36fee6302202c9b62c6cf9064a2df424563f9f805e51c4092482253e4c258d53b80a2d26eec9fcdc104f7124d876a3ad573a7f419b0d67a41a34dac9d8f28cf9519b9c2677c9d1e720667d5fce26091d64c6df8b46c98b58017de0d055651e8caa3a230f57aef214ae2f27fa85400e34ce7087538fb6b854a6ad534780052210b8b8c90b4de4c2afbad9f58a71770ec186cfa44b61b53876bf904972078673845ec3181caaccf11f71a8e2a502deaf144f16df1df3bd81277dfbf6e1ae5a17363725ec31759b743066fbd4cafb5eda6e09418bc375f42e0dcbd4624dbe26c5fabb77152124f400e677004fcf3c862a9b5576140cbeb800fcde4409caae06286cb643842687bc6b89738374c7c759c911d7bbec8613f1fdd996d4b970fb6f2a9290a84c34d5fea6b8006357c8e6e9d4048d5a8ec476dab0b55e8358ecf7d27c31da86681f3fa74d072b1150223eaa21c4027378a99c8a2dbdc07d4062c401e92eddfff82841292bda2798c4e2ee9e09f618cc181c91a4dbefa44c410dff5cb705ee005e3a0470c13baddf9066109797a3b51e73a0ef229796d330aee0c0160529a4ca3b39e861ee5c4a0f78619007ecdf32266c7c42f0c972b91cccc45f6f8688b2692f298721cb5da39cbca9a5adef6969a2592ba421680241f8a5384bb92e70acf79c2f41d1171dfc6e1939887b9c8ea94429bcbf3532919fdcfcd0f443d3c95515b41e3f9c84bdcd3de1fd481f98482f667f2d017e3579208341e9a225f85516c8ca133cbada77598b6f596e6151eca377fcc8029cc99a879b26d975684173c0874509117ece4136bd2d69848f858c05e8ba3421499d7fb5e3e7645fc135117d8fdd1dc46bebaedfbad4dc7cc23fad6e696fe349712cf7579b4e63b38cc7d02a4c6a33ee4117d7ccdb86ea02cd791756b2a3c516d59d39ed83a8c328823f1934731820c187624219b487ca86edcc2f61a064e4e8d17f58f4a71462f3f0cfef6be95c0eb3737616de5954096d761a51534b36d798c651541acfe2e5bed6e58c45c46e014923a342409d49e782054f2a4877332e0adb0663dce0e84df0ff0d71c4c5ef18d9cacc8b8d47c78d53fc7649bab719334601c79a345d2101e65d4c3f1616741b24fdd9f7d6569fb8de67799648b323856c2ca96ac91823aa12249934c7050505258c43763ac9b174d55fee71c7817d65056c30d7853500656040621eff9f291e9db198772451cd3d58bc9421f6191a863777edf49125543b22ba127ea3063e1989bc4635d50bb22270948ba594b2066d91e1589aa0c1f476af8b170820ae0d2409df83819579621161ba55cc8d020e1ea68cedbccc9a737746d824b06e12cd2e3730260fdc52a68b6e142bdb997d8f93f25d241360285e7372939828fd54c015ba90bb4d553558ffa2558a43098644357860785addc455bf1ef4ffa5aebb8f002eb0f6a8ddd6f45edcc7cfe88d7ae7141b9113a4ab851b5fa8ff39c7024d2b3202841266f256b1f4ce4e4ea8b83d0067555ddd56fb1f8ed6cb5ce7340cdc403fac1dd3b48c373629202c70f1f95c0001b4f94a9b4bad9e1c64429b541ff57a2f2ea0c1fb2af8f0e490fac415cc3bcdd5739f2069e2bfb873206b8c8811619f1db39386cd2dd748c6301239b4e873f3d4618a43c52ef7d8abc0ca127881dc8809dc20a8730718c64c5a132cf638ec1e3b3cedaae55763637b4c6341baeff17e14c1e3c34e5d23befdddec0c7e25f0ebfa90a0bca07a0f5446507b7fb9cf91cb3cb8d24a111f46e7dbe3ea62b384eebecaf8de49b15b17f9cf151c4c3d33220b3adcf9f87222813ff2125120e77c638ab19c1daf9631d53b3efee67c3c40c9c23495848d4c5ecafc0998bf2704bb78ade666f414e9c6bb100b90451d93397d062b741a3ef20e7e6ebebab8238e2adf415775179c866eb4a2f628924674b20f711d2515d3b024e7e0fd3af6e116cfb0030709fb9bed4a441646c03dfa0b11cb460415ccb3c0999b738a0b07d55be741f3d2646a3d9e22bbfeb46b87acb6fcc2d83cdf44b656d2269a0734259a738d83a7429bfc99da7238b9497fbb10e0f623dc1f793e3be2326a7e55677e20ebb152f71794fd70d7698d0cff1334341b3a8eee38d66a021cae6f8dfe67913fdeb8d46efd9b77f28950aee7ce112f8f0dfc04132a99d95dfa923d391e06a578056ec8d15ddfb0fe8cd2790ed55f8254c6351d471c7273c2e61c2694bf6b0a1173cdc2d422246ca5cc51a9b8669dc331fe33bfe330d5167a244cf041f8444775562eaa8ddb92e0623d4c689db0919ece87a7feeb1ddd2d034a0d884d6bc8b5fa5fc7df00cf667dfc82c9e98e9b57fbe07fed391729034c467b46d3d16ed72c8ded069a117ca2d28e71ef4c37f1b1939590af19433ff2a784ff38134aacc59719673c53ed047d79e0c36f3acc03f64458826107853ff8d02de9362ffada79feabc597d019de6afb6577dbbefcaeaee801a49b1718151690b43a4d70b2fcb73ece3e3ea5fe2a9616cc6a9a494b8c6c7121497688652eb854e7bae19af3e5ae1a8df75138ce18621d11f15054ac8971f6ac084bd90e3909b46db321916c9e3c8950f3cc8e0a10dd255bd6b359c73dfde7de6e01538d03609253968177af14d327337bc1bc4e866c75ab5b69125f9e9a758f061418110a615b97f733f899382e2a14fa0ff0d1bda3b7449e1f54362697aef064fc9dd50692ad2b9ec286a1b7c1f845b09f4b1ccd46142f9e272d018eabf76c23c26b1831762a8a2c9152ef0cc843ebba20bf979e851e76141f41e817cca0ac60c1baf239a6c920a244b0be031a3b65d76eebae15bd9d49c53dd3e4303ca379f26840901f1da886d330d8ab4408a25eaa280ddb545b968b4aa59ca6f9cecbf82984264a3232b97498be0729f3d97dbd64823393b42794ec1676244212af382c37d53d66019a5db34c3d8ac156cac852ecb1c57f0f6057815460eb9f666c368acca6dfee0d2b7bdacd2148d74cea3bbac8b528f00809f403b1964b9d199d2db93363a53732efd97c66f28cb51442dbfb1c912dce078944e02889f9395ff2655e2d7118a11848e3ca64efb5eca119240b537b5d4548a744d96962e9b2a99af73bc4d753df16fe75a08005da7773b7bef68a44f56951a3a93995c5d0516a8b2c39abd2057b3d86ba7fe511dc33292596fcc4d3c67df88812e26d3628527752a81c8ce6eba711ae7ea8748229caa2580e18937f45cbfb0041f0a9254eade41c95ef4f390db6174e6b0ba89af344c215393b627348ebf00901e343c1599c832bd2cfb751750808719f18119ab3fee6baf5fd4b8bf7c92a271ff24576984610abaf1b2297c18a2784f57d7aad26f52c0d60fa6cd2484492a1524dd14924eebf53348ee2dca0643ef47381541b91d1843817067a94bb7c79e4e08c4d81c7266afefeda4a0db21b0db629cedf13b4f6ba11e6480116a7c9780009ee0e1e2bd543dbb68bea356a6010a1e3ded4229c4d8035420833fc83337dce4bc483eec76f479f33be2d6a8fb013813952eb66bc247f37f9def7e9bea0f277f380079aeb48c192b9c2c24f909435586bcb994ae6f75eea111c8842b855f90df21e956f839aef89bb1b96899e343cc66814ac08eed4defe5e2a62c54cf83a27f0499224e02bac652aebe6529143372c483edcdbfbdd5a02106fd3651875f23724d2154c0138ace745d038d6cf6b233ae2bbb8313c8ab59dc896844da5a6610845d9147e57518ada61b7debcd66111d609587632cccb936751d099639735f09f77b2b9aa1177e95ac0f8070bcbeb01bbfb3e7a638811d919016ed628865e2405aa17f5129ea43a836a76ec7cbd943e20b1e388d47db2df3394785e27dd7efbe350ccec6057af7483303a6a588d4005c05ff7f3c90dc5b9a0f95c3c541ea40615f6b0ed6cd3787e608e7612b52199062991a63511b3055dfab25b18ab55948d9d529aff91a0d8aa7705afc187e32d1107c07623a309390f32c62e1abb830bb090a7dc4c6817b554720fce354563662d78cc2bcd0483149b304ab86502f0ad36ba2c262fa60b1b84be2499e56fd72129c0fdf1961214df8dd6c9b831109fadc7464df090aac96d221ab387b6eee3080ea0d94e195ca795b5d80c42946c0c353e39075bb1aa4f3fac36a77445cd57b11b3c7ef0e89aca911be35fbb72e1e2fff84b7ece66bb8b3dea52b0aff473475d298f730e79ff77e955856817514908baaec1b53f39f9d5dcbb1cef29536a483a1845d8538e5ec43f634914bae4f2319579adcf3f0fbb151c80b54f02be54be612f9417f916579863dc16da5af07fab05db2094c77612b445b7b9784198abbfc8387486449969118d3a83142022017d69b939d30fd6b1c5ba360c0e37f264b5d604c7ebdaf327874b22d4092dcf35aad93f0f0b3037f90000d4a1892dab827d3c2f1ddede948d330706ef17bf442f8228c168401541ea89a837f81cfffde8480e1b6014f2f5d3132ee740e04622600ad93dba41e39267f17554b29102390f8196094de19e8d966d3c03a9e3348494b54045629224612734a1304ed76d17a465c305675bf99b7aff1950dd2012e6cbe8d15a9e35a7c16081bf647e2766c7b8e9d12ef8a2c94fd7531f6d1a7ac7ce6bac028917a2a71c8eded4f3ce3be8c7d98422094e88414338fc25839a582b5965c71179ce3ddf7a645bb163f3265f4bc4ebe91ff25d86520696d237741ba73084070e23494d6a890e1ae748091a6936a3137d16dd14571f86ee118bcb17c8ecd2ed20c25cbab79a78c53fba1d5db4fdb15e6a124bdb2d41fef080e7318f78c67451beff04b58a182f592fec3feab6011be4663dca8b62ad2a8e40c716b3c8a170e1574517c44e146109d223529b0de480aa168b5a4b0522cea03dd26a684b08c58aa2e1fe41f44ba8837737a74a4681b0508d9604aa7484c5ec68ccb369c056702b03f75722033597ce5b55e5a88f14e3ee23b1c96f5d38604128cf2e901a745996f4a29d412e5ce1b4ee82cf2f248aa80f8c8f2eb7b6951f1b0910857a17edc319bc76b1a59fe05f9394a5b16a91ef15afba9ee2e115c9c9afc51a8d7c4a61cb335724855007f564fec341342d53717023118917304c2dfcf0bd79e456c94718b8388767564d6055aad1d505f36506fd6e8cb1a10f6fe8a67e772030dab78b43ec15fae0322fe991944be86cd0bd78ba00110474dec84dd9597a602c4a6c97a27f13159ff1e32fa63e28f63278b09c9d051cabf8bb49f2780d4c33ca061ff16c6288ff29d46a22e31c719dfaf6087590ea8197c066f9057e0c24b40f5eb205b730985daaf7e7d85fecd7449677c0ec1abd7111d795de6de4a6ab30cf266987dd55569f2a705ae16f51de738fcc4cc218f2cb9dab8af509ba26ed93ddc7a73028d9187527fa6d554b491faade05852eb50847affb81b58d2501989d5b4a9de4237b33bea154c4d016b08f3e1c39ee61382fb500be2123ccfcd30e37c88979a19d636c9dcf5fcec822e5558cb2939e40e1af039aa942b503c9fce95f8ff51a2977f58e4d5032f9099fb4783b7764dd1299a1a89f21c1f5e38038f219e9a4e9d6c6edaef70132ee1f2a580227b256c9139d339183e278277a9dd260bf7d8a9853c4185f9b6509ab9b67a3563ed0b9afca6f2db28258025d8c2036cc4cd9fb4f7007dca96597c26476def29191cb0c77c44df80994ad3c79833820ce2f1108d17a083fa857397d2839c37899ce2e634578b3eee0135f66cfe1aeb7bcb8732fedba16093a6e666321236f56e285058d00c1bba2db3263844e4b0ea013e7a8d370ecae9ac7a9620eaaa244b25be1eb6e71368f550736d3ca13747edfb6254c9a373aadcc30a148907d39e81bdda8a53e8644b39a1625de851fc5d759686c63c76bb162b244415175eb0ccaf3a63d4ad910369e30313bdeb175ace63ad33e400e642dbdcb472a336d82d2f818e6888e5aef472d03fd298a5d14b8da432b72e6c5f5694887a7e4e165bc41055379bd204298d65796d5351a9121f949904bd6c87510649127ef5797d432c6c759939c99026d57076db225d7d0df01ab9b9e3e1221e7e323ff752eb7988cd2b2bbfc8ae7fdd23c3f7cfd2ae2679014e986e3c01b6c66a67fbf69483ad3e89c1f2dd0867f411151e048d81212c0b5e2fbba9d317f283f97c9576180121f41856355b906a22c69869bc27729db5974c5b1257b35d186dcb4e9f7bc51dc331c0ff9baed5955e5052a6ac7743b"
let t = readZebraTransaction h
it "Sapling component is read" $ do
case t of
Nothing -> assertFailure "Couldn't decode"
Just t' -> do
let sb = zt_sBundle t'
fromRawSBundle sb `shouldNotBe` Nothing
it "Orchard component is read" $ do
case t of
Nothing -> assertFailure "Couldn't decode"
Just t' -> do
let ob = zt_oBundle t'
fromRawOBundle ob `shouldNotBe` Nothing
describe "Raw transaction with Transparent inputs" $ do
let h =
hexString
"0400008085202f89014b6ded3d2ee43e54135c04f9a305b473d7d741bbe6f383aa636e03e948705e0d01000000fdfd0000483045022100b34ca0fb34959230b95a48e9de95521dc4c013bdc0e6bd2a77a67b373fadea42022030a1b13f16993ab212d9f674b7b8dd3c6723137c183dbd41a9bbfcf66d7811c40147304402200f0bd12663a52ccb5e6211ec633932bbc7f0151ab51194038534abf88f689025022051fe62591dfa11a96095b4aeee2114c77a0d773242939f7ac2fa8e5262ff0865014c6952210231ee0c161e846bc133ad41d295f560d7e24829415afc78ead24d4b10198bb7342103b0b11f2dd10611d06cd6232233678dce736ce2b2141c62bdf0b4fe6f79d736da21029cbeda22b05352f66a338561604cbe11e8332f836385f16abf5088045c39d4dd53aefdffffff02b63500000000000017a91499a8b5b1f3d3a1a12e92dd4f3d94bee8fc34c527873362fa020000000017a914d75fe4791fcd50f2874f1b7457fca5833293b3a38700000000000000000000000000000000000000"
let t = readZebraTransaction h
it "TxIn parsing" $ do
case t of
Nothing -> assertFailure "Couldn't decode"
Just t' -> do
let tb = zt_tBundle t'
print tb
show tb `shouldNotBe` ""
-- | Properties
prop_PhraseLength :: Property
prop_PhraseLength =
ioProperty $ do
p <- generateWalletSeedPhrase
return $ BS.length (getBytes p) >= 95
prop_SeedLength :: Property
prop_SeedLength =
ioProperty $ do
p <- generateWalletSeedPhrase
let s = getWalletSeed p
return $ maybe 0 (BS.length . getBytes) s === 64
prop_OrchardSpendingKey :: Seed -> CoinType -> NonNegative Int -> Property
prop_OrchardSpendingKey s c (NonNegative i) =
genOrchardSpendingKey s c i =/= Nothing
prop_OrchardReceiver ::
Seed -> CoinType -> NonNegative Int -> NonNegative Int -> Scope -> Property
prop_OrchardReceiver s c (NonNegative i) (NonNegative j) scope =
genOrchardReceiver
j
scope
(fromMaybe (OrchardSpendingKey "") $ genOrchardSpendingKey s c i) =/=
Nothing
prop_SaplingSpendingKey :: Seed -> CoinType -> NonNegative Int -> Property
prop_SaplingSpendingKey s c (NonNegative i) =
genSaplingSpendingKey s c i =/= Nothing
prop_SaplingReceiver ::
Seed -> CoinType -> NonNegative Int -> NonNegative Int -> Property
prop_SaplingReceiver s c (NonNegative i) (NonNegative j) =
genSaplingPaymentAddress
i
(fromMaybe (SaplingSpendingKey "") $ genSaplingSpendingKey s c j) =/=
Nothing
prop_SaplingRecRepeated :: Seed -> CoinType -> NonNegative Int -> Property
prop_SaplingRecRepeated s c (NonNegative i) =
genSaplingPaymentAddress
i
(fromMaybe (SaplingSpendingKey "") $ genSaplingSpendingKey s c 1) =/=
genSaplingPaymentAddress
(i + 1)
(fromMaybe (SaplingSpendingKey "") $ genSaplingSpendingKey s c 1)
prop_OrchardRecRepeated ::
Seed -> CoinType -> NonNegative Int -> NonNegative Int -> Scope -> Property
prop_OrchardRecRepeated s c (NonNegative i) (NonNegative j) scope =
genOrchardReceiver
j
scope
(fromMaybe (OrchardSpendingKey "") $ genOrchardSpendingKey s c i) =/=
genOrchardReceiver
(j + 1)
scope
(fromMaybe (OrchardSpendingKey "") $ genOrchardSpendingKey s c i)
prop_TransparentSpendingKey :: Seed -> CoinType -> NonNegative Int -> Property
prop_TransparentSpendingKey s coinType (NonNegative i) =
ioProperty $ do
k <- genTransparentPrvKey s coinType i
return $ xPrvChild k == fromIntegral i
prop_TransparentReceiver ::
Seed -> CoinType -> Scope -> NonNegative Int -> NonNegative Int -> Property
prop_TransparentReceiver s coinType scope (NonNegative i) (NonNegative j) =
ioProperty $ do
k <- genTransparentPrvKey s coinType i
r <- genTransparentReceiver j scope k
return $ ta_type r == P2PKH
-- | Generators
genOrcArgs :: Gen (CoinType, Int, Int)
genOrcArgs = do
i <- arbitrarySizedNatural
j <- arbitrarySizedNatural
c <- elements [MainNetCoin, TestNetCoin, RegTestNetCoin]
return (c, i, j)
genSapArgs :: Gen Int
genSapArgs = choose (1, 50)
getSeed :: IO Seed
getSeed = do
p <- generateWalletSeedPhrase
let s = getWalletSeed p
case s of
Nothing -> throwIO $ userError "Couldn't generate seed"
Just s' -> return s'
-- | Arbitrary instances
instance Arbitrary CoinType where
arbitrary = elements [MainNetCoin, TestNetCoin, RegTestNetCoin]
instance Arbitrary Scope where
arbitrary = elements [External, Internal]