Addition of functinality for manipulating Unified Addresses and Viewing Keys #1

Merged
pitmutt merged 17 commits from dev020 into master 2023-12-04 16:31:17 +00:00
7 changed files with 193 additions and 19 deletions
Showing only changes of commit deb3ef33da - Show all commits

View file

@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Type for block response
- Type for raw transaction response
- JSON parsers for block response, transaction response, `ShieldedOutput` and `OrchardAction`
- Tests for JSON parsers
- Haddock annotations - Haddock annotations
### Changed ### Changed

75
block.json Normal file
View file

@ -0,0 +1,75 @@
{
"hash": "000000000079250b2cb5f3a04f47623db0f2552abeeb5fef914d8833c827ff63",
"confirmations": 5,
"size": 19301,
"height": 2196277,
"version": 4,
"merkleroot": "bbeb085e2e69afd760e48512f2cc4af788331a19ad03cf1442dc2c38bf1819ef",
"blockcommitments": "9af507deaee501f8a9a9efb367d199b21d08874393f0408412c408352f967845",
"authdataroot": "562acdacbf061ef8ef5b84917247669b45935f83280adfedcd0f9b39efaf25ef",
"finalsaplingroot": "625ebbfa357830e0ecf7b14b149939e9c95c75ef19ae17b32f660783add33196",
"finalorchardroot": "d54d40365258b350642ede76ec8d411220b93b4bd16c63bff803715b87154e0b",
"chainhistoryroot": "b4438f23544049ed0185baca65cfbc06a09eee7577b4fe567e3f6bb08f107c56",
"tx": [
"795fabb4070cc221480e3b8deba2f76a9c5d16026a5f8e2c29c833e5b6088eb4",
"66637dc7703bbacc385ef7f2e087bd5fcc56763515217822906e352f504eb820",
"b2384cd27fb12cb119754f91077453ffdc553da3be384d156b1f16ce4e88a9c5",
"c4c1c3d962f2e56b65585be3b5a09c7b42e1a6ea66c0f6492ad3d3ea2e0775d0",
"e1acb17e24b7d2df5a2c23349a1fc66d1084b1a9a85cfe760ed72fb37f960a12",
"e5aeac0d023259551616cdec6727219048535aa619bba4e722e887424cf9ebef"
],
"time": 1692399702,
"nonce": "ddca0340000000000000000000370000000000000000000000000000093e790d",
"solution": "003b65d98e5199710d69e661f6def0120bc519c7bd1a4ec4b727edf953746a261046760f1dd584f743781478251d65a4b7e1f775c192c8f01aecf2301753bd1eb472ea4b9bb33d9c6236d6f94551c6ee699a20be02342d54196ed2a1ce43c0a56cb20baeda8578498a2cd783b49970a65b8bc2c9d45d7b6863b86e5fb5291b5af986da9e11f5342477173b68cd8e58099791b028031725459bb81353f398baee5acb0390243e36e1039720df4108697dab0772b844ded785119a3cb4f30483221042c965efcb0190dbcbe8eac0f4c0ac51a404ec0f06bf83cfae33a9163c73e7402e07c1f59fb01b692167359a5ea2fd30452b723443454e22ec32de0556e899860cb029439e04642f2cc4815265b521e207ba7d794d498157d1f0e364762f32b32a375e483c19f4a7419846fc75be75729a2cff99f8f5b690d58d40a3bd1043a2caeb79aa44a97d792b0d60d1d6c2460105c304c9418fd5f859b1ebb649854a9473394057103edad7e518bf7afe1165ceff7e50365c7b1dac6c3b9e35ea842ce251b041566c3f576e961485770806459a1e752ee2fac542693999ad7c268aecd87d37550285a6a1420ba2af5007c2ac3c678401c92dbb63a423f003537bd7b93961c32314667dc8dddfc49b84dc0896bb7611da7d5347b1019f7aacf3e19c16ddf91d30ddec8f40ea919156aa75b8644981ae909f98f433012173489f443a11e1d9e50649a95299d0aa91b9d50343c70b4c209ce77222a2200dc1406d98bfacc9ac09f98d1e1d440af18b3c8327d0a1c0027e9c7fadfe181a4d62b9d3869d38c542e1b22c271b6f491f49ea0b684b4a3ca841c1ebb5b1efe443cd1b94653cc8d70c220dc95e9611c561f19188391fe2be3b9bf84e2615ca99f87a4d7421964002018b4199c8a9037b44304133c7c4bcd6a55d7aeec4f5d12d9359dbc97802350072885f8f2ea93feaa3e3b03e7afc2ad581b6aea30cafb2ea8891cc0df673b2b8ca5e1a692d3ab32b31132b3e6882937443e872c34818305f390500bb37a921b1094e05d894c6e62913c402bc6deef5989f98990256b0f99c212bd3d810f1459a30f281196edebf531392d72368df449b3ee2a2c3c8a36349bd985215630701decafe90648edebec3f263bd70969955bb839b37a724a9c9d0420abc80e8172fc1ca5a7d3b587ea305fd1d2c021e760cf662f19079bbe56a454e9e284e465adebb3c12d4d9353fa5c002c037af529f3fb9ab067ebf1a7b30807b89803751665f6b5aeea117f03e15d66e1b1aef675b9674d512b5d0d895ca5cd5cc920f35020eaaa76637c198124c2dc33da4d71bdfc49e15f5c79ca4b33f0df22682d5541f2714cba71207d91acecb0fe88dd960eb61a3c8aec32b822b4abc11ba1f63b920191a62b4e4bc42b2b151ed1e701cbd408100bb2b4fe393da9b81b708f3884cee7e7414944a481b1e1c5f2851477acc7803e622ffab7e444d7e8faa3c46d6187ed31d02f3c6790453e67f7ac622db35ac5edee7b72aa4acf16f6bd8cb3dd878c7b0223ef2ce017dcf919d120dc0c83d5401bf4c6baaed245eabea031b3c2fbce6d7a3bd3ea0886e1e0c8067bd724de003c837947284569e5a39666bb7ce0a21af3d11f82114b75d5556504d31e229b3c2942a28f51b378bdb15059e0073e9a60f515770315c0d8dd58ab3b89bd6cd3e9bd2109b67cfe5732ff68cdb6aa0f29b90f92f3707cbed01a0c20bec9c427735af54983ec4369a253521d4c42e4ca1bff59adb02878cd8b26cb952b71a0506305b8ffe695581eae625d23bb4e3be2e84bed7ac193d0267386846efa7ccd1b3b6bd04d52271bf62dd08590125c49f9fefe32a859380bc638fd4f31eecc11087e627b44a7a73786b23614b6864bec39afacf18",
"bits": "1c01b44d",
"difficulty": 78752260.61608158,
"chainwork": "0000000000000000000000000000000000000000000000000e4f2c44f6a82cfb",
"anchor": "638a7385e9910d3e18ae4240735ed4a5f6b0f410b0a1bef9d831452e0cff0a3c",
"chainSupply": {
"monitored": false,
"valueDelta": 3.12500000,
"valueDeltaZat": 312500000
},
"valuePools": [
{
"id": "transparent",
"monitored": false,
"valueDelta": -134.79807867,
"valueDeltaZat": -13479807867
},
{
"id": "sprout",
"monitored": true,
"chainValue": 26762.63007004,
"chainValueZat": 2676263007004,
"valueDelta": 0.00000000,
"valueDeltaZat": 0
},
{
"id": "sapling",
"monitored": true,
"chainValue": 1155712.35104510,
"chainValueZat": 115571235104510,
"valueDelta": 68.96131433,
"valueDeltaZat": 6896131433
},
{
"id": "orchard",
"monitored": true,
"chainValue": 96151.73011093,
"chainValueZat": 9615173011093,
"valueDelta": 68.96176434,
"valueDeltaZat": 6896176434
}
],
"trees": {
"sapling": {
"size": 72943241
},
"orchard": {
"size": 48645942
}
},
"previousblockhash": "0000000000a67420fd68bf269b63d821b158cd1da20d067e219adaa66977970d",
"nextblockhash": "00000000016ebe0a0da97446c677478aa30df66b1b503fd297ad895ee7941d5e"
}

View file

@ -48,3 +48,4 @@ tests:
- hspec - hspec
- bytestring - bytestring
- text - text
- aeson

View file

@ -20,6 +20,7 @@ module ZcashHaskell.Types where
import Codec.Borsh import Codec.Borsh
import Data.Aeson import Data.Aeson
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as C
import Data.Int import Data.Int
import Data.Structured import Data.Structured
import qualified Data.Text as T import qualified Data.Text as T
@ -43,7 +44,7 @@ data BlockResponse = BlockResponse
{ bl_confirmations :: Integer -- ^ Block confirmations { bl_confirmations :: Integer -- ^ Block confirmations
, bl_height :: Integer -- ^ Block height , bl_height :: Integer -- ^ Block height
, bl_time :: Integer -- ^ Block time , bl_time :: Integer -- ^ Block time
, bl_txs :: [BS.ByteString] -- ^ List of transaction IDs in the block , bl_txs :: [T.Text] -- ^ List of transaction IDs in the block
} deriving (Prelude.Show, Eq) } deriving (Prelude.Show, Eq)
instance FromJSON BlockResponse where instance FromJSON BlockResponse where
@ -53,7 +54,7 @@ instance FromJSON BlockResponse where
h <- obj .: "height" h <- obj .: "height"
t <- obj .: "time" t <- obj .: "time"
txs <- obj .: "tx" txs <- obj .: "tx"
pure $ BlockResponse c h t (BS.pack <$> txs) pure $ BlockResponse c h t txs
-- | Type to represent response from the `zcashd` RPC `getrawtransaction` -- | Type to represent response from the `zcashd` RPC `getrawtransaction`
data RawTxResponse = RawTxResponse data RawTxResponse = RawTxResponse
@ -96,12 +97,12 @@ instance FromJSON ShieldedOutput where
p <- obj .: "proof" p <- obj .: "proof"
pure $ pure $
ShieldedOutput ShieldedOutput
(BS.pack cv) (C.pack cv)
(BS.pack cmu) (C.pack cmu)
(BS.pack ephKey) (C.pack ephKey)
(BS.pack encText) (C.pack encText)
(BS.pack outText) (C.pack outText)
(BS.pack p) (C.pack p)
-- * Orchard -- * Orchard
-- | Type to represent a Unified Full Viewing Key -- | Type to represent a Unified Full Viewing Key
@ -138,19 +139,19 @@ instance FromJSON OrchardAction where
c <- obj .: "cmx" c <- obj .: "cmx"
ephKey <- obj .: "ephemeralKey" ephKey <- obj .: "ephemeralKey"
encText <- obj .: "encCiphertext" encText <- obj .: "encCiphertext"
outText <- obj .: "outCipherText" outText <- obj .: "outCiphertext"
cval <- obj .: "cv" cval <- obj .: "cv"
a <- obj .: "spendAuthSig" a <- obj .: "spendAuthSig"
pure $ pure $
OrchardAction OrchardAction
(BS.pack n) (C.pack n)
(BS.pack r) (C.pack r)
(BS.pack c) (C.pack c)
(BS.pack ephKey) (C.pack ephKey)
(BS.pack encText) (C.pack encText)
(BS.pack outText) (C.pack outText)
(BS.pack cval) (C.pack cval)
(BS.pack a) (C.pack a)
-- | Type to represent a decoded Orchard Action -- | Type to represent a decoded Orchard Action
data OrchardDecodedAction = OrchardDecodedAction data OrchardDecodedAction = OrchardDecodedAction

View file

@ -1,8 +1,12 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
import C.Zcash (rustWrapperIsUA) import C.Zcash (rustWrapperIsUA)
import Data.Aeson
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import qualified Data.Text as T
import qualified Data.Text.Encoding as E 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 Data.Word
import Test.Hspec import Test.Hspec
import ZcashHaskell.Orchard import ZcashHaskell.Orchard
@ -12,9 +16,12 @@ import ZcashHaskell.Sapling
, matchSaplingAddress , matchSaplingAddress
) )
import ZcashHaskell.Types import ZcashHaskell.Types
( OrchardAction(..) ( BlockResponse(..)
, OrchardAction(..)
, OrchardDecodedAction(..) , OrchardDecodedAction(..)
, RawData(..) , RawData(..)
, RawTxResponse(..)
, ShieldedOutput(s_cmu)
, UnifiedFullViewingKey(..) , UnifiedFullViewingKey(..)
) )
import ZcashHaskell.Utils import ZcashHaskell.Utils
@ -233,6 +240,21 @@ main = do
, 0x22 , 0x22
] :: [Word8] ] :: [Word8]
f4UnJumble (BS.pack out) `shouldBe` BS.pack input 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 ->
rt_id x `shouldBe`
"5242b51f22a7d6fe9dee237137271cde704d306a5fff6a862bffaebb6f0e7e56"
describe "Sapling address" $ do describe "Sapling address" $ do
it "succeeds with valid address" $ do it "succeeds with valid address" $ do
let sa = let sa =

70
tx.json Normal file

File diff suppressed because one or more lines are too long

View file

@ -56,7 +56,8 @@ test-suite zcash-haskell-test
test test
ghc-options: -threaded -rtsopts -with-rtsopts=-N ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends: build-depends:
base >=4.7 && <5 aeson
, base >=4.7 && <5
, bytestring , bytestring
, hspec , hspec
, text , text