{-# LANGUAGE DeriveAnyClass    #-}
{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE OverloadedStrings #-}
{-|
Module      : Haskoin.Script.Common
Copyright   : No rights reserved
License     : MIT
Maintainer  : jprupp@protonmail.ch
Stability   : experimental
Portability : POSIX

Common script-related functions and data types.
-}
module Haskoin.Script.Common
    ( -- * Scripts
      ScriptOp(..)
    , Script(..)
    , PushDataType(..)
    , isPushOp
    , opPushData
    , intToScriptOp
    , scriptOpToInt
    ) where

import           Control.DeepSeq
import           Control.Monad
import           Data.Binary       (Binary (..))
import           Data.ByteString   (ByteString)
import qualified Data.ByteString   as B
import           Data.Bytes.Get
import           Data.Bytes.Put
import           Data.Bytes.Serial
import           Data.Hashable
import           Data.Serialize    (Serialize (..))
import           Data.Word         (Word8)
import           GHC.Generics      (Generic)

-- | Data type representing a transaction script. Scripts are defined as lists
-- of script operators 'ScriptOp'. Scripts are used to:
--
-- * Define the spending conditions in the output of a transaction.
-- * Provide signatures in the input of a transaction (except SegWit).
--
-- SigWit only: the segregated witness data structure, and not the input script,
-- contains signatures and redeem script for pay-to-witness-script and
-- pay-to-witness-public-key-hash transactions.
newtype Script =
    Script {
             -- | script operators defining this script
             Script -> [ScriptOp]
scriptOps :: [ScriptOp]
           }
    deriving (Script -> Script -> Bool
(Script -> Script -> Bool)
-> (Script -> Script -> Bool) -> Eq Script
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Script -> Script -> Bool
$c/= :: Script -> Script -> Bool
== :: Script -> Script -> Bool
$c== :: Script -> Script -> Bool
Eq, Int -> Script -> ShowS
[Script] -> ShowS
Script -> String
(Int -> Script -> ShowS)
-> (Script -> String) -> ([Script] -> ShowS) -> Show Script
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Script] -> ShowS
$cshowList :: [Script] -> ShowS
show :: Script -> String
$cshow :: Script -> String
showsPrec :: Int -> Script -> ShowS
$cshowsPrec :: Int -> Script -> ShowS
Show, ReadPrec [Script]
ReadPrec Script
Int -> ReadS Script
ReadS [Script]
(Int -> ReadS Script)
-> ReadS [Script]
-> ReadPrec Script
-> ReadPrec [Script]
-> Read Script
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Script]
$creadListPrec :: ReadPrec [Script]
readPrec :: ReadPrec Script
$creadPrec :: ReadPrec Script
readList :: ReadS [Script]
$creadList :: ReadS [Script]
readsPrec :: Int -> ReadS Script
$creadsPrec :: Int -> ReadS Script
Read, (forall x. Script -> Rep Script x)
-> (forall x. Rep Script x -> Script) -> Generic Script
forall x. Rep Script x -> Script
forall x. Script -> Rep Script x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Script x -> Script
$cfrom :: forall x. Script -> Rep Script x
Generic, Int -> Script -> Int
Script -> Int
(Int -> Script -> Int) -> (Script -> Int) -> Hashable Script
forall a. (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: Script -> Int
$chash :: Script -> Int
hashWithSalt :: Int -> Script -> Int
$chashWithSalt :: Int -> Script -> Int
Hashable, Script -> ()
(Script -> ()) -> NFData Script
forall a. (a -> ()) -> NFData a
rnf :: Script -> ()
$crnf :: Script -> ()
NFData)

instance Serial Script where
    deserialize :: m Script
deserialize =
        [ScriptOp] -> Script
Script ([ScriptOp] -> Script) -> m [ScriptOp] -> m Script
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m [ScriptOp]
getScriptOps
      where
        getScriptOps :: m [ScriptOp]
getScriptOps = do
            Bool
empty <- m Bool
forall (m :: * -> *). MonadGet m => m Bool
isEmpty
            if Bool
empty
                then [ScriptOp] -> m [ScriptOp]
forall (m :: * -> *) a. Monad m => a -> m a
return []
                else (:) (ScriptOp -> [ScriptOp] -> [ScriptOp])
-> m ScriptOp -> m ([ScriptOp] -> [ScriptOp])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m ScriptOp
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize m ([ScriptOp] -> [ScriptOp]) -> m [ScriptOp] -> m [ScriptOp]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> m [ScriptOp]
getScriptOps

    serialize :: Script -> m ()
serialize (Script ops :: [ScriptOp]
ops) = [ScriptOp] -> (ScriptOp -> m ()) -> m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [ScriptOp]
ops ScriptOp -> m ()
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize

instance Binary Script where
    put :: Script -> Put
put = Script -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize
    get :: Get Script
get = Get Script
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize

instance Serialize Script where
    put :: Putter Script
put = Putter Script
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize
    get :: Get Script
get = Get Script
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize

-- | Data type representing the type of an OP_PUSHDATA opcode.
data PushDataType
    =
      -- | next opcode bytes is data to be pushed
      OPCODE
      -- | next byte contains number of bytes of data to be pushed
    | OPDATA1
      -- | next two bytes contains number of bytes to be pushed
    | OPDATA2
      -- | next four bytes contains the number of bytes to be pushed
    | OPDATA4
    deriving (Int -> PushDataType -> ShowS
[PushDataType] -> ShowS
PushDataType -> String
(Int -> PushDataType -> ShowS)
-> (PushDataType -> String)
-> ([PushDataType] -> ShowS)
-> Show PushDataType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PushDataType] -> ShowS
$cshowList :: [PushDataType] -> ShowS
show :: PushDataType -> String
$cshow :: PushDataType -> String
showsPrec :: Int -> PushDataType -> ShowS
$cshowsPrec :: Int -> PushDataType -> ShowS
Show, ReadPrec [PushDataType]
ReadPrec PushDataType
Int -> ReadS PushDataType
ReadS [PushDataType]
(Int -> ReadS PushDataType)
-> ReadS [PushDataType]
-> ReadPrec PushDataType
-> ReadPrec [PushDataType]
-> Read PushDataType
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [PushDataType]
$creadListPrec :: ReadPrec [PushDataType]
readPrec :: ReadPrec PushDataType
$creadPrec :: ReadPrec PushDataType
readList :: ReadS [PushDataType]
$creadList :: ReadS [PushDataType]
readsPrec :: Int -> ReadS PushDataType
$creadsPrec :: Int -> ReadS PushDataType
Read, PushDataType -> PushDataType -> Bool
(PushDataType -> PushDataType -> Bool)
-> (PushDataType -> PushDataType -> Bool) -> Eq PushDataType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PushDataType -> PushDataType -> Bool
$c/= :: PushDataType -> PushDataType -> Bool
== :: PushDataType -> PushDataType -> Bool
$c== :: PushDataType -> PushDataType -> Bool
Eq, (forall x. PushDataType -> Rep PushDataType x)
-> (forall x. Rep PushDataType x -> PushDataType)
-> Generic PushDataType
forall x. Rep PushDataType x -> PushDataType
forall x. PushDataType -> Rep PushDataType x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep PushDataType x -> PushDataType
$cfrom :: forall x. PushDataType -> Rep PushDataType x
Generic, Int -> PushDataType -> Int
PushDataType -> Int
(Int -> PushDataType -> Int)
-> (PushDataType -> Int) -> Hashable PushDataType
forall a. (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: PushDataType -> Int
$chash :: PushDataType -> Int
hashWithSalt :: Int -> PushDataType -> Int
$chashWithSalt :: Int -> PushDataType -> Int
Hashable, PushDataType -> ()
(PushDataType -> ()) -> NFData PushDataType
forall a. (a -> ()) -> NFData a
rnf :: PushDataType -> ()
$crnf :: PushDataType -> ()
NFData)

-- | Data type representing an operator allowed inside a 'Script'.
data ScriptOp
      -- Pushing Data
    = OP_PUSHDATA !ByteString
                  !PushDataType
    | OP_0
    | OP_1NEGATE
    | OP_RESERVED
    | OP_1
    | OP_2
    | OP_3
    | OP_4
    | OP_5
    | OP_6
    | OP_7
    | OP_8
    | OP_9
    | OP_10
    | OP_11
    | OP_12
    | OP_13
    | OP_14
    | OP_15
    | OP_16
      -- Flow control
    | OP_NOP
    | OP_VER -- reserved
    | OP_IF
    | OP_NOTIF
    | OP_VERIF -- resreved
    | OP_VERNOTIF -- reserved
    | OP_ELSE
    | OP_ENDIF
    | OP_VERIFY
    | OP_RETURN
      -- Stack operations
    | OP_TOALTSTACK
    | OP_FROMALTSTACK
    | OP_IFDUP
    | OP_DEPTH
    | OP_DROP
    | OP_DUP
    | OP_NIP
    | OP_OVER
    | OP_PICK
    | OP_ROLL
    | OP_ROT
    | OP_SWAP
    | OP_TUCK
    | OP_2DROP
    | OP_2DUP
    | OP_3DUP
    | OP_2OVER
    | OP_2ROT
    | OP_2SWAP
      -- Splice
    | OP_CAT
    | OP_SUBSTR
    | OP_LEFT
    | OP_RIGHT
    | OP_SIZE
      -- Bitwise logic
    | OP_INVERT
    | OP_AND
    | OP_OR
    | OP_XOR
    | OP_EQUAL
    | OP_EQUALVERIFY
    | OP_RESERVED1
    | OP_RESERVED2
      -- Arithmetic
    | OP_1ADD
    | OP_1SUB
    | OP_2MUL
    | OP_2DIV
    | OP_NEGATE
    | OP_ABS
    | OP_NOT
    | OP_0NOTEQUAL
    | OP_ADD
    | OP_SUB
    | OP_MUL
    | OP_DIV
    | OP_MOD
    | OP_LSHIFT
    | OP_RSHIFT
    | OP_BOOLAND
    | OP_BOOLOR
    | OP_NUMEQUAL
    | OP_NUMEQUALVERIFY
    | OP_NUMNOTEQUAL
    | OP_LESSTHAN
    | OP_GREATERTHAN
    | OP_LESSTHANOREQUAL
    | OP_GREATERTHANOREQUAL
    | OP_MIN
    | OP_MAX
    | OP_WITHIN
      -- Crypto
    | OP_RIPEMD160
    | OP_SHA1
    | OP_SHA256
    | OP_HASH160
    | OP_HASH256
    | OP_CODESEPARATOR
    | OP_CHECKSIG
    | OP_CHECKSIGVERIFY
    | OP_CHECKMULTISIG
    | OP_CHECKMULTISIGVERIFY
      -- Expansion
    | OP_NOP1
    | OP_CHECKLOCKTIMEVERIFY
    | OP_CHECKSEQUENCEVERIFY
    | OP_NOP4
    | OP_NOP5
    | OP_NOP6
    | OP_NOP7
    | OP_NOP8
    | OP_NOP9
    | OP_NOP10
      -- Bitcoin Cash Nov 2018 hard fork
    | OP_CHECKDATASIG
    | OP_CHECKDATASIGVERIFY
      -- Bitcoin Cash May 2020 hard fork
    | OP_REVERSEBYTES
      -- Other
    | OP_PUBKEYHASH
    | OP_PUBKEY
    | OP_INVALIDOPCODE !Word8
    deriving (Int -> ScriptOp -> ShowS
[ScriptOp] -> ShowS
ScriptOp -> String
(Int -> ScriptOp -> ShowS)
-> (ScriptOp -> String) -> ([ScriptOp] -> ShowS) -> Show ScriptOp
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ScriptOp] -> ShowS
$cshowList :: [ScriptOp] -> ShowS
show :: ScriptOp -> String
$cshow :: ScriptOp -> String
showsPrec :: Int -> ScriptOp -> ShowS
$cshowsPrec :: Int -> ScriptOp -> ShowS
Show, ReadPrec [ScriptOp]
ReadPrec ScriptOp
Int -> ReadS ScriptOp
ReadS [ScriptOp]
(Int -> ReadS ScriptOp)
-> ReadS [ScriptOp]
-> ReadPrec ScriptOp
-> ReadPrec [ScriptOp]
-> Read ScriptOp
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [ScriptOp]
$creadListPrec :: ReadPrec [ScriptOp]
readPrec :: ReadPrec ScriptOp
$creadPrec :: ReadPrec ScriptOp
readList :: ReadS [ScriptOp]
$creadList :: ReadS [ScriptOp]
readsPrec :: Int -> ReadS ScriptOp
$creadsPrec :: Int -> ReadS ScriptOp
Read, ScriptOp -> ScriptOp -> Bool
(ScriptOp -> ScriptOp -> Bool)
-> (ScriptOp -> ScriptOp -> Bool) -> Eq ScriptOp
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ScriptOp -> ScriptOp -> Bool
$c/= :: ScriptOp -> ScriptOp -> Bool
== :: ScriptOp -> ScriptOp -> Bool
$c== :: ScriptOp -> ScriptOp -> Bool
Eq, (forall x. ScriptOp -> Rep ScriptOp x)
-> (forall x. Rep ScriptOp x -> ScriptOp) -> Generic ScriptOp
forall x. Rep ScriptOp x -> ScriptOp
forall x. ScriptOp -> Rep ScriptOp x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep ScriptOp x -> ScriptOp
$cfrom :: forall x. ScriptOp -> Rep ScriptOp x
Generic, Int -> ScriptOp -> Int
ScriptOp -> Int
(Int -> ScriptOp -> Int) -> (ScriptOp -> Int) -> Hashable ScriptOp
forall a. (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: ScriptOp -> Int
$chash :: ScriptOp -> Int
hashWithSalt :: Int -> ScriptOp -> Int
$chashWithSalt :: Int -> ScriptOp -> Int
Hashable, ScriptOp -> ()
(ScriptOp -> ()) -> NFData ScriptOp
forall a. (a -> ()) -> NFData a
rnf :: ScriptOp -> ()
$crnf :: ScriptOp -> ()
NFData)

instance Serial ScriptOp where
    deserialize :: m ScriptOp
deserialize = Word8 -> m ScriptOp
forall (m :: * -> *). MonadGet m => Word8 -> m ScriptOp
go (Word8 -> m ScriptOp) -> m Word8 -> m ScriptOp
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (Word8 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8 -> Word8) -> m Word8 -> m Word8
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m Word8
forall (m :: * -> *). MonadGet m => m Word8
getWord8)
      where
        go :: Word8 -> m ScriptOp
go op :: Word8
op
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x00 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_0
            | Word8
op Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= 0x4b = do
                ByteString
payload <- Int -> m ByteString
forall (m :: * -> *). MonadGet m => Int -> m ByteString
getByteString (Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
op)
                ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return (ScriptOp -> m ScriptOp) -> ScriptOp -> m ScriptOp
forall a b. (a -> b) -> a -> b
$ ByteString -> PushDataType -> ScriptOp
OP_PUSHDATA ByteString
payload PushDataType
OPCODE
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x4c = do
                Word8
len  <- m Word8
forall (m :: * -> *). MonadGet m => m Word8
getWord8
                ByteString
payload <- Int -> m ByteString
forall (m :: * -> *). MonadGet m => Int -> m ByteString
getByteString (Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
len)
                ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return (ScriptOp -> m ScriptOp) -> ScriptOp -> m ScriptOp
forall a b. (a -> b) -> a -> b
$ ByteString -> PushDataType -> ScriptOp
OP_PUSHDATA ByteString
payload PushDataType
OPDATA1
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x4d = do
                Word16
len  <- m Word16
forall (m :: * -> *). MonadGet m => m Word16
getWord16le
                ByteString
payload <- Int -> m ByteString
forall (m :: * -> *). MonadGet m => Int -> m ByteString
getByteString (Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
len)
                ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return (ScriptOp -> m ScriptOp) -> ScriptOp -> m ScriptOp
forall a b. (a -> b) -> a -> b
$ ByteString -> PushDataType -> ScriptOp
OP_PUSHDATA ByteString
payload PushDataType
OPDATA2
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x4e = do
                Word32
len  <- m Word32
forall (m :: * -> *). MonadGet m => m Word32
getWord32le
                ByteString
payload <- Int -> m ByteString
forall (m :: * -> *). MonadGet m => Int -> m ByteString
getByteString (Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
len)
                ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return (ScriptOp -> m ScriptOp) -> ScriptOp -> m ScriptOp
forall a b. (a -> b) -> a -> b
$ ByteString -> PushDataType -> ScriptOp
OP_PUSHDATA ByteString
payload PushDataType
OPDATA4

            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x4f = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_1NEGATE
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x50 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_RESERVED
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x51 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_1
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x52 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_2
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x53 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_3
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x54 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_4
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x55 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_5
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x56 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_6
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x57 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_7
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x58 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_8
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x59 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_9
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x5a = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_10
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x5b = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_11
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x5c = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_12
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x5d = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_13
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x5e = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_14
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x5f = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_15
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x60 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_16

            -- Flow control
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x61 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x62 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_VER        -- reserved
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x63 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_IF
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x64 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOTIF
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x65 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_VERIF      -- reserved
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x66 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_VERNOTIF   -- reserved
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x67 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_ELSE
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x68 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_ENDIF
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x69 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_VERIFY
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x6a = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_RETURN

            -- Stack
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x6b = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_TOALTSTACK
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x6c = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_FROMALTSTACK
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x6d = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_2DROP
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x6e = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_2DUP
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x6f = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_3DUP
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x70 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_2OVER
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x71 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_2ROT
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x72 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_2SWAP
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x73 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_IFDUP
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x74 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_DEPTH
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x75 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_DROP
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x76 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_DUP
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x77 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NIP
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x78 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_OVER
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x79 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_PICK
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x7a = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_ROLL
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x7b = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_ROT
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x7c = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_SWAP
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x7d = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_TUCK

            -- Splice
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x7e = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CAT
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x7f = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_SUBSTR
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x80 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_LEFT
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x81 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_RIGHT
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x82 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_SIZE

            -- Bitwise logic
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x83 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_INVERT
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x84 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_AND
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x85 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_OR
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x86 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_XOR
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x87 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_EQUAL
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x88 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_EQUALVERIFY
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x89 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_RESERVED1
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x8a = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_RESERVED2

            -- Arithmetic
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x8b = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_1ADD
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x8c = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_1SUB
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x8d = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_2MUL
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x8e = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_2DIV
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x8f = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NEGATE
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x90 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_ABS
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x91 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOT
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x92 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_0NOTEQUAL
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x93 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_ADD
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x94 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_SUB
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x95 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_MUL
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x96 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_DIV
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x97 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_MOD
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x98 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_LSHIFT
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x99 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_RSHIFT
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x9a = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_BOOLAND
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x9b = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_BOOLOR
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x9c = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NUMEQUAL
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x9d = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NUMEQUALVERIFY
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x9e = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NUMNOTEQUAL
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x9f = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_LESSTHAN
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xa0 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_GREATERTHAN
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xa1 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_LESSTHANOREQUAL
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xa2 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_GREATERTHANOREQUAL
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xa3 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_MIN
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xa4 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_MAX
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xa5 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_WITHIN

            -- Crypto
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xa6 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_RIPEMD160
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xa7 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_SHA1
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xa8 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_SHA256
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xa9 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_HASH160
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xaa = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_HASH256
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xab = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CODESEPARATOR
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xac = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CHECKSIG
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xad = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CHECKSIGVERIFY
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xae = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CHECKMULTISIG
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xaf = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CHECKMULTISIGVERIFY

            -- More NOPs
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xb0 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP1
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xb1 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CHECKLOCKTIMEVERIFY
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xb2 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CHECKSEQUENCEVERIFY
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xb3 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP4
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xb4 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP5
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xb5 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP6
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xb6 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP7
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xb7 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP8
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xb8 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP9
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xb9 = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP10

            -- Bitcoin Cash Nov 2018 hard fork
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xba = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CHECKDATASIG
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xbb = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CHECKDATASIGVERIFY

            -- Bitcoin Cash May 2020 hard fork
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xbc = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_REVERSEBYTES

            -- Constants
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xfd = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_PUBKEYHASH
            | Word8
op Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0xfe = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_PUBKEY

            | Bool
otherwise = ScriptOp -> m ScriptOp
forall (m :: * -> *) a. Monad m => a -> m a
return (ScriptOp -> m ScriptOp) -> ScriptOp -> m ScriptOp
forall a b. (a -> b) -> a -> b
$ Word8 -> ScriptOp
OP_INVALIDOPCODE Word8
op

    serialize :: ScriptOp -> m ()
serialize op :: ScriptOp
op = case ScriptOp
op of

        (OP_PUSHDATA payload :: ByteString
payload optype :: PushDataType
optype)-> do
            let len :: Int
len = ByteString -> Int
B.length ByteString
payload
            case PushDataType
optype of
                OPCODE -> do
                    Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= 0x4b) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
                        String -> m ()
forall a. HasCallStack => String -> a
error "OP_PUSHDATA OPCODE: Payload size too big"
                    Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 (Word8 -> m ()) -> Word8 -> m ()
forall a b. (a -> b) -> a -> b
$ Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len
                OPDATA1 -> do
                    Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= 0xff) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
                        String -> m ()
forall a. HasCallStack => String -> a
error "OP_PUSHDATA OPDATA1: Payload size too big"
                    Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x4c
                    Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 (Word8 -> m ()) -> Word8 -> m ()
forall a b. (a -> b) -> a -> b
$ Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len
                OPDATA2 -> do
                    Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= 0xffff) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
                        String -> m ()
forall a. HasCallStack => String -> a
error "OP_PUSHDATA OPDATA2: Payload size too big"
                    Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x4d
                    Word16 -> m ()
forall (m :: * -> *). MonadPut m => Word16 -> m ()
putWord16le (Word16 -> m ()) -> Word16 -> m ()
forall a b. (a -> b) -> a -> b
$ Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len
                OPDATA4 -> do
                    Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= 0x7fffffff) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
                        String -> m ()
forall a. HasCallStack => String -> a
error "OP_PUSHDATA OPDATA4: Payload size too big"
                    Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x4e
                    Word32 -> m ()
forall (m :: * -> *). MonadPut m => Word32 -> m ()
putWord32le (Word32 -> m ()) -> Word32 -> m ()
forall a b. (a -> b) -> a -> b
$ Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len
            ByteString -> m ()
forall (m :: * -> *). MonadPut m => ByteString -> m ()
putByteString ByteString
payload

        -- Constants
        OP_0                 -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x00
        OP_1NEGATE           -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x4f
        OP_RESERVED          -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x50
        OP_1                 -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x51
        OP_2                 -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x52
        OP_3                 -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x53
        OP_4                 -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x54
        OP_5                 -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x55
        OP_6                 -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x56
        OP_7                 -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x57
        OP_8                 -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x58
        OP_9                 -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x59
        OP_10                -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x5a
        OP_11                -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x5b
        OP_12                -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x5c
        OP_13                -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x5d
        OP_14                -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x5e
        OP_15                -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x5f
        OP_16                -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x60

        -- Crypto Constants
        OP_PUBKEY            -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xfe
        OP_PUBKEYHASH        -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xfd

        -- Invalid Opcodes
        (OP_INVALIDOPCODE x :: Word8
x) -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
x

        -- Flow Control
        OP_NOP               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x61
        OP_VER               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x62
        OP_IF                -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x63
        OP_NOTIF             -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x64
        OP_VERIF             -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x65
        OP_VERNOTIF          -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x66
        OP_ELSE              -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x67
        OP_ENDIF             -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x68
        OP_VERIFY            -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x69
        OP_RETURN            -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x6a

        -- Stack Operations
        OP_TOALTSTACK        -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x6b
        OP_FROMALTSTACK      -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x6c
        OP_2DROP             -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x6d
        OP_2DUP              -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x6e
        OP_3DUP              -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x6f
        OP_2OVER             -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x70
        OP_2ROT              -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x71
        OP_2SWAP             -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x72
        OP_IFDUP             -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x73
        OP_DEPTH             -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x74
        OP_DROP              -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x75
        OP_DUP               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x76
        OP_NIP               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x77
        OP_OVER              -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x78
        OP_PICK              -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x79
        OP_ROLL              -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x7a
        OP_ROT               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x7b
        OP_SWAP              -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x7c
        OP_TUCK              -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x7d

        -- Splice
        OP_CAT               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x7e
        OP_SUBSTR            -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x7f
        OP_LEFT              -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x80
        OP_RIGHT             -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x81
        OP_SIZE              -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x82

        -- Bitwise Logic
        OP_INVERT            -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x83
        OP_AND               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x84
        OP_OR                -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x85
        OP_XOR               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x86
        OP_EQUAL             -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x87
        OP_EQUALVERIFY       -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x88
        OP_RESERVED1         -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x89
        OP_RESERVED2         -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x8a

        -- Arithmetic
        OP_1ADD              -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x8b
        OP_1SUB              -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x8c
        OP_2MUL              -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x8d
        OP_2DIV              -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x8e
        OP_NEGATE            -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x8f
        OP_ABS               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x90
        OP_NOT               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x91
        OP_0NOTEQUAL         -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x92
        OP_ADD               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x93
        OP_SUB               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x94
        OP_MUL               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x95
        OP_DIV               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x96
        OP_MOD               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x97
        OP_LSHIFT            -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x98
        OP_RSHIFT            -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x99
        OP_BOOLAND           -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x9a
        OP_BOOLOR            -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x9b
        OP_NUMEQUAL          -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x9c
        OP_NUMEQUALVERIFY    -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x9d
        OP_NUMNOTEQUAL       -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x9e
        OP_LESSTHAN          -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0x9f
        OP_GREATERTHAN       -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xa0
        OP_LESSTHANOREQUAL   -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xa1
        OP_GREATERTHANOREQUAL-> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xa2
        OP_MIN               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xa3
        OP_MAX               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xa4
        OP_WITHIN            -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xa5

        -- Crypto
        OP_RIPEMD160           -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xa6
        OP_SHA1                -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xa7
        OP_SHA256              -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xa8
        OP_HASH160             -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xa9
        OP_HASH256             -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xaa
        OP_CODESEPARATOR       -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xab
        OP_CHECKSIG            -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xac
        OP_CHECKSIGVERIFY      -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xad
        OP_CHECKMULTISIG       -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xae
        OP_CHECKMULTISIGVERIFY -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xaf

        -- More NOPs
        OP_NOP1                -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xb0
        OP_CHECKLOCKTIMEVERIFY -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xb1
        OP_CHECKSEQUENCEVERIFY -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xb2
        OP_NOP4                -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xb3
        OP_NOP5                -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xb4
        OP_NOP6                -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xb5
        OP_NOP7                -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xb6
        OP_NOP8                -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xb7
        OP_NOP9                -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xb8
        OP_NOP10               -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xb9

        -- Bitcoin Cash Nov 2018 hard fork
        OP_CHECKDATASIG       -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xba
        OP_CHECKDATASIGVERIFY -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xbb

        -- Bitcoin Cash May 2020 hard fork
        OP_REVERSEBYTES      -> Word8 -> m ()
forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 0xbc

instance Binary ScriptOp where
    put :: ScriptOp -> Put
put = ScriptOp -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize
    get :: Get ScriptOp
get = Get ScriptOp
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize

instance Serialize ScriptOp where
    put :: Putter ScriptOp
put = Putter ScriptOp
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize
    get :: Get ScriptOp
get = Get ScriptOp
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize

-- | Check whether opcode is only data.
isPushOp :: ScriptOp -> Bool
isPushOp :: ScriptOp -> Bool
isPushOp op :: ScriptOp
op = case ScriptOp
op of
    OP_PUSHDATA _ _ -> Bool
True
    OP_0            -> Bool
True
    OP_1NEGATE      -> Bool
True
    OP_1            -> Bool
True
    OP_2            -> Bool
True
    OP_3            -> Bool
True
    OP_4            -> Bool
True
    OP_5            -> Bool
True
    OP_6            -> Bool
True
    OP_7            -> Bool
True
    OP_8            -> Bool
True
    OP_9            -> Bool
True
    OP_10           -> Bool
True
    OP_11           -> Bool
True
    OP_12           -> Bool
True
    OP_13           -> Bool
True
    OP_14           -> Bool
True
    OP_15           -> Bool
True
    OP_16           -> Bool
True
    _               -> Bool
False

-- | Optimally encode data using one of the 4 types of data pushing opcodes.
opPushData :: ByteString -> ScriptOp
opPushData :: ByteString -> ScriptOp
opPushData bs :: ByteString
bs
    | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= 0x4b       = ByteString -> PushDataType -> ScriptOp
OP_PUSHDATA ByteString
bs PushDataType
OPCODE
    | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= 0xff       = ByteString -> PushDataType -> ScriptOp
OP_PUSHDATA ByteString
bs PushDataType
OPDATA1
    | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= 0xffff     = ByteString -> PushDataType -> ScriptOp
OP_PUSHDATA ByteString
bs PushDataType
OPDATA2
    | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= 0xffffffff = ByteString -> PushDataType -> ScriptOp
OP_PUSHDATA ByteString
bs PushDataType
OPDATA4
    | Bool
otherwise         = String -> ScriptOp
forall a. HasCallStack => String -> a
error "opPushData: payload size too big"
  where
    len :: Int
len = ByteString -> Int
B.length ByteString
bs

-- | Transforms integers @[1 .. 16]@ to 'ScriptOp' @[OP_1 .. OP_16]@.
intToScriptOp :: Int -> ScriptOp
intToScriptOp :: Int -> ScriptOp
intToScriptOp i :: Int
i
    | Int
i Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [1 .. 16] = ScriptOp
op
    | Bool
otherwise = ScriptOp
forall a. a
err
  where
    op :: ScriptOp
op = (String -> ScriptOp)
-> (ScriptOp -> ScriptOp) -> Either String ScriptOp -> ScriptOp
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either
        (ScriptOp -> String -> ScriptOp
forall a b. a -> b -> a
const ScriptOp
forall a. a
err)
        ScriptOp -> ScriptOp
forall a. a -> a
id (Either String ScriptOp -> ScriptOp)
-> (Int -> Either String ScriptOp) -> Int -> ScriptOp
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
        Get ScriptOp -> ByteString -> Either String ScriptOp
forall a. Get a -> ByteString -> Either String a
runGetS Get ScriptOp
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize (ByteString -> Either String ScriptOp)
-> (Int -> ByteString) -> Int -> Either String ScriptOp
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
        Word8 -> ByteString
B.singleton (Word8 -> ByteString) -> (Int -> Word8) -> Int -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
        Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> ScriptOp) -> Int -> ScriptOp
forall a b. (a -> b) -> a -> b
$
        Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 0x50
    err :: a
err = String -> a
forall a. HasCallStack => String -> a
error (String -> a) -> String -> a
forall a b. (a -> b) -> a -> b
$ "intToScriptOp: Invalid integer " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
i

-- | Decode 'ScriptOp' @[OP_1 .. OP_16]@ to integers @[1 .. 16]@. This functions
-- fails for other values of 'ScriptOp'
scriptOpToInt :: ScriptOp -> Either String Int
scriptOpToInt :: ScriptOp -> Either String Int
scriptOpToInt s :: ScriptOp
s
    | Int
res Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [1..16] = Int -> Either String Int
forall (m :: * -> *) a. Monad m => a -> m a
return Int
res
    | Bool
otherwise          = String -> Either String Int
forall a b. a -> Either a b
Left (String -> Either String Int) -> String -> Either String Int
forall a b. (a -> b) -> a -> b
$ "scriptOpToInt: invalid opcode " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ScriptOp -> String
forall a. Show a => a -> String
show ScriptOp
s
  where
    res :: Int
res = Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Word8
B.head (ByteString -> Word8) -> ByteString -> Word8
forall a b. (a -> b) -> a -> b
$ Put -> ByteString
runPutS (Put -> ByteString) -> Put -> ByteString
forall a b. (a -> b) -> a -> b
$ Putter ScriptOp
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize ScriptOp
s) Int -> Int -> Int
forall a. Num a => a -> a -> a
- 0x50