{-# 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.Either (fromRight)
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
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
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]
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. 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, Eq Script
Int -> Script -> Int
Script -> Int
forall a. Eq a -> (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: Script -> Int
$chash :: Script -> Int
hashWithSalt :: Int -> Script -> Int
$chashWithSalt :: Int -> Script -> Int
Hashable, Script -> ()
forall a. (a -> ()) -> NFData a
rnf :: Script -> ()
$crnf :: Script -> ()
NFData)

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

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

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

instance Serialize Script where
    put :: Putter Script
put = forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize
    get :: Get Script
get = 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
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]
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
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. 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, Eq PushDataType
Int -> PushDataType -> Int
PushDataType -> Int
forall a. Eq a -> (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: PushDataType -> Int
$chash :: PushDataType -> Int
hashWithSalt :: Int -> PushDataType -> Int
$chashWithSalt :: Int -> PushDataType -> Int
Hashable, 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
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]
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
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. 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, Eq ScriptOp
Int -> ScriptOp -> Int
ScriptOp -> Int
forall a. Eq a -> (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: ScriptOp -> Int
$chash :: ScriptOp -> Int
hashWithSalt :: Int -> ScriptOp -> Int
$chashWithSalt :: Int -> ScriptOp -> Int
Hashable, ScriptOp -> ()
forall a. (a -> ()) -> NFData a
rnf :: ScriptOp -> ()
$crnf :: ScriptOp -> ()
NFData)

instance Serial ScriptOp where
    deserialize :: forall (m :: * -> *). MonadGet m => m ScriptOp
deserialize = forall {m :: * -> *}. MonadGet m => Word8 -> m ScriptOp
go forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (Integral a, Num b) => a -> b
fromIntegral forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (m :: * -> *). MonadGet m => m Word8
getWord8
      where
        go :: Word8 -> m ScriptOp
go Word8
op
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x00 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_0
            | Word8
op forall a. Ord a => a -> a -> Bool
<= Word8
0x4b = do
                ByteString
payload <- forall (m :: * -> *). MonadGet m => Int -> m ByteString
getByteString (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
op)
                forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ ByteString -> PushDataType -> ScriptOp
OP_PUSHDATA ByteString
payload PushDataType
OPCODE
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x4c = do
                Word8
len <- forall (m :: * -> *). MonadGet m => m Word8
getWord8
                ByteString
payload <- forall (m :: * -> *). MonadGet m => Int -> m ByteString
getByteString (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
len)
                forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ ByteString -> PushDataType -> ScriptOp
OP_PUSHDATA ByteString
payload PushDataType
OPDATA1
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x4d = do
                Word16
len <- forall (m :: * -> *). MonadGet m => m Word16
getWord16le
                ByteString
payload <- forall (m :: * -> *). MonadGet m => Int -> m ByteString
getByteString (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
len)
                forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ ByteString -> PushDataType -> ScriptOp
OP_PUSHDATA ByteString
payload PushDataType
OPDATA2
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x4e = do
                Word32
len <- forall (m :: * -> *). MonadGet m => m Word32
getWord32le
                ByteString
payload <- forall (m :: * -> *). MonadGet m => Int -> m ByteString
getByteString (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
len)
                forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ ByteString -> PushDataType -> ScriptOp
OP_PUSHDATA ByteString
payload PushDataType
OPDATA4
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x4f = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_1NEGATE
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x50 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_RESERVED
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x51 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_1
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x52 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_2
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x53 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_3
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x54 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_4
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x55 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_5
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x56 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_6
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x57 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_7
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x58 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_8
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x59 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_9
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x5a = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_10
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x5b = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_11
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x5c = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_12
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x5d = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_13
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x5e = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_14
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x5f = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_15
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x60 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_16
            -- Flow control
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x61 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x62 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_VER -- reserved
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x63 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_IF
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x64 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOTIF
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x65 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_VERIF -- reserved
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x66 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_VERNOTIF -- reserved
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x67 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_ELSE
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x68 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_ENDIF
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x69 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_VERIFY
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x6a = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_RETURN
            -- Stack
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x6b = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_TOALTSTACK
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x6c = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_FROMALTSTACK
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x6d = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_2DROP
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x6e = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_2DUP
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x6f = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_3DUP
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x70 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_2OVER
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x71 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_2ROT
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x72 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_2SWAP
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x73 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_IFDUP
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x74 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_DEPTH
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x75 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_DROP
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x76 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_DUP
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x77 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NIP
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x78 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_OVER
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x79 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_PICK
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x7a = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_ROLL
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x7b = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_ROT
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x7c = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_SWAP
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x7d = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_TUCK
            -- Splice
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x7e = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CAT
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x7f = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_SUBSTR
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x80 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_LEFT
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x81 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_RIGHT
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x82 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_SIZE
            -- Bitwise logic
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x83 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_INVERT
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x84 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_AND
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x85 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_OR
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x86 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_XOR
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x87 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_EQUAL
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x88 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_EQUALVERIFY
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x89 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_RESERVED1
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x8a = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_RESERVED2
            -- Arithmetic
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x8b = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_1ADD
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x8c = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_1SUB
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x8d = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_2MUL
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x8e = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_2DIV
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x8f = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NEGATE
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x90 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_ABS
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x91 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOT
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x92 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_0NOTEQUAL
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x93 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_ADD
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x94 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_SUB
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x95 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_MUL
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x96 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_DIV
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x97 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_MOD
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x98 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_LSHIFT
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x99 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_RSHIFT
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x9a = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_BOOLAND
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x9b = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_BOOLOR
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x9c = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NUMEQUAL
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x9d = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NUMEQUALVERIFY
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x9e = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NUMNOTEQUAL
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0x9f = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_LESSTHAN
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xa0 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_GREATERTHAN
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xa1 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_LESSTHANOREQUAL
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xa2 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_GREATERTHANOREQUAL
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xa3 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_MIN
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xa4 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_MAX
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xa5 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_WITHIN
            -- Crypto
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xa6 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_RIPEMD160
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xa7 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_SHA1
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xa8 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_SHA256
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xa9 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_HASH160
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xaa = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_HASH256
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xab = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CODESEPARATOR
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xac = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CHECKSIG
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xad = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CHECKSIGVERIFY
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xae = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CHECKMULTISIG
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xaf = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CHECKMULTISIGVERIFY
            -- More NOPs
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xb0 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP1
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xb1 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CHECKLOCKTIMEVERIFY
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xb2 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CHECKSEQUENCEVERIFY
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xb3 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP4
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xb4 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP5
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xb5 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP6
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xb6 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP7
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xb7 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP8
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xb8 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP9
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xb9 = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_NOP10
            -- Bitcoin Cash Nov 2018 hard fork
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xba = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CHECKDATASIG
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xbb = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_CHECKDATASIGVERIFY
            -- Bitcoin Cash May 2020 hard fork
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xbc = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_REVERSEBYTES
            -- Constants
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xfd = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_PUBKEYHASH
            | Word8
op forall a. Eq a => a -> a -> Bool
== Word8
0xfe = forall (m :: * -> *) a. Monad m => a -> m a
return ScriptOp
OP_PUBKEY
            | Bool
otherwise = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Word8 -> ScriptOp
OP_INVALIDOPCODE Word8
op

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

        -- Constants
        ScriptOp
OP_0 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x00
        ScriptOp
OP_1NEGATE -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x4f
        ScriptOp
OP_RESERVED -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x50
        ScriptOp
OP_1 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x51
        ScriptOp
OP_2 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x52
        ScriptOp
OP_3 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x53
        ScriptOp
OP_4 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x54
        ScriptOp
OP_5 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x55
        ScriptOp
OP_6 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x56
        ScriptOp
OP_7 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x57
        ScriptOp
OP_8 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x58
        ScriptOp
OP_9 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x59
        ScriptOp
OP_10 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x5a
        ScriptOp
OP_11 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x5b
        ScriptOp
OP_12 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x5c
        ScriptOp
OP_13 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x5d
        ScriptOp
OP_14 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x5e
        ScriptOp
OP_15 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x5f
        ScriptOp
OP_16 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x60
        -- Crypto Constants
        ScriptOp
OP_PUBKEY -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xfe
        ScriptOp
OP_PUBKEYHASH -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xfd
        -- Invalid Opcodes
        (OP_INVALIDOPCODE Word8
x) -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
x
        -- Flow Control
        ScriptOp
OP_NOP -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x61
        ScriptOp
OP_VER -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x62
        ScriptOp
OP_IF -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x63
        ScriptOp
OP_NOTIF -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x64
        ScriptOp
OP_VERIF -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x65
        ScriptOp
OP_VERNOTIF -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x66
        ScriptOp
OP_ELSE -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x67
        ScriptOp
OP_ENDIF -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x68
        ScriptOp
OP_VERIFY -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x69
        ScriptOp
OP_RETURN -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x6a
        -- Stack Operations
        ScriptOp
OP_TOALTSTACK -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x6b
        ScriptOp
OP_FROMALTSTACK -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x6c
        ScriptOp
OP_2DROP -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x6d
        ScriptOp
OP_2DUP -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x6e
        ScriptOp
OP_3DUP -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x6f
        ScriptOp
OP_2OVER -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x70
        ScriptOp
OP_2ROT -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x71
        ScriptOp
OP_2SWAP -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x72
        ScriptOp
OP_IFDUP -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x73
        ScriptOp
OP_DEPTH -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x74
        ScriptOp
OP_DROP -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x75
        ScriptOp
OP_DUP -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x76
        ScriptOp
OP_NIP -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x77
        ScriptOp
OP_OVER -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x78
        ScriptOp
OP_PICK -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x79
        ScriptOp
OP_ROLL -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x7a
        ScriptOp
OP_ROT -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x7b
        ScriptOp
OP_SWAP -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x7c
        ScriptOp
OP_TUCK -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x7d
        -- Splice
        ScriptOp
OP_CAT -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x7e
        ScriptOp
OP_SUBSTR -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x7f
        ScriptOp
OP_LEFT -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x80
        ScriptOp
OP_RIGHT -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x81
        ScriptOp
OP_SIZE -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x82
        -- Bitwise Logic
        ScriptOp
OP_INVERT -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x83
        ScriptOp
OP_AND -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x84
        ScriptOp
OP_OR -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x85
        ScriptOp
OP_XOR -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x86
        ScriptOp
OP_EQUAL -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x87
        ScriptOp
OP_EQUALVERIFY -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x88
        ScriptOp
OP_RESERVED1 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x89
        ScriptOp
OP_RESERVED2 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x8a
        -- Arithmetic
        ScriptOp
OP_1ADD -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x8b
        ScriptOp
OP_1SUB -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x8c
        ScriptOp
OP_2MUL -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x8d
        ScriptOp
OP_2DIV -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x8e
        ScriptOp
OP_NEGATE -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x8f
        ScriptOp
OP_ABS -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x90
        ScriptOp
OP_NOT -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x91
        ScriptOp
OP_0NOTEQUAL -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x92
        ScriptOp
OP_ADD -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x93
        ScriptOp
OP_SUB -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x94
        ScriptOp
OP_MUL -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x95
        ScriptOp
OP_DIV -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x96
        ScriptOp
OP_MOD -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x97
        ScriptOp
OP_LSHIFT -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x98
        ScriptOp
OP_RSHIFT -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x99
        ScriptOp
OP_BOOLAND -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x9a
        ScriptOp
OP_BOOLOR -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x9b
        ScriptOp
OP_NUMEQUAL -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x9c
        ScriptOp
OP_NUMEQUALVERIFY -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x9d
        ScriptOp
OP_NUMNOTEQUAL -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x9e
        ScriptOp
OP_LESSTHAN -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0x9f
        ScriptOp
OP_GREATERTHAN -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xa0
        ScriptOp
OP_LESSTHANOREQUAL -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xa1
        ScriptOp
OP_GREATERTHANOREQUAL -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xa2
        ScriptOp
OP_MIN -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xa3
        ScriptOp
OP_MAX -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xa4
        ScriptOp
OP_WITHIN -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xa5
        -- Crypto
        ScriptOp
OP_RIPEMD160 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xa6
        ScriptOp
OP_SHA1 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xa7
        ScriptOp
OP_SHA256 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xa8
        ScriptOp
OP_HASH160 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xa9
        ScriptOp
OP_HASH256 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xaa
        ScriptOp
OP_CODESEPARATOR -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xab
        ScriptOp
OP_CHECKSIG -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xac
        ScriptOp
OP_CHECKSIGVERIFY -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xad
        ScriptOp
OP_CHECKMULTISIG -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xae
        ScriptOp
OP_CHECKMULTISIGVERIFY -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xaf
        -- More NOPs
        ScriptOp
OP_NOP1 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xb0
        ScriptOp
OP_CHECKLOCKTIMEVERIFY -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xb1
        ScriptOp
OP_CHECKSEQUENCEVERIFY -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xb2
        ScriptOp
OP_NOP4 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xb3
        ScriptOp
OP_NOP5 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xb4
        ScriptOp
OP_NOP6 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xb5
        ScriptOp
OP_NOP7 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xb6
        ScriptOp
OP_NOP8 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xb7
        ScriptOp
OP_NOP9 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xb8
        ScriptOp
OP_NOP10 -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xb9
        -- Bitcoin Cash Nov 2018 hard fork
        ScriptOp
OP_CHECKDATASIG -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xba
        ScriptOp
OP_CHECKDATASIGVERIFY -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xbb
        -- Bitcoin Cash May 2020 hard fork
        ScriptOp
OP_REVERSEBYTES -> forall (m :: * -> *). MonadPut m => Word8 -> m ()
putWord8 Word8
0xbc

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

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

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

-- | Optimally encode data using one of the 4 types of data pushing opcodes.
opPushData :: ByteString -> ScriptOp
opPushData :: ByteString -> ScriptOp
opPushData ByteString
bs
    | Int
len forall a. Ord a => a -> a -> Bool
<= Int
0x4b = ByteString -> PushDataType -> ScriptOp
OP_PUSHDATA ByteString
bs PushDataType
OPCODE
    | Int
len forall a. Ord a => a -> a -> Bool
<= Int
0xff = ByteString -> PushDataType -> ScriptOp
OP_PUSHDATA ByteString
bs PushDataType
OPDATA1
    | Int
len forall a. Ord a => a -> a -> Bool
<= Int
0xffff = ByteString -> PushDataType -> ScriptOp
OP_PUSHDATA ByteString
bs PushDataType
OPDATA2
    | Int
len forall a. Ord a => a -> a -> Bool
<= Int
0xffffffff = ByteString -> PushDataType -> ScriptOp
OP_PUSHDATA ByteString
bs PushDataType
OPDATA4
    | Bool
otherwise = forall a. HasCallStack => String -> a
error String
"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 Int
i
    | Int
i forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int
1 .. Int
16] = ScriptOp
op
    | Bool
otherwise = forall {a}. a
err
  where
    op :: ScriptOp
op =
        forall b a. b -> Either a b -> b
fromRight forall {a}. a
err
            forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Get a -> ByteString -> Either String a
runGetS forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize
            forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> ByteString
B.singleton
            forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (Integral a, Num b) => a -> b
fromIntegral
            forall a b. (a -> b) -> a -> b
$ Int
i forall a. Num a => a -> a -> a
+ Int
0x50
    err :: a
err = forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ String
"intToScriptOp: Invalid integer " forall a. [a] -> [a] -> [a]
++ 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 ScriptOp
s
    | Int
res forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int
1 .. Int
16] = forall (m :: * -> *) a. Monad m => a -> m a
return Int
res
    | Bool
otherwise = forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ String
"scriptOpToInt: invalid opcode " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show ScriptOp
s
  where
    res :: Int
res = forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Word8
B.head forall a b. (a -> b) -> a -> b
$ Put -> ByteString
runPutS forall a b. (a -> b) -> a -> b
$ forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize ScriptOp
s) forall a. Num a => a -> a -> a
- Int
0x50