Addition of functinality for manipulating Unified Addresses and Viewing Keys #1
7 changed files with 193 additions and 19 deletions
|
@ -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
75
block.json
Normal 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"
|
||||||
|
}
|
|
@ -48,3 +48,4 @@ tests:
|
||||||
- hspec
|
- hspec
|
||||||
- bytestring
|
- bytestring
|
||||||
- text
|
- text
|
||||||
|
- aeson
|
||||||
|
|
|
@ -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
|
||||||
|
|
24
test/Spec.hs
24
test/Spec.hs
|
@ -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
70
tx.json
Normal file
File diff suppressed because one or more lines are too long
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue