module Network.Haskoin.Protocol.Tx
( Tx(..)
, TxIn(..)
, TxOut(..)
, OutPoint(..)
, CoinbaseTx(..)
, txid
, cbid
, encodeTxid
, decodeTxid
) where
import Control.Monad (replicateM, forM_, liftM2, unless)
import Control.Applicative ((<$>),(<*>))
import Data.Word (Word32, Word64)
import Data.Binary (Binary, get, put)
import Data.Binary.Get
( getWord32le
, getWord64le
, getByteString
)
import Data.Binary.Put
( putWord32le
, putWord64le
, putByteString
)
import qualified Data.ByteString as BS
( ByteString
, length
, reverse
)
import Network.Haskoin.Protocol.VarInt
import Network.Haskoin.Protocol.Script
import Network.Haskoin.Crypto.Hash
import Network.Haskoin.Util
data Tx =
Tx {
txVersion :: !Word32
, txIn :: ![TxIn]
, txOut :: ![TxOut]
, txLockTime :: !Word32
} deriving (Eq, Show, Read)
instance Binary Tx where
get = Tx <$> getWord32le
<*> (replicateList =<< get)
<*> (replicateList =<< get)
<*> getWord32le
where
replicateList (VarInt c) = replicateM (fromIntegral c) get
put (Tx v is os l) = do
putWord32le v
put $ VarInt $ fromIntegral $ length is
forM_ is put
put $ VarInt $ fromIntegral $ length os
forM_ os put
putWord32le l
data CoinbaseTx =
CoinbaseTx {
cbVersion :: !Word32
, cbPrevOutput :: !OutPoint
, cbData :: !BS.ByteString
, cbInSequence :: !Word32
, cbOut :: ![TxOut]
, cbLockTime :: !Word32
} deriving (Eq, Show, Read)
instance Binary CoinbaseTx where
get = do
v <- getWord32le
(VarInt len) <- get
unless (len == 1) $ fail "CoinbaseTx get: Input size is not 1"
op <- get
(VarInt cbLen) <- get
cb <- getByteString (fromIntegral cbLen)
sq <- getWord32le
(VarInt oLen) <- get
os <- replicateM (fromIntegral oLen) get
lt <- getWord32le
return $ CoinbaseTx v op cb sq os lt
put (CoinbaseTx v op cb sq os lt) = do
putWord32le v
put $ VarInt 1
put op
put $ VarInt $ fromIntegral $ BS.length cb
putByteString cb
putWord32le sq
put $ VarInt $ fromIntegral $ length os
forM_ os put
putWord32le lt
data TxIn =
TxIn {
prevOutput :: !OutPoint
, scriptInput :: !Script
, txInSequence :: !Word32
} deriving (Eq, Show, Read)
instance Binary TxIn where
get = TxIn <$> get <*> get <*> getWord32le
put (TxIn o s q) = put o >> put s >> putWord32le q
data TxOut =
TxOut {
outValue :: !Word64
, scriptOutput :: !Script
} deriving (Eq, Show, Read)
instance Binary TxOut where
get = do
val <- getWord64le
unless (val <= 2100000000000000) $ fail $
"Invalid TxOut value: " ++ (show val)
TxOut val <$> get
put (TxOut o s) = putWord64le o >> put s
data OutPoint =
OutPoint {
outPointHash :: !Hash256
, outPointIndex :: !Word32
} deriving (Read, Show, Eq)
instance Binary OutPoint where
get = do
(h,i) <- liftM2 (,) get getWord32le
return $ OutPoint h i
put (OutPoint h i) = put h >> putWord32le i
txid :: Tx -> Hash256
txid = doubleHash256 . encode'
cbid :: CoinbaseTx -> Hash256
cbid = doubleHash256 . encode'
encodeTxid :: Hash256 -> String
encodeTxid = bsToHex . BS.reverse . encode'
decodeTxid :: String -> Maybe Hash256
decodeTxid = (decodeToMaybe . BS.reverse =<<) . hexToBS