{-# OPTIONS_HADDOCK prune #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Bitcoin.Prim.Tx (
Tx(..)
, TxIn(..)
, TxOut(..)
, OutPoint(..)
, Witness(..)
, TxId(..)
, mkTxId
, to_bytes
, from_bytes
, to_bytes_legacy
, to_base16
, from_base16
, txid
, put_word32_le
, put_word64_le
, put_compact
, put_outpoint
, put_txout
, to_strict
) where
import qualified Crypto.Hash.SHA256 as SHA256
import Data.Bits ((.|.), shiftL)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Base16 as B16
import qualified Data.ByteString.Builder as BSB
import qualified Data.ByteString.Lazy as BL
import Data.List.NonEmpty (NonEmpty(..))
import qualified Data.List.NonEmpty as NE
import Data.Word (Word32, Word64)
import GHC.Generics (Generic)
newtype TxId = TxId BS.ByteString
deriving (TxId -> TxId -> Bool
(TxId -> TxId -> Bool) -> (TxId -> TxId -> Bool) -> Eq TxId
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TxId -> TxId -> Bool
== :: TxId -> TxId -> Bool
$c/= :: TxId -> TxId -> Bool
/= :: TxId -> TxId -> Bool
Eq, Int -> TxId -> ShowS
[TxId] -> ShowS
TxId -> String
(Int -> TxId -> ShowS)
-> (TxId -> String) -> ([TxId] -> ShowS) -> Show TxId
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TxId -> ShowS
showsPrec :: Int -> TxId -> ShowS
$cshow :: TxId -> String
show :: TxId -> String
$cshowList :: [TxId] -> ShowS
showList :: [TxId] -> ShowS
Show, (forall x. TxId -> Rep TxId x)
-> (forall x. Rep TxId x -> TxId) -> Generic TxId
forall x. Rep TxId x -> TxId
forall x. TxId -> Rep TxId x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. TxId -> Rep TxId x
from :: forall x. TxId -> Rep TxId x
$cto :: forall x. Rep TxId x -> TxId
to :: forall x. Rep TxId x -> TxId
Generic)
mkTxId :: BS.ByteString -> Maybe TxId
mkTxId :: ByteString -> Maybe TxId
mkTxId ByteString
bs
| ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
32 = TxId -> Maybe TxId
forall a. a -> Maybe a
Just (ByteString -> TxId
TxId ByteString
bs)
| Bool
otherwise = Maybe TxId
forall a. Maybe a
Nothing
data OutPoint = OutPoint
{ OutPoint -> TxId
op_txid :: {-# UNPACK #-} !TxId
, OutPoint -> Word32
op_vout :: {-# UNPACK #-} !Word32
} deriving (OutPoint -> OutPoint -> Bool
(OutPoint -> OutPoint -> Bool)
-> (OutPoint -> OutPoint -> Bool) -> Eq OutPoint
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: OutPoint -> OutPoint -> Bool
== :: OutPoint -> OutPoint -> Bool
$c/= :: OutPoint -> OutPoint -> Bool
/= :: OutPoint -> OutPoint -> Bool
Eq, Int -> OutPoint -> ShowS
[OutPoint] -> ShowS
OutPoint -> String
(Int -> OutPoint -> ShowS)
-> (OutPoint -> String) -> ([OutPoint] -> ShowS) -> Show OutPoint
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> OutPoint -> ShowS
showsPrec :: Int -> OutPoint -> ShowS
$cshow :: OutPoint -> String
show :: OutPoint -> String
$cshowList :: [OutPoint] -> ShowS
showList :: [OutPoint] -> ShowS
Show, (forall x. OutPoint -> Rep OutPoint x)
-> (forall x. Rep OutPoint x -> OutPoint) -> Generic OutPoint
forall x. Rep OutPoint x -> OutPoint
forall x. OutPoint -> Rep OutPoint x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. OutPoint -> Rep OutPoint x
from :: forall x. OutPoint -> Rep OutPoint x
$cto :: forall x. Rep OutPoint x -> OutPoint
to :: forall x. Rep OutPoint x -> OutPoint
Generic)
data TxIn = TxIn
{ TxIn -> OutPoint
txin_prevout :: {-# UNPACK #-} !OutPoint
, TxIn -> ByteString
txin_script_sig :: !BS.ByteString
, TxIn -> Word32
txin_sequence :: {-# UNPACK #-} !Word32
} deriving (TxIn -> TxIn -> Bool
(TxIn -> TxIn -> Bool) -> (TxIn -> TxIn -> Bool) -> Eq TxIn
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TxIn -> TxIn -> Bool
== :: TxIn -> TxIn -> Bool
$c/= :: TxIn -> TxIn -> Bool
/= :: TxIn -> TxIn -> Bool
Eq, Int -> TxIn -> ShowS
[TxIn] -> ShowS
TxIn -> String
(Int -> TxIn -> ShowS)
-> (TxIn -> String) -> ([TxIn] -> ShowS) -> Show TxIn
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TxIn -> ShowS
showsPrec :: Int -> TxIn -> ShowS
$cshow :: TxIn -> String
show :: TxIn -> String
$cshowList :: [TxIn] -> ShowS
showList :: [TxIn] -> ShowS
Show, (forall x. TxIn -> Rep TxIn x)
-> (forall x. Rep TxIn x -> TxIn) -> Generic TxIn
forall x. Rep TxIn x -> TxIn
forall x. TxIn -> Rep TxIn x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. TxIn -> Rep TxIn x
from :: forall x. TxIn -> Rep TxIn x
$cto :: forall x. Rep TxIn x -> TxIn
to :: forall x. Rep TxIn x -> TxIn
Generic)
data TxOut = TxOut
{ TxOut -> Word64
txout_value :: {-# UNPACK #-} !Word64
, TxOut -> ByteString
txout_script_pubkey :: !BS.ByteString
} deriving (TxOut -> TxOut -> Bool
(TxOut -> TxOut -> Bool) -> (TxOut -> TxOut -> Bool) -> Eq TxOut
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TxOut -> TxOut -> Bool
== :: TxOut -> TxOut -> Bool
$c/= :: TxOut -> TxOut -> Bool
/= :: TxOut -> TxOut -> Bool
Eq, Int -> TxOut -> ShowS
[TxOut] -> ShowS
TxOut -> String
(Int -> TxOut -> ShowS)
-> (TxOut -> String) -> ([TxOut] -> ShowS) -> Show TxOut
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TxOut -> ShowS
showsPrec :: Int -> TxOut -> ShowS
$cshow :: TxOut -> String
show :: TxOut -> String
$cshowList :: [TxOut] -> ShowS
showList :: [TxOut] -> ShowS
Show, (forall x. TxOut -> Rep TxOut x)
-> (forall x. Rep TxOut x -> TxOut) -> Generic TxOut
forall x. Rep TxOut x -> TxOut
forall x. TxOut -> Rep TxOut x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. TxOut -> Rep TxOut x
from :: forall x. TxOut -> Rep TxOut x
$cto :: forall x. Rep TxOut x -> TxOut
to :: forall x. Rep TxOut x -> TxOut
Generic)
newtype Witness = Witness [BS.ByteString]
deriving (Witness -> Witness -> Bool
(Witness -> Witness -> Bool)
-> (Witness -> Witness -> Bool) -> Eq Witness
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Witness -> Witness -> Bool
== :: Witness -> Witness -> Bool
$c/= :: Witness -> Witness -> Bool
/= :: Witness -> Witness -> Bool
Eq, Int -> Witness -> ShowS
[Witness] -> ShowS
Witness -> String
(Int -> Witness -> ShowS)
-> (Witness -> String) -> ([Witness] -> ShowS) -> Show Witness
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Witness -> ShowS
showsPrec :: Int -> Witness -> ShowS
$cshow :: Witness -> String
show :: Witness -> String
$cshowList :: [Witness] -> ShowS
showList :: [Witness] -> ShowS
Show, (forall x. Witness -> Rep Witness x)
-> (forall x. Rep Witness x -> Witness) -> Generic Witness
forall x. Rep Witness x -> Witness
forall x. Witness -> Rep Witness x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Witness -> Rep Witness x
from :: forall x. Witness -> Rep Witness x
$cto :: forall x. Rep Witness x -> Witness
to :: forall x. Rep Witness x -> Witness
Generic)
data Tx = Tx
{ Tx -> Word32
tx_version :: {-# UNPACK #-} !Word32
, Tx -> NonEmpty TxIn
tx_inputs :: !(NonEmpty TxIn)
, Tx -> NonEmpty TxOut
tx_outputs :: !(NonEmpty TxOut)
, Tx -> [Witness]
tx_witnesses :: ![Witness]
, Tx -> Word32
tx_locktime :: {-# UNPACK #-} !Word32
} deriving (Tx -> Tx -> Bool
(Tx -> Tx -> Bool) -> (Tx -> Tx -> Bool) -> Eq Tx
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Tx -> Tx -> Bool
== :: Tx -> Tx -> Bool
$c/= :: Tx -> Tx -> Bool
/= :: Tx -> Tx -> Bool
Eq, Int -> Tx -> ShowS
[Tx] -> ShowS
Tx -> String
(Int -> Tx -> ShowS)
-> (Tx -> String) -> ([Tx] -> ShowS) -> Show Tx
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Tx -> ShowS
showsPrec :: Int -> Tx -> ShowS
$cshow :: Tx -> String
show :: Tx -> String
$cshowList :: [Tx] -> ShowS
showList :: [Tx] -> ShowS
Show, (forall x. Tx -> Rep Tx x)
-> (forall x. Rep Tx x -> Tx) -> Generic Tx
forall x. Rep Tx x -> Tx
forall x. Tx -> Rep Tx x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Tx -> Rep Tx x
from :: forall x. Tx -> Rep Tx x
$cto :: forall x. Rep Tx x -> Tx
to :: forall x. Rep Tx x -> Tx
Generic)
to_bytes :: Tx -> BS.ByteString
to_bytes :: Tx -> ByteString
to_bytes tx :: Tx
tx@Tx {[Witness]
Word32
NonEmpty TxOut
NonEmpty TxIn
tx_version :: Tx -> Word32
tx_inputs :: Tx -> NonEmpty TxIn
tx_outputs :: Tx -> NonEmpty TxOut
tx_witnesses :: Tx -> [Witness]
tx_locktime :: Tx -> Word32
tx_version :: Word32
tx_inputs :: NonEmpty TxIn
tx_outputs :: NonEmpty TxOut
tx_witnesses :: [Witness]
tx_locktime :: Word32
..}
| [Witness] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Witness]
tx_witnesses = Tx -> ByteString
to_bytes_legacy Tx
tx
| Bool
otherwise = Builder -> ByteString
to_strict (Builder -> ByteString) -> Builder -> ByteString
forall a b. (a -> b) -> a -> b
$
Word32 -> Builder
put_word32_le Word32
tx_version
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
BSB.word8 Word8
0x00
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
BSB.word8 Word8
0x01
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word64 -> Builder
put_compact (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (NonEmpty TxIn -> Int
forall a. NonEmpty a -> Int
NE.length NonEmpty TxIn
tx_inputs))
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> (TxIn -> Builder) -> NonEmpty TxIn -> Builder
forall m a. Monoid m => (a -> m) -> NonEmpty a -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap TxIn -> Builder
put_txin NonEmpty TxIn
tx_inputs
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word64 -> Builder
put_compact (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (NonEmpty TxOut -> Int
forall a. NonEmpty a -> Int
NE.length NonEmpty TxOut
tx_outputs))
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> (TxOut -> Builder) -> NonEmpty TxOut -> Builder
forall m a. Monoid m => (a -> m) -> NonEmpty a -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap TxOut -> Builder
put_txout NonEmpty TxOut
tx_outputs
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> (Witness -> Builder) -> [Witness] -> Builder
forall m a. Monoid m => (a -> m) -> [a] -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap Witness -> Builder
put_witness [Witness]
tx_witnesses
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word32 -> Builder
put_word32_le Word32
tx_locktime
to_bytes_legacy :: Tx -> BS.ByteString
to_bytes_legacy :: Tx -> ByteString
to_bytes_legacy Tx {[Witness]
Word32
NonEmpty TxOut
NonEmpty TxIn
tx_version :: Tx -> Word32
tx_inputs :: Tx -> NonEmpty TxIn
tx_outputs :: Tx -> NonEmpty TxOut
tx_witnesses :: Tx -> [Witness]
tx_locktime :: Tx -> Word32
tx_version :: Word32
tx_inputs :: NonEmpty TxIn
tx_outputs :: NonEmpty TxOut
tx_witnesses :: [Witness]
tx_locktime :: Word32
..} = Builder -> ByteString
to_strict (Builder -> ByteString) -> Builder -> ByteString
forall a b. (a -> b) -> a -> b
$
Word32 -> Builder
put_word32_le Word32
tx_version
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word64 -> Builder
put_compact (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (NonEmpty TxIn -> Int
forall a. NonEmpty a -> Int
NE.length NonEmpty TxIn
tx_inputs))
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> (TxIn -> Builder) -> NonEmpty TxIn -> Builder
forall m a. Monoid m => (a -> m) -> NonEmpty a -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap TxIn -> Builder
put_txin NonEmpty TxIn
tx_inputs
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word64 -> Builder
put_compact (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (NonEmpty TxOut -> Int
forall a. NonEmpty a -> Int
NE.length NonEmpty TxOut
tx_outputs))
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> (TxOut -> Builder) -> NonEmpty TxOut -> Builder
forall m a. Monoid m => (a -> m) -> NonEmpty a -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap TxOut -> Builder
put_txout NonEmpty TxOut
tx_outputs
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word32 -> Builder
put_word32_le Word32
tx_locktime
to_base16 :: Tx -> BS.ByteString
to_base16 :: Tx -> ByteString
to_base16 Tx
tx = ByteString -> ByteString
B16.encode (Tx -> ByteString
to_bytes Tx
tx)
from_base16 :: BS.ByteString -> Maybe Tx
from_base16 :: ByteString -> Maybe Tx
from_base16 ByteString
b16 = do
bs <- ByteString -> Maybe ByteString
B16.decode ByteString
b16
from_bytes bs
to_strict :: BSB.Builder -> BS.ByteString
to_strict :: Builder -> ByteString
to_strict = LazyByteString -> ByteString
BL.toStrict (LazyByteString -> ByteString)
-> (Builder -> LazyByteString) -> Builder -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> LazyByteString
BSB.toLazyByteString
{-# INLINE to_strict #-}
put_word32_le :: Word32 -> BSB.Builder
put_word32_le :: Word32 -> Builder
put_word32_le = Word32 -> Builder
BSB.word32LE
{-# INLINE put_word32_le #-}
put_word64_le :: Word64 -> BSB.Builder
put_word64_le :: Word64 -> Builder
put_word64_le = Word64 -> Builder
BSB.word64LE
{-# INLINE put_word64_le #-}
put_compact :: Word64 -> BSB.Builder
put_compact :: Word64 -> Builder
put_compact !Word64
n
| Word64
n Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word64
0xfc = Word8 -> Builder
BSB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
n)
| Word64
n Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word64
0xffff = Word8 -> Builder
BSB.word8 Word8
0xfd Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word16 -> Builder
BSB.word16LE (Word64 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
n)
| Word64
n Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word64
0xffffffff = Word8 -> Builder
BSB.word8 Word8
0xfe Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word32 -> Builder
BSB.word32LE (Word64 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
n)
| Bool
otherwise = Word8 -> Builder
BSB.word8 Word8
0xff Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word64 -> Builder
BSB.word64LE Word64
n
{-# INLINE put_compact #-}
put_outpoint :: OutPoint -> BSB.Builder
put_outpoint :: OutPoint -> Builder
put_outpoint OutPoint {Word32
TxId
op_txid :: OutPoint -> TxId
op_vout :: OutPoint -> Word32
op_txid :: TxId
op_vout :: Word32
..} =
let !(TxId !ByteString
txid_bs) = TxId
op_txid
in ByteString -> Builder
BSB.byteString ByteString
txid_bs Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word32 -> Builder
put_word32_le Word32
op_vout
{-# INLINE put_outpoint #-}
put_txin :: TxIn -> BSB.Builder
put_txin :: TxIn -> Builder
put_txin TxIn {Word32
ByteString
OutPoint
txin_prevout :: TxIn -> OutPoint
txin_script_sig :: TxIn -> ByteString
txin_sequence :: TxIn -> Word32
txin_prevout :: OutPoint
txin_script_sig :: ByteString
txin_sequence :: Word32
..} =
OutPoint -> Builder
put_outpoint OutPoint
txin_prevout
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word64 -> Builder
put_compact (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int
BS.length ByteString
txin_script_sig))
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> ByteString -> Builder
BSB.byteString ByteString
txin_script_sig
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word32 -> Builder
put_word32_le Word32
txin_sequence
{-# INLINE put_txin #-}
put_txout :: TxOut -> BSB.Builder
put_txout :: TxOut -> Builder
put_txout TxOut {Word64
ByteString
txout_value :: TxOut -> Word64
txout_script_pubkey :: TxOut -> ByteString
txout_value :: Word64
txout_script_pubkey :: ByteString
..} =
Word64 -> Builder
put_word64_le Word64
txout_value
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word64 -> Builder
put_compact (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int
BS.length ByteString
txout_script_pubkey))
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> ByteString -> Builder
BSB.byteString ByteString
txout_script_pubkey
{-# INLINE put_txout #-}
put_witness :: Witness -> BSB.Builder
put_witness :: Witness -> Builder
put_witness (Witness [ByteString]
items) =
Word64 -> Builder
put_compact (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([ByteString] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [ByteString]
items))
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> (ByteString -> Builder) -> [ByteString] -> Builder
forall m a. Monoid m => (a -> m) -> [a] -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap ByteString -> Builder
put_witness_item [ByteString]
items
where
put_witness_item :: BS.ByteString -> BSB.Builder
put_witness_item :: ByteString -> Builder
put_witness_item !ByteString
item =
Word64 -> Builder
put_compact (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int
BS.length ByteString
item))
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> ByteString -> Builder
BSB.byteString ByteString
item
{-# INLINE put_witness #-}
from_bytes :: BS.ByteString -> Maybe Tx
from_bytes :: ByteString -> Maybe Tx
from_bytes !ByteString
bs = do
Bool -> Maybe ()
guard (ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
4)
let !version :: Word32
version = ByteString -> Int -> Word32
get_word32_le ByteString
bs Int
0
!off0 :: Int
off0 = Int
4
if ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
off0 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
Bool -> Bool -> Bool
&& HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs Int
off0 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x00
Bool -> Bool -> Bool
&& HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs (Int
off0 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x01
then ByteString -> Word32 -> Int -> Maybe Tx
parse_segwit ByteString
bs Word32
version (Int
off0 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2)
else ByteString -> Word32 -> Int -> Maybe Tx
parse_legacy ByteString
bs Word32
version Int
off0
parse_legacy :: BS.ByteString -> Word32 -> Int -> Maybe Tx
parse_legacy :: ByteString -> Word32 -> Int -> Maybe Tx
parse_legacy !ByteString
bs !Word32
version !Int
off0 = do
(input_count, off1) <- ByteString -> Int -> Maybe (Word64, Int)
get_compact ByteString
bs Int
off0
(inputs_list, off2) <- get_many get_txin bs off1 (fromIntegral input_count)
inputs <- NE.nonEmpty inputs_list
(output_count, off3) <- get_compact bs off2
(outputs_list, off4) <- get_many get_txout bs off3 (fromIntegral output_count)
outputs <- NE.nonEmpty outputs_list
guard (BS.length bs >= off4 + 4)
let !locktime = ByteString -> Int -> Word32
get_word32_le ByteString
bs Int
off4
!off5 = Int
off4 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4
guard (off5 == BS.length bs)
pure $! Tx version inputs outputs [] locktime
parse_segwit :: BS.ByteString -> Word32 -> Int -> Maybe Tx
parse_segwit :: ByteString -> Word32 -> Int -> Maybe Tx
parse_segwit !ByteString
bs !Word32
version !Int
off0 = do
(input_count, off1) <- ByteString -> Int -> Maybe (Word64, Int)
get_compact ByteString
bs Int
off0
(inputs_list, off2) <- get_many get_txin bs off1 (fromIntegral input_count)
inputs <- NE.nonEmpty inputs_list
(output_count, off3) <- get_compact bs off2
(outputs_list, off4) <- get_many get_txout bs off3 (fromIntegral output_count)
outputs <- NE.nonEmpty outputs_list
(witnesses, off5) <- get_many get_witness bs off4 (fromIntegral input_count)
guard (BS.length bs >= off5 + 4)
let !locktime = ByteString -> Int -> Word32
get_word32_le ByteString
bs Int
off5
!off6 = Int
off5 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4
guard (off6 == BS.length bs)
pure $! Tx version inputs outputs witnesses locktime
guard :: Bool -> Maybe ()
guard :: Bool -> Maybe ()
guard Bool
True = () -> Maybe ()
forall a. a -> Maybe a
Just ()
guard Bool
False = Maybe ()
forall a. Maybe a
Nothing
{-# INLINE guard #-}
get_word32_le :: BS.ByteString -> Int -> Word32
get_word32_le :: ByteString -> Int -> Word32
get_word32_le !ByteString
bs !Int
off =
let !b0 :: Word32
b0 = Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs Int
off) :: Word32
!b1 :: Word32
b1 = Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)) :: Word32
!b2 :: Word32
b2 = Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2)) :: Word32
!b3 :: Word32
b3 = Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3)) :: Word32
in Word32
b0 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. (Word32
b1 Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`shiftL` Int
8) Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. (Word32
b2 Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`shiftL` Int
16) Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. (Word32
b3 Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`shiftL` Int
24)
{-# INLINE get_word32_le #-}
get_word64_le :: BS.ByteString -> Int -> Word64
get_word64_le :: ByteString -> Int -> Word64
get_word64_le !ByteString
bs !Int
off =
let !b0 :: Word64
b0 = Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs Int
off) :: Word64
!b1 :: Word64
b1 = Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)) :: Word64
!b2 :: Word64
b2 = Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2)) :: Word64
!b3 :: Word64
b3 = Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3)) :: Word64
!b4 :: Word64
b4 = Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4)) :: Word64
!b5 :: Word64
b5 = Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
5)) :: Word64
!b6 :: Word64
b6 = Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
6)) :: Word64
!b7 :: Word64
b7 = Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
7)) :: Word64
in Word64
b0 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
b1 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
8) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
b2 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
16) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
b3 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
24)
Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
b4 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
32) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
b5 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
40)
Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
b6 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
48) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
b7 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
56)
{-# INLINE get_word64_le #-}
get_word16_le :: BS.ByteString -> Int -> Word64
get_word16_le :: ByteString -> Int -> Word64
get_word16_le !ByteString
bs !Int
off =
let !b0 :: Word64
b0 = Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs Int
off) :: Word64
!b1 :: Word64
b1 = Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)) :: Word64
in Word64
b0 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
b1 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
8)
{-# INLINE get_word16_le #-}
get_compact :: BS.ByteString -> Int -> Maybe (Word64, Int)
get_compact :: ByteString -> Int -> Maybe (Word64, Int)
get_compact !ByteString
bs !Int
off
| Int
off Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= ByteString -> Int
BS.length ByteString
bs = Maybe (Word64, Int)
forall a. Maybe a
Nothing
| Bool
otherwise = case HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs Int
off of
Word8
tag | Word8
tag Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
0xfc ->
(Word64, Int) -> Maybe (Word64, Int)
forall a. a -> Maybe a
Just (Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
tag, Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
Word8
0xfd ->
if ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3
then Maybe (Word64, Int)
forall a. Maybe a
Nothing
else
let !val :: Word64
val = ByteString -> Int -> Word64
get_word16_le ByteString
bs (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
in if Word64
val Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
0xfd
then Maybe (Word64, Int)
forall a. Maybe a
Nothing
else (Word64, Int) -> Maybe (Word64, Int)
forall a. a -> Maybe a
Just (Word64
val, Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3)
Word8
0xfe ->
if ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
5
then Maybe (Word64, Int)
forall a. Maybe a
Nothing
else
let !val :: Word64
val = Word32 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int -> Word32
get_word32_le ByteString
bs (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)) :: Word64
in if Word64
val Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word64
0xffff
then Maybe (Word64, Int)
forall a. Maybe a
Nothing
else (Word64, Int) -> Maybe (Word64, Int)
forall a. a -> Maybe a
Just (Word64
val, Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
5)
Word8
_ ->
if ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
9
then Maybe (Word64, Int)
forall a. Maybe a
Nothing
else
let !val :: Word64
val = ByteString -> Int -> Word64
get_word64_le ByteString
bs (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
in if Word64
val Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word64
0xffffffff
then Maybe (Word64, Int)
forall a. Maybe a
Nothing
else (Word64, Int) -> Maybe (Word64, Int)
forall a. a -> Maybe a
Just (Word64
val, Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
9)
{-# INLINE get_compact #-}
get_outpoint :: BS.ByteString -> Int -> Maybe (OutPoint, Int)
get_outpoint :: ByteString -> Int -> Maybe (OutPoint, Int)
get_outpoint !ByteString
bs !Int
off
| ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
36 = Maybe (OutPoint, Int)
forall a. Maybe a
Nothing
| Bool
otherwise =
let !txid_bytes :: ByteString
txid_bytes = Int -> ByteString -> ByteString
BS.take Int
32 (Int -> ByteString -> ByteString
BS.drop Int
off ByteString
bs)
!vout :: Word32
vout = ByteString -> Int -> Word32
get_word32_le ByteString
bs (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
32)
in (OutPoint, Int) -> Maybe (OutPoint, Int)
forall a. a -> Maybe a
Just (TxId -> Word32 -> OutPoint
OutPoint (ByteString -> TxId
TxId ByteString
txid_bytes) Word32
vout, Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
36)
{-# INLINE get_outpoint #-}
get_txin :: BS.ByteString -> Int -> Maybe (TxIn, Int)
get_txin :: ByteString -> Int -> Maybe (TxIn, Int)
get_txin !ByteString
bs !Int
off0 = do
(outpoint, off1) <- ByteString -> Int -> Maybe (OutPoint, Int)
get_outpoint ByteString
bs Int
off0
(script_len, off2) <- get_compact bs off1
let !slen = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
script_len
guard (BS.length bs >= off2 + slen)
let !script_sig = Int -> ByteString -> ByteString
BS.take Int
slen (Int -> ByteString -> ByteString
BS.drop Int
off2 ByteString
bs)
!off3 = Int
off2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
slen
guard (BS.length bs >= off3 + 4)
let !seqn = ByteString -> Int -> Word32
get_word32_le ByteString
bs Int
off3
!off4 = Int
off3 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4
pure (TxIn outpoint script_sig seqn, off4)
get_txout :: BS.ByteString -> Int -> Maybe (TxOut, Int)
get_txout :: ByteString -> Int -> Maybe (TxOut, Int)
get_txout !ByteString
bs !Int
off0 = do
Bool -> Maybe ()
guard (ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
off0 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
8)
let !value :: Word64
value = ByteString -> Int -> Word64
get_word64_le ByteString
bs Int
off0
!off1 :: Int
off1 = Int
off0 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
8
(script_len, off2) <- ByteString -> Int -> Maybe (Word64, Int)
get_compact ByteString
bs Int
off1
let !slen = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
script_len
guard (BS.length bs >= off2 + slen)
let !script_pk = Int -> ByteString -> ByteString
BS.take Int
slen (Int -> ByteString -> ByteString
BS.drop Int
off2 ByteString
bs)
!off3 = Int
off2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
slen
pure (TxOut value script_pk, off3)
get_witness :: BS.ByteString -> Int -> Maybe (Witness, Int)
get_witness :: ByteString -> Int -> Maybe (Witness, Int)
get_witness !ByteString
bs !Int
off0 = do
(item_count, off1) <- ByteString -> Int -> Maybe (Word64, Int)
get_compact ByteString
bs Int
off0
(items, off2) <- get_many get_witness_item bs off1 (fromIntegral item_count)
pure (Witness items, off2)
get_witness_item :: BS.ByteString -> Int -> Maybe (BS.ByteString, Int)
get_witness_item :: ByteString -> Int -> Maybe (ByteString, Int)
get_witness_item !ByteString
bs !Int
off0 = do
(item_len, off1) <- ByteString -> Int -> Maybe (Word64, Int)
get_compact ByteString
bs Int
off0
let !ilen = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
item_len
guard (BS.length bs >= off1 + ilen)
let !item = Int -> ByteString -> ByteString
BS.take Int
ilen (Int -> ByteString -> ByteString
BS.drop Int
off1 ByteString
bs)
pure (item, off1 + ilen)
get_many :: (BS.ByteString -> Int -> Maybe (a, Int))
-> BS.ByteString -> Int -> Int -> Maybe ([a], Int)
get_many :: forall a.
(ByteString -> Int -> Maybe (a, Int))
-> ByteString -> Int -> Int -> Maybe ([a], Int)
get_many ByteString -> Int -> Maybe (a, Int)
getter !ByteString
bs = [a] -> Int -> Int -> Maybe ([a], Int)
forall {t}. (Ord t, Num t) => [a] -> Int -> t -> Maybe ([a], Int)
go []
where
go :: [a] -> Int -> t -> Maybe ([a], Int)
go ![a]
acc !Int
off !t
n
| t
n t -> t -> Bool
forall a. Ord a => a -> a -> Bool
<= t
0 = ([a], Int) -> Maybe ([a], Int)
forall a. a -> Maybe a
Just ([a] -> [a]
forall a. [a] -> [a]
reverse [a]
acc, Int
off)
| Bool
otherwise = do
(item, off') <- ByteString -> Int -> Maybe (a, Int)
getter ByteString
bs Int
off
go (item : acc) off' (n - 1)
{-# INLINE get_many #-}
txid :: Tx -> TxId
txid :: Tx -> TxId
txid Tx
tx = ByteString -> TxId
TxId (ByteString -> ByteString
SHA256.hash (ByteString -> ByteString
SHA256.hash (Tx -> ByteString
to_bytes_legacy Tx
tx)))