haskoin-core 0.13.5 → 0.13.6
raw patch · 35 files changed
+1259/−1231 lines, 35 files
Files
- CHANGELOG.md +4/−0
- haskoin-core.cabal +24/−13
- src/Haskoin/Block/Common.hs +3/−2
- src/Haskoin/Util/Arbitrary.hs +23/−0
- src/Haskoin/Util/Arbitrary/Address.hs +33/−0
- src/Haskoin/Util/Arbitrary/Block.hs +69/−0
- src/Haskoin/Util/Arbitrary/Crypto.hs +33/−0
- src/Haskoin/Util/Arbitrary/Keys.hs +85/−0
- src/Haskoin/Util/Arbitrary/Message.hs +52/−0
- src/Haskoin/Util/Arbitrary/Network.hs +178/−0
- src/Haskoin/Util/Arbitrary/Script.hs +379/−0
- src/Haskoin/Util/Arbitrary/Transaction.hs +278/−0
- src/Haskoin/Util/Arbitrary/Util.hs +44/−0
- test/Haskoin/AddressSpec.hs +1/−1
- test/Haskoin/BlockSpec.hs +1/−1
- test/Haskoin/Crypto/HashSpec.hs +1/−1
- test/Haskoin/Crypto/SignatureSpec.hs +15/−15
- test/Haskoin/Keys/ExtendedSpec.hs +1/−1
- test/Haskoin/Keys/MnemonicSpec.hs +12/−12
- test/Haskoin/KeysSpec.hs +1/−1
- test/Haskoin/NetworkSpec.hs +7/−7
- test/Haskoin/ScriptSpec.hs +1/−1
- test/Haskoin/Test.hs +0/−23
- test/Haskoin/Test/Address.hs +0/−25
- test/Haskoin/Test/Block.hs +0/−69
- test/Haskoin/Test/Crypto.hs +0/−33
- test/Haskoin/Test/Keys.hs +0/−85
- test/Haskoin/Test/Message.hs +0/−52
- test/Haskoin/Test/Network.hs +0/−178
- test/Haskoin/Test/Script.hs +0/−379
- test/Haskoin/Test/Transaction.hs +0/−278
- test/Haskoin/Test/Util.hs +0/−40
- test/Haskoin/Transaction/PartialSpec.hs +1/−1
- test/Haskoin/TransactionSpec.hs +1/−1
- test/Haskoin/UtilSpec.hs +12/−12
CHANGELOG.md view
@@ -4,6 +4,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## 0.13.6+### Changed+- Expose the Arbitrary test instances under Haskoin.Util.Arbitrary+ ## 0.13.5 ### Changed - Provide meaningful JSON instances for most types.
haskoin-core.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 9d9195e4ebe6a0ef3c20fc7252c63ad4bca7d0844dfaf15f479f7e08fc98b009+-- hash: 14c9f49e8a8cbf3de72ab19366de7910b9e4f84ea0bf5191e211116e71102f98 name: haskoin-core-version: 0.13.5+version: 0.13.6 synopsis: Bitcoin & Bitcoin Cash library for Haskell description: Haskoin Core is a complete Bitcoin and Bitcoin Cash library of functions and data types for Haskell developers. category: Bitcoin, Finance, Network@@ -46,6 +46,7 @@ Haskoin.Script Haskoin.Transaction Haskoin.Util+ Haskoin.Util.Arbitrary other-modules: Haskoin.Address.Base58 Haskoin.Address.Bech32@@ -69,11 +70,21 @@ Haskoin.Transaction.Common Haskoin.Transaction.Partial Haskoin.Transaction.Segwit+ Haskoin.Util.Arbitrary.Address+ Haskoin.Util.Arbitrary.Block+ Haskoin.Util.Arbitrary.Crypto+ Haskoin.Util.Arbitrary.Keys+ Haskoin.Util.Arbitrary.Message+ Haskoin.Util.Arbitrary.Network+ Haskoin.Util.Arbitrary.Script+ Haskoin.Util.Arbitrary.Transaction+ Haskoin.Util.Arbitrary.Util Paths_haskoin_core hs-source-dirs: src build-depends:- aeson >=1.4.6.0+ QuickCheck >=2.13.2+ , aeson >=1.4.6.0 , array >=0.5.4.0 , base >=4.9 && <5 , base16-bytestring >=0.1.1.6@@ -117,16 +128,6 @@ Haskoin.KeysSpec Haskoin.NetworkSpec Haskoin.ScriptSpec- Haskoin.Test- Haskoin.Test.Address- Haskoin.Test.Block- Haskoin.Test.Crypto- Haskoin.Test.Keys- Haskoin.Test.Message- Haskoin.Test.Network- Haskoin.Test.Script- Haskoin.Test.Transaction- Haskoin.Test.Util Haskoin.Transaction.PartialSpec Haskoin.TransactionSpec Haskoin.UtilSpec@@ -162,6 +163,16 @@ Haskoin.Transaction.Partial Haskoin.Transaction.Segwit Haskoin.Util+ Haskoin.Util.Arbitrary+ Haskoin.Util.Arbitrary.Address+ Haskoin.Util.Arbitrary.Block+ Haskoin.Util.Arbitrary.Crypto+ Haskoin.Util.Arbitrary.Keys+ Haskoin.Util.Arbitrary.Message+ Haskoin.Util.Arbitrary.Network+ Haskoin.Util.Arbitrary.Script+ Haskoin.Util.Arbitrary.Transaction+ Haskoin.Util.Arbitrary.Util Paths_haskoin_core hs-source-dirs: test
src/Haskoin/Block/Common.hs view
@@ -274,8 +274,9 @@ -- | The 'Headers' type is used to return a list of block headers in -- response to a 'GetHeaders' message.-newtype Headers = Headers -- | list of block headers with transaction count- { headersList :: [BlockHeaderCount]+newtype Headers = Headers+ { -- | list of block headers with transaction count+ headersList :: [BlockHeaderCount] } deriving (Eq, Show, Generic, NFData) instance Serialize Headers where
+ src/Haskoin/Util/Arbitrary.hs view
@@ -0,0 +1,23 @@+{-|+Module : Haskoin.Test+Copyright : No rights reserved+License : UNLICENSE+Maintainer : jprupp@protonmail.ch+Stability : experimental+Portability : POSIX++Arbitrary instances for testing.+-}+module Haskoin.Util.Arbitrary+ ( module X+ ) where++import Haskoin.Util.Arbitrary.Address as X+import Haskoin.Util.Arbitrary.Block as X+import Haskoin.Util.Arbitrary.Crypto as X+import Haskoin.Util.Arbitrary.Keys as X+import Haskoin.Util.Arbitrary.Message as X+import Haskoin.Util.Arbitrary.Network as X+import Haskoin.Util.Arbitrary.Script as X+import Haskoin.Util.Arbitrary.Transaction as X+import Haskoin.Util.Arbitrary.Util as X
+ src/Haskoin/Util/Arbitrary/Address.hs view
@@ -0,0 +1,33 @@+{-|+Module : Haskoin.Test.Address+Copyright : No rights reserved+License : UNLICENSE+Maintainer : jprupp@protonmail.ch+Stability : experimental+Portability : POSIX+-}+module Haskoin.Util.Arbitrary.Address where++import Haskoin.Address+import Haskoin.Util.Arbitrary.Crypto+import Test.QuickCheck++-- | Arbitrary pay-to-public-key-hash or pay-to-script-hash address.+arbitraryAddress :: Gen Address+arbitraryAddress = oneof [arbitraryPubKeyAddress, arbitraryScriptAddress]++-- | Arbitrary pay-to-public-key-hash address.+arbitraryPubKeyAddress :: Gen Address+arbitraryPubKeyAddress = PubKeyAddress <$> arbitraryHash160++-- | Arbitrary pay-to-script-hash address.+arbitraryScriptAddress :: Gen Address+arbitraryScriptAddress = ScriptAddress <$> arbitraryHash160++-- | Arbitrary pay-to-witness public key hash+arbitraryWitnessPubKeyAddress :: Gen Address+arbitraryWitnessPubKeyAddress = WitnessPubKeyAddress <$> arbitraryHash160 ++-- | Arbitrary pay-to-witness script hash+arbitraryWitnessScriptAddress :: Gen Address+arbitraryWitnessScriptAddress = WitnessPubKeyAddress <$> arbitraryHash160
+ src/Haskoin/Util/Arbitrary/Block.hs view
@@ -0,0 +1,69 @@+{-|+Module : Haskoin.Test.Block+Copyright : No rights reserved+License : UNLICENSE+Maintainer : jprupp@protonmail.ch+Stability : experimental+Portability : POSIX+-}+module Haskoin.Util.Arbitrary.Block where++import Haskoin.Block.Common+import Haskoin.Block.Merkle+import Haskoin.Constants+import Haskoin.Util.Arbitrary.Crypto+import Haskoin.Util.Arbitrary.Network+import Haskoin.Util.Arbitrary.Transaction+import Test.QuickCheck++-- | Block full or arbitrary transactions.+arbitraryBlock :: Network -> Gen Block+arbitraryBlock net = do+ h <- arbitraryBlockHeader+ c <- choose (0,10)+ txs <- vectorOf c (arbitraryTx net)+ return $ Block h txs++-- | Block header with random hash.+arbitraryBlockHeader :: Gen BlockHeader+arbitraryBlockHeader =+ BlockHeader <$> arbitrary+ <*> arbitraryBlockHash+ <*> arbitraryHash256+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary++-- | Arbitrary block hash.+arbitraryBlockHash :: Gen BlockHash+arbitraryBlockHash = BlockHash <$> arbitraryHash256++-- | Arbitrary 'GetBlocks' object with at least one block hash.+arbitraryGetBlocks :: Gen GetBlocks+arbitraryGetBlocks =+ GetBlocks <$> arbitrary+ <*> listOf1 arbitraryBlockHash+ <*> arbitraryBlockHash++-- | Arbitrary 'GetHeaders' object with at least one block header.+arbitraryGetHeaders :: Gen GetHeaders+arbitraryGetHeaders =+ GetHeaders <$> arbitrary+ <*> listOf1 arbitraryBlockHash+ <*> arbitraryBlockHash++-- | Arbitrary 'Headers' object with at least one block header.+arbitraryHeaders :: Gen Headers+arbitraryHeaders =+ Headers <$> listOf1 ((,) <$> arbitraryBlockHeader <*> arbitraryVarInt)++-- | Arbitrary 'MerkleBlock' with at least one hash.+arbitraryMerkleBlock :: Gen MerkleBlock+arbitraryMerkleBlock = do+ bh <- arbitraryBlockHeader+ ntx <- arbitrary+ hashes <- listOf1 arbitraryHash256+ c <- choose (1,10)+ flags <- vectorOf (c*8) arbitrary+ return $ MerkleBlock bh ntx hashes flags+
+ src/Haskoin/Util/Arbitrary/Crypto.hs view
@@ -0,0 +1,33 @@+{-|+Module : Haskoin.Test.Crypto+Copyright : No rights reserved+License : UNLICENSE+Maintainer : jprupp@protonmail.ch+Stability : experimental+Portability : POSIX+-}+module Haskoin.Util.Arbitrary.Crypto where++import Haskoin.Crypto.Hash+import Haskoin.Util.Arbitrary.Util+import Test.QuickCheck++-- | Arbitrary 160-bit hash.+arbitraryHash160 :: Gen Hash160+arbitraryHash160 =+ ripemd160 <$> arbitraryBSn 20++-- | Arbitrary 256-bit hash.+arbitraryHash256 :: Gen Hash256+arbitraryHash256 =+ sha256 <$> arbitraryBSn 32++-- | Arbitrary 512-bit hash.+arbitraryHash512 :: Gen Hash512+arbitraryHash512 =+ sha512 <$> arbitraryBSn 64++-- | Arbitrary 32-bit checksum.+arbitraryCheckSum32 :: Gen CheckSum32+arbitraryCheckSum32 =+ checkSum32 <$> arbitraryBSn 4
+ src/Haskoin/Util/Arbitrary/Keys.hs view
@@ -0,0 +1,85 @@+{-|+Module : Haskoin.Test.Keys+Copyright : No rights reserved+License : UNLICENSE+Maintainer : jprupp@protonmail.ch+Stability : experimental+Portability : POSIX+-}+module Haskoin.Util.Arbitrary.Keys where++import Data.Bits (clearBit)+import Data.List (foldl')+import Data.Word (Word32)+import Haskoin.Crypto+import Haskoin.Keys.Common+import Haskoin.Keys.Extended+import Haskoin.Util.Arbitrary.Crypto+import Test.QuickCheck++-- | Arbitrary private key with arbitrary compressed flag.+arbitrarySecKeyI :: Gen SecKeyI+arbitrarySecKeyI = wrapSecKey <$> arbitrary <*> arbitrary++-- | Arbitrary keypair, both either compressed or not.+arbitraryKeyPair :: Gen (SecKeyI, PubKeyI)+arbitraryKeyPair = do+ k <- arbitrarySecKeyI+ return (k, derivePubKeyI k)++-- | Arbitrary extended private key.+arbitraryXPrvKey :: Gen XPrvKey+arbitraryXPrvKey =+ XPrvKey <$> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitraryHash256+ <*> arbitrary++-- | Arbitrary extended public key with its corresponding private key.+arbitraryXPubKey :: Gen (XPrvKey, XPubKey)+arbitraryXPubKey = (\k -> (k, deriveXPubKey k)) <$> arbitraryXPrvKey++{- Custom derivations -}++-- | Arbitrary derivation index with last bit unset.+genIndex :: Gen Word32+genIndex = (`clearBit` 31) <$> arbitrary++-- | Arbitrary BIP-32 path index. Can be hardened or not.+arbitraryBip32PathIndex :: Gen Bip32PathIndex+arbitraryBip32PathIndex =+ oneof [ Bip32SoftIndex <$> genIndex+ , Bip32HardIndex <$> genIndex+ ]++-- | Arbitrary BIP-32 derivation path composed of only hardened derivations.+arbitraryHardPath :: Gen HardPath+arbitraryHardPath = foldl' (:|) Deriv <$> listOf genIndex++-- | Arbitrary BIP-32 derivation path composed of only non-hardened derivations.+arbitrarySoftPath :: Gen SoftPath+arbitrarySoftPath = foldl' (:/) Deriv <$> listOf genIndex++-- | Arbitrary derivation path composed of hardened and non-hardened derivations.+arbitraryDerivPath :: Gen DerivPath+arbitraryDerivPath = concatBip32Segments <$> listOf arbitraryBip32PathIndex++-- | Arbitrary parsed derivation path. Can contain 'ParsedPrv', 'ParsedPub' or+-- 'ParsedEmpty' elements.+arbitraryParsedPath :: Gen ParsedPath+arbitraryParsedPath =+ oneof [ ParsedPrv <$> arbitraryDerivPath+ , ParsedPub <$> arbitraryDerivPath+ , ParsedEmpty <$> arbitraryDerivPath+ ]++-- | Arbitrary message hash, private key, nonce and corresponding signature. The+-- signature is generated with a random message, random private key and a random+-- nonce.+arbitrarySignature :: Gen (Hash256, SecKey, Sig)+arbitrarySignature = do+ m <- arbitraryHash256+ key <- arbitrary+ let sig = signHash key m+ return (m, key, sig)
+ src/Haskoin/Util/Arbitrary/Message.hs view
@@ -0,0 +1,52 @@+{-|+Module : Haskoin.Test.Message+Copyright : No rights reserved+License : UNLICENSE+Maintainer : jprupp@protonmail.ch+Stability : experimental+Portability : POSIX+-}+module Haskoin.Util.Arbitrary.Message where++import Haskoin.Constants+import Haskoin.Network.Message+import Haskoin.Util.Arbitrary.Block+import Haskoin.Util.Arbitrary.Crypto+import Haskoin.Util.Arbitrary.Network+import Haskoin.Util.Arbitrary.Transaction+import Test.QuickCheck++-- | Arbitrary 'MessageHeader'.+arbitraryMessageHeader :: Gen MessageHeader+arbitraryMessageHeader =+ MessageHeader <$> arbitrary+ <*> arbitraryMessageCommand+ <*> arbitrary+ <*> arbitraryCheckSum32++-- | Arbitrary 'Message'.+arbitraryMessage :: Network -> Gen Message+arbitraryMessage net =+ oneof+ [ MVersion <$> arbitraryVersion+ , return MVerAck+ , MAddr <$> arbitraryAddr1+ , MInv <$> arbitraryInv1+ , MGetData <$> arbitraryGetData+ , MNotFound <$> arbitraryNotFound+ , MGetBlocks <$> arbitraryGetBlocks+ , MGetHeaders <$> arbitraryGetHeaders+ , MTx <$> arbitraryTx net+ , MBlock <$> arbitraryBlock net+ , MMerkleBlock <$> arbitraryMerkleBlock+ , MHeaders <$> arbitraryHeaders+ , return MGetAddr+ , MFilterLoad <$> arbitraryFilterLoad+ , MFilterAdd <$> arbitraryFilterAdd+ , return MFilterClear+ , MPing <$> arbitraryPing+ , MPong <$> arbitraryPong+ , MAlert <$> arbitraryAlert+ , MReject <$> arbitraryReject+ , return MSendHeaders+ ]
+ src/Haskoin/Util/Arbitrary/Network.hs view
@@ -0,0 +1,178 @@+{-|+Module : Haskoin.Test.Network+Copyright : No rights reserved+License : UNLICENSE+Maintainer : jprupp@protonmail.ch+Stability : experimental+Portability : POSIX+-}+module Haskoin.Util.Arbitrary.Network where++import qualified Data.ByteString as BS (empty, pack)+import qualified Data.ByteString.Char8 as C8+import Data.Word (Word16, Word32)+import Haskoin.Network+import Haskoin.Util.Arbitrary.Crypto+import Haskoin.Util.Arbitrary.Util+import Network.Socket (SockAddr (..))+import Test.QuickCheck++-- | Arbitrary 'VarInt'.+arbitraryVarInt :: Gen VarInt+arbitraryVarInt = VarInt <$> arbitrary++-- | Arbitrary 'VarString'.+arbitraryVarString :: Gen VarString+arbitraryVarString = VarString <$> arbitraryBS++-- | Arbitrary 'NetworkAddress'.+arbitraryNetworkAddress :: Gen NetworkAddress+arbitraryNetworkAddress = do+ s <- arbitrary+ a <- arbitrary+ p <- arbitrary+ d <- oneof+ [ do+ b <- arbitrary+ c <- arbitrary+ d <- arbitrary+ return $ SockAddrInet6 (fromIntegral p) 0 (a,b,c,d) 0+ , return $ SockAddrInet (fromIntegral (p :: Word16)) a+ ]+ let n = sockToHostAddress d+ return $ NetworkAddress s n++-- | Arbitrary 'NetworkAddressTime'.+arbitraryNetworkAddressTime :: Gen (Word32, NetworkAddress)+arbitraryNetworkAddressTime = (,) <$> arbitrary <*> arbitraryNetworkAddress++-- | Arbitrary 'InvType'.+arbitraryInvType :: Gen InvType+arbitraryInvType = elements [InvError, InvTx, InvBlock, InvMerkleBlock]++-- | Arbitrary 'InvVector'.+arbitraryInvVector :: Gen InvVector+arbitraryInvVector = InvVector <$> arbitraryInvType <*> arbitraryHash256++-- | Arbitrary non-empty 'Inv'.+arbitraryInv1 :: Gen Inv+arbitraryInv1 = Inv <$> listOf1 arbitraryInvVector++-- | Arbitrary 'Version'.+arbitraryVersion :: Gen Version+arbitraryVersion =+ Version <$> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitraryNetworkAddress+ <*> arbitraryNetworkAddress+ <*> arbitrary+ <*> arbitraryVarString+ <*> arbitrary+ <*> arbitrary++-- | Arbitrary non-empty 'Addr'.+arbitraryAddr1 :: Gen Addr+arbitraryAddr1 = Addr <$> listOf1 arbitraryNetworkAddressTime++-- | Arbitrary 'Alert' with random payload and signature. Signature is not+-- valid.+arbitraryAlert :: Gen Alert+arbitraryAlert = Alert <$> arbitraryVarString <*> arbitraryVarString++-- | Arbitrary 'Reject'.+arbitraryReject :: Gen Reject+arbitraryReject = do+ m <- arbitraryMessageCommand+ c <- arbitraryRejectCode+ s <- arbitraryVarString+ d <- oneof [ return BS.empty+ , BS.pack <$> vectorOf 32 arbitrary+ ]+ return $ Reject m c s d++-- | Arbitrary 'RejectCode'.+arbitraryRejectCode :: Gen RejectCode+arbitraryRejectCode =+ elements+ [ RejectMalformed+ , RejectInvalid+ , RejectInvalid+ , RejectDuplicate+ , RejectNonStandard+ , RejectDust+ , RejectInsufficientFee+ , RejectCheckpoint+ ]++-- | Arbitrary non-empty 'GetData'.+arbitraryGetData :: Gen GetData+arbitraryGetData = GetData <$> listOf1 arbitraryInvVector++-- | Arbitrary 'NotFound'.+arbitraryNotFound :: Gen NotFound+arbitraryNotFound = NotFound <$> listOf1 arbitraryInvVector++-- | Arbitrary 'Ping'.+arbitraryPing :: Gen Ping+arbitraryPing = Ping <$> arbitrary++-- | Arbitrary 'Pong'.+arbitraryPong :: Gen Pong+arbitraryPong = Pong <$> arbitrary++-- | Arbitrary bloom filter flags.+arbitraryBloomFlags :: Gen BloomFlags+arbitraryBloomFlags =+ elements+ [ BloomUpdateNone+ , BloomUpdateAll+ , BloomUpdateP2PubKeyOnly+ ]++-- | Arbitrary bloom filter with its corresponding number of elements+-- and false positive rate.+arbitraryBloomFilter :: Gen (Int, Double, BloomFilter)+arbitraryBloomFilter = do+ n <- choose (0,100000)+ fp <- choose (1e-8,1)+ tweak <- arbitrary+ fl <- arbitraryBloomFlags+ return (n, fp, bloomCreate n fp tweak fl)++-- | Arbitrary 'FilterLoad'.+arbitraryFilterLoad :: Gen FilterLoad+arbitraryFilterLoad = do+ (_, _, bf) <- arbitraryBloomFilter+ return $ FilterLoad bf++-- | Arbitrary 'FilterAdd'.+arbitraryFilterAdd :: Gen FilterAdd+arbitraryFilterAdd = FilterAdd <$> arbitraryBS++-- | Arbitrary 'MessageCommand'.+arbitraryMessageCommand :: Gen MessageCommand+arbitraryMessageCommand = do+ ASCIIString str <- arbitrary+ elements+ [ MCVersion+ , MCVerAck+ , MCAddr+ , MCInv+ , MCGetData+ , MCNotFound+ , MCGetBlocks+ , MCGetHeaders+ , MCTx+ , MCBlock+ , MCMerkleBlock+ , MCHeaders+ , MCGetAddr+ , MCFilterLoad+ , MCFilterAdd+ , MCFilterClear+ , MCPing+ , MCPong+ , MCAlert+ , MCOther (C8.take 12 (C8.pack (filter (/= '\NUL') str)))+ ]
+ src/Haskoin/Util/Arbitrary/Script.hs view
@@ -0,0 +1,379 @@+{-# LANGUAGE LambdaCase #-}+{-|+Module : Haskoin.Test.Script+Copyright : No rights reserved+License : UNLICENSE+Maintainer : jprupp@protonmail.ch+Stability : experimental+Portability : POSIX+-}+module Haskoin.Util.Arbitrary.Script where++import Crypto.Secp256k1+import Data.Maybe+import Data.Word+import Haskoin.Address+import Haskoin.Constants+import Haskoin.Keys.Common+import Haskoin.Script+import Haskoin.Transaction.Common+import Haskoin.Util+import Haskoin.Util.Arbitrary.Address+import Haskoin.Util.Arbitrary.Crypto+import Haskoin.Util.Arbitrary.Keys+import Haskoin.Util.Arbitrary.Util+import Test.QuickCheck++-- | Arbitrary 'Script' with random script ops.+arbitraryScript :: Gen Script+arbitraryScript = Script <$> listOf arbitraryScriptOp++-- | Arbitrary 'ScriptOp' (push operations have random data).+arbitraryScriptOp :: Gen ScriptOp+arbitraryScriptOp =+ oneof+ -- Pushing Data+ [ opPushData <$> arbitraryBS1+ , return OP_0+ , return OP_1NEGATE+ , return OP_RESERVED+ , return OP_1+ , return OP_2+ , return OP_3+ , return OP_4+ , return OP_5+ , return OP_6+ , return OP_7+ , return OP_8+ , return OP_9+ , return OP_10+ , return OP_11+ , return OP_12+ , return OP_13+ , return OP_14+ , return OP_15+ , return OP_16+ -- Flow control+ , return OP_NOP+ , return OP_VER+ , return OP_IF+ , return OP_NOTIF+ , return OP_VERIF+ , return OP_VERNOTIF+ , return OP_ELSE+ , return OP_ENDIF+ , return OP_VERIFY+ , return OP_RETURN+ -- Stack operations+ , return OP_TOALTSTACK+ , return OP_FROMALTSTACK+ , return OP_IFDUP+ , return OP_DEPTH+ , return OP_DROP+ , return OP_DUP+ , return OP_NIP+ , return OP_OVER+ , return OP_PICK+ , return OP_ROLL+ , return OP_ROT+ , return OP_SWAP+ , return OP_TUCK+ , return OP_2DROP+ , return OP_2DUP+ , return OP_3DUP+ , return OP_2OVER+ , return OP_2ROT+ , return OP_2SWAP+ -- Splice+ , return OP_CAT+ , return OP_SUBSTR+ , return OP_LEFT+ , return OP_RIGHT+ , return OP_SIZE+ -- Bitwise logic+ , return OP_INVERT+ , return OP_AND+ , return OP_OR+ , return OP_XOR+ , return OP_EQUAL+ , return OP_EQUALVERIFY+ , return OP_RESERVED1+ , return OP_RESERVED2+ -- Arithmetic+ , return OP_1ADD+ , return OP_1SUB+ , return OP_2MUL+ , return OP_2DIV+ , return OP_NEGATE+ , return OP_ABS+ , return OP_NOT+ , return OP_0NOTEQUAL+ , return OP_ADD+ , return OP_SUB+ , return OP_MUL+ , return OP_DIV+ , return OP_MOD+ , return OP_LSHIFT+ , return OP_RSHIFT+ , return OP_BOOLAND+ , return OP_BOOLOR+ , return OP_NUMEQUAL+ , return OP_NUMEQUALVERIFY+ , return OP_NUMNOTEQUAL+ , return OP_LESSTHAN+ , return OP_GREATERTHAN+ , return OP_LESSTHANOREQUAL+ , return OP_GREATERTHANOREQUAL+ , return OP_MIN+ , return OP_MAX+ , return OP_WITHIN+ -- Crypto+ , return OP_RIPEMD160+ , return OP_SHA1+ , return OP_SHA256+ , return OP_HASH160+ , return OP_HASH256+ , return OP_CODESEPARATOR+ , return OP_CHECKSIG+ , return OP_CHECKSIGVERIFY+ , return OP_CHECKMULTISIG+ , return OP_CHECKMULTISIGVERIFY+ -- Expansion+ , return OP_NOP1+ , return OP_NOP2+ , return OP_NOP3+ , return OP_NOP4+ , return OP_NOP5+ , return OP_NOP6+ , return OP_NOP7+ , return OP_NOP8+ , return OP_NOP9+ , return OP_NOP10+ -- Bitcoin Cash Nov 2018 hard fork+ , return OP_CHECKDATASIG+ , return OP_CHECKDATASIGVERIFY+ -- Bitcoin Cash May 2020 hard fork+ , return OP_REVERSEBYTES+ -- Other+ , return OP_PUBKEYHASH+ , return OP_PUBKEY+ , return $ OP_INVALIDOPCODE 0xff+ ]++-- | Arbtirary 'ScriptOp' with a value in @[OP_1 .. OP_16]@.+arbitraryIntScriptOp :: Gen ScriptOp+arbitraryIntScriptOp =+ elements+ [ OP_1, OP_2, OP_3, OP_4+ , OP_5, OP_6, OP_7, OP_8+ , OP_9, OP_10, OP_11, OP_12+ , OP_13, OP_14, OP_15, OP_16+ ]++-- | Arbitrary 'PushDataType'.+arbitraryPushDataType :: Gen PushDataType+arbitraryPushDataType = elements [OPCODE, OPDATA1, OPDATA2, OPDATA4]++-- | Arbitrary 'SigHash' (including invalid/unknown sighash codes).+arbitrarySigHash :: Gen SigHash+arbitrarySigHash = fromIntegral <$> (arbitrary :: Gen Word32)++-- | Arbitrary valid 'SigHash'.+arbitraryValidSigHash :: Network -> Gen SigHash+arbitraryValidSigHash net = do+ sh <- elements [sigHashAll, sigHashNone, sigHashSingle]+ f1 <-+ elements $+ if isJust (getSigHashForkId net)+ then [id, setForkIdFlag]+ else [id]+ f2 <- elements [id, setAnyoneCanPayFlag]+ return $ f1 $ f2 sh++-- | Arbitrary message hash, private key and corresponding 'TxSignature'. The+-- signature is generated deterministically using a random message and a random+-- private key.+arbitraryTxSignature :: Network -> Gen (TxHash, SecKey, TxSignature)+arbitraryTxSignature net = do+ (m, key, sig) <- arbitrarySignature+ sh <- (fromIntegral <$> (arbitrary :: Gen Word8)) `suchThat` filterBad+ let txsig = TxSignature sig sh+ return (TxHash m, key, txsig)+ where+ filterBad sh = not $+ isSigHashUnknown sh ||+ isNothing (getSigHashForkId net) && hasForkIdFlag sh++-- | Arbitrary transaction signature that could also be empty.+arbitraryTxSignatureEmpty :: Network -> Gen TxSignature+arbitraryTxSignatureEmpty net =+ frequency [ (1, return TxSignatureEmpty)+ , (10, lst3 <$> arbitraryTxSignature net)+ ]++-- | Arbitrary m of n parameters.+arbitraryMSParam :: Gen (Int, Int)+arbitraryMSParam = do+ m <- choose (1,16)+ n <- choose (m,16)+ return (m, n)++-- | Arbitrary 'ScriptOutput' (Can by any valid type).+arbitraryScriptOutput :: Network -> Gen ScriptOutput+arbitraryScriptOutput net =+ oneof $+ [ arbitraryPKOutput+ , arbitraryPKHashOutput+ , arbitraryMSOutput+ , arbitrarySHOutput+ , arbitraryDCOutput+ ] +++ if getSegWit net+ then [arbitraryWPKHashOutput, arbitraryWSHOutput]+ else []++-- | Arbitrary 'ScriptOutput' of type 'PayPK', 'PayPKHash' or 'PayMS'+-- (Not 'PayScriptHash', 'DataCarrier', or SegWit)+arbitrarySimpleOutput :: Gen ScriptOutput+arbitrarySimpleOutput =+ oneof+ [ arbitraryPKOutput+ , arbitraryPKHashOutput+ , arbitraryMSOutput+ ]++-- | Arbitrary 'ScriptOutput' of type 'PayPK'+arbitraryPKOutput :: Gen ScriptOutput+arbitraryPKOutput = PayPK . snd <$> arbitraryKeyPair++-- | Arbitrary 'ScriptOutput' of type 'PayPKHash'+arbitraryPKHashOutput :: Gen ScriptOutput+arbitraryPKHashOutput = PayPKHash <$> arbitraryHash160++-- | Arbitrary 'PayWitnessPKHash' output.+arbitraryWPKHashOutput :: Gen ScriptOutput+arbitraryWPKHashOutput = PayWitnessPKHash <$> arbitraryHash160++-- | Arbitrary 'PayWitnessScriptHash' output.+arbitraryWSHOutput :: Gen ScriptOutput+arbitraryWSHOutput = PayWitnessScriptHash <$> arbitraryHash256++-- | Arbitrary 'ScriptOutput' of type 'PayMS'.+arbitraryMSOutput :: Gen ScriptOutput+arbitraryMSOutput = do+ (m, n) <- arbitraryMSParam+ keys <- map snd <$> vectorOf n arbitraryKeyPair+ return $ PayMulSig keys m++-- | Arbitrary 'ScriptOutput' of type 'PayMS', only using compressed keys.+arbitraryMSOutputC :: Gen ScriptOutput+arbitraryMSOutputC = do+ (m, n) <- arbitraryMSParam+ keys <-+ map snd <$>+ vectorOf n (arbitraryKeyPair `suchThat` (pubKeyCompressed . snd))+ return $ PayMulSig keys m++-- | Arbitrary 'ScriptOutput' of type 'PayScriptHash'.+arbitrarySHOutput :: Gen ScriptOutput+arbitrarySHOutput = PayScriptHash . getAddrHash160 <$> arbitraryScriptAddress++-- | Arbitrary 'ScriptOutput' of type 'DataCarrier'.+arbitraryDCOutput :: Gen ScriptOutput+arbitraryDCOutput = DataCarrier <$> arbitraryBS1++-- | Arbitrary 'ScriptInput'.+arbitraryScriptInput :: Network -> Gen ScriptInput+arbitraryScriptInput net =+ oneof+ [ arbitraryPKInput net+ , arbitraryPKHashInput net+ , arbitraryMSInput net+ , arbitrarySHInput net+ ]++-- | Arbitrary 'ScriptInput' of type 'SpendPK', 'SpendPKHash' or 'SpendMulSig'+-- (not 'ScriptHashInput')+arbitrarySimpleInput :: Network -> Gen ScriptInput+arbitrarySimpleInput net =+ oneof+ [ arbitraryPKInput net+ , arbitraryPKHashInput net+ , arbitraryMSInput net+ ]++-- | Arbitrary 'ScriptInput' of type 'SpendPK'.+arbitraryPKInput :: Network -> Gen ScriptInput+arbitraryPKInput net = RegularInput . SpendPK <$> arbitraryTxSignatureEmpty net++-- | Arbitrary 'ScriptInput' of type 'SpendPK'.+arbitraryPKHashInput :: Network -> Gen ScriptInput+arbitraryPKHashInput net = do+ sig <- arbitraryTxSignatureEmpty net+ key <- snd <$> arbitraryKeyPair+ return $ RegularInput $ SpendPKHash sig key++-- | Like 'arbitraryPKHashInput' without empty signatures.+arbitraryPKHashInputFull :: Network -> Gen ScriptInput+arbitraryPKHashInputFull net = do+ sig <- lst3 <$> arbitraryTxSignature net+ key <- snd <$> arbitraryKeyPair+ return $ RegularInput $ SpendPKHash sig key++-- | Like above but only compressed.+arbitraryPKHashInputFullC :: Network -> Gen ScriptInput+arbitraryPKHashInputFullC net = do+ sig <- lst3 <$> arbitraryTxSignature net+ key <- fmap snd $ arbitraryKeyPair `suchThat` (pubKeyCompressed . snd)+ return $ RegularInput $ SpendPKHash sig key++-- | Arbitrary 'ScriptInput' of type 'SpendMulSig'.+arbitraryMSInput :: Network -> Gen ScriptInput+arbitraryMSInput net = do+ m <- fst <$> arbitraryMSParam+ sigs <- vectorOf m (arbitraryTxSignatureEmpty net)+ return $ RegularInput $ SpendMulSig sigs++-- | Arbitrary 'ScriptInput' of type 'ScriptHashInput'.+arbitrarySHInput :: Network -> Gen ScriptInput+arbitrarySHInput net = do+ i <- arbitrarySimpleInput net+ ScriptHashInput (getRegularInput i) <$> arbitrarySimpleOutput++-- | Arbitrary 'ScriptInput' of type 'ScriptHashInput' containing a+-- 'RedeemScript' of type 'PayMulSig' and an input of type 'SpendMulSig'.+arbitraryMulSigSHInput :: Network -> Gen ScriptInput+arbitraryMulSigSHInput net =+ arbitraryMSOutput >>= \case+ rdm@(PayMulSig _ m) -> do+ sigs <- vectorOf m (arbitraryTxSignatureEmpty net)+ return $ ScriptHashInput (SpendMulSig sigs) rdm+ _ -> undefined++-- | Arbitrary 'ScriptInput' of type 'ScriptHashInput' containing a+-- 'RedeemScript' of type 'PayMulSig' and an input of type 'SpendMulSig'.+arbitraryMulSigSHInputC :: Network -> Gen ScriptInput+arbitraryMulSigSHInputC net =+ arbitraryMSOutputC >>= \case+ rdm@(PayMulSig _ m) -> do+ sigs <- vectorOf m (arbitraryTxSignatureEmpty net)+ return $ ScriptHashInput (SpendMulSig sigs) rdm+ _ -> undefined++-- | Like 'arbitraryMulSigSHCInput' with no empty signatures.+arbitraryMulSigSHInputFull :: Network -> Gen ScriptInput+arbitraryMulSigSHInputFull net =+ arbitraryMSOutput >>= \case+ rdm@(PayMulSig _ m) -> do+ sigs <- map lst3 <$> vectorOf m (arbitraryTxSignature net)+ return $ ScriptHashInput (SpendMulSig sigs) rdm+ _ -> undefined++-- | Like 'arbitraryMulSigSHCInput' with no empty signatures.+arbitraryMulSigSHInputFullC :: Network -> Gen ScriptInput+arbitraryMulSigSHInputFullC net =+ arbitraryMSOutputC >>= \case+ rdm@(PayMulSig _ m) -> do+ sigs <- map lst3 <$> vectorOf m (arbitraryTxSignature net)+ return $ ScriptHashInput (SpendMulSig sigs) rdm+ _ -> undefined
+ src/Haskoin/Util/Arbitrary/Transaction.hs view
@@ -0,0 +1,278 @@+{-|+Module : Haskoin.Test.Transaction+Copyright : No rights reserved+License : UNLICENSE+Maintainer : jprupp@protonmail.ch+Stability : experimental+Portability : POSIX+-}+module Haskoin.Util.Arbitrary.Transaction where++import Control.Monad+import qualified Data.ByteString as BS+import Data.Either (fromRight)+import Data.List (nub, nubBy, permutations)+import Data.Word (Word64)+import Haskoin.Address+import Haskoin.Constants+import Haskoin.Keys.Common+import Haskoin.Script+import Haskoin.Util.Arbitrary.Crypto+import Haskoin.Util.Arbitrary.Keys+import Haskoin.Util.Arbitrary.Script+import Haskoin.Util.Arbitrary.Util+import Haskoin.Transaction+import Test.QuickCheck++-- | Wrapped coin value for testing.+newtype TestCoin = TestCoin { getTestCoin :: Word64 }+ deriving (Eq, Show)++instance Coin TestCoin where+ coinValue = getTestCoin++-- | Arbitrary transaction hash (for non-existent transaction).+arbitraryTxHash :: Gen TxHash+arbitraryTxHash = TxHash <$> arbitraryHash256++-- | Arbitrary amount of Satoshi as 'Word64' (Between 1 and 21e14)+arbitrarySatoshi :: Network -> Gen TestCoin+arbitrarySatoshi net = TestCoin <$> choose (1, getMaxSatoshi net)++-- | Arbitrary 'OutPoint'.+arbitraryOutPoint :: Gen OutPoint+arbitraryOutPoint = OutPoint <$> arbitraryTxHash <*> arbitrary++-- | Arbitrary 'TxOut'.+arbitraryTxOut :: Network -> Gen TxOut+arbitraryTxOut net =+ TxOut <$> (getTestCoin <$> arbitrarySatoshi net)+ <*> (encodeOutputBS <$> arbitraryScriptOutput net)++-- | Arbitrary 'TxIn'.+arbitraryTxIn :: Network -> Gen TxIn+arbitraryTxIn net =+ TxIn <$> arbitraryOutPoint+ <*> (encodeInputBS <$> arbitraryScriptInput net)+ <*> arbitrary++-- | Arbitrary transaction. Can be regular or with witnesses.+arbitraryTx :: Network -> Gen Tx+arbitraryTx net = oneof [arbitraryLegacyTx net, arbitraryWitnessTx net]++-- | Arbitrary regular transaction.+arbitraryLegacyTx :: Network -> Gen Tx+arbitraryLegacyTx net = arbitraryWLTx net False++-- | Arbitrary witness transaction (witness data is fake).+arbitraryWitnessTx :: Network -> Gen Tx+arbitraryWitnessTx net = arbitraryWLTx net True++-- | Arbitrary witness or legacy transaction.+arbitraryWLTx :: Network -> Bool -> Gen Tx+arbitraryWLTx net wit = do+ ni <- choose (0, 5)+ no <-+ if wit+ then choose (0, 5)+ else choose+ ( if ni == 0+ then 2+ else 0+ , 5 -- avoid witness case+ )+ inps <- vectorOf ni (arbitraryTxIn net)+ outs <- vectorOf no (arbitraryTxOut net)+ let uniqueInps = nubBy (\a b -> prevOutput a == prevOutput b) inps+ w <-+ if wit+ then vectorOf (length uniqueInps) (listOf arbitraryBS)+ else return []+ Tx <$> arbitrary <*> pure uniqueInps <*> pure outs <*> pure w <*> arbitrary++-- | Arbitrary transaction containing only inputs of type 'SpendPKHash',+-- 'SpendScriptHash' (multisig) and outputs of type 'PayPKHash' and 'PaySH'.+-- Only compressed public keys are used.+arbitraryAddrOnlyTx :: Network -> Gen Tx+arbitraryAddrOnlyTx net = do+ ni <- choose (0, 5)+ no <- choose (0, 5)+ inps <- vectorOf ni (arbitraryAddrOnlyTxIn net)+ outs <- vectorOf no (arbitraryAddrOnlyTxOut net)+ Tx <$> arbitrary <*> pure inps <*> pure outs <*> pure [] <*> arbitrary++-- | Like 'arbitraryAddrOnlyTx' without empty signatures in the inputs.+arbitraryAddrOnlyTxFull :: Network -> Gen Tx+arbitraryAddrOnlyTxFull net = do+ ni <- choose (0, 5)+ no <- choose (0, 5)+ inps <- vectorOf ni (arbitraryAddrOnlyTxInFull net)+ outs <- vectorOf no (arbitraryAddrOnlyTxOut net)+ Tx <$> arbitrary <*> pure inps <*> pure outs <*> pure [] <*> arbitrary++-- | Arbitrary TxIn that can only be of type 'SpendPKHash' or 'SpendScriptHash'+-- (multisig). Only compressed public keys are used.+arbitraryAddrOnlyTxIn :: Network -> Gen TxIn+arbitraryAddrOnlyTxIn net = do+ inp <- oneof [arbitraryPKHashInput net, arbitraryMulSigSHInput net]+ TxIn <$> arbitraryOutPoint <*> pure (encodeInputBS inp) <*> arbitrary++-- | like 'arbitraryAddrOnlyTxIn' with no empty signatures.+arbitraryAddrOnlyTxInFull :: Network -> Gen TxIn+arbitraryAddrOnlyTxInFull net = do+ inp <-+ oneof [arbitraryPKHashInputFullC net, arbitraryMulSigSHInputFullC net]+ TxIn <$> arbitraryOutPoint <*> pure (encodeInputBS inp) <*> arbitrary++-- | Arbitrary 'TxOut' that can only be of type 'PayPKHash' or 'PaySH'.+arbitraryAddrOnlyTxOut :: Network -> Gen TxOut+arbitraryAddrOnlyTxOut net = do+ v <- getTestCoin <$> arbitrarySatoshi net+ out <- oneof [arbitraryPKHashOutput, arbitrarySHOutput]+ return $ TxOut v $ encodeOutputBS out++-- | Arbitrary 'SigInput' with the corresponding private keys used+-- to generate the 'ScriptOutput' or 'RedeemScript'.+arbitrarySigInput :: Network -> Gen (SigInput, [SecKeyI])+arbitrarySigInput net =+ oneof+ [ wrapKey <$> arbitraryPKSigInput net+ , wrapKey <$> arbitraryPKHashSigInput net+ , arbitraryMSSigInput net+ , arbitrarySHSigInput net+ , wrapKey <$> arbitraryWPKHSigInput net+ , arbitraryWSHSigInput net+ ]++-- | Arbitrary 'SigInput' with a 'ScriptOutput' of type 'PayPK'.+arbitraryPKSigInput :: Network -> Gen (SigInput, SecKeyI)+arbitraryPKSigInput net = arbitraryAnyInput net False++-- | Arbitrary 'SigInput' with a 'ScriptOutput' of type 'PayPKHash'.+arbitraryPKHashSigInput :: Network -> Gen (SigInput, SecKeyI)+arbitraryPKHashSigInput net = arbitraryAnyInput net True++-- | Arbitrary 'SigInput'.+arbitraryAnyInput :: Network -> Bool -> Gen (SigInput, SecKeyI)+arbitraryAnyInput net pkh = do+ (k, p) <- arbitraryKeyPair+ let out | pkh = PayPKHash $ getAddrHash160 $ pubKeyAddr p+ | otherwise = PayPK p+ (val, op, sh) <- arbitraryInputStuff net+ return (SigInput out val op sh Nothing, k)++-- | Arbitrary value, out point and sighash for an input.+arbitraryInputStuff :: Network -> Gen (Word64, OutPoint, SigHash)+arbitraryInputStuff net = do+ val <- getTestCoin <$> arbitrarySatoshi net+ op <- arbitraryOutPoint+ sh <- arbitraryValidSigHash net+ return (val, op, sh)++-- | Arbitrary 'SigInput' with a 'ScriptOutput' of type 'PayMulSig'.+arbitraryMSSigInput :: Network -> Gen (SigInput, [SecKeyI])+arbitraryMSSigInput net = do+ (m, n) <- arbitraryMSParam+ ks <- vectorOf n arbitraryKeyPair+ let out = PayMulSig (map snd ks) m+ (val, op, sh) <- arbitraryInputStuff net+ perm <- choose (0, n - 1)+ let ksPerm = map fst $ take m $ permutations ks !! perm+ return (SigInput out val op sh Nothing, ksPerm)++-- | Arbitrary 'SigInput' with 'ScriptOutput' of type 'PaySH' and a+-- 'RedeemScript'.+arbitrarySHSigInput :: Network -> Gen (SigInput, [SecKeyI])+arbitrarySHSigInput net = do+ (SigInput rdm val op sh _, ks) <- oneof+ [ wrapKey <$> arbitraryPKSigInput net+ , wrapKey <$> arbitraryPKHashSigInput net+ , arbitraryMSSigInput net+ ]+ let out = PayScriptHash $ getAddrHash160 $ payToScriptAddress rdm+ return (SigInput out val op sh $ Just rdm, ks)++arbitraryWPKHSigInput :: Network -> Gen (SigInput, SecKeyI)+arbitraryWPKHSigInput net = do+ (k, p) <- arbitraryKeyPair+ (val, op, sh) <- arbitraryInputStuff net+ let out = PayWitnessPKHash . getAddrHash160 $ pubKeyAddr p+ return (SigInput out val op sh Nothing, k)++arbitraryWSHSigInput :: Network -> Gen (SigInput, [SecKeyI])+arbitraryWSHSigInput net = do+ (SigInput rdm val op sh _, ks) <- oneof+ [ wrapKey <$> arbitraryPKSigInput net+ , wrapKey <$> arbitraryPKHashSigInput net+ , arbitraryMSSigInput net+ ]+ let out = PayWitnessScriptHash . getAddrHash256 $ payToWitnessScriptAddress rdm+ return (SigInput out val op sh $ Just rdm, ks)++-- | Arbitrary 'Tx' (empty 'TxIn'), 'SigInputs' and private keys that can be+-- passed to 'signTx' or 'detSignTx' to fully sign the 'Tx'.+arbitrarySigningData :: Network -> Gen (Tx, [SigInput], [SecKeyI])+arbitrarySigningData net = do+ v <- arbitrary+ ni <- choose (1, 5)+ no <- choose (1, 5)+ sigis <- vectorOf ni (arbitrarySigInput net)+ let uSigis = nubBy (\(a, _) (b, _) -> sigInputOP a == sigInputOP b) sigis+ inps <- forM uSigis $ \(s, _) -> TxIn (sigInputOP s) BS.empty <$> arbitrary+ outs <- vectorOf no (arbitraryTxOut net)+ l <- arbitrary+ perm <- choose (0, length inps - 1)+ let tx = Tx v (permutations inps !! perm) outs [] l+ keys = concatMap snd uSigis+ return (tx, map fst uSigis, keys)++-- | Arbitrary transaction with empty inputs.+arbitraryEmptyTx :: Network -> Gen Tx+arbitraryEmptyTx net = do+ v <- arbitrary+ no <- choose (1,5)+ ni <- choose (1,5)+ outs <- vectorOf no (arbitraryTxOut net)+ ops <- vectorOf ni arbitraryOutPoint+ t <- arbitrary+ s <- arbitrary+ return $ Tx v (map (\op -> TxIn op BS.empty s) (nub ops)) outs [] t++-- | Arbitrary partially-signed transactions.+arbitraryPartialTxs ::+ Network -> Gen ([Tx], [(ScriptOutput, Word64, OutPoint, Int, Int)])+arbitraryPartialTxs net = do+ tx <- arbitraryEmptyTx net+ res <-+ forM (map prevOutput $ txIn tx) $ \op -> do+ (so, val, rdmM, prvs, m, n) <- arbitraryData+ txs <- mapM (singleSig so val rdmM tx op . secKeyData) prvs+ return (txs, (so, val, op, m, n))+ return (concatMap fst res, map snd res)+ where+ singleSig so val rdmM tx op prv = do+ sh <- arbitraryValidSigHash net+ let sigi = SigInput so val op sh rdmM+ return . fromRight (error "Could not decode transaction") $+ signTx net tx [sigi] [prv]+ arbitraryData = do+ (m, n) <- arbitraryMSParam+ val <- getTestCoin <$> arbitrarySatoshi net+ nPrv <- choose (m, n)+ keys <- vectorOf n arbitraryKeyPair+ perm <- choose (0, length keys - 1)+ let pubKeys = map snd keys+ prvKeys = take nPrv $ permutations (map fst keys) !! perm+ let so = PayMulSig pubKeys m+ elements+ [ (so, val, Nothing, prvKeys, m, n)+ , ( PayScriptHash $ getAddrHash160 $ payToScriptAddress so+ , val+ , Just so+ , prvKeys+ , m+ , n)+ ]++wrapKey :: (SigInput, SecKeyI) -> (SigInput, [SecKeyI])+wrapKey (s, k) = (s, [k])
+ src/Haskoin/Util/Arbitrary/Util.hs view
@@ -0,0 +1,44 @@+{-|+Module : Haskoin.Test.Util+Copyright : No rights reserved+License : UNLICENSE+Maintainer : jprupp@protonmail.ch+Stability : experimental+Portability : POSIX+-}+module Haskoin.Util.Arbitrary.Util where++import Data.ByteString (ByteString, pack)+import Data.Time.Clock (UTCTime (..))+import Data.Time.Clock.POSIX (posixSecondsToUTCTime)+import Data.Word (Word32)+import Test.QuickCheck+import Haskoin.Constants++-- | Arbitrary strict 'ByteString'.+arbitraryBS :: Gen ByteString+arbitraryBS = pack <$> arbitrary++-- | Arbitrary non-empty strict ByteString+arbitraryBS1 :: Gen ByteString+arbitraryBS1 = pack <$> listOf1 arbitrary++-- | Arbitrary strict ByteString of a given length+arbitraryBSn :: Int -> Gen ByteString+arbitraryBSn n = pack <$> vectorOf n arbitrary++-- | Arbitrary UTCTime that generates dates after 01 Jan 1970 01:00:00 CET+arbitraryUTCTime :: Gen UTCTime+arbitraryUTCTime = do+ w <- arbitrary :: Gen Word32+ return $ posixSecondsToUTCTime $ realToFrac w++-- | Generate a Maybe from a Gen a+arbitraryMaybe :: Gen a -> Gen (Maybe a)+arbitraryMaybe g = frequency [ (1, return Nothing)+ , (5, Just <$> g)+ ]++arbitraryNetwork :: Gen Network+arbitraryNetwork = elements allNets+
test/Haskoin/AddressSpec.hs view
@@ -8,7 +8,7 @@ import Haskoin.Address import Haskoin.Constants import Haskoin.Keys (derivePubKeyI)-import Haskoin.Test+import Haskoin.Util.Arbitrary import Haskoin.UtilSpec (testCustomEncoding, testCustomJSON) import Test.Hspec import Test.HUnit (Assertion, assertBool, assertEqual)
test/Haskoin/BlockSpec.hs view
@@ -11,8 +11,8 @@ import Data.Text (Text) import Haskoin.Block import Haskoin.Constants-import Haskoin.Test import Haskoin.Transaction+import Haskoin.Util.Arbitrary import Haskoin.UtilSpec (cerealID, testJsonID) import Test.Hspec import Test.HUnit hiding (State)
test/Haskoin/Crypto/HashSpec.hs view
@@ -9,8 +9,8 @@ import Data.String.Conversions import Haskoin.Block import Haskoin.Crypto-import Haskoin.Test import Haskoin.Util+import Haskoin.Util.Arbitrary import Test.Hspec import Test.HUnit (Assertion, assertBool) import Test.QuickCheck
test/Haskoin/Crypto/SignatureSpec.hs view
@@ -1,21 +1,21 @@ {-# LANGUAGE OverloadedStrings #-} module Haskoin.Crypto.SignatureSpec (spec) where -import Data.Bits (testBit)-import Data.ByteString (ByteString)-import qualified Data.ByteString as BS (index, length)-import Data.Serialize as S-import Data.Text (Text)-import Haskoin.Crypto (SecKey, Sig, decodeStrictSig,- derivePubKey, exportSig,- importCompactSig, isCanonicalHalfOrder,- sha256, signHash, verifyHashSig)-import Haskoin.Test (arbitrarySignature)-import Haskoin.Util (decodeHex, eitherToMaybe, lst3)-import Test.Hspec (Spec, describe, it)-import Test.Hspec.QuickCheck (prop)-import Test.HUnit (Assertion, assertBool)-import Test.QuickCheck (forAll)+import Data.Bits (testBit)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS (index, length)+import Data.Serialize as S+import Data.Text (Text)+import Haskoin.Crypto (SecKey, Sig, decodeStrictSig,+ derivePubKey, exportSig,+ importCompactSig, isCanonicalHalfOrder,+ sha256, signHash, verifyHashSig)+import Haskoin.Util (decodeHex, eitherToMaybe, lst3)+import Haskoin.Util.Arbitrary (arbitrarySignature)+import Test.Hspec (Spec, describe, it)+import Test.Hspec.QuickCheck (prop)+import Test.HUnit (Assertion, assertBool)+import Test.QuickCheck (forAll) spec :: Spec spec = do
test/Haskoin/Keys/ExtendedSpec.hs view
@@ -14,8 +14,8 @@ import Haskoin.Address import Haskoin.Constants import Haskoin.Keys-import Haskoin.Test import Haskoin.Util+import Haskoin.Util.Arbitrary import Haskoin.UtilSpec (cerealID, customCerealID, testCustomEncoding, testCustomJSON, testJsonID)
test/Haskoin/Keys/MnemonicSpec.hs view
@@ -1,22 +1,22 @@ {-# LANGUAGE OverloadedStrings #-} module Haskoin.Keys.MnemonicSpec (spec) where -import Control.Monad (zipWithM_)-import Data.Bits (shiftR, (.&.))-import qualified Data.ByteString as BS-import Data.Either (fromRight)-import Data.List (isPrefixOf)-import Data.Maybe (fromJust)-import Data.Serialize (Serialize, encode)-import Data.Text (Text)-import qualified Data.Text as T-import Data.Word (Word32, Word64)+import Control.Monad (zipWithM_)+import Data.Bits (shiftR, (.&.))+import qualified Data.ByteString as BS+import Data.Either (fromRight)+import Data.List (isPrefixOf)+import Data.Maybe (fromJust)+import Data.Serialize (Serialize, encode)+import Data.Text (Text)+import qualified Data.Text as T+import Data.Word (Word32, Word64) import Haskoin.Keys-import Haskoin.Test import Haskoin.Util+import Haskoin.Util.Arbitrary import Test.Hspec import Test.HUnit-import Test.QuickCheck hiding ((.&.))+import Test.QuickCheck hiding ((.&.)) spec :: Spec spec =
test/Haskoin/KeysSpec.hs view
@@ -10,7 +10,7 @@ import Haskoin.Constants import Haskoin.Crypto import Haskoin.Keys-import Haskoin.Test+import Haskoin.Util.Arbitrary import Haskoin.Util import Test.Hspec import Test.QuickCheck
test/Haskoin/NetworkSpec.hs view
@@ -1,20 +1,20 @@ {-# LANGUAGE OverloadedStrings #-} module Haskoin.NetworkSpec (spec) where -import Data.Maybe (fromJust)-import Data.Serialize as S-import Data.Text (Text)-import Data.Word (Word32)+import Data.Maybe (fromJust)+import Data.Serialize as S+import Data.Text (Text)+import Data.Word (Word32) import Haskoin.Address import Haskoin.Constants import Haskoin.Keys import Haskoin.Network-import Haskoin.Test import Haskoin.Transaction import Haskoin.Util-import Haskoin.UtilSpec (cerealID, customCerealID)+import Haskoin.Util.Arbitrary+import Haskoin.UtilSpec (cerealID, customCerealID) import Test.Hspec-import Test.HUnit (Assertion, assertBool, assertEqual)+import Test.HUnit (Assertion, assertBool, assertEqual) import Test.QuickCheck spec :: Spec
test/Haskoin/ScriptSpec.hs view
@@ -18,9 +18,9 @@ import Haskoin.Constants import Haskoin.Keys import Haskoin.Script-import Haskoin.Test import Haskoin.Transaction import Haskoin.Util+import Haskoin.Util.Arbitrary import Haskoin.UtilSpec (cerealID, testJsonID) import Test.Hspec import Test.HUnit as HUnit
− test/Haskoin/Test.hs
@@ -1,23 +0,0 @@-{-|-Module : Haskoin.Test-Copyright : No rights reserved-License : UNLICENSE-Maintainer : jprupp@protonmail.ch-Stability : experimental-Portability : POSIX--Arbitrary instances for testing.--}-module Haskoin.Test- ( module X- ) where--import Haskoin.Test.Address as X-import Haskoin.Test.Block as X-import Haskoin.Test.Crypto as X-import Haskoin.Test.Keys as X-import Haskoin.Test.Message as X-import Haskoin.Test.Network as X-import Haskoin.Test.Script as X-import Haskoin.Test.Transaction as X-import Haskoin.Test.Util as X
− test/Haskoin/Test/Address.hs
@@ -1,25 +0,0 @@-{-|-Module : Haskoin.Test.Address-Copyright : No rights reserved-License : UNLICENSE-Maintainer : jprupp@protonmail.ch-Stability : experimental-Portability : POSIX--}-module Haskoin.Test.Address where--import Haskoin.Address-import Haskoin.Test.Crypto-import Test.QuickCheck---- | Arbitrary pay-to-public-key-hash or pay-to-script-hash address.-arbitraryAddress :: Gen Address-arbitraryAddress = oneof [arbitraryPubKeyAddress, arbitraryScriptAddress]---- | Arbitrary pay-to-public-key-hash address.-arbitraryPubKeyAddress :: Gen Address-arbitraryPubKeyAddress = p2pkhAddr <$> arbitraryHash160---- | Arbitrary pay-to-script-hash address.-arbitraryScriptAddress :: Gen Address-arbitraryScriptAddress = p2shAddr <$> arbitraryHash160
− test/Haskoin/Test/Block.hs
@@ -1,69 +0,0 @@-{-|-Module : Haskoin.Test.Block-Copyright : No rights reserved-License : UNLICENSE-Maintainer : jprupp@protonmail.ch-Stability : experimental-Portability : POSIX--}-module Haskoin.Test.Block where--import Haskoin.Block.Common-import Haskoin.Block.Merkle-import Haskoin.Constants-import Haskoin.Test.Crypto-import Haskoin.Test.Network-import Haskoin.Test.Transaction-import Test.QuickCheck---- | Block full or arbitrary transactions.-arbitraryBlock :: Network -> Gen Block-arbitraryBlock net = do- h <- arbitraryBlockHeader- c <- choose (0,10)- txs <- vectorOf c (arbitraryTx net)- return $ Block h txs---- | Block header with random hash.-arbitraryBlockHeader :: Gen BlockHeader-arbitraryBlockHeader =- BlockHeader <$> arbitrary- <*> arbitraryBlockHash- <*> arbitraryHash256- <*> arbitrary- <*> arbitrary- <*> arbitrary---- | Arbitrary block hash.-arbitraryBlockHash :: Gen BlockHash-arbitraryBlockHash = BlockHash <$> arbitraryHash256---- | Arbitrary 'GetBlocks' object with at least one block hash.-arbitraryGetBlocks :: Gen GetBlocks-arbitraryGetBlocks =- GetBlocks <$> arbitrary- <*> listOf1 arbitraryBlockHash- <*> arbitraryBlockHash---- | Arbitrary 'GetHeaders' object with at least one block header.-arbitraryGetHeaders :: Gen GetHeaders-arbitraryGetHeaders =- GetHeaders <$> arbitrary- <*> listOf1 arbitraryBlockHash- <*> arbitraryBlockHash---- | Arbitrary 'Headers' object with at least one block header.-arbitraryHeaders :: Gen Headers-arbitraryHeaders =- Headers <$> listOf1 ((,) <$> arbitraryBlockHeader <*> arbitraryVarInt)---- | Arbitrary 'MerkleBlock' with at least one hash.-arbitraryMerkleBlock :: Gen MerkleBlock-arbitraryMerkleBlock = do- bh <- arbitraryBlockHeader- ntx <- arbitrary- hashes <- listOf1 arbitraryHash256- c <- choose (1,10)- flags <- vectorOf (c*8) arbitrary- return $ MerkleBlock bh ntx hashes flags-
− test/Haskoin/Test/Crypto.hs
@@ -1,33 +0,0 @@-{-|-Module : Haskoin.Test.Crypto-Copyright : No rights reserved-License : UNLICENSE-Maintainer : jprupp@protonmail.ch-Stability : experimental-Portability : POSIX--}-module Haskoin.Test.Crypto where--import Haskoin.Crypto.Hash-import Haskoin.Test.Util-import Test.QuickCheck---- | Arbitrary 160-bit hash.-arbitraryHash160 :: Gen Hash160-arbitraryHash160 =- ripemd160 <$> arbitraryBSn 20---- | Arbitrary 256-bit hash.-arbitraryHash256 :: Gen Hash256-arbitraryHash256 =- sha256 <$> arbitraryBSn 32---- | Arbitrary 512-bit hash.-arbitraryHash512 :: Gen Hash512-arbitraryHash512 =- sha512 <$> arbitraryBSn 64---- | Arbitrary 32-bit checksum.-arbitraryCheckSum32 :: Gen CheckSum32-arbitraryCheckSum32 =- checkSum32 <$> arbitraryBSn 4
− test/Haskoin/Test/Keys.hs
@@ -1,85 +0,0 @@-{-|-Module : Haskoin.Test.Keys-Copyright : No rights reserved-License : UNLICENSE-Maintainer : jprupp@protonmail.ch-Stability : experimental-Portability : POSIX--}-module Haskoin.Test.Keys where--import Data.Bits (clearBit)-import Data.List (foldl')-import Data.Word (Word32)-import Haskoin.Crypto-import Haskoin.Keys.Common-import Haskoin.Keys.Extended-import Haskoin.Test.Crypto-import Test.QuickCheck---- | Arbitrary private key with arbitrary compressed flag.-arbitrarySecKeyI :: Gen SecKeyI-arbitrarySecKeyI = wrapSecKey <$> arbitrary <*> arbitrary---- | Arbitrary keypair, both either compressed or not.-arbitraryKeyPair :: Gen (SecKeyI, PubKeyI)-arbitraryKeyPair = do- k <- arbitrarySecKeyI- return (k, derivePubKeyI k)---- | Arbitrary extended private key.-arbitraryXPrvKey :: Gen XPrvKey-arbitraryXPrvKey =- XPrvKey <$> arbitrary- <*> arbitrary- <*> arbitrary- <*> arbitraryHash256- <*> arbitrary---- | Arbitrary extended public key with its corresponding private key.-arbitraryXPubKey :: Gen (XPrvKey, XPubKey)-arbitraryXPubKey = (\k -> (k, deriveXPubKey k)) <$> arbitraryXPrvKey--{- Custom derivations -}---- | Arbitrary derivation index with last bit unset.-genIndex :: Gen Word32-genIndex = (`clearBit` 31) <$> arbitrary---- | Arbitrary BIP-32 path index. Can be hardened or not.-arbitraryBip32PathIndex :: Gen Bip32PathIndex-arbitraryBip32PathIndex =- oneof [ Bip32SoftIndex <$> genIndex- , Bip32HardIndex <$> genIndex- ]---- | Arbitrary BIP-32 derivation path composed of only hardened derivations.-arbitraryHardPath :: Gen HardPath-arbitraryHardPath = foldl' (:|) Deriv <$> listOf genIndex---- | Arbitrary BIP-32 derivation path composed of only non-hardened derivations.-arbitrarySoftPath :: Gen SoftPath-arbitrarySoftPath = foldl' (:/) Deriv <$> listOf genIndex---- | Arbitrary derivation path composed of hardened and non-hardened derivations.-arbitraryDerivPath :: Gen DerivPath-arbitraryDerivPath = concatBip32Segments <$> listOf arbitraryBip32PathIndex---- | Arbitrary parsed derivation path. Can contain 'ParsedPrv', 'ParsedPub' or--- 'ParsedEmpty' elements.-arbitraryParsedPath :: Gen ParsedPath-arbitraryParsedPath =- oneof [ ParsedPrv <$> arbitraryDerivPath- , ParsedPub <$> arbitraryDerivPath- , ParsedEmpty <$> arbitraryDerivPath- ]---- | Arbitrary message hash, private key, nonce and corresponding signature. The--- signature is generated with a random message, random private key and a random--- nonce.-arbitrarySignature :: Gen (Hash256, SecKey, Sig)-arbitrarySignature = do- m <- arbitraryHash256- key <- arbitrary- let sig = signHash key m- return (m, key, sig)
− test/Haskoin/Test/Message.hs
@@ -1,52 +0,0 @@-{-|-Module : Haskoin.Test.Message-Copyright : No rights reserved-License : UNLICENSE-Maintainer : jprupp@protonmail.ch-Stability : experimental-Portability : POSIX--}-module Haskoin.Test.Message where--import Haskoin.Constants-import Haskoin.Network.Message-import Haskoin.Test.Block-import Haskoin.Test.Crypto-import Haskoin.Test.Network-import Haskoin.Test.Transaction-import Test.QuickCheck---- | Arbitrary 'MessageHeader'.-arbitraryMessageHeader :: Gen MessageHeader-arbitraryMessageHeader =- MessageHeader <$> arbitrary- <*> arbitraryMessageCommand- <*> arbitrary- <*> arbitraryCheckSum32---- | Arbitrary 'Message'.-arbitraryMessage :: Network -> Gen Message-arbitraryMessage net =- oneof- [ MVersion <$> arbitraryVersion- , return MVerAck- , MAddr <$> arbitraryAddr1- , MInv <$> arbitraryInv1- , MGetData <$> arbitraryGetData- , MNotFound <$> arbitraryNotFound- , MGetBlocks <$> arbitraryGetBlocks- , MGetHeaders <$> arbitraryGetHeaders- , MTx <$> arbitraryTx net- , MBlock <$> arbitraryBlock net- , MMerkleBlock <$> arbitraryMerkleBlock- , MHeaders <$> arbitraryHeaders- , return MGetAddr- , MFilterLoad <$> arbitraryFilterLoad- , MFilterAdd <$> arbitraryFilterAdd- , return MFilterClear- , MPing <$> arbitraryPing- , MPong <$> arbitraryPong- , MAlert <$> arbitraryAlert- , MReject <$> arbitraryReject- , return MSendHeaders- ]
− test/Haskoin/Test/Network.hs
@@ -1,178 +0,0 @@-{-|-Module : Haskoin.Test.Network-Copyright : No rights reserved-License : UNLICENSE-Maintainer : jprupp@protonmail.ch-Stability : experimental-Portability : POSIX--}-module Haskoin.Test.Network where--import qualified Data.ByteString as BS (empty, pack)-import qualified Data.ByteString.Char8 as C8-import Data.Word (Word16, Word32)-import Haskoin.Network-import Haskoin.Test.Crypto-import Haskoin.Test.Util-import Network.Socket (SockAddr (..))-import Test.QuickCheck---- | Arbitrary 'VarInt'.-arbitraryVarInt :: Gen VarInt-arbitraryVarInt = VarInt <$> arbitrary---- | Arbitrary 'VarString'.-arbitraryVarString :: Gen VarString-arbitraryVarString = VarString <$> arbitraryBS---- | Arbitrary 'NetworkAddress'.-arbitraryNetworkAddress :: Gen NetworkAddress-arbitraryNetworkAddress = do- s <- arbitrary- a <- arbitrary- p <- arbitrary- d <- oneof- [ do- b <- arbitrary- c <- arbitrary- d <- arbitrary- return $ SockAddrInet6 (fromIntegral p) 0 (a,b,c,d) 0- , return $ SockAddrInet (fromIntegral (p :: Word16)) a- ]- let n = sockToHostAddress d- return $ NetworkAddress s n---- | Arbitrary 'NetworkAddressTime'.-arbitraryNetworkAddressTime :: Gen (Word32, NetworkAddress)-arbitraryNetworkAddressTime = (,) <$> arbitrary <*> arbitraryNetworkAddress---- | Arbitrary 'InvType'.-arbitraryInvType :: Gen InvType-arbitraryInvType = elements [InvError, InvTx, InvBlock, InvMerkleBlock]---- | Arbitrary 'InvVector'.-arbitraryInvVector :: Gen InvVector-arbitraryInvVector = InvVector <$> arbitraryInvType <*> arbitraryHash256---- | Arbitrary non-empty 'Inv'.-arbitraryInv1 :: Gen Inv-arbitraryInv1 = Inv <$> listOf1 arbitraryInvVector---- | Arbitrary 'Version'.-arbitraryVersion :: Gen Version-arbitraryVersion =- Version <$> arbitrary- <*> arbitrary- <*> arbitrary- <*> arbitraryNetworkAddress- <*> arbitraryNetworkAddress- <*> arbitrary- <*> arbitraryVarString- <*> arbitrary- <*> arbitrary---- | Arbitrary non-empty 'Addr'.-arbitraryAddr1 :: Gen Addr-arbitraryAddr1 = Addr <$> listOf1 arbitraryNetworkAddressTime---- | Arbitrary 'Alert' with random payload and signature. Signature is not--- valid.-arbitraryAlert :: Gen Alert-arbitraryAlert = Alert <$> arbitraryVarString <*> arbitraryVarString---- | Arbitrary 'Reject'.-arbitraryReject :: Gen Reject-arbitraryReject = do- m <- arbitraryMessageCommand- c <- arbitraryRejectCode- s <- arbitraryVarString- d <- oneof [ return BS.empty- , BS.pack <$> vectorOf 32 arbitrary- ]- return $ Reject m c s d---- | Arbitrary 'RejectCode'.-arbitraryRejectCode :: Gen RejectCode-arbitraryRejectCode =- elements- [ RejectMalformed- , RejectInvalid- , RejectInvalid- , RejectDuplicate- , RejectNonStandard- , RejectDust- , RejectInsufficientFee- , RejectCheckpoint- ]---- | Arbitrary non-empty 'GetData'.-arbitraryGetData :: Gen GetData-arbitraryGetData = GetData <$> listOf1 arbitraryInvVector---- | Arbitrary 'NotFound'.-arbitraryNotFound :: Gen NotFound-arbitraryNotFound = NotFound <$> listOf1 arbitraryInvVector---- | Arbitrary 'Ping'.-arbitraryPing :: Gen Ping-arbitraryPing = Ping <$> arbitrary---- | Arbitrary 'Pong'.-arbitraryPong :: Gen Pong-arbitraryPong = Pong <$> arbitrary---- | Arbitrary bloom filter flags.-arbitraryBloomFlags :: Gen BloomFlags-arbitraryBloomFlags =- elements- [ BloomUpdateNone- , BloomUpdateAll- , BloomUpdateP2PubKeyOnly- ]---- | Arbitrary bloom filter with its corresponding number of elements--- and false positive rate.-arbitraryBloomFilter :: Gen (Int, Double, BloomFilter)-arbitraryBloomFilter = do- n <- choose (0,100000)- fp <- choose (1e-8,1)- tweak <- arbitrary- fl <- arbitraryBloomFlags- return (n, fp, bloomCreate n fp tweak fl)---- | Arbitrary 'FilterLoad'.-arbitraryFilterLoad :: Gen FilterLoad-arbitraryFilterLoad = do- (_, _, bf) <- arbitraryBloomFilter- return $ FilterLoad bf---- | Arbitrary 'FilterAdd'.-arbitraryFilterAdd :: Gen FilterAdd-arbitraryFilterAdd = FilterAdd <$> arbitraryBS---- | Arbitrary 'MessageCommand'.-arbitraryMessageCommand :: Gen MessageCommand-arbitraryMessageCommand = do- ASCIIString str <- arbitrary- elements- [ MCVersion- , MCVerAck- , MCAddr- , MCInv- , MCGetData- , MCNotFound- , MCGetBlocks- , MCGetHeaders- , MCTx- , MCBlock- , MCMerkleBlock- , MCHeaders- , MCGetAddr- , MCFilterLoad- , MCFilterAdd- , MCFilterClear- , MCPing- , MCPong- , MCAlert- , MCOther (C8.take 12 (C8.pack (filter (/= '\NUL') str)))- ]
− test/Haskoin/Test/Script.hs
@@ -1,379 +0,0 @@-{-# LANGUAGE LambdaCase #-}-{-|-Module : Haskoin.Test.Script-Copyright : No rights reserved-License : UNLICENSE-Maintainer : jprupp@protonmail.ch-Stability : experimental-Portability : POSIX--}-module Haskoin.Test.Script where--import Crypto.Secp256k1-import Data.Maybe-import Data.Word-import Haskoin.Address-import Haskoin.Constants-import Haskoin.Keys.Common-import Haskoin.Script-import Haskoin.Test.Address-import Haskoin.Test.Crypto-import Haskoin.Test.Keys-import Haskoin.Test.Util-import Haskoin.Transaction.Common-import Haskoin.Util-import Test.QuickCheck---- | Arbitrary 'Script' with random script ops.-arbitraryScript :: Gen Script-arbitraryScript = Script <$> listOf arbitraryScriptOp---- | Arbitrary 'ScriptOp' (push operations have random data).-arbitraryScriptOp :: Gen ScriptOp-arbitraryScriptOp =- oneof- -- Pushing Data- [ opPushData <$> arbitraryBS1- , return OP_0- , return OP_1NEGATE- , return OP_RESERVED- , return OP_1- , return OP_2- , return OP_3- , return OP_4- , return OP_5- , return OP_6- , return OP_7- , return OP_8- , return OP_9- , return OP_10- , return OP_11- , return OP_12- , return OP_13- , return OP_14- , return OP_15- , return OP_16- -- Flow control- , return OP_NOP- , return OP_VER- , return OP_IF- , return OP_NOTIF- , return OP_VERIF- , return OP_VERNOTIF- , return OP_ELSE- , return OP_ENDIF- , return OP_VERIFY- , return OP_RETURN- -- Stack operations- , return OP_TOALTSTACK- , return OP_FROMALTSTACK- , return OP_IFDUP- , return OP_DEPTH- , return OP_DROP- , return OP_DUP- , return OP_NIP- , return OP_OVER- , return OP_PICK- , return OP_ROLL- , return OP_ROT- , return OP_SWAP- , return OP_TUCK- , return OP_2DROP- , return OP_2DUP- , return OP_3DUP- , return OP_2OVER- , return OP_2ROT- , return OP_2SWAP- -- Splice- , return OP_CAT- , return OP_SUBSTR- , return OP_LEFT- , return OP_RIGHT- , return OP_SIZE- -- Bitwise logic- , return OP_INVERT- , return OP_AND- , return OP_OR- , return OP_XOR- , return OP_EQUAL- , return OP_EQUALVERIFY- , return OP_RESERVED1- , return OP_RESERVED2- -- Arithmetic- , return OP_1ADD- , return OP_1SUB- , return OP_2MUL- , return OP_2DIV- , return OP_NEGATE- , return OP_ABS- , return OP_NOT- , return OP_0NOTEQUAL- , return OP_ADD- , return OP_SUB- , return OP_MUL- , return OP_DIV- , return OP_MOD- , return OP_LSHIFT- , return OP_RSHIFT- , return OP_BOOLAND- , return OP_BOOLOR- , return OP_NUMEQUAL- , return OP_NUMEQUALVERIFY- , return OP_NUMNOTEQUAL- , return OP_LESSTHAN- , return OP_GREATERTHAN- , return OP_LESSTHANOREQUAL- , return OP_GREATERTHANOREQUAL- , return OP_MIN- , return OP_MAX- , return OP_WITHIN- -- Crypto- , return OP_RIPEMD160- , return OP_SHA1- , return OP_SHA256- , return OP_HASH160- , return OP_HASH256- , return OP_CODESEPARATOR- , return OP_CHECKSIG- , return OP_CHECKSIGVERIFY- , return OP_CHECKMULTISIG- , return OP_CHECKMULTISIGVERIFY- -- Expansion- , return OP_NOP1- , return OP_NOP2- , return OP_NOP3- , return OP_NOP4- , return OP_NOP5- , return OP_NOP6- , return OP_NOP7- , return OP_NOP8- , return OP_NOP9- , return OP_NOP10- -- Bitcoin Cash Nov 2018 hard fork- , return OP_CHECKDATASIG- , return OP_CHECKDATASIGVERIFY- -- Bitcoin Cash May 2020 hard fork- , return OP_REVERSEBYTES- -- Other- , return OP_PUBKEYHASH- , return OP_PUBKEY- , return $ OP_INVALIDOPCODE 0xff- ]---- | Arbtirary 'ScriptOp' with a value in @[OP_1 .. OP_16]@.-arbitraryIntScriptOp :: Gen ScriptOp-arbitraryIntScriptOp =- elements- [ OP_1, OP_2, OP_3, OP_4- , OP_5, OP_6, OP_7, OP_8- , OP_9, OP_10, OP_11, OP_12- , OP_13, OP_14, OP_15, OP_16- ]---- | Arbitrary 'PushDataType'.-arbitraryPushDataType :: Gen PushDataType-arbitraryPushDataType = elements [OPCODE, OPDATA1, OPDATA2, OPDATA4]---- | Arbitrary 'SigHash' (including invalid/unknown sighash codes).-arbitrarySigHash :: Gen SigHash-arbitrarySigHash = fromIntegral <$> (arbitrary :: Gen Word32)---- | Arbitrary valid 'SigHash'.-arbitraryValidSigHash :: Network -> Gen SigHash-arbitraryValidSigHash net = do- sh <- elements [sigHashAll, sigHashNone, sigHashSingle]- f1 <-- elements $- if isJust (getSigHashForkId net)- then [id, setForkIdFlag]- else [id]- f2 <- elements [id, setAnyoneCanPayFlag]- return $ f1 $ f2 sh---- | Arbitrary message hash, private key and corresponding 'TxSignature'. The--- signature is generated deterministically using a random message and a random--- private key.-arbitraryTxSignature :: Network -> Gen (TxHash, SecKey, TxSignature)-arbitraryTxSignature net = do- (m, key, sig) <- arbitrarySignature- sh <- (fromIntegral <$> (arbitrary :: Gen Word8)) `suchThat` filterBad- let txsig = TxSignature sig sh- return (TxHash m, key, txsig)- where- filterBad sh = not $- isSigHashUnknown sh ||- isNothing (getSigHashForkId net) && hasForkIdFlag sh---- | Arbitrary transaction signature that could also be empty.-arbitraryTxSignatureEmpty :: Network -> Gen TxSignature-arbitraryTxSignatureEmpty net =- frequency [ (1, return TxSignatureEmpty)- , (10, lst3 <$> arbitraryTxSignature net)- ]---- | Arbitrary m of n parameters.-arbitraryMSParam :: Gen (Int, Int)-arbitraryMSParam = do- m <- choose (1,16)- n <- choose (m,16)- return (m, n)---- | Arbitrary 'ScriptOutput' (Can by any valid type).-arbitraryScriptOutput :: Network -> Gen ScriptOutput-arbitraryScriptOutput net =- oneof $- [ arbitraryPKOutput- , arbitraryPKHashOutput- , arbitraryMSOutput- , arbitrarySHOutput- , arbitraryDCOutput- ] ++- if getSegWit net- then [arbitraryWPKHashOutput, arbitraryWSHOutput]- else []---- | Arbitrary 'ScriptOutput' of type 'PayPK', 'PayPKHash' or 'PayMS'--- (Not 'PayScriptHash', 'DataCarrier', or SegWit)-arbitrarySimpleOutput :: Gen ScriptOutput-arbitrarySimpleOutput =- oneof- [ arbitraryPKOutput- , arbitraryPKHashOutput- , arbitraryMSOutput- ]---- | Arbitrary 'ScriptOutput' of type 'PayPK'-arbitraryPKOutput :: Gen ScriptOutput-arbitraryPKOutput = PayPK . snd <$> arbitraryKeyPair---- | Arbitrary 'ScriptOutput' of type 'PayPKHash'-arbitraryPKHashOutput :: Gen ScriptOutput-arbitraryPKHashOutput = PayPKHash <$> arbitraryHash160---- | Arbitrary 'PayWitnessPKHash' output.-arbitraryWPKHashOutput :: Gen ScriptOutput-arbitraryWPKHashOutput = PayWitnessPKHash <$> arbitraryHash160---- | Arbitrary 'PayWitnessScriptHash' output.-arbitraryWSHOutput :: Gen ScriptOutput-arbitraryWSHOutput = PayWitnessScriptHash <$> arbitraryHash256---- | Arbitrary 'ScriptOutput' of type 'PayMS'.-arbitraryMSOutput :: Gen ScriptOutput-arbitraryMSOutput = do- (m, n) <- arbitraryMSParam- keys <- map snd <$> vectorOf n arbitraryKeyPair- return $ PayMulSig keys m---- | Arbitrary 'ScriptOutput' of type 'PayMS', only using compressed keys.-arbitraryMSOutputC :: Gen ScriptOutput-arbitraryMSOutputC = do- (m, n) <- arbitraryMSParam- keys <-- map snd <$>- vectorOf n (arbitraryKeyPair `suchThat` (pubKeyCompressed . snd))- return $ PayMulSig keys m---- | Arbitrary 'ScriptOutput' of type 'PayScriptHash'.-arbitrarySHOutput :: Gen ScriptOutput-arbitrarySHOutput = PayScriptHash . getAddrHash160 <$> arbitraryScriptAddress---- | Arbitrary 'ScriptOutput' of type 'DataCarrier'.-arbitraryDCOutput :: Gen ScriptOutput-arbitraryDCOutput = DataCarrier <$> arbitraryBS1---- | Arbitrary 'ScriptInput'.-arbitraryScriptInput :: Network -> Gen ScriptInput-arbitraryScriptInput net =- oneof- [ arbitraryPKInput net- , arbitraryPKHashInput net- , arbitraryMSInput net- , arbitrarySHInput net- ]---- | Arbitrary 'ScriptInput' of type 'SpendPK', 'SpendPKHash' or 'SpendMulSig'--- (not 'ScriptHashInput')-arbitrarySimpleInput :: Network -> Gen ScriptInput-arbitrarySimpleInput net =- oneof- [ arbitraryPKInput net- , arbitraryPKHashInput net- , arbitraryMSInput net- ]---- | Arbitrary 'ScriptInput' of type 'SpendPK'.-arbitraryPKInput :: Network -> Gen ScriptInput-arbitraryPKInput net = RegularInput . SpendPK <$> arbitraryTxSignatureEmpty net---- | Arbitrary 'ScriptInput' of type 'SpendPK'.-arbitraryPKHashInput :: Network -> Gen ScriptInput-arbitraryPKHashInput net = do- sig <- arbitraryTxSignatureEmpty net- key <- snd <$> arbitraryKeyPair- return $ RegularInput $ SpendPKHash sig key---- | Like 'arbitraryPKHashInput' without empty signatures.-arbitraryPKHashInputFull :: Network -> Gen ScriptInput-arbitraryPKHashInputFull net = do- sig <- lst3 <$> arbitraryTxSignature net- key <- snd <$> arbitraryKeyPair- return $ RegularInput $ SpendPKHash sig key---- | Like above but only compressed.-arbitraryPKHashInputFullC :: Network -> Gen ScriptInput-arbitraryPKHashInputFullC net = do- sig <- lst3 <$> arbitraryTxSignature net- key <- fmap snd $ arbitraryKeyPair `suchThat` (pubKeyCompressed . snd)- return $ RegularInput $ SpendPKHash sig key---- | Arbitrary 'ScriptInput' of type 'SpendMulSig'.-arbitraryMSInput :: Network -> Gen ScriptInput-arbitraryMSInput net = do- m <- fst <$> arbitraryMSParam- sigs <- vectorOf m (arbitraryTxSignatureEmpty net)- return $ RegularInput $ SpendMulSig sigs---- | Arbitrary 'ScriptInput' of type 'ScriptHashInput'.-arbitrarySHInput :: Network -> Gen ScriptInput-arbitrarySHInput net = do- i <- arbitrarySimpleInput net- ScriptHashInput (getRegularInput i) <$> arbitrarySimpleOutput---- | Arbitrary 'ScriptInput' of type 'ScriptHashInput' containing a--- 'RedeemScript' of type 'PayMulSig' and an input of type 'SpendMulSig'.-arbitraryMulSigSHInput :: Network -> Gen ScriptInput-arbitraryMulSigSHInput net =- arbitraryMSOutput >>= \case- rdm@(PayMulSig _ m) -> do- sigs <- vectorOf m (arbitraryTxSignatureEmpty net)- return $ ScriptHashInput (SpendMulSig sigs) rdm- _ -> undefined---- | Arbitrary 'ScriptInput' of type 'ScriptHashInput' containing a--- 'RedeemScript' of type 'PayMulSig' and an input of type 'SpendMulSig'.-arbitraryMulSigSHInputC :: Network -> Gen ScriptInput-arbitraryMulSigSHInputC net =- arbitraryMSOutputC >>= \case- rdm@(PayMulSig _ m) -> do- sigs <- vectorOf m (arbitraryTxSignatureEmpty net)- return $ ScriptHashInput (SpendMulSig sigs) rdm- _ -> undefined---- | Like 'arbitraryMulSigSHCInput' with no empty signatures.-arbitraryMulSigSHInputFull :: Network -> Gen ScriptInput-arbitraryMulSigSHInputFull net =- arbitraryMSOutput >>= \case- rdm@(PayMulSig _ m) -> do- sigs <- map lst3 <$> vectorOf m (arbitraryTxSignature net)- return $ ScriptHashInput (SpendMulSig sigs) rdm- _ -> undefined---- | Like 'arbitraryMulSigSHCInput' with no empty signatures.-arbitraryMulSigSHInputFullC :: Network -> Gen ScriptInput-arbitraryMulSigSHInputFullC net =- arbitraryMSOutputC >>= \case- rdm@(PayMulSig _ m) -> do- sigs <- map lst3 <$> vectorOf m (arbitraryTxSignature net)- return $ ScriptHashInput (SpendMulSig sigs) rdm- _ -> undefined
− test/Haskoin/Test/Transaction.hs
@@ -1,278 +0,0 @@-{-|-Module : Haskoin.Test.Transaction-Copyright : No rights reserved-License : UNLICENSE-Maintainer : jprupp@protonmail.ch-Stability : experimental-Portability : POSIX--}-module Haskoin.Test.Transaction where--import Control.Monad-import qualified Data.ByteString as BS-import Data.Either (fromRight)-import Data.List (nub, nubBy, permutations)-import Data.Word (Word64)-import Haskoin.Address-import Haskoin.Constants-import Haskoin.Keys.Common-import Haskoin.Script-import Haskoin.Test.Crypto-import Haskoin.Test.Keys-import Haskoin.Test.Script-import Haskoin.Test.Util-import Haskoin.Transaction-import Test.QuickCheck---- | Wrapped coin value for testing.-newtype TestCoin = TestCoin { getTestCoin :: Word64 }- deriving (Eq, Show)--instance Coin TestCoin where- coinValue = getTestCoin---- | Arbitrary transaction hash (for non-existent transaction).-arbitraryTxHash :: Gen TxHash-arbitraryTxHash = TxHash <$> arbitraryHash256---- | Arbitrary amount of Satoshi as 'Word64' (Between 1 and 21e14)-arbitrarySatoshi :: Network -> Gen TestCoin-arbitrarySatoshi net = TestCoin <$> choose (1, getMaxSatoshi net)---- | Arbitrary 'OutPoint'.-arbitraryOutPoint :: Gen OutPoint-arbitraryOutPoint = OutPoint <$> arbitraryTxHash <*> arbitrary---- | Arbitrary 'TxOut'.-arbitraryTxOut :: Network -> Gen TxOut-arbitraryTxOut net =- TxOut <$> (getTestCoin <$> arbitrarySatoshi net)- <*> (encodeOutputBS <$> arbitraryScriptOutput net)---- | Arbitrary 'TxIn'.-arbitraryTxIn :: Network -> Gen TxIn-arbitraryTxIn net =- TxIn <$> arbitraryOutPoint- <*> (encodeInputBS <$> arbitraryScriptInput net)- <*> arbitrary---- | Arbitrary transaction. Can be regular or with witnesses.-arbitraryTx :: Network -> Gen Tx-arbitraryTx net = oneof [arbitraryLegacyTx net, arbitraryWitnessTx net]---- | Arbitrary regular transaction.-arbitraryLegacyTx :: Network -> Gen Tx-arbitraryLegacyTx net = arbitraryWLTx net False---- | Arbitrary witness transaction (witness data is fake).-arbitraryWitnessTx :: Network -> Gen Tx-arbitraryWitnessTx net = arbitraryWLTx net True---- | Arbitrary witness or legacy transaction.-arbitraryWLTx :: Network -> Bool -> Gen Tx-arbitraryWLTx net wit = do- ni <- choose (0, 5)- no <-- if wit- then choose (0, 5)- else choose- ( if ni == 0- then 2- else 0- , 5 -- avoid witness case- )- inps <- vectorOf ni (arbitraryTxIn net)- outs <- vectorOf no (arbitraryTxOut net)- let uniqueInps = nubBy (\a b -> prevOutput a == prevOutput b) inps- w <-- if wit- then vectorOf (length uniqueInps) (listOf arbitraryBS)- else return []- Tx <$> arbitrary <*> pure uniqueInps <*> pure outs <*> pure w <*> arbitrary---- | Arbitrary transaction containing only inputs of type 'SpendPKHash',--- 'SpendScriptHash' (multisig) and outputs of type 'PayPKHash' and 'PaySH'.--- Only compressed public keys are used.-arbitraryAddrOnlyTx :: Network -> Gen Tx-arbitraryAddrOnlyTx net = do- ni <- choose (0, 5)- no <- choose (0, 5)- inps <- vectorOf ni (arbitraryAddrOnlyTxIn net)- outs <- vectorOf no (arbitraryAddrOnlyTxOut net)- Tx <$> arbitrary <*> pure inps <*> pure outs <*> pure [] <*> arbitrary---- | Like 'arbitraryAddrOnlyTx' without empty signatures in the inputs.-arbitraryAddrOnlyTxFull :: Network -> Gen Tx-arbitraryAddrOnlyTxFull net = do- ni <- choose (0, 5)- no <- choose (0, 5)- inps <- vectorOf ni (arbitraryAddrOnlyTxInFull net)- outs <- vectorOf no (arbitraryAddrOnlyTxOut net)- Tx <$> arbitrary <*> pure inps <*> pure outs <*> pure [] <*> arbitrary---- | Arbitrary TxIn that can only be of type 'SpendPKHash' or 'SpendScriptHash'--- (multisig). Only compressed public keys are used.-arbitraryAddrOnlyTxIn :: Network -> Gen TxIn-arbitraryAddrOnlyTxIn net = do- inp <- oneof [arbitraryPKHashInput net, arbitraryMulSigSHInput net]- TxIn <$> arbitraryOutPoint <*> pure (encodeInputBS inp) <*> arbitrary---- | like 'arbitraryAddrOnlyTxIn' with no empty signatures.-arbitraryAddrOnlyTxInFull :: Network -> Gen TxIn-arbitraryAddrOnlyTxInFull net = do- inp <-- oneof [arbitraryPKHashInputFullC net, arbitraryMulSigSHInputFullC net]- TxIn <$> arbitraryOutPoint <*> pure (encodeInputBS inp) <*> arbitrary---- | Arbitrary 'TxOut' that can only be of type 'PayPKHash' or 'PaySH'.-arbitraryAddrOnlyTxOut :: Network -> Gen TxOut-arbitraryAddrOnlyTxOut net = do- v <- getTestCoin <$> arbitrarySatoshi net- out <- oneof [arbitraryPKHashOutput, arbitrarySHOutput]- return $ TxOut v $ encodeOutputBS out---- | Arbitrary 'SigInput' with the corresponding private keys used--- to generate the 'ScriptOutput' or 'RedeemScript'.-arbitrarySigInput :: Network -> Gen (SigInput, [SecKeyI])-arbitrarySigInput net =- oneof- [ wrapKey <$> arbitraryPKSigInput net- , wrapKey <$> arbitraryPKHashSigInput net- , arbitraryMSSigInput net- , arbitrarySHSigInput net- , wrapKey <$> arbitraryWPKHSigInput net- , arbitraryWSHSigInput net- ]---- | Arbitrary 'SigInput' with a 'ScriptOutput' of type 'PayPK'.-arbitraryPKSigInput :: Network -> Gen (SigInput, SecKeyI)-arbitraryPKSigInput net = arbitraryAnyInput net False---- | Arbitrary 'SigInput' with a 'ScriptOutput' of type 'PayPKHash'.-arbitraryPKHashSigInput :: Network -> Gen (SigInput, SecKeyI)-arbitraryPKHashSigInput net = arbitraryAnyInput net True---- | Arbitrary 'SigInput'.-arbitraryAnyInput :: Network -> Bool -> Gen (SigInput, SecKeyI)-arbitraryAnyInput net pkh = do- (k, p) <- arbitraryKeyPair- let out | pkh = PayPKHash $ getAddrHash160 $ pubKeyAddr p- | otherwise = PayPK p- (val, op, sh) <- arbitraryInputStuff net- return (SigInput out val op sh Nothing, k)---- | Arbitrary value, out point and sighash for an input.-arbitraryInputStuff :: Network -> Gen (Word64, OutPoint, SigHash)-arbitraryInputStuff net = do- val <- getTestCoin <$> arbitrarySatoshi net- op <- arbitraryOutPoint- sh <- arbitraryValidSigHash net- return (val, op, sh)---- | Arbitrary 'SigInput' with a 'ScriptOutput' of type 'PayMulSig'.-arbitraryMSSigInput :: Network -> Gen (SigInput, [SecKeyI])-arbitraryMSSigInput net = do- (m, n) <- arbitraryMSParam- ks <- vectorOf n arbitraryKeyPair- let out = PayMulSig (map snd ks) m- (val, op, sh) <- arbitraryInputStuff net- perm <- choose (0, n - 1)- let ksPerm = map fst $ take m $ permutations ks !! perm- return (SigInput out val op sh Nothing, ksPerm)---- | Arbitrary 'SigInput' with 'ScriptOutput' of type 'PaySH' and a--- 'RedeemScript'.-arbitrarySHSigInput :: Network -> Gen (SigInput, [SecKeyI])-arbitrarySHSigInput net = do- (SigInput rdm val op sh _, ks) <- oneof- [ wrapKey <$> arbitraryPKSigInput net- , wrapKey <$> arbitraryPKHashSigInput net- , arbitraryMSSigInput net- ]- let out = PayScriptHash $ getAddrHash160 $ payToScriptAddress rdm- return (SigInput out val op sh $ Just rdm, ks)--arbitraryWPKHSigInput :: Network -> Gen (SigInput, SecKeyI)-arbitraryWPKHSigInput net = do- (k, p) <- arbitraryKeyPair- (val, op, sh) <- arbitraryInputStuff net- let out = PayWitnessPKHash . getAddrHash160 $ pubKeyAddr p- return (SigInput out val op sh Nothing, k)--arbitraryWSHSigInput :: Network -> Gen (SigInput, [SecKeyI])-arbitraryWSHSigInput net = do- (SigInput rdm val op sh _, ks) <- oneof- [ wrapKey <$> arbitraryPKSigInput net- , wrapKey <$> arbitraryPKHashSigInput net- , arbitraryMSSigInput net- ]- let out = PayWitnessScriptHash . getAddrHash256 $ payToWitnessScriptAddress rdm- return (SigInput out val op sh $ Just rdm, ks)---- | Arbitrary 'Tx' (empty 'TxIn'), 'SigInputs' and private keys that can be--- passed to 'signTx' or 'detSignTx' to fully sign the 'Tx'.-arbitrarySigningData :: Network -> Gen (Tx, [SigInput], [SecKeyI])-arbitrarySigningData net = do- v <- arbitrary- ni <- choose (1, 5)- no <- choose (1, 5)- sigis <- vectorOf ni (arbitrarySigInput net)- let uSigis = nubBy (\(a, _) (b, _) -> sigInputOP a == sigInputOP b) sigis- inps <- forM uSigis $ \(s, _) -> TxIn (sigInputOP s) BS.empty <$> arbitrary- outs <- vectorOf no (arbitraryTxOut net)- l <- arbitrary- perm <- choose (0, length inps - 1)- let tx = Tx v (permutations inps !! perm) outs [] l- keys = concatMap snd uSigis- return (tx, map fst uSigis, keys)---- | Arbitrary transaction with empty inputs.-arbitraryEmptyTx :: Network -> Gen Tx-arbitraryEmptyTx net = do- v <- arbitrary- no <- choose (1,5)- ni <- choose (1,5)- outs <- vectorOf no (arbitraryTxOut net)- ops <- vectorOf ni arbitraryOutPoint- t <- arbitrary- s <- arbitrary- return $ Tx v (map (\op -> TxIn op BS.empty s) (nub ops)) outs [] t---- | Arbitrary partially-signed transactions.-arbitraryPartialTxs ::- Network -> Gen ([Tx], [(ScriptOutput, Word64, OutPoint, Int, Int)])-arbitraryPartialTxs net = do- tx <- arbitraryEmptyTx net- res <-- forM (map prevOutput $ txIn tx) $ \op -> do- (so, val, rdmM, prvs, m, n) <- arbitraryData- txs <- mapM (singleSig so val rdmM tx op . secKeyData) prvs- return (txs, (so, val, op, m, n))- return (concatMap fst res, map snd res)- where- singleSig so val rdmM tx op prv = do- sh <- arbitraryValidSigHash net- let sigi = SigInput so val op sh rdmM- return . fromRight (error "Could not decode transaction") $- signTx net tx [sigi] [prv]- arbitraryData = do- (m, n) <- arbitraryMSParam- val <- getTestCoin <$> arbitrarySatoshi net- nPrv <- choose (m, n)- keys <- vectorOf n arbitraryKeyPair- perm <- choose (0, length keys - 1)- let pubKeys = map snd keys- prvKeys = take nPrv $ permutations (map fst keys) !! perm- let so = PayMulSig pubKeys m- elements- [ (so, val, Nothing, prvKeys, m, n)- , ( PayScriptHash $ getAddrHash160 $ payToScriptAddress so- , val- , Just so- , prvKeys- , m- , n)- ]--wrapKey :: (SigInput, SecKeyI) -> (SigInput, [SecKeyI])-wrapKey (s, k) = (s, [k])
− test/Haskoin/Test/Util.hs
@@ -1,40 +0,0 @@-{-|-Module : Haskoin.Test.Util-Copyright : No rights reserved-License : UNLICENSE-Maintainer : jprupp@protonmail.ch-Stability : experimental-Portability : POSIX--}-module Haskoin.Test.Util where--import Data.ByteString (ByteString, pack)-import Data.Time.Clock (UTCTime (..))-import Data.Time.Clock.POSIX (posixSecondsToUTCTime)-import Data.Word (Word32)-import Test.QuickCheck---- | Arbitrary strict 'ByteString'.-arbitraryBS :: Gen ByteString-arbitraryBS = pack <$> arbitrary---- | Arbitrary non-empty strict ByteString-arbitraryBS1 :: Gen ByteString-arbitraryBS1 = pack <$> listOf1 arbitrary---- | Arbitrary strict ByteString of a given length-arbitraryBSn :: Int -> Gen ByteString-arbitraryBSn n = pack <$> vectorOf n arbitrary---- | Arbitrary UTCTime that generates dates after 01 Jan 1970 01:00:00 CET-arbitraryUTCTime :: Gen UTCTime-arbitraryUTCTime = do- w <- arbitrary :: Gen Word32- return $ posixSecondsToUTCTime $ realToFrac w---- | Generate a Maybe from a Gen a-arbitraryMaybe :: Gen a -> Gen (Maybe a)-arbitraryMaybe g = frequency [ (1, return Nothing)- , (5, Just <$> g)- ]-
test/Haskoin/Transaction/PartialSpec.hs view
@@ -19,10 +19,10 @@ import Haskoin.Crypto import Haskoin.Keys import Haskoin.Script-import Haskoin.Test import Haskoin.Transaction import Haskoin.Transaction.Partial import Haskoin.Util+import Haskoin.Util.Arbitrary spec :: Spec spec = describe "partially signed bitcoin transaction unit tests" $ do
test/Haskoin/TransactionSpec.hs view
@@ -14,10 +14,10 @@ import Haskoin.Constants import Haskoin.Keys import Haskoin.Script-import Haskoin.Test import Haskoin.Transaction import Haskoin.Transaction.Segwit (isSegwit) import Haskoin.Util+import Haskoin.Util.Arbitrary import Haskoin.UtilSpec (cerealID, testJsonID) import Safe (readMay) import Test.Hspec
test/Haskoin/UtilSpec.hs view
@@ -7,20 +7,20 @@ , customCerealID ) where -import Data.Aeson (FromJSON, ToJSON)-import qualified Data.Aeson as A-import Data.Aeson.Encoding (encodingToLazyByteString)-import Data.Aeson.Types (Parser, parseMaybe)-import qualified Data.ByteString as BS-import Data.Either (fromLeft, fromRight, isLeft, isRight)-import Data.Foldable (toList)-import Data.List (permutations)-import Data.Map.Strict (singleton)+import Data.Aeson (FromJSON, ToJSON)+import qualified Data.Aeson as A+import Data.Aeson.Encoding (encodingToLazyByteString)+import Data.Aeson.Types (Parser, parseMaybe)+import qualified Data.ByteString as BS+import Data.Either (fromLeft, fromRight, isLeft, isRight)+import Data.Foldable (toList)+import Data.List (permutations)+import Data.Map.Strict (singleton) import Data.Maybe-import qualified Data.Sequence as Seq-import Data.Serialize as S-import Haskoin.Test+import qualified Data.Sequence as Seq+import Data.Serialize as S import Haskoin.Util+import Haskoin.Util.Arbitrary import Test.Hspec import Test.QuickCheck