{-# OPTIONS_HADDOCK prune #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveGeneric #-}
module Lightning.Protocol.BOLT3.Decode (
DecodeError(..)
, RawTx(..)
, RawInput(..)
, RawOutput(..)
, decode_tx
, decode_witness
, decode_varint
, decode_le32
, decode_le64
, decode_outpoint
, decode_output
) where
import Data.Bits ((.|.), shiftL)
import Data.Word (Word8, Word32, Word64)
import qualified Data.ByteString as BS
import GHC.Generics (Generic)
import Lightning.Protocol.BOLT3.Types
data DecodeError
= InsufficientBytes !Int !Int
| InvalidMarker !Word8
| InvalidFlag !Word8
| InvalidVarint
| EmptyInput
deriving (DecodeError -> DecodeError -> Bool
(DecodeError -> DecodeError -> Bool)
-> (DecodeError -> DecodeError -> Bool) -> Eq DecodeError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DecodeError -> DecodeError -> Bool
== :: DecodeError -> DecodeError -> Bool
$c/= :: DecodeError -> DecodeError -> Bool
/= :: DecodeError -> DecodeError -> Bool
Eq, Int -> DecodeError -> ShowS
[DecodeError] -> ShowS
DecodeError -> String
(Int -> DecodeError -> ShowS)
-> (DecodeError -> String)
-> ([DecodeError] -> ShowS)
-> Show DecodeError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DecodeError -> ShowS
showsPrec :: Int -> DecodeError -> ShowS
$cshow :: DecodeError -> String
show :: DecodeError -> String
$cshowList :: [DecodeError] -> ShowS
showList :: [DecodeError] -> ShowS
Show, (forall x. DecodeError -> Rep DecodeError x)
-> (forall x. Rep DecodeError x -> DecodeError)
-> Generic DecodeError
forall x. Rep DecodeError x -> DecodeError
forall x. DecodeError -> Rep DecodeError x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. DecodeError -> Rep DecodeError x
from :: forall x. DecodeError -> Rep DecodeError x
$cto :: forall x. Rep DecodeError x -> DecodeError
to :: forall x. Rep DecodeError x -> DecodeError
Generic)
data RawInput = RawInput
{ RawInput -> Outpoint
ri_outpoint :: !Outpoint
, RawInput -> ByteString
ri_script_sig :: !BS.ByteString
, RawInput -> Sequence
ri_sequence :: !Sequence
} deriving (RawInput -> RawInput -> Bool
(RawInput -> RawInput -> Bool)
-> (RawInput -> RawInput -> Bool) -> Eq RawInput
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: RawInput -> RawInput -> Bool
== :: RawInput -> RawInput -> Bool
$c/= :: RawInput -> RawInput -> Bool
/= :: RawInput -> RawInput -> Bool
Eq, Int -> RawInput -> ShowS
[RawInput] -> ShowS
RawInput -> String
(Int -> RawInput -> ShowS)
-> (RawInput -> String) -> ([RawInput] -> ShowS) -> Show RawInput
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RawInput -> ShowS
showsPrec :: Int -> RawInput -> ShowS
$cshow :: RawInput -> String
show :: RawInput -> String
$cshowList :: [RawInput] -> ShowS
showList :: [RawInput] -> ShowS
Show, (forall x. RawInput -> Rep RawInput x)
-> (forall x. Rep RawInput x -> RawInput) -> Generic RawInput
forall x. Rep RawInput x -> RawInput
forall x. RawInput -> Rep RawInput x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. RawInput -> Rep RawInput x
from :: forall x. RawInput -> Rep RawInput x
$cto :: forall x. Rep RawInput x -> RawInput
to :: forall x. Rep RawInput x -> RawInput
Generic)
data RawOutput = RawOutput
{ RawOutput -> Satoshi
ro_value :: !Satoshi
, RawOutput -> Script
ro_script :: !Script
} deriving (RawOutput -> RawOutput -> Bool
(RawOutput -> RawOutput -> Bool)
-> (RawOutput -> RawOutput -> Bool) -> Eq RawOutput
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: RawOutput -> RawOutput -> Bool
== :: RawOutput -> RawOutput -> Bool
$c/= :: RawOutput -> RawOutput -> Bool
/= :: RawOutput -> RawOutput -> Bool
Eq, Int -> RawOutput -> ShowS
[RawOutput] -> ShowS
RawOutput -> String
(Int -> RawOutput -> ShowS)
-> (RawOutput -> String)
-> ([RawOutput] -> ShowS)
-> Show RawOutput
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RawOutput -> ShowS
showsPrec :: Int -> RawOutput -> ShowS
$cshow :: RawOutput -> String
show :: RawOutput -> String
$cshowList :: [RawOutput] -> ShowS
showList :: [RawOutput] -> ShowS
Show, (forall x. RawOutput -> Rep RawOutput x)
-> (forall x. Rep RawOutput x -> RawOutput) -> Generic RawOutput
forall x. Rep RawOutput x -> RawOutput
forall x. RawOutput -> Rep RawOutput x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. RawOutput -> Rep RawOutput x
from :: forall x. RawOutput -> Rep RawOutput x
$cto :: forall x. Rep RawOutput x -> RawOutput
to :: forall x. Rep RawOutput x -> RawOutput
Generic)
data RawTx = RawTx
{ RawTx -> Word32
rtx_version :: {-# UNPACK #-} !Word32
, RawTx -> [RawInput]
rtx_inputs :: ![RawInput]
, RawTx -> [RawOutput]
rtx_outputs :: ![RawOutput]
, RawTx -> [[ByteString]]
rtx_witness :: ![[BS.ByteString]]
, RawTx -> Locktime
rtx_locktime :: !Locktime
} deriving (RawTx -> RawTx -> Bool
(RawTx -> RawTx -> Bool) -> (RawTx -> RawTx -> Bool) -> Eq RawTx
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: RawTx -> RawTx -> Bool
== :: RawTx -> RawTx -> Bool
$c/= :: RawTx -> RawTx -> Bool
/= :: RawTx -> RawTx -> Bool
Eq, Int -> RawTx -> ShowS
[RawTx] -> ShowS
RawTx -> String
(Int -> RawTx -> ShowS)
-> (RawTx -> String) -> ([RawTx] -> ShowS) -> Show RawTx
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RawTx -> ShowS
showsPrec :: Int -> RawTx -> ShowS
$cshow :: RawTx -> String
show :: RawTx -> String
$cshowList :: [RawTx] -> ShowS
showList :: [RawTx] -> ShowS
Show, (forall x. RawTx -> Rep RawTx x)
-> (forall x. Rep RawTx x -> RawTx) -> Generic RawTx
forall x. Rep RawTx x -> RawTx
forall x. RawTx -> Rep RawTx x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. RawTx -> Rep RawTx x
from :: forall x. RawTx -> Rep RawTx x
$cto :: forall x. Rep RawTx x -> RawTx
to :: forall x. Rep RawTx x -> RawTx
Generic)
decode_le32 :: BS.ByteString -> Either DecodeError (Word32, BS.ByteString)
decode_le32 :: ByteString -> Either DecodeError (Word32, ByteString)
decode_le32 !ByteString
bs
| ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
4 = DecodeError -> Either DecodeError (Word32, ByteString)
forall a b. a -> Either a b
Left (Int -> Int -> DecodeError
InsufficientBytes Int
4 (ByteString -> Int
BS.length ByteString
bs))
| Bool
otherwise =
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
0)
!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
1)
!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
2)
!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
3)
!val :: Word32
val = 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)
!rest :: ByteString
rest = Int -> ByteString -> ByteString
BS.drop Int
4 ByteString
bs
in (Word32, ByteString) -> Either DecodeError (Word32, ByteString)
forall a b. b -> Either a b
Right (Word32
val, ByteString
rest)
{-# INLINE decode_le32 #-}
decode_le64 :: BS.ByteString -> Either DecodeError (Word64, BS.ByteString)
decode_le64 :: ByteString -> Either DecodeError (Word64, ByteString)
decode_le64 !ByteString
bs
| ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
8 = DecodeError -> Either DecodeError (Word64, ByteString)
forall a b. a -> Either a b
Left (Int -> Int -> DecodeError
InsufficientBytes Int
8 (ByteString -> Int
BS.length ByteString
bs))
| Bool
otherwise =
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
0)
!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
1)
!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
2)
!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
3)
!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
4)
!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
5)
!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
6)
!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
7)
!val :: Word64
val = 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)
!rest :: ByteString
rest = Int -> ByteString -> ByteString
BS.drop Int
8 ByteString
bs
in (Word64, ByteString) -> Either DecodeError (Word64, ByteString)
forall a b. b -> Either a b
Right (Word64
val, ByteString
rest)
{-# INLINE decode_le64 #-}
decode_varint :: BS.ByteString -> Either DecodeError (Word64, BS.ByteString)
decode_varint :: ByteString -> Either DecodeError (Word64, ByteString)
decode_varint !ByteString
bs
| ByteString -> Bool
BS.null ByteString
bs = DecodeError -> Either DecodeError (Word64, ByteString)
forall a b. a -> Either a b
Left DecodeError
EmptyInput
| Bool
otherwise =
let !first :: Word8
first = HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs Int
0
!rest :: ByteString
rest = Int -> ByteString -> ByteString
BS.drop Int
1 ByteString
bs
in case Word8
first of
Word8
0xFD -> ByteString -> Either DecodeError (Word64, ByteString)
decode_varint_16 ByteString
rest
Word8
0xFE -> ByteString -> Either DecodeError (Word64, ByteString)
decode_varint_32 ByteString
rest
Word8
0xFF -> ByteString -> Either DecodeError (Word64, ByteString)
decode_le64 ByteString
rest
Word8
_ -> (Word64, ByteString) -> Either DecodeError (Word64, ByteString)
forall a b. b -> Either a b
Right (Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
first, ByteString
rest)
{-# INLINE decode_varint #-}
decode_varint_16 :: BS.ByteString -> Either DecodeError (Word64, BS.ByteString)
decode_varint_16 :: ByteString -> Either DecodeError (Word64, ByteString)
decode_varint_16 !ByteString
bs
| ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
2 = DecodeError -> Either DecodeError (Word64, ByteString)
forall a b. a -> Either a b
Left (Int -> Int -> DecodeError
InsufficientBytes Int
2 (ByteString -> Int
BS.length ByteString
bs))
| Bool
otherwise =
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
0) :: 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
1) :: Word64
!val :: Word64
val = 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)
!rest :: ByteString
rest = Int -> ByteString -> ByteString
BS.drop Int
2 ByteString
bs
in (Word64, ByteString) -> Either DecodeError (Word64, ByteString)
forall a b. b -> Either a b
Right (Word64
val, ByteString
rest)
{-# INLINE decode_varint_16 #-}
decode_varint_32 :: BS.ByteString -> Either DecodeError (Word64, BS.ByteString)
decode_varint_32 :: ByteString -> Either DecodeError (Word64, ByteString)
decode_varint_32 !ByteString
bs
| ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
4 = DecodeError -> Either DecodeError (Word64, ByteString)
forall a b. a -> Either a b
Left (Int -> Int -> DecodeError
InsufficientBytes Int
4 (ByteString -> Int
BS.length ByteString
bs))
| Bool
otherwise =
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
0) :: 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
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
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
3) :: Word64
!val :: Word64
val = 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)
!rest :: ByteString
rest = Int -> ByteString -> ByteString
BS.drop Int
4 ByteString
bs
in (Word64, ByteString) -> Either DecodeError (Word64, ByteString)
forall a b. b -> Either a b
Right (Word64
val, ByteString
rest)
{-# INLINE decode_varint_32 #-}
decode_outpoint
:: BS.ByteString
-> Either DecodeError (Outpoint, BS.ByteString)
decode_outpoint :: ByteString -> Either DecodeError (Outpoint, ByteString)
decode_outpoint !ByteString
bs
| ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
36 = DecodeError -> Either DecodeError (Outpoint, ByteString)
forall a b. a -> Either a b
Left (Int -> Int -> DecodeError
InsufficientBytes Int
36 (ByteString -> Int
BS.length ByteString
bs))
| Bool
otherwise =
let !txid :: TxId
txid = ByteString -> TxId
TxId (Int -> ByteString -> ByteString
BS.take Int
32 ByteString
bs)
!rest1 :: ByteString
rest1 = Int -> ByteString -> ByteString
BS.drop Int
32 ByteString
bs
in case ByteString -> Either DecodeError (Word32, ByteString)
decode_le32 ByteString
rest1 of
Left DecodeError
err -> DecodeError -> Either DecodeError (Outpoint, ByteString)
forall a b. a -> Either a b
Left DecodeError
err
Right (!Word32
idx, !ByteString
rest2) ->
let !outpoint :: Outpoint
outpoint = TxId -> Word32 -> Outpoint
Outpoint TxId
txid Word32
idx
in (Outpoint, ByteString) -> Either DecodeError (Outpoint, ByteString)
forall a b. b -> Either a b
Right (Outpoint
outpoint, ByteString
rest2)
{-# INLINE decode_outpoint #-}
decode_output :: BS.ByteString -> Either DecodeError (RawOutput, BS.ByteString)
decode_output :: ByteString -> Either DecodeError (RawOutput, ByteString)
decode_output !ByteString
bs = do
(!value, !rest1) <- ByteString -> Either DecodeError (Word64, ByteString)
decode_le64 ByteString
bs
(!scriptLen, !rest2) <- decode_varint rest1
let !len = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
scriptLen
if BS.length rest2 < len
then Left (InsufficientBytes len (BS.length rest2))
else
let !script = ByteString -> Script
Script (Int -> ByteString -> ByteString
BS.take Int
len ByteString
rest2)
!rest3 = Int -> ByteString -> ByteString
BS.drop Int
len ByteString
rest2
!output = Satoshi -> Script -> RawOutput
RawOutput (Word64 -> Satoshi
Satoshi Word64
value) Script
script
in Right (output, rest3)
{-# INLINE decode_output #-}
decode_witness
:: BS.ByteString
-> Either DecodeError (Witness, BS.ByteString)
decode_witness :: ByteString -> Either DecodeError (Witness, ByteString)
decode_witness !ByteString
bs = do
(!numItems, !rest1) <- ByteString -> Either DecodeError (Word64, ByteString)
decode_varint ByteString
bs
(!items, !rest2) <- decode_witness_items (fromIntegral numItems) rest1 []
Right (Witness items, rest2)
{-# INLINE decode_witness #-}
decode_witness_items
:: Int
-> BS.ByteString
-> [BS.ByteString]
-> Either DecodeError ([BS.ByteString], BS.ByteString)
decode_witness_items :: Int
-> ByteString
-> [ByteString]
-> Either DecodeError ([ByteString], ByteString)
decode_witness_items Int
0 !ByteString
bs ![ByteString]
acc = ([ByteString], ByteString)
-> Either DecodeError ([ByteString], ByteString)
forall a b. b -> Either a b
Right ([ByteString] -> [ByteString]
forall a. [a] -> [a]
reverse [ByteString]
acc, ByteString
bs)
decode_witness_items !Int
n !ByteString
bs ![ByteString]
acc = do
(!itemLen, !rest1) <- ByteString -> Either DecodeError (Word64, ByteString)
decode_varint ByteString
bs
let !len = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
itemLen
if BS.length rest1 < len
then Left (InsufficientBytes len (BS.length rest1))
else
let !item = Int -> ByteString -> ByteString
BS.take Int
len ByteString
rest1
!rest2 = Int -> ByteString -> ByteString
BS.drop Int
len ByteString
rest1
in decode_witness_items (n - 1) rest2 (item : acc)
decode_witness_stacks
:: Int
-> BS.ByteString
-> [[BS.ByteString]]
-> Either DecodeError ([[BS.ByteString]], BS.ByteString)
decode_witness_stacks :: Int
-> ByteString
-> [[ByteString]]
-> Either DecodeError ([[ByteString]], ByteString)
decode_witness_stacks Int
0 !ByteString
bs ![[ByteString]]
acc = ([[ByteString]], ByteString)
-> Either DecodeError ([[ByteString]], ByteString)
forall a b. b -> Either a b
Right ([[ByteString]] -> [[ByteString]]
forall a. [a] -> [a]
reverse [[ByteString]]
acc, ByteString
bs)
decode_witness_stacks !Int
n !ByteString
bs ![[ByteString]]
acc = do
(Witness !items, !rest) <- ByteString -> Either DecodeError (Witness, ByteString)
decode_witness ByteString
bs
decode_witness_stacks (n - 1) rest (items : acc)
decode_tx :: BS.ByteString -> Either DecodeError RawTx
decode_tx :: ByteString -> Either DecodeError RawTx
decode_tx !ByteString
bs = do
(!version, !rest1) <- ByteString -> Either DecodeError (Word32, ByteString)
decode_le32 ByteString
bs
let !hasWitness = ByteString -> Int
BS.length ByteString
rest1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
2 Bool -> Bool -> Bool
&&
HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
rest1 Int
0 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
rest1 Int
1 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x01
if hasWitness
then decode_tx_segwit version (BS.drop 2 rest1)
else decode_tx_legacy version rest1
{-# INLINE decode_tx #-}
decode_tx_segwit
:: Word32
-> BS.ByteString
-> Either DecodeError RawTx
decode_tx_segwit :: Word32 -> ByteString -> Either DecodeError RawTx
decode_tx_segwit !Word32
version !ByteString
bs = do
(!inputCount, !rest1) <- ByteString -> Either DecodeError (Word64, ByteString)
decode_varint ByteString
bs
(!inputs, !rest2) <- decode_inputs (fromIntegral inputCount) rest1 []
(!outputCount, !rest3) <- decode_varint rest2
(!outputs, !rest4) <- decode_outputs (fromIntegral outputCount) rest3 []
(!witnesses, !rest5) <- decode_witness_stacks (length inputs) rest4 []
(!locktime, !_rest6) <- decode_le32 rest5
Right RawTx
{ rtx_version = version
, rtx_inputs = inputs
, rtx_outputs = outputs
, rtx_witness = witnesses
, rtx_locktime = Locktime locktime
}
decode_tx_legacy
:: Word32
-> BS.ByteString
-> Either DecodeError RawTx
decode_tx_legacy :: Word32 -> ByteString -> Either DecodeError RawTx
decode_tx_legacy !Word32
version !ByteString
bs = do
(!inputCount, !rest1) <- ByteString -> Either DecodeError (Word64, ByteString)
decode_varint ByteString
bs
(!inputs, !rest2) <- decode_inputs (fromIntegral inputCount) rest1 []
(!outputCount, !rest3) <- decode_varint rest2
(!outputs, !rest4) <- decode_outputs (fromIntegral outputCount) rest3 []
(!locktime, !_rest5) <- decode_le32 rest4
Right RawTx
{ rtx_version = version
, rtx_inputs = inputs
, rtx_outputs = outputs
, rtx_witness = []
, rtx_locktime = Locktime locktime
}
decode_inputs
:: Int
-> BS.ByteString
-> [RawInput]
-> Either DecodeError ([RawInput], BS.ByteString)
decode_inputs :: Int
-> ByteString
-> [RawInput]
-> Either DecodeError ([RawInput], ByteString)
decode_inputs Int
0 !ByteString
bs ![RawInput]
acc = ([RawInput], ByteString)
-> Either DecodeError ([RawInput], ByteString)
forall a b. b -> Either a b
Right ([RawInput] -> [RawInput]
forall a. [a] -> [a]
reverse [RawInput]
acc, ByteString
bs)
decode_inputs !Int
n !ByteString
bs ![RawInput]
acc = do
(!input, !rest) <- ByteString -> Either DecodeError (RawInput, ByteString)
decode_input ByteString
bs
decode_inputs (n - 1) rest (input : acc)
decode_input :: BS.ByteString -> Either DecodeError (RawInput, BS.ByteString)
decode_input :: ByteString -> Either DecodeError (RawInput, ByteString)
decode_input !ByteString
bs = do
(!outpoint, !rest1) <- ByteString -> Either DecodeError (Outpoint, ByteString)
decode_outpoint ByteString
bs
(!scriptLen, !rest2) <- decode_varint rest1
let !len = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
scriptLen
if BS.length rest2 < len
then Left (InsufficientBytes len (BS.length rest2))
else do
let !scriptSig = Int -> ByteString -> ByteString
BS.take Int
len ByteString
rest2
!rest3 = Int -> ByteString -> ByteString
BS.drop Int
len ByteString
rest2
(!seqNum, !rest4) <- decode_le32 rest3
let !input = Outpoint -> ByteString -> Sequence -> RawInput
RawInput Outpoint
outpoint ByteString
scriptSig (Word32 -> Sequence
Sequence Word32
seqNum)
Right (input, rest4)
decode_outputs
:: Int
-> BS.ByteString
-> [RawOutput]
-> Either DecodeError ([RawOutput], BS.ByteString)
decode_outputs :: Int
-> ByteString
-> [RawOutput]
-> Either DecodeError ([RawOutput], ByteString)
decode_outputs Int
0 !ByteString
bs ![RawOutput]
acc = ([RawOutput], ByteString)
-> Either DecodeError ([RawOutput], ByteString)
forall a b. b -> Either a b
Right ([RawOutput] -> [RawOutput]
forall a. [a] -> [a]
reverse [RawOutput]
acc, ByteString
bs)
decode_outputs !Int
n !ByteString
bs ![RawOutput]
acc = do
(!output, !rest) <- ByteString -> Either DecodeError (RawOutput, ByteString)
decode_output ByteString
bs
decode_outputs (n - 1) rest (output : acc)