{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Bitcoin.Util where
import Bitcoin.Internal.Util
import Data.String (fromString)
import Data.Word (Word32)
import qualified Data.ByteString as B
import qualified Data.ByteString.Base16 as B16
import qualified Data.List.NonEmpty as NE
import qualified Data.Serialize as Bin
import qualified Network.Haskoin.Crypto as HC
import qualified Network.Haskoin.Node as HN
import qualified Network.Haskoin.Script as HS
import qualified Network.Haskoin.Transaction as HT
import qualified Network.Haskoin.Util as HU
instance Monoid HS.Script where
mempty = HS.Script []
mappend (HS.Script scr1) (HS.Script scr2) =
HS.Script $ scr1 `mappend` scr2
serTxWitness :: NE.NonEmpty HS.Script -> B.ByteString
serTxWitness = NE.head . NE.scanr foldScript B.empty
where
foldScript scr !bsAccum = serScript scr <> bsAccum
serScript scr = Bin.encode (HN.VarInt $ scrLen scr) <> Bin.encode scr
scrLen (HS.Script ops) = fromIntegral $ length ops
calcTxSize :: HT.Tx -> Word
calcTxSize = fromIntegral . B.length . Bin.encode
dummyHash256 :: HC.Hash256
dummyHash256 = fromString "0000000000000000000000000000000000000000000000000000000000000000"
hash256 :: Bin.Serialize a => a -> HC.Hash256
hash256 = HC.hash256 . serialize
hash160 :: Bin.Serialize a => a -> HC.Hash160
hash160 = HC.hash160 . HC.getHash256 . HC.hash256 . serialize
opPush :: Bin.Serialize a => a -> HS.ScriptOp
opPush = HS.opPushData . Bin.encode
addressToScript :: HC.Address -> HS.ScriptOutput
addressToScript addr =
case addr of
a@(HC.PubKeyAddress _) -> HS.PayPKHash a
a@(HC.ScriptAddress _) -> HS.PayScriptHash a
decodeScriptHash :: B.ByteString -> Either String HC.Hash160
decodeScriptHash bs =
HS.decodeOutputBS bs >>=
\scrOut -> case scrOut of
HS.PayScriptHash a -> getP2SHAddr a
x -> Left $ "Expected P2SH output, found: " ++ show x
where
getP2SHAddr (HC.ScriptAddress h) = Right h
getP2SHAddr (HC.PubKeyAddress _) = Left "Expected P2SH address, found P2PKH address"
addressToScriptPubKeyBS :: HC.Address -> B.ByteString
addressToScriptPubKeyBS = HS.encodeOutputBS . addressToScript
replaceScriptInput :: Word32 -> HS.Script -> HT.Tx -> HT.Tx
replaceScriptInput index scriptIn tx =
HT.createTx (HT.txVersion tx) newTxIns (HT.txOut tx) (HT.txLockTime tx)
where newTxIns = HU.updateIndex (fromIntegral index) (HT.txIn tx) replaceScriptIn
replaceScriptIn txIn = txIn { HT.scriptInput = Bin.encode scriptIn}
removeOutputs :: HT.Tx -> HT.Tx
removeOutputs tx =
HT.createTx (HT.txVersion tx) (HT.txIn tx) [] (HT.txLockTime tx)
appendOutput :: HT.Tx -> HT.TxOut -> HT.Tx
appendOutput tx txOut =
HT.createTx (HT.txVersion tx) (HT.txIn tx) ( oldOuts ++ [txOut] ) (HT.txLockTime tx)
where oldOuts = HT.txOut tx
bitcoinPayPK :: HC.PubKeyC -> HS.Script
bitcoinPayPK pk = HS.encodeOutput $ HS.PayPKHash $ HC.pubKeyAddr pk
bitcoinPayPKBS = serialize . bitcoinPayPK
where serialize = Bin.encode