haskoin-core-0.3.0: tests/Network/Haskoin/Transaction/Units.hs
{-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-}
module Network.Haskoin.Transaction.Units (tests, satoshiCoreTxTests) where
import Test.HUnit (Assertion, assertBool)
import Test.Framework (Test, testGroup)
import Test.Framework.Providers.HUnit (testCase)
import Data.Word (Word32, Word64)
import Data.Maybe (fromJust)
import Data.Binary.Get (getWord32le)
import Data.Binary.Put (putWord32le)
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS (reverse)
import qualified Data.ByteString.Lazy as LBS
import Safe (readMay)
import GHC.Exts( IsString(..) )
import qualified Data.Aeson as Aeson
import qualified Data.Aeson.Types as Aeson.Types
import qualified Data.Vector as V
import Data.String.Conversions (convertString)
import Data.List (groupBy)
import qualified Data.Either
import Network.Haskoin.Transaction
import Network.Haskoin.Script
import Network.Haskoin.Util
tests :: [Test]
tests =
[ testGroup "Computing TxID from Tx"
( map mapTxIDVec $ zip txIDVec [0..] )
, testGroup "Build PKHash Transaction (generated from bitcoind)"
( map mapPKHashVec $ zip pkHashVec [0..] )
, testGroup "Verify transaction (bitcoind /test/data/tx_valid.json)"
( map mapVerifyVec $ zip verifyVec [0..] )
, testCase "" tEncodeSatoshiCoreScriptPubKey
]
mapTxIDVec :: ((ByteString, ByteString), Int) -> Test.Framework.Test
mapTxIDVec (v,i) = testCase name $ runTxIDVec v
where
name = "Compute TxID " ++ (show i)
runTxIDVec :: (ByteString, ByteString) -> Assertion
runTxIDVec (tid,tx) = assertBool "TxID" $
(txHashToHex $ txHash txBS) == tid
where
txBS = decode' $ fromJust $ decodeHex tx
txIDVec :: [(ByteString, ByteString)]
txIDVec =
[ ( "23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"
, "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000"
)
, ( "c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73"
, "01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000"
)
, ( "f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb"
, "01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000"
)
, ( "afd9c17f8913577ec3509520bd6e5d63e9c0fd2a5f70c787993b097ba6ca9fae"
, "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000"
)
]
mapPKHashVec :: (([(ByteString, Word32)], [(ByteString, Word64)], ByteString), Int)
-> Test.Framework.Test
mapPKHashVec (v, i) = testCase name $ runPKHashVec v
where name = "Build PKHash Tx " ++ (show i)
runPKHashVec :: ([(ByteString, Word32)], [(ByteString, Word64)], ByteString) -> Assertion
runPKHashVec (xs, ys, res) =
assertBool "Build PKHash Tx" $ (encodeHex $ encode' tx) == res
where tx = fromRight $ buildAddrTx (map f xs) ys
f (tid,ix) = OutPoint (fromJust $ hexToTxHash tid) ix
mapVerifyVec :: (SatoshiCoreTxTest, Int)
-> Test.Framework.Test
mapVerifyVec (v, i) = testCase name $ runVerifyVec v i
where name = "Verify Tx " ++ (show i) ++ ", about: " ++ (satCoreTxTestDescription $ v)
runVerifyVec :: SatoshiCoreTxTest -> Int -> Assertion
runVerifyVec (SatoshiCoreTxTest description is bsTx) i =
assertBool name $ verifyStdTx tx outputsAndOutpoints
where
name = " > Verify transaction " ++ (show i) ++ "bsTx: " ++ convertString bsTx
tx :: Tx
tx = decode' . fromJust . decodeHex $ bsTx
outputsAndOutpoints :: [(ScriptOutput, OutPoint)]
outputsAndOutpoints = map f is
f (SatoshiCoreTxTestInput bsOutputHash bsOutputIndex bsOutputScriptPubKey) =
let s :: ScriptOutput
s = either (\e -> error $ "could not decode: " ++ convertString bsOutputScriptPubKey) id
. decodeOutputBS . fromJust . decodeHex $ bsOutputScriptPubKey
op :: OutPoint
op = OutPoint
(decode' . BS.reverse . fromJust . decodeHex $ bsOutputHash)
(runGet' getWord32le . fromJust . decodeHex $ bsOutputIndex)
in (s, op)
-- These test vectors have been generated from bitcoind raw transaction api
pkHashVec :: [([(ByteString, Word32)], [(ByteString, Word64)], ByteString)]
pkHashVec =
[
( [("eb29eba154166f6541ebcc9cbdf5088756e026af051f123bcfb526df594549db",14)]
, [("14LsRquZfURNFrzpcLVGdaHTfAPjjwiSPb",90000000)]
, "0100000001db494559df26b5cf3b121f05af26e0568708f5bd9ccceb41656f1654a1eb29eb0e00000000ffffffff01804a5d05000000001976a91424aa604689cc582292b97668bedd91dd5bf9374c88ac00000000"
)
, ( [ ("eb29eba154166f6541ebcc9cbdf5088756e026af051f123bcfb526df594549db",0)
, ("0001000000000000000000000000000000000000000000000000000000000000",2147483647)
]
, [ ("14LsRquZfURNFrzpcLVGdaHTfAPjjwiSPb",1)
, ("19VCgS642vzEA1sdByoSn6GsWBwraV8D4n",2100000000000000)
]
, "0100000002db494559df26b5cf3b121f05af26e0568708f5bd9ccceb41656f1654a1eb29eb0000000000ffffffff0000000000000000000000000000000000000000000000000000000000000100ffffff7f00ffffffff0201000000000000001976a91424aa604689cc582292b97668bedd91dd5bf9374c88ac0040075af07507001976a9145d16672f53981ff21c5f42b40d1954993cbca54f88ac00000000"
)
, ( [ ("eb29eba154166f6541ebcc9cbdf5088756e026af051f123bcfb526df594549db",0)
, ("0001000000000000000000000000000000000000000000000000000000000000",2147483647)
]
, []
, "0100000002db494559df26b5cf3b121f05af26e0568708f5bd9ccceb41656f1654a1eb29eb0000000000ffffffff0000000000000000000000000000000000000000000000000000000000000100ffffff7f00ffffffff0000000000"
)
, ( []
, [ ("14LsRquZfURNFrzpcLVGdaHTfAPjjwiSPb",1)
, ("19VCgS642vzEA1sdByoSn6GsWBwraV8D4n",2100000000000000)
]
, "01000000000201000000000000001976a91424aa604689cc582292b97668bedd91dd5bf9374c88ac0040075af07507001976a9145d16672f53981ff21c5f42b40d1954993cbca54f88ac00000000"
)
]
data SatoshiCoreTxTest =
SatoshiCoreTxTest { satCoreTxTestDescription :: String,
satCoreTxTestInputs :: [SatoshiCoreTxTestInput],
satCoreTxTestSerTx :: ByteString}
deriving (Read,Show)
data SatoshiCoreTxTestInput =
SatoshiCoreTxTestInput { satCoreTxTestPrevoutHash :: ByteString,
satCoreTxTestPrevoutIndex :: ByteString,
satCoreTxTestPrevoutScriptPubKey :: ByteString}
deriving (Read,Show)
{- Test vectors from bitcoind -}
-- github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json
-- [[(prevout hash, prevout index, prevout scriptPubKey)], serialized tx],
verifyVec :: [SatoshiCoreTxTest]
verifyVec =
let toSatCoreTest (is, sertx, description) = SatoshiCoreTxTest description (map toInputs is) sertx
toInputs (a,b,c) = SatoshiCoreTxTestInput a b c
in map toSatCoreTest
[
( [
( "60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1"
, "00000000"
, "514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52ae"
)
]
, "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000"
, "It is of particular interest because it contains an invalidly-encoded signature which OpenSSL accepts"
)
, ( [
( "60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1"
, "00000000"
, "514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52ae"
)
]
, "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004A0048304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2bab01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000"
, "It has an arbitrary extra byte stuffed into the signature at pos length - 2"
)
, ( [
( "406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602"
, "00000000"
, "76a914dc44b1164188067c3a32d4780f5996fa14a4f2d988ac"
)
]
, "01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000"
, "it is of interest because it contains a 0-sequence as well as a signature of SIGHASH type 0 (which is not a real type)"
)
, ( [
( "b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d"
, "00000000"
, "76a914bef80ecf3a44500fda1bc92176e442891662aed288ac"
)
, ( "b7978cc96e59a8b13e0865d3f95657561a7f725be952438637475920bac9eb21"
, "01000000"
, "76a914bef80ecf3a44500fda1bc92176e442891662aed288ac"
)
]
, "01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000"
, "It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation"
)
, ( [
( "0000000000000000000000000000000000000000000000000000000000000100"
, "00000000"
, "76a914e52b482f2faa8ecbf0db344f93c84ac908557f3388ac"
)
, ( "0000000000000000000000000000000000000000000000000000000000000200"
, "00000000"
, "76a914751e76e8199196d454941c45d1b3a323f1433bd688ac"
)
]
, "01000000020002000000000000000000000000000000000000000000000000000000000000000000006a47304402200469f169b8091cd18a2770136be7411f079b3ac2b5c199885eb66a80aa3ed75002201fa89f3e6f80974e1b3474e70a0fbe907c766137ff231e4dd05a555d8544536701210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000"
, "-- It results in signing the constant 1, instead of something generated based on the transaction,\
\-- when the input doing the signing has an index greater than the maximum output index"
)
, ( [
( "0000000000000000000000000000000000000000000000000000000000000100"
, "00000000"
, "a9148febbed40483661de6958d957412f82deed8e2f787"
)
]
, "01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000"
, "A valid P2SH Transaction using the standard transaction type put forth in BIP 16"
)
, ( [
( "0000000000000000000000000000000000000000000000000000000000000100"
, "00000000"
, "a91432afac281462b822adbec5094b8d4d337dd5bd6a87"
)
]
, "01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000"
, "MAX_MONEY output"
)
, ( [
( "0000000000000000000000000000000000000000000000000000000000000100"
, "00000000"
, "a914b558cbf4930954aa6a344363a15668d7477ae71687"
)
]
, "01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000"
, "MAX_MONEY output + 0 output"
)
, ( [
( "0000000000000000000000000000000000000000000000000000000000000100"
, "00000000"
, "21035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac"
)
, ( "0000000000000000000000000000000000000000000000000000000000000200"
, "00000000"
, "21035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac"
)
]
, "010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000"
, "Simple transaction with first input is signed with SIGHASH_ALL, second with SIGHASH_ANYONECANPAY"
)
, ( [
( "0000000000000000000000000000000000000000000000000000000000000100"
, "00000000"
, "21035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac"
)
, ( "0000000000000000000000000000000000000000000000000000000000000200"
, "00000000"
, "21035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac"
)
]
, "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000"
, "Same as above, but we change the sequence number of the first input to check that SIGHASH_ANYONECANPAY is being followed"
)
, ( [
( "63cfa5a09dc540bf63e53713b82d9ea3692ca97cd608c384f2aa88e51a0aac70"
, "00000000"
, "76a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88ac"
)
, ( "04e8d0fcf3846c6734477b98f0f3d4badfb78f020ee097a0be5fe347645b817d"
, "01000000"
, "76a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88ac"
)
, ( "ee1377aff5d0579909e11782e1d2f5f7b84d26537be7f5516dd4e43373091f3f"
, "01000000"
, "76a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88ac"
)
]
, "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000"
, "several SIGHASH_SINGLE signatures"
)
]
tEncodeSatoshiCoreScriptPubKey :: Assertion
tEncodeSatoshiCoreScriptPubKey = assertBool "tEncodeSatoshiCoreScriptPubKey" $
t1BsOutputScriptPubKey == encodeSatoshiCoreScriptPubKey t1SatoshiCoreJsonScriptPubKey
where
t1BsOutputScriptPubKey :: ByteString
t1BsOutputScriptPubKey = "514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52ae"
t1SatoshiCoreJsonScriptPubKey :: String
t1SatoshiCoreJsonScriptPubKey = "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"
encodeSatoshiCoreScriptPubKey :: String -> ByteString
encodeSatoshiCoreScriptPubKey =
mconcat . map encodeSatoshiCoreScriptPiece . words
where
encodeSatoshiCoreScriptPiece :: String -> ByteString
encodeSatoshiCoreScriptPiece s = case (readMay ("OP_" ++ s) :: Maybe ScriptOp) of
Just op -> encodeHex . encode' $ op
Nothing -> case (take 2 s) of
"OP" -> encodeHex . encode' . (read :: String -> ScriptOp) $ s
"0x" -> ( fromString . drop 2 :: String -> ByteString) $ s
_ -> case (readMay s :: Maybe Int) of -- can we get rid of this case now?
Just i -> encodeHex . encode' . intToScriptOp $ i
Nothing -> error $ "encodeSatoshiCoreScriptPubKey: " ++ s
satoshiCoreTxTests :: IO [Test]
satoshiCoreTxTests = do
txVec <- satoshiCoreTxVec
return $ [
testGroup "Verify transaction (bitcoind /test/data/tx_valid.json) (using copied source json)"
( map mapVerifyVec . filter isCurrentlyPassing $ zip txVec [0..] )
]
where
passingTests = [0..5] ++ [8] ++ [11..13] ++ [16..18] ++ [20] ++ [52]
isCurrentlyPassing (_, testNum) = elem testNum passingTests
type TestComment = String
satoshiCoreTxVec :: IO [SatoshiCoreTxTest]
satoshiCoreTxVec = do
tx_validBS <- LBS.readFile "tests/data/tx_valid.json"
let testsAndComments = maybe (error $ "satoshiCoreTxVec, couldn't decode json") id . Aeson.decode $ tx_validBS
return $ case testsAndComments of
(Aeson.Array arr) ->
let testsOrComments = map toTestOrComment . V.toList $ arr
in processTestsAndComments testsOrComments
_ -> error $ "satoshiCoreTxVec, testsAndComments not an array"
where
processTestsAndComments :: [Either TestComment SatoshiCoreTxTest] -> [SatoshiCoreTxTest]
processTestsAndComments testOrComments =
-- ghetto parser, because this older version of ootb aeson parser isn't parsec based
-- to do ideally soon, upgrade aeson, use aeson/attoparsec, should be much cleaner
let grouper = Data.List.groupBy (\x y -> (Data.Either.isLeft x && Data.Either.isLeft y)
|| (Data.Either.isRight x && Data.Either.isRight y))
takePairs (a:b:xs) = (a,b):takePairs xs
takePairs _ = [] -- ugh, wish we were using a real parser.
includeDescriptions (descriptionLines,tests') = map updateDescription tests'
where updateDescription (Right (SatoshiCoreTxTest _ inputs ser)) = SatoshiCoreTxTest description inputs ser
updateDescription e = error $ "updateDescription: " ++ show e
description = unwords . map fromLeft $ descriptionLines
in concat . map includeDescriptions . takePairs . grouper $ testOrComments
toTestOrComment :: Aeson.Value -> (Either TestComment SatoshiCoreTxTest)
toTestOrComment testVectorOrComment =
case testVectorOrComment of
(Aeson.Types.Array arr) ->
case (V.length arr) of
1 -> let comment = arr V.! 0
in case comment of
Aeson.Types.String txt -> Left . convertString $ txt
_ -> error $ "toTestOrComment, comment not text"
3 -> let inputs = case ( arr V.! 0 ) of
(Aeson.Array inputsV) ->
let toInput ( Aeson.Array oneInputV ) =
let hash = case oneInputV V.! 0 of
Aeson.String txt -> convertString txt
_ -> error "processItem, hash not a string"
index = case oneInputV V.! 01 of
Aeson.Number n -> encodeHex . runPut' . putWord32le . floor $ n
_ -> error "processItem, n not a number"
pubkey = case oneInputV V.! 2 of
Aeson.String txt -> encodeSatoshiCoreScriptPubKey . convertString $ txt
_ -> error "processItem, pubkey not a string"
in SatoshiCoreTxTestInput hash index pubkey
toInput _ = error "processItem, oneInputV not an array"
in map toInput . V.toList $ inputsV
_ -> error "inputs not an array"
tx = let txVal = arr V.! 1
in case txVal of
Aeson.Types.String txt -> convertString txt
_ -> error $ "toTestOrComment, tx, not text"
-- flags -- v V.! 2 -- ignored for now?
in Right $ SatoshiCoreTxTest "" inputs tx
i -> error $ "toTestOrComment, bad length: " ++ show i
_ -> error "testVectorOrComment is not an array"