{- |
Module      : Haskoin.Test.Transaction
Copyright   : No rights reserved
License     : MIT
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.Data
import Haskoin.Keys.Common
import Haskoin.Script
import Haskoin.Transaction
import Haskoin.Util.Arbitrary.Crypto
import Haskoin.Util.Arbitrary.Keys
import Haskoin.Util.Arbitrary.Script
import Haskoin.Util.Arbitrary.Util
import Test.QuickCheck

-- | Wrapped coin value for testing.
newtype TestCoin = TestCoin {TestCoin -> Word64
getTestCoin :: Word64}
    deriving (TestCoin -> TestCoin -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: TestCoin -> TestCoin -> Bool
$c/= :: TestCoin -> TestCoin -> Bool
== :: TestCoin -> TestCoin -> Bool
$c== :: TestCoin -> TestCoin -> Bool
Eq, Int -> TestCoin -> ShowS
[TestCoin] -> ShowS
TestCoin -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TestCoin] -> ShowS
$cshowList :: [TestCoin] -> ShowS
show :: TestCoin -> String
$cshow :: TestCoin -> String
showsPrec :: Int -> TestCoin -> ShowS
$cshowsPrec :: Int -> TestCoin -> ShowS
Show)

instance Coin TestCoin where
    coinValue :: TestCoin -> Word64
coinValue = TestCoin -> Word64
getTestCoin

-- | Arbitrary transaction hash (for non-existent transaction).
arbitraryTxHash :: Gen TxHash
arbitraryTxHash :: Gen TxHash
arbitraryTxHash = Hash256 -> TxHash
TxHash forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Hash256
arbitraryHash256

-- | Arbitrary amount of Satoshi as 'Word64' (Between 1 and 21e14)
arbitrarySatoshi :: Network -> Gen TestCoin
arbitrarySatoshi :: Network -> Gen TestCoin
arbitrarySatoshi Network
net = Word64 -> TestCoin
TestCoin forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Random a => (a, a) -> Gen a
choose (Word64
1, Network -> Word64
getMaxSatoshi Network
net)

-- | Arbitrary 'OutPoint'.
arbitraryOutPoint :: Gen OutPoint
arbitraryOutPoint :: Gen OutPoint
arbitraryOutPoint = TxHash -> Word32 -> OutPoint
OutPoint forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen TxHash
arbitraryTxHash forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall a. Arbitrary a => Gen a
arbitrary

-- | Arbitrary 'TxOut'.
arbitraryTxOut :: Network -> Gen TxOut
arbitraryTxOut :: Network -> Gen TxOut
arbitraryTxOut Network
net =
    Word64 -> ByteString -> TxOut
TxOut forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (TestCoin -> Word64
getTestCoin forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Network -> Gen TestCoin
arbitrarySatoshi Network
net)
        forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (ScriptOutput -> ByteString
encodeOutputBS forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Network -> Gen ScriptOutput
arbitraryScriptOutput Network
net)

-- | Arbitrary 'TxIn'.
arbitraryTxIn :: Network -> Gen TxIn
arbitraryTxIn :: Network -> Gen TxIn
arbitraryTxIn Network
net =
    OutPoint -> ByteString -> Word32 -> TxIn
TxIn forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen OutPoint
arbitraryOutPoint
        forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (ScriptInput -> ByteString
encodeInputBS forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Network -> Gen ScriptInput
arbitraryScriptInput Network
net)
        forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall a. Arbitrary a => Gen a
arbitrary

-- | Arbitrary transaction. Can be regular or with witnesses.
arbitraryTx :: Network -> Gen Tx
arbitraryTx :: Network -> Gen Tx
arbitraryTx Network
net = forall a. [Gen a] -> Gen a
oneof [Network -> Gen Tx
arbitraryLegacyTx Network
net, Network -> Gen Tx
arbitraryWitnessTx Network
net]

-- | Arbitrary regular transaction.
arbitraryLegacyTx :: Network -> Gen Tx
arbitraryLegacyTx :: Network -> Gen Tx
arbitraryLegacyTx Network
net = Network -> Bool -> Gen Tx
arbitraryWLTx Network
net Bool
False

-- | Arbitrary witness transaction (witness data is fake).
arbitraryWitnessTx :: Network -> Gen Tx
arbitraryWitnessTx :: Network -> Gen Tx
arbitraryWitnessTx Network
net = Network -> Bool -> Gen Tx
arbitraryWLTx Network
net Bool
True

-- | Arbitrary witness or legacy transaction.
arbitraryWLTx :: Network -> Bool -> Gen Tx
arbitraryWLTx :: Network -> Bool -> Gen Tx
arbitraryWLTx Network
net Bool
wit = do
    Int
ni <- forall a. Random a => (a, a) -> Gen a
choose (Int
1, Int
5)
    Int
no <- forall a. Random a => (a, a) -> Gen a
choose (Int
1, Int
5)
    [TxIn]
inps <- forall a. Int -> Gen a -> Gen [a]
vectorOf Int
ni (Network -> Gen TxIn
arbitraryTxIn Network
net)
    [TxOut]
outs <- forall a. Int -> Gen a -> Gen [a]
vectorOf Int
no (Network -> Gen TxOut
arbitraryTxOut Network
net)
    let uniqueInps :: [TxIn]
uniqueInps = forall a. (a -> a -> Bool) -> [a] -> [a]
nubBy (\TxIn
a TxIn
b -> TxIn -> OutPoint
prevOutput TxIn
a forall a. Eq a => a -> a -> Bool
== TxIn -> OutPoint
prevOutput TxIn
b) [TxIn]
inps
    [[ByteString]]
w <-
        if Bool
wit
            then forall a. Int -> Gen a -> Gen [a]
vectorOf (forall (t :: * -> *) a. Foldable t => t a -> Int
length [TxIn]
uniqueInps) (forall a. Gen a -> Gen [a]
listOf Gen ByteString
arbitraryBS)
            else forall (m :: * -> *) a. Monad m => a -> m a
return []
    Word32 -> [TxIn] -> [TxOut] -> [[ByteString]] -> Word32 -> Tx
Tx forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Arbitrary a => Gen a
arbitrary forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (f :: * -> *) a. Applicative f => a -> f a
pure [TxIn]
uniqueInps forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (f :: * -> *) a. Applicative f => a -> f a
pure [TxOut]
outs forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (f :: * -> *) a. Applicative f => a -> f a
pure [[ByteString]]
w forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall a. Arbitrary a => Gen a
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 :: Network -> Gen Tx
arbitraryAddrOnlyTx Network
net = do
    Int
ni <- forall a. Random a => (a, a) -> Gen a
choose (Int
1, Int
5)
    Int
no <- forall a. Random a => (a, a) -> Gen a
choose (Int
1, Int
5)
    [TxIn]
inps <- forall a. Int -> Gen a -> Gen [a]
vectorOf Int
ni (Network -> Gen TxIn
arbitraryAddrOnlyTxIn Network
net)
    [TxOut]
outs <- forall a. Int -> Gen a -> Gen [a]
vectorOf Int
no (Network -> Gen TxOut
arbitraryAddrOnlyTxOut Network
net)
    Word32 -> [TxIn] -> [TxOut] -> [[ByteString]] -> Word32 -> Tx
Tx forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Arbitrary a => Gen a
arbitrary forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (f :: * -> *) a. Applicative f => a -> f a
pure [TxIn]
inps forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (f :: * -> *) a. Applicative f => a -> f a
pure [TxOut]
outs forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (f :: * -> *) a. Applicative f => a -> f a
pure [] forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall a. Arbitrary a => Gen a
arbitrary

-- | Like 'arbitraryAddrOnlyTx' without empty signatures in the inputs.
arbitraryAddrOnlyTxFull :: Network -> Gen Tx
arbitraryAddrOnlyTxFull :: Network -> Gen Tx
arbitraryAddrOnlyTxFull Network
net = do
    Int
ni <- forall a. Random a => (a, a) -> Gen a
choose (Int
1, Int
5)
    Int
no <- forall a. Random a => (a, a) -> Gen a
choose (Int
1, Int
5)
    [TxIn]
inps <- forall a. Int -> Gen a -> Gen [a]
vectorOf Int
ni (Network -> Gen TxIn
arbitraryAddrOnlyTxInFull Network
net)
    [TxOut]
outs <- forall a. Int -> Gen a -> Gen [a]
vectorOf Int
no (Network -> Gen TxOut
arbitraryAddrOnlyTxOut Network
net)
    Word32 -> [TxIn] -> [TxOut] -> [[ByteString]] -> Word32 -> Tx
Tx forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Arbitrary a => Gen a
arbitrary forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (f :: * -> *) a. Applicative f => a -> f a
pure [TxIn]
inps forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (f :: * -> *) a. Applicative f => a -> f a
pure [TxOut]
outs forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (f :: * -> *) a. Applicative f => a -> f a
pure [] forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall a. Arbitrary a => Gen a
arbitrary

{- | Arbitrary TxIn that can only be of type 'SpendPKHash' or 'SpendScriptHash'
 (multisig). Only compressed public keys are used.
-}
arbitraryAddrOnlyTxIn :: Network -> Gen TxIn
arbitraryAddrOnlyTxIn :: Network -> Gen TxIn
arbitraryAddrOnlyTxIn Network
net = do
    ScriptInput
inp <- forall a. [Gen a] -> Gen a
oneof [Network -> Gen ScriptInput
arbitraryPKHashInput Network
net, Network -> Gen ScriptInput
arbitraryMulSigSHInput Network
net]
    OutPoint -> ByteString -> Word32 -> TxIn
TxIn forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen OutPoint
arbitraryOutPoint forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (f :: * -> *) a. Applicative f => a -> f a
pure (ScriptInput -> ByteString
encodeInputBS ScriptInput
inp) forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall a. Arbitrary a => Gen a
arbitrary

-- | like 'arbitraryAddrOnlyTxIn' with no empty signatures.
arbitraryAddrOnlyTxInFull :: Network -> Gen TxIn
arbitraryAddrOnlyTxInFull :: Network -> Gen TxIn
arbitraryAddrOnlyTxInFull Network
net = do
    ScriptInput
inp <-
        forall a. [Gen a] -> Gen a
oneof [Network -> Gen ScriptInput
arbitraryPKHashInputFullC Network
net, Network -> Gen ScriptInput
arbitraryMulSigSHInputFullC Network
net]
    OutPoint -> ByteString -> Word32 -> TxIn
TxIn forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen OutPoint
arbitraryOutPoint forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (f :: * -> *) a. Applicative f => a -> f a
pure (ScriptInput -> ByteString
encodeInputBS ScriptInput
inp) forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall a. Arbitrary a => Gen a
arbitrary

-- | Arbitrary 'TxOut' that can only be of type 'PayPKHash' or 'PaySH'.
arbitraryAddrOnlyTxOut :: Network -> Gen TxOut
arbitraryAddrOnlyTxOut :: Network -> Gen TxOut
arbitraryAddrOnlyTxOut Network
net = do
    Word64
v <- TestCoin -> Word64
getTestCoin forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Network -> Gen TestCoin
arbitrarySatoshi Network
net
    ScriptOutput
out <- forall a. [Gen a] -> Gen a
oneof [Gen ScriptOutput
arbitraryPKHashOutput, Gen ScriptOutput
arbitrarySHOutput]
    forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Word64 -> ByteString -> TxOut
TxOut Word64
v forall a b. (a -> b) -> a -> b
$ ScriptOutput -> ByteString
encodeOutputBS ScriptOutput
out

{- | Arbitrary 'SigInput' with the corresponding private keys used
 to generate the 'ScriptOutput' or 'RedeemScript'.
-}
arbitrarySigInput :: Network -> Gen (SigInput, [SecKeyI])
arbitrarySigInput :: Network -> Gen (SigInput, [SecKeyI])
arbitrarySigInput Network
net =
    forall a. [Gen a] -> Gen a
oneof
        [ (SigInput, SecKeyI) -> (SigInput, [SecKeyI])
wrapKey forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Network -> Gen (SigInput, SecKeyI)
arbitraryPKSigInput Network
net
        , (SigInput, SecKeyI) -> (SigInput, [SecKeyI])
wrapKey forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Network -> Gen (SigInput, SecKeyI)
arbitraryPKHashSigInput Network
net
        , Network -> Gen (SigInput, [SecKeyI])
arbitraryMSSigInput Network
net
        , Network -> Gen (SigInput, [SecKeyI])
arbitrarySHSigInput Network
net
        , (SigInput, SecKeyI) -> (SigInput, [SecKeyI])
wrapKey forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Network -> Gen (SigInput, SecKeyI)
arbitraryWPKHSigInput Network
net
        , Network -> Gen (SigInput, [SecKeyI])
arbitraryWSHSigInput Network
net
        ]

-- | Arbitrary 'SigInput' with a 'ScriptOutput' of type 'PayPK'.
arbitraryPKSigInput :: Network -> Gen (SigInput, SecKeyI)
arbitraryPKSigInput :: Network -> Gen (SigInput, SecKeyI)
arbitraryPKSigInput Network
net = Network -> Bool -> Gen (SigInput, SecKeyI)
arbitraryAnyInput Network
net Bool
False

-- | Arbitrary 'SigInput' with a 'ScriptOutput' of type 'PayPKHash'.
arbitraryPKHashSigInput :: Network -> Gen (SigInput, SecKeyI)
arbitraryPKHashSigInput :: Network -> Gen (SigInput, SecKeyI)
arbitraryPKHashSigInput Network
net = Network -> Bool -> Gen (SigInput, SecKeyI)
arbitraryAnyInput Network
net Bool
True

-- | Arbitrary 'SigInput'.
arbitraryAnyInput :: Network -> Bool -> Gen (SigInput, SecKeyI)
arbitraryAnyInput :: Network -> Bool -> Gen (SigInput, SecKeyI)
arbitraryAnyInput Network
net Bool
pkh = do
    (SecKeyI
k, PubKeyI
p) <- Gen (SecKeyI, PubKeyI)
arbitraryKeyPair
    let out :: ScriptOutput
out
            | Bool
pkh = Hash160 -> ScriptOutput
PayPKHash forall a b. (a -> b) -> a -> b
$ Address -> Hash160
getAddrHash160 forall a b. (a -> b) -> a -> b
$ PubKeyI -> Address
pubKeyAddr PubKeyI
p
            | Bool
otherwise = PubKeyI -> ScriptOutput
PayPK PubKeyI
p
    (Word64
val, OutPoint
op, SigHash
sh) <- Network -> Gen (Word64, OutPoint, SigHash)
arbitraryInputStuff Network
net
    forall (m :: * -> *) a. Monad m => a -> m a
return (ScriptOutput
-> Word64 -> OutPoint -> SigHash -> Maybe ScriptOutput -> SigInput
SigInput ScriptOutput
out Word64
val OutPoint
op SigHash
sh forall a. Maybe a
Nothing, SecKeyI
k)

-- | Arbitrary value, out point and sighash for an input.
arbitraryInputStuff :: Network -> Gen (Word64, OutPoint, SigHash)
arbitraryInputStuff :: Network -> Gen (Word64, OutPoint, SigHash)
arbitraryInputStuff Network
net = do
    Word64
val <- TestCoin -> Word64
getTestCoin forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Network -> Gen TestCoin
arbitrarySatoshi Network
net
    OutPoint
op <- Gen OutPoint
arbitraryOutPoint
    SigHash
sh <- Network -> Gen SigHash
arbitraryValidSigHash Network
net
    forall (m :: * -> *) a. Monad m => a -> m a
return (Word64
val, OutPoint
op, SigHash
sh)

-- | Arbitrary 'SigInput' with a 'ScriptOutput' of type 'PayMulSig'.
arbitraryMSSigInput :: Network -> Gen (SigInput, [SecKeyI])
arbitraryMSSigInput :: Network -> Gen (SigInput, [SecKeyI])
arbitraryMSSigInput Network
net = do
    (Int
m, Int
n) <- Gen (Int, Int)
arbitraryMSParam
    [(SecKeyI, PubKeyI)]
ks <- forall a. Int -> Gen a -> Gen [a]
vectorOf Int
n Gen (SecKeyI, PubKeyI)
arbitraryKeyPair
    let out :: ScriptOutput
out = [PubKeyI] -> Int -> ScriptOutput
PayMulSig (forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd [(SecKeyI, PubKeyI)]
ks) Int
m
    (Word64
val, OutPoint
op, SigHash
sh) <- Network -> Gen (Word64, OutPoint, SigHash)
arbitraryInputStuff Network
net
    Int
perm <- forall a. Random a => (a, a) -> Gen a
choose (Int
0, Int
n forall a. Num a => a -> a -> a
- Int
1)
    let ksPerm :: [SecKeyI]
ksPerm = forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> a
fst forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> [a]
take Int
m forall a b. (a -> b) -> a -> b
$ forall a. [a] -> [[a]]
permutations [(SecKeyI, PubKeyI)]
ks forall a. [a] -> Int -> a
!! Int
perm
    forall (m :: * -> *) a. Monad m => a -> m a
return (ScriptOutput
-> Word64 -> OutPoint -> SigHash -> Maybe ScriptOutput -> SigInput
SigInput ScriptOutput
out Word64
val OutPoint
op SigHash
sh forall a. Maybe a
Nothing, [SecKeyI]
ksPerm)

{- | Arbitrary 'SigInput' with 'ScriptOutput' of type 'PaySH' and a
 'RedeemScript'.
-}
arbitrarySHSigInput :: Network -> Gen (SigInput, [SecKeyI])
arbitrarySHSigInput :: Network -> Gen (SigInput, [SecKeyI])
arbitrarySHSigInput Network
net = do
    (SigInput ScriptOutput
rdm Word64
val OutPoint
op SigHash
sh Maybe ScriptOutput
_, [SecKeyI]
ks) <-
        forall a. [Gen a] -> Gen a
oneof
            [ (SigInput, SecKeyI) -> (SigInput, [SecKeyI])
wrapKey forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Network -> Gen (SigInput, SecKeyI)
arbitraryPKSigInput Network
net
            , (SigInput, SecKeyI) -> (SigInput, [SecKeyI])
wrapKey forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Network -> Gen (SigInput, SecKeyI)
arbitraryPKHashSigInput Network
net
            , Network -> Gen (SigInput, [SecKeyI])
arbitraryMSSigInput Network
net
            ]
    let out :: ScriptOutput
out = Hash160 -> ScriptOutput
PayScriptHash forall a b. (a -> b) -> a -> b
$ Address -> Hash160
getAddrHash160 forall a b. (a -> b) -> a -> b
$ ScriptOutput -> Address
payToScriptAddress ScriptOutput
rdm
    forall (m :: * -> *) a. Monad m => a -> m a
return (ScriptOutput
-> Word64 -> OutPoint -> SigHash -> Maybe ScriptOutput -> SigInput
SigInput ScriptOutput
out Word64
val OutPoint
op SigHash
sh forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a
Just ScriptOutput
rdm, [SecKeyI]
ks)

arbitraryWPKHSigInput :: Network -> Gen (SigInput, SecKeyI)
arbitraryWPKHSigInput :: Network -> Gen (SigInput, SecKeyI)
arbitraryWPKHSigInput Network
net = do
    (SecKeyI
k, PubKeyI
p) <- Gen (SecKeyI, PubKeyI)
arbitraryKeyPair
    (Word64
val, OutPoint
op, SigHash
sh) <- Network -> Gen (Word64, OutPoint, SigHash)
arbitraryInputStuff Network
net
    let out :: ScriptOutput
out = Hash160 -> ScriptOutput
PayWitnessPKHash forall b c a. (b -> c) -> (a -> b) -> a -> c
. Address -> Hash160
getAddrHash160 forall a b. (a -> b) -> a -> b
$ PubKeyI -> Address
pubKeyAddr PubKeyI
p
    forall (m :: * -> *) a. Monad m => a -> m a
return (ScriptOutput
-> Word64 -> OutPoint -> SigHash -> Maybe ScriptOutput -> SigInput
SigInput ScriptOutput
out Word64
val OutPoint
op SigHash
sh forall a. Maybe a
Nothing, SecKeyI
k)

arbitraryWSHSigInput :: Network -> Gen (SigInput, [SecKeyI])
arbitraryWSHSigInput :: Network -> Gen (SigInput, [SecKeyI])
arbitraryWSHSigInput Network
net = do
    (SigInput ScriptOutput
rdm Word64
val OutPoint
op SigHash
sh Maybe ScriptOutput
_, [SecKeyI]
ks) <-
        forall a. [Gen a] -> Gen a
oneof
            [ (SigInput, SecKeyI) -> (SigInput, [SecKeyI])
wrapKey forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Network -> Gen (SigInput, SecKeyI)
arbitraryPKSigInput Network
net
            , (SigInput, SecKeyI) -> (SigInput, [SecKeyI])
wrapKey forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Network -> Gen (SigInput, SecKeyI)
arbitraryPKHashSigInput Network
net
            , Network -> Gen (SigInput, [SecKeyI])
arbitraryMSSigInput Network
net
            ]
    let out :: ScriptOutput
out = Hash256 -> ScriptOutput
PayWitnessScriptHash forall b c a. (b -> c) -> (a -> b) -> a -> c
. Address -> Hash256
getAddrHash256 forall a b. (a -> b) -> a -> b
$ ScriptOutput -> Address
payToWitnessScriptAddress ScriptOutput
rdm
    forall (m :: * -> *) a. Monad m => a -> m a
return (ScriptOutput
-> Word64 -> OutPoint -> SigHash -> Maybe ScriptOutput -> SigInput
SigInput ScriptOutput
out Word64
val OutPoint
op SigHash
sh forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a
Just ScriptOutput
rdm, [SecKeyI]
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 :: Network -> Gen (Tx, [SigInput], [SecKeyI])
arbitrarySigningData Network
net = do
    Word32
v <- forall a. Arbitrary a => Gen a
arbitrary
    Int
ni <- forall a. Random a => (a, a) -> Gen a
choose (Int
1, Int
5)
    Int
no <- forall a. Random a => (a, a) -> Gen a
choose (Int
1, Int
5)
    [(SigInput, [SecKeyI])]
sigis <- forall a. Int -> Gen a -> Gen [a]
vectorOf Int
ni (Network -> Gen (SigInput, [SecKeyI])
arbitrarySigInput Network
net)
    let uSigis :: [(SigInput, [SecKeyI])]
uSigis = forall a. (a -> a -> Bool) -> [a] -> [a]
nubBy (\(SigInput
a, [SecKeyI]
_) (SigInput
b, [SecKeyI]
_) -> SigInput -> OutPoint
sigInputOP SigInput
a forall a. Eq a => a -> a -> Bool
== SigInput -> OutPoint
sigInputOP SigInput
b) [(SigInput, [SecKeyI])]
sigis
    [TxIn]
inps <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [(SigInput, [SecKeyI])]
uSigis forall a b. (a -> b) -> a -> b
$ \(SigInput
s, [SecKeyI]
_) -> OutPoint -> ByteString -> Word32 -> TxIn
TxIn (SigInput -> OutPoint
sigInputOP SigInput
s) ByteString
BS.empty forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Arbitrary a => Gen a
arbitrary
    [TxOut]
outs <- forall a. Int -> Gen a -> Gen [a]
vectorOf Int
no (Network -> Gen TxOut
arbitraryTxOut Network
net)
    Word32
l <- forall a. Arbitrary a => Gen a
arbitrary
    Int
perm <- forall a. Random a => (a, a) -> Gen a
choose (Int
0, forall (t :: * -> *) a. Foldable t => t a -> Int
length [TxIn]
inps forall a. Num a => a -> a -> a
- Int
1)
    let tx :: Tx
tx = Word32 -> [TxIn] -> [TxOut] -> [[ByteString]] -> Word32 -> Tx
Tx Word32
v (forall a. [a] -> [[a]]
permutations [TxIn]
inps forall a. [a] -> Int -> a
!! Int
perm) [TxOut]
outs [] Word32
l
        keys :: [SecKeyI]
keys = forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap forall a b. (a, b) -> b
snd [(SigInput, [SecKeyI])]
uSigis
    forall (m :: * -> *) a. Monad m => a -> m a
return (Tx
tx, forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> a
fst [(SigInput, [SecKeyI])]
uSigis, [SecKeyI]
keys)

-- | Arbitrary transaction with empty inputs.
arbitraryEmptyTx :: Network -> Gen Tx
arbitraryEmptyTx :: Network -> Gen Tx
arbitraryEmptyTx Network
net = do
    Word32
v <- forall a. Arbitrary a => Gen a
arbitrary
    Int
no <- forall a. Random a => (a, a) -> Gen a
choose (Int
1, Int
5)
    Int
ni <- forall a. Random a => (a, a) -> Gen a
choose (Int
1, Int
5)
    [TxOut]
outs <- forall a. Int -> Gen a -> Gen [a]
vectorOf Int
no (Network -> Gen TxOut
arbitraryTxOut Network
net)
    [OutPoint]
ops <- forall a. Int -> Gen a -> Gen [a]
vectorOf Int
ni Gen OutPoint
arbitraryOutPoint
    Word32
t <- forall a. Arbitrary a => Gen a
arbitrary
    Word32
s <- forall a. Arbitrary a => Gen a
arbitrary
    forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Word32 -> [TxIn] -> [TxOut] -> [[ByteString]] -> Word32 -> Tx
Tx Word32
v (forall a b. (a -> b) -> [a] -> [b]
map (\OutPoint
op -> OutPoint -> ByteString -> Word32 -> TxIn
TxIn OutPoint
op ByteString
BS.empty Word32
s) (forall a. Eq a => [a] -> [a]
nub [OutPoint]
ops)) [TxOut]
outs [] Word32
t

-- | Arbitrary partially-signed transactions.
arbitraryPartialTxs ::
    Network -> Gen ([Tx], [(ScriptOutput, Word64, OutPoint, Int, Int)])
arbitraryPartialTxs :: Network -> Gen ([Tx], [(ScriptOutput, Word64, OutPoint, Int, Int)])
arbitraryPartialTxs Network
net = do
    Tx
tx <- Network -> Gen Tx
arbitraryEmptyTx Network
net
    [([Tx], (ScriptOutput, Word64, OutPoint, Int, Int))]
res <-
        forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM (forall a b. (a -> b) -> [a] -> [b]
map TxIn -> OutPoint
prevOutput forall a b. (a -> b) -> a -> b
$ Tx -> [TxIn]
txIn Tx
tx) forall a b. (a -> b) -> a -> b
$ \OutPoint
op -> do
            (ScriptOutput
so, Word64
val, Maybe ScriptOutput
rdmM, [SecKeyI]
prvs, Int
m, Int
n) <- Gen (ScriptOutput, Word64, Maybe ScriptOutput, [SecKeyI], Int, Int)
arbitraryData
            [Tx]
txs <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (ScriptOutput
-> Word64
-> Maybe ScriptOutput
-> Tx
-> OutPoint
-> SecKey
-> Gen Tx
singleSig ScriptOutput
so Word64
val Maybe ScriptOutput
rdmM Tx
tx OutPoint
op forall b c a. (b -> c) -> (a -> b) -> a -> c
. SecKeyI -> SecKey
secKeyData) [SecKeyI]
prvs
            forall (m :: * -> *) a. Monad m => a -> m a
return ([Tx]
txs, (ScriptOutput
so, Word64
val, OutPoint
op, Int
m, Int
n))
    forall (m :: * -> *) a. Monad m => a -> m a
return (forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap forall a b. (a, b) -> a
fst [([Tx], (ScriptOutput, Word64, OutPoint, Int, Int))]
res, forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd [([Tx], (ScriptOutput, Word64, OutPoint, Int, Int))]
res)
  where
    singleSig :: ScriptOutput
-> Word64
-> Maybe ScriptOutput
-> Tx
-> OutPoint
-> SecKey
-> Gen Tx
singleSig ScriptOutput
so Word64
val Maybe ScriptOutput
rdmM Tx
tx OutPoint
op SecKey
prv = do
        SigHash
sh <- Network -> Gen SigHash
arbitraryValidSigHash Network
net
        let sigi :: SigInput
sigi = ScriptOutput
-> Word64 -> OutPoint -> SigHash -> Maybe ScriptOutput -> SigInput
SigInput ScriptOutput
so Word64
val OutPoint
op SigHash
sh Maybe ScriptOutput
rdmM
        forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b a. b -> Either a b -> b
fromRight (forall a. HasCallStack => String -> a
error String
"Could not decode transaction") forall a b. (a -> b) -> a -> b
$
            Network -> Tx -> [SigInput] -> [SecKey] -> Either String Tx
signTx Network
net Tx
tx [SigInput
sigi] [SecKey
prv]
    arbitraryData :: Gen (ScriptOutput, Word64, Maybe ScriptOutput, [SecKeyI], Int, Int)
arbitraryData = do
        (Int
m, Int
n) <- Gen (Int, Int)
arbitraryMSParam
        Word64
val <- TestCoin -> Word64
getTestCoin forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Network -> Gen TestCoin
arbitrarySatoshi Network
net
        Int
nPrv <- forall a. Random a => (a, a) -> Gen a
choose (Int
m, Int
n)
        [(SecKeyI, PubKeyI)]
keys <- forall a. Int -> Gen a -> Gen [a]
vectorOf Int
n Gen (SecKeyI, PubKeyI)
arbitraryKeyPair
        Int
perm <- forall a. Random a => (a, a) -> Gen a
choose (Int
0, forall (t :: * -> *) a. Foldable t => t a -> Int
length [(SecKeyI, PubKeyI)]
keys forall a. Num a => a -> a -> a
- Int
1)
        let pubKeys :: [PubKeyI]
pubKeys = forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd [(SecKeyI, PubKeyI)]
keys
            prvKeys :: [SecKeyI]
prvKeys = forall a. Int -> [a] -> [a]
take Int
nPrv forall a b. (a -> b) -> a -> b
$ forall a. [a] -> [[a]]
permutations (forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> a
fst [(SecKeyI, PubKeyI)]
keys) forall a. [a] -> Int -> a
!! Int
perm
        let so :: ScriptOutput
so = [PubKeyI] -> Int -> ScriptOutput
PayMulSig [PubKeyI]
pubKeys Int
m
        forall a. [a] -> Gen a
elements
            [ (ScriptOutput
so, Word64
val, forall a. Maybe a
Nothing, [SecKeyI]
prvKeys, Int
m, Int
n)
            ,
                ( Hash160 -> ScriptOutput
PayScriptHash forall a b. (a -> b) -> a -> b
$ Address -> Hash160
getAddrHash160 forall a b. (a -> b) -> a -> b
$ ScriptOutput -> Address
payToScriptAddress ScriptOutput
so
                , Word64
val
                , forall a. a -> Maybe a
Just ScriptOutput
so
                , [SecKeyI]
prvKeys
                , Int
m
                , Int
n
                )
            ]

wrapKey :: (SigInput, SecKeyI) -> (SigInput, [SecKeyI])
wrapKey :: (SigInput, SecKeyI) -> (SigInput, [SecKeyI])
wrapKey (SigInput
s, SecKeyI
k) = (SigInput
s, [SecKeyI
k])