packages feed

bitcoin-script 0.9.1 → 0.10.0

raw patch · 7 files changed

+576/−578 lines, 7 filesdep −hspec-expectationsPVP ok

version bump matches the API change (PVP)

Dependencies removed: hspec-expectations

API changes (from Hackage documentation)

- Bitcoin.Script: OPCODE :: PushDataType
- Bitcoin.Script: OPDATA1 :: PushDataType
- Bitcoin.Script: OPDATA2 :: PushDataType
- Bitcoin.Script: OPDATA4 :: PushDataType
- Bitcoin.Script: OP_0 :: ScriptOp
- Bitcoin.Script: OP_0NOTEQUAL :: ScriptOp
- Bitcoin.Script: OP_1 :: ScriptOp
- Bitcoin.Script: OP_10 :: ScriptOp
- Bitcoin.Script: OP_11 :: ScriptOp
- Bitcoin.Script: OP_12 :: ScriptOp
- Bitcoin.Script: OP_13 :: ScriptOp
- Bitcoin.Script: OP_14 :: ScriptOp
- Bitcoin.Script: OP_15 :: ScriptOp
- Bitcoin.Script: OP_16 :: ScriptOp
- Bitcoin.Script: OP_1ADD :: ScriptOp
- Bitcoin.Script: OP_1NEGATE :: ScriptOp
- Bitcoin.Script: OP_1SUB :: ScriptOp
- Bitcoin.Script: OP_2 :: ScriptOp
- Bitcoin.Script: OP_2DIV :: ScriptOp
- Bitcoin.Script: OP_2DROP :: ScriptOp
- Bitcoin.Script: OP_2DUP :: ScriptOp
- Bitcoin.Script: OP_2MUL :: ScriptOp
- Bitcoin.Script: OP_2OVER :: ScriptOp
- Bitcoin.Script: OP_2ROT :: ScriptOp
- Bitcoin.Script: OP_2SWAP :: ScriptOp
- Bitcoin.Script: OP_3 :: ScriptOp
- Bitcoin.Script: OP_3DUP :: ScriptOp
- Bitcoin.Script: OP_4 :: ScriptOp
- Bitcoin.Script: OP_5 :: ScriptOp
- Bitcoin.Script: OP_6 :: ScriptOp
- Bitcoin.Script: OP_7 :: ScriptOp
- Bitcoin.Script: OP_8 :: ScriptOp
- Bitcoin.Script: OP_9 :: ScriptOp
- Bitcoin.Script: OP_ABS :: ScriptOp
- Bitcoin.Script: OP_ADD :: ScriptOp
- Bitcoin.Script: OP_AND :: ScriptOp
- Bitcoin.Script: OP_BOOLAND :: ScriptOp
- Bitcoin.Script: OP_BOOLOR :: ScriptOp
- Bitcoin.Script: OP_CAT :: ScriptOp
- Bitcoin.Script: OP_CHECKMULTISIG :: ScriptOp
- Bitcoin.Script: OP_CHECKMULTISIGVERIFY :: ScriptOp
- Bitcoin.Script: OP_CHECKSIG :: ScriptOp
- Bitcoin.Script: OP_CHECKSIGVERIFY :: ScriptOp
- Bitcoin.Script: OP_CODESEPARATOR :: ScriptOp
- Bitcoin.Script: OP_DEPTH :: ScriptOp
- Bitcoin.Script: OP_DIV :: ScriptOp
- Bitcoin.Script: OP_DROP :: ScriptOp
- Bitcoin.Script: OP_DUP :: ScriptOp
- Bitcoin.Script: OP_ELSE :: ScriptOp
- Bitcoin.Script: OP_ENDIF :: ScriptOp
- Bitcoin.Script: OP_EQUAL :: ScriptOp
- Bitcoin.Script: OP_EQUALVERIFY :: ScriptOp
- Bitcoin.Script: OP_FROMALTSTACK :: ScriptOp
- Bitcoin.Script: OP_GREATERTHAN :: ScriptOp
- Bitcoin.Script: OP_GREATERTHANOREQUAL :: ScriptOp
- Bitcoin.Script: OP_HASH160 :: ScriptOp
- Bitcoin.Script: OP_HASH256 :: ScriptOp
- Bitcoin.Script: OP_IF :: ScriptOp
- Bitcoin.Script: OP_IFDUP :: ScriptOp
- Bitcoin.Script: OP_INVALIDOPCODE :: !Word8 -> ScriptOp
- Bitcoin.Script: OP_INVERT :: ScriptOp
- Bitcoin.Script: OP_LEFT :: ScriptOp
- Bitcoin.Script: OP_LESSTHAN :: ScriptOp
- Bitcoin.Script: OP_LESSTHANOREQUAL :: ScriptOp
- Bitcoin.Script: OP_LSHIFT :: ScriptOp
- Bitcoin.Script: OP_MAX :: ScriptOp
- Bitcoin.Script: OP_MIN :: ScriptOp
- Bitcoin.Script: OP_MOD :: ScriptOp
- Bitcoin.Script: OP_MUL :: ScriptOp
- Bitcoin.Script: OP_NEGATE :: ScriptOp
- Bitcoin.Script: OP_NIP :: ScriptOp
- Bitcoin.Script: OP_NOP :: ScriptOp
- Bitcoin.Script: OP_NOP1 :: ScriptOp
- Bitcoin.Script: OP_NOP10 :: ScriptOp
- Bitcoin.Script: OP_NOP2 :: ScriptOp
- Bitcoin.Script: OP_NOP3 :: ScriptOp
- Bitcoin.Script: OP_NOP4 :: ScriptOp
- Bitcoin.Script: OP_NOP5 :: ScriptOp
- Bitcoin.Script: OP_NOP6 :: ScriptOp
- Bitcoin.Script: OP_NOP7 :: ScriptOp
- Bitcoin.Script: OP_NOP8 :: ScriptOp
- Bitcoin.Script: OP_NOP9 :: ScriptOp
- Bitcoin.Script: OP_NOT :: ScriptOp
- Bitcoin.Script: OP_NOTIF :: ScriptOp
- Bitcoin.Script: OP_NUMEQUAL :: ScriptOp
- Bitcoin.Script: OP_NUMEQUALVERIFY :: ScriptOp
- Bitcoin.Script: OP_NUMNOTEQUAL :: ScriptOp
- Bitcoin.Script: OP_OR :: ScriptOp
- Bitcoin.Script: OP_OVER :: ScriptOp
- Bitcoin.Script: OP_PICK :: ScriptOp
- Bitcoin.Script: OP_PUBKEY :: ScriptOp
- Bitcoin.Script: OP_PUBKEYHASH :: ScriptOp
- Bitcoin.Script: OP_PUSHDATA :: !ByteString -> !PushDataType -> ScriptOp
- Bitcoin.Script: OP_RESERVED :: ScriptOp
- Bitcoin.Script: OP_RESERVED1 :: ScriptOp
- Bitcoin.Script: OP_RESERVED2 :: ScriptOp
- Bitcoin.Script: OP_RETURN :: ScriptOp
- Bitcoin.Script: OP_RIGHT :: ScriptOp
- Bitcoin.Script: OP_RIPEMD160 :: ScriptOp
- Bitcoin.Script: OP_ROLL :: ScriptOp
- Bitcoin.Script: OP_ROT :: ScriptOp
- Bitcoin.Script: OP_RSHIFT :: ScriptOp
- Bitcoin.Script: OP_SHA1 :: ScriptOp
- Bitcoin.Script: OP_SHA256 :: ScriptOp
- Bitcoin.Script: OP_SIZE :: ScriptOp
- Bitcoin.Script: OP_SUB :: ScriptOp
- Bitcoin.Script: OP_SUBSTR :: ScriptOp
- Bitcoin.Script: OP_SWAP :: ScriptOp
- Bitcoin.Script: OP_TOALTSTACK :: ScriptOp
- Bitcoin.Script: OP_TUCK :: ScriptOp
- Bitcoin.Script: OP_VER :: ScriptOp
- Bitcoin.Script: OP_VERIF :: ScriptOp
- Bitcoin.Script: OP_VERIFY :: ScriptOp
- Bitcoin.Script: OP_VERNOTIF :: ScriptOp
- Bitcoin.Script: OP_WITHIN :: ScriptOp
- Bitcoin.Script: OP_XOR :: ScriptOp
- Bitcoin.Script: Script :: ![ScriptOp] -> Script
- Bitcoin.Script: data PushDataType
- Bitcoin.Script: data Script
- Bitcoin.Script: data ScriptOp
- Bitcoin.Script: decode :: ByteString -> Script
- Bitcoin.Script: encode :: Script -> ByteString
- Bitcoin.Script: scriptOps :: Script -> ![ScriptOp]
+ Network.Bitcoin.Script: OPCODE :: PushDataType
+ Network.Bitcoin.Script: OPDATA1 :: PushDataType
+ Network.Bitcoin.Script: OPDATA2 :: PushDataType
+ Network.Bitcoin.Script: OPDATA4 :: PushDataType
+ Network.Bitcoin.Script: OP_0 :: ScriptOp
+ Network.Bitcoin.Script: OP_0NOTEQUAL :: ScriptOp
+ Network.Bitcoin.Script: OP_1 :: ScriptOp
+ Network.Bitcoin.Script: OP_10 :: ScriptOp
+ Network.Bitcoin.Script: OP_11 :: ScriptOp
+ Network.Bitcoin.Script: OP_12 :: ScriptOp
+ Network.Bitcoin.Script: OP_13 :: ScriptOp
+ Network.Bitcoin.Script: OP_14 :: ScriptOp
+ Network.Bitcoin.Script: OP_15 :: ScriptOp
+ Network.Bitcoin.Script: OP_16 :: ScriptOp
+ Network.Bitcoin.Script: OP_1ADD :: ScriptOp
+ Network.Bitcoin.Script: OP_1NEGATE :: ScriptOp
+ Network.Bitcoin.Script: OP_1SUB :: ScriptOp
+ Network.Bitcoin.Script: OP_2 :: ScriptOp
+ Network.Bitcoin.Script: OP_2DIV :: ScriptOp
+ Network.Bitcoin.Script: OP_2DROP :: ScriptOp
+ Network.Bitcoin.Script: OP_2DUP :: ScriptOp
+ Network.Bitcoin.Script: OP_2MUL :: ScriptOp
+ Network.Bitcoin.Script: OP_2OVER :: ScriptOp
+ Network.Bitcoin.Script: OP_2ROT :: ScriptOp
+ Network.Bitcoin.Script: OP_2SWAP :: ScriptOp
+ Network.Bitcoin.Script: OP_3 :: ScriptOp
+ Network.Bitcoin.Script: OP_3DUP :: ScriptOp
+ Network.Bitcoin.Script: OP_4 :: ScriptOp
+ Network.Bitcoin.Script: OP_5 :: ScriptOp
+ Network.Bitcoin.Script: OP_6 :: ScriptOp
+ Network.Bitcoin.Script: OP_7 :: ScriptOp
+ Network.Bitcoin.Script: OP_8 :: ScriptOp
+ Network.Bitcoin.Script: OP_9 :: ScriptOp
+ Network.Bitcoin.Script: OP_ABS :: ScriptOp
+ Network.Bitcoin.Script: OP_ADD :: ScriptOp
+ Network.Bitcoin.Script: OP_AND :: ScriptOp
+ Network.Bitcoin.Script: OP_BOOLAND :: ScriptOp
+ Network.Bitcoin.Script: OP_BOOLOR :: ScriptOp
+ Network.Bitcoin.Script: OP_CAT :: ScriptOp
+ Network.Bitcoin.Script: OP_CHECKMULTISIG :: ScriptOp
+ Network.Bitcoin.Script: OP_CHECKMULTISIGVERIFY :: ScriptOp
+ Network.Bitcoin.Script: OP_CHECKSIG :: ScriptOp
+ Network.Bitcoin.Script: OP_CHECKSIGVERIFY :: ScriptOp
+ Network.Bitcoin.Script: OP_CODESEPARATOR :: ScriptOp
+ Network.Bitcoin.Script: OP_DEPTH :: ScriptOp
+ Network.Bitcoin.Script: OP_DIV :: ScriptOp
+ Network.Bitcoin.Script: OP_DROP :: ScriptOp
+ Network.Bitcoin.Script: OP_DUP :: ScriptOp
+ Network.Bitcoin.Script: OP_ELSE :: ScriptOp
+ Network.Bitcoin.Script: OP_ENDIF :: ScriptOp
+ Network.Bitcoin.Script: OP_EQUAL :: ScriptOp
+ Network.Bitcoin.Script: OP_EQUALVERIFY :: ScriptOp
+ Network.Bitcoin.Script: OP_FROMALTSTACK :: ScriptOp
+ Network.Bitcoin.Script: OP_GREATERTHAN :: ScriptOp
+ Network.Bitcoin.Script: OP_GREATERTHANOREQUAL :: ScriptOp
+ Network.Bitcoin.Script: OP_HASH160 :: ScriptOp
+ Network.Bitcoin.Script: OP_HASH256 :: ScriptOp
+ Network.Bitcoin.Script: OP_IF :: ScriptOp
+ Network.Bitcoin.Script: OP_IFDUP :: ScriptOp
+ Network.Bitcoin.Script: OP_INVALIDOPCODE :: !Word8 -> ScriptOp
+ Network.Bitcoin.Script: OP_INVERT :: ScriptOp
+ Network.Bitcoin.Script: OP_LEFT :: ScriptOp
+ Network.Bitcoin.Script: OP_LESSTHAN :: ScriptOp
+ Network.Bitcoin.Script: OP_LESSTHANOREQUAL :: ScriptOp
+ Network.Bitcoin.Script: OP_LSHIFT :: ScriptOp
+ Network.Bitcoin.Script: OP_MAX :: ScriptOp
+ Network.Bitcoin.Script: OP_MIN :: ScriptOp
+ Network.Bitcoin.Script: OP_MOD :: ScriptOp
+ Network.Bitcoin.Script: OP_MUL :: ScriptOp
+ Network.Bitcoin.Script: OP_NEGATE :: ScriptOp
+ Network.Bitcoin.Script: OP_NIP :: ScriptOp
+ Network.Bitcoin.Script: OP_NOP :: ScriptOp
+ Network.Bitcoin.Script: OP_NOP1 :: ScriptOp
+ Network.Bitcoin.Script: OP_NOP10 :: ScriptOp
+ Network.Bitcoin.Script: OP_NOP2 :: ScriptOp
+ Network.Bitcoin.Script: OP_NOP3 :: ScriptOp
+ Network.Bitcoin.Script: OP_NOP4 :: ScriptOp
+ Network.Bitcoin.Script: OP_NOP5 :: ScriptOp
+ Network.Bitcoin.Script: OP_NOP6 :: ScriptOp
+ Network.Bitcoin.Script: OP_NOP7 :: ScriptOp
+ Network.Bitcoin.Script: OP_NOP8 :: ScriptOp
+ Network.Bitcoin.Script: OP_NOP9 :: ScriptOp
+ Network.Bitcoin.Script: OP_NOT :: ScriptOp
+ Network.Bitcoin.Script: OP_NOTIF :: ScriptOp
+ Network.Bitcoin.Script: OP_NUMEQUAL :: ScriptOp
+ Network.Bitcoin.Script: OP_NUMEQUALVERIFY :: ScriptOp
+ Network.Bitcoin.Script: OP_NUMNOTEQUAL :: ScriptOp
+ Network.Bitcoin.Script: OP_OR :: ScriptOp
+ Network.Bitcoin.Script: OP_OVER :: ScriptOp
+ Network.Bitcoin.Script: OP_PICK :: ScriptOp
+ Network.Bitcoin.Script: OP_PUBKEY :: ScriptOp
+ Network.Bitcoin.Script: OP_PUBKEYHASH :: ScriptOp
+ Network.Bitcoin.Script: OP_PUSHDATA :: !ByteString -> !PushDataType -> ScriptOp
+ Network.Bitcoin.Script: OP_RESERVED :: ScriptOp
+ Network.Bitcoin.Script: OP_RESERVED1 :: ScriptOp
+ Network.Bitcoin.Script: OP_RESERVED2 :: ScriptOp
+ Network.Bitcoin.Script: OP_RETURN :: ScriptOp
+ Network.Bitcoin.Script: OP_RIGHT :: ScriptOp
+ Network.Bitcoin.Script: OP_RIPEMD160 :: ScriptOp
+ Network.Bitcoin.Script: OP_ROLL :: ScriptOp
+ Network.Bitcoin.Script: OP_ROT :: ScriptOp
+ Network.Bitcoin.Script: OP_RSHIFT :: ScriptOp
+ Network.Bitcoin.Script: OP_SHA1 :: ScriptOp
+ Network.Bitcoin.Script: OP_SHA256 :: ScriptOp
+ Network.Bitcoin.Script: OP_SIZE :: ScriptOp
+ Network.Bitcoin.Script: OP_SUB :: ScriptOp
+ Network.Bitcoin.Script: OP_SUBSTR :: ScriptOp
+ Network.Bitcoin.Script: OP_SWAP :: ScriptOp
+ Network.Bitcoin.Script: OP_TOALTSTACK :: ScriptOp
+ Network.Bitcoin.Script: OP_TUCK :: ScriptOp
+ Network.Bitcoin.Script: OP_VER :: ScriptOp
+ Network.Bitcoin.Script: OP_VERIF :: ScriptOp
+ Network.Bitcoin.Script: OP_VERIFY :: ScriptOp
+ Network.Bitcoin.Script: OP_VERNOTIF :: ScriptOp
+ Network.Bitcoin.Script: OP_WITHIN :: ScriptOp
+ Network.Bitcoin.Script: OP_XOR :: ScriptOp
+ Network.Bitcoin.Script: Script :: ![ScriptOp] -> Script
+ Network.Bitcoin.Script: data PushDataType
+ Network.Bitcoin.Script: data Script
+ Network.Bitcoin.Script: data ScriptOp
+ Network.Bitcoin.Script: decode :: ByteString -> Script
+ Network.Bitcoin.Script: encode :: Script -> ByteString
+ Network.Bitcoin.Script: scriptOps :: Script -> ![ScriptOp]

Files

bitcoin-script.cabal view
@@ -1,6 +1,6 @@ name: bitcoin-script
 category: Network, Finance
-version: 0.9.1
+version: 0.10.0
 license: MIT
 license-file: LICENSE
 copyright: (c) 2015 Leon Mergen
@@ -28,9 +28,9 @@   ghc-options:         -Wall -ferror-spans
   default-language:    Haskell2010
 
-  exposed-modules:     Bitcoin.Script
+  exposed-modules:     Network.Bitcoin.Script
 
-  other-modules:       Bitcoin.Script.Types 
+  other-modules:       Network.Bitcoin.Script.Types 
   
   build-depends:       base                     >= 4.3          && < 5
                      , text
@@ -45,13 +45,12 @@   hs-source-dirs:      test
   main-is:             Main.hs
 
-  other-modules:       Bitcoin.ScriptSpec
+  other-modules:       Network.Bitcoin.ScriptSpec
                        Spec
                        Main
 
   build-depends:       base                     >= 4.3          && < 5
                      , hspec
-                     , hspec-expectations
 
                      , bytestring
                      , bitcoin-script
− src/Bitcoin/Script.hs
@@ -1,21 +0,0 @@-module Bitcoin.Script ( decode
-                      , encode
-                      , ScriptOp (..)
-                      , Script (..)
-                      , PushDataType (..) ) where
-
-import qualified Data.Binary                 as B
-import qualified Data.ByteString.Base16.Lazy as BS16L
-import qualified Data.ByteString.Lazy        as BSL
-
-import           Bitcoin.Script.Types
-
--- | Decodes a hex representation of a script into a 'Script' object.
-decode :: BSL.ByteString -> Script
-decode =
-  B.decode . fst . BS16L.decode
-
--- | Encodes a 'Script' object into a hex representation
-encode :: Script -> BSL.ByteString
-encode =
-  BS16L.encode . B.encode
− src/Bitcoin/Script/Types.hs
@@ -1,528 +0,0 @@-module Bitcoin.Script.Types
-( ScriptOp(..)
-, Script(..)
-, PushDataType(..)
-, isPushOp
-, opPushData
-) where
-
-import Control.Monad (liftM2, unless, forM_)
-import Control.Applicative ((<$>))
-
-import Data.Word (Word8)
-import Data.Binary (Binary, get, put)
-import Data.Binary.Get
-    ( isEmpty
-    , getWord8
-    , getWord16le
-    , getWord32le
-    , getByteString
-    )
-import Data.Binary.Put
-    ( putWord8
-    , putWord16le
-    , putWord32le
-    , putByteString
-    )
-import qualified Data.ByteString as BS
-    ( ByteString
-    , length
-    )
-
--- | 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 the spending signatures in the input of a transaction
-data Script =
-    Script {
-             -- | List of script operators defining this script
-             scriptOps :: ![ScriptOp]
-           }
-    deriving (Eq, Show, Read)
-
-instance Binary Script where
-    get =
-        Script <$> getScriptOps
-      where
-        getScriptOps = do
-            empty <- isEmpty
-            if empty
-                then return []
-                else liftM2 (:) get getScriptOps
-
-    put (Script ops) = forM_ ops put
-
--- | Data type representing the type of an OP_PUSHDATA opcode.
-data PushDataType
-    =
-      -- | The next opcode bytes is data to be pushed onto the stack
-      OPCODE
-      -- | The next byte contains the number of bytes to be pushed onto
-      -- the stack
-    | OPDATA1
-      -- | The next two bytes contains the number of bytes to be pushed onto
-      -- the stack
-    | OPDATA2
-      -- | The next four bytes contains the number of bytes to be pushed onto
-      -- the stack
-    | OPDATA4
-    deriving (Show, Read, Eq)
-
--- | Data type representing all of the operators allowed inside a 'Script'.
-data ScriptOp
-      -- Pushing Data
-    = OP_PUSHDATA !BS.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_NOP2 | OP_NOP3 | OP_NOP4 | OP_NOP5
-    | OP_NOP6 | OP_NOP7 | OP_NOP8 | OP_NOP9 | OP_NOP10
-
-
-      -- Other
-    | OP_PUBKEYHASH
-    | OP_PUBKEY
-    | OP_INVALIDOPCODE !Word8
-
-        deriving (Show, Read, Eq)
-
-instance Binary ScriptOp where
-
-    get = go =<< (fromIntegral <$> getWord8)
-      where
-        go op
-            | op == 0x00 = return OP_0
-            | op <= 0x4b = do
-                payload <- getByteString (fromIntegral op)
-                return $ OP_PUSHDATA payload OPCODE
-            | op == 0x4c = do
-                len  <- getWord8
-                payload <- getByteString (fromIntegral len)
-                return $ OP_PUSHDATA payload OPDATA1
-            | op == 0x4d = do
-                len  <- getWord16le
-                payload <- getByteString (fromIntegral len)
-                return $ OP_PUSHDATA payload OPDATA2
-            | op == 0x4e = do
-                len  <- getWord32le
-                payload <- getByteString (fromIntegral len)
-                return $ OP_PUSHDATA payload OPDATA4
-
-            | op == 0x4f = return OP_1NEGATE
-            | op == 0x50 = return OP_RESERVED
-            | op == 0x51 = return OP_1
-            | op == 0x52 = return OP_2
-            | op == 0x53 = return OP_3
-            | op == 0x54 = return OP_4
-            | op == 0x55 = return OP_5
-            | op == 0x56 = return OP_6
-            | op == 0x57 = return OP_7
-            | op == 0x58 = return OP_8
-            | op == 0x59 = return OP_9
-            | op == 0x5a = return OP_10
-            | op == 0x5b = return OP_11
-            | op == 0x5c = return OP_12
-            | op == 0x5d = return OP_13
-            | op == 0x5e = return OP_14
-            | op == 0x5f = return OP_15
-            | op == 0x60 = return OP_16
-            -- Flow control
-            | op == 0x61 = return OP_NOP
-            | op == 0x62 = return OP_VER        -- reserved
-            | op == 0x63 = return OP_IF
-            | op == 0x64 = return OP_NOTIF
-            | op == 0x65 = return OP_VERIF      -- reserved
-            | op == 0x66 = return OP_VERNOTIF   -- reserved
-            | op == 0x67 = return OP_ELSE
-            | op == 0x68 = return OP_ENDIF
-            | op == 0x69 = return OP_VERIFY
-            | op == 0x6a = return OP_RETURN
-
-            -- Stack
-            | op == 0x6b = return OP_TOALTSTACK
-            | op == 0x6c = return OP_FROMALTSTACK
-            | op == 0x6d = return OP_2DROP
-            | op == 0x6e = return OP_2DUP
-            | op == 0x6f = return OP_3DUP
-            | op == 0x70 = return OP_2OVER
-            | op == 0x71 = return OP_2ROT
-            | op == 0x72 = return OP_2SWAP
-            | op == 0x73 = return OP_IFDUP
-            | op == 0x74 = return OP_DEPTH
-            | op == 0x75 = return OP_DROP
-            | op == 0x76 = return OP_DUP
-            | op == 0x77 = return OP_NIP
-            | op == 0x78 = return OP_OVER
-            | op == 0x79 = return OP_PICK
-            | op == 0x7a = return OP_ROLL
-            | op == 0x7b = return OP_ROT
-            | op == 0x7c = return OP_SWAP
-            | op == 0x7d = return OP_TUCK
-
-            -- Splice
-            | op == 0x7e = return OP_CAT
-            | op == 0x7f = return OP_SUBSTR
-            | op == 0x80 = return OP_LEFT
-            | op == 0x81 = return OP_RIGHT
-            | op == 0x82 = return OP_SIZE
-
-            -- Bitwise logic
-            | op == 0x83 = return OP_INVERT
-            | op == 0x84 = return OP_AND
-            | op == 0x85 = return OP_OR
-            | op == 0x86 = return OP_XOR
-            | op == 0x87 = return OP_EQUAL
-            | op == 0x88 = return OP_EQUALVERIFY
-            | op == 0x89 = return OP_RESERVED1
-            | op == 0x8a = return OP_RESERVED2
-
-            -- Arithmetic
-            | op == 0x8b = return OP_1ADD
-            | op == 0x8c = return OP_1SUB
-            | op == 0x8d = return OP_2MUL
-            | op == 0x8e = return OP_2DIV
-            | op == 0x8f = return OP_NEGATE
-            | op == 0x90 = return OP_ABS
-            | op == 0x91 = return OP_NOT
-            | op == 0x92 = return OP_0NOTEQUAL
-            | op == 0x93 = return OP_ADD
-            | op == 0x94 = return OP_SUB
-            | op == 0x95 = return OP_MUL
-            | op == 0x96 = return OP_DIV
-            | op == 0x97 = return OP_MOD
-            | op == 0x98 = return OP_LSHIFT
-            | op == 0x99 = return OP_RSHIFT
-            | op == 0x9a = return OP_BOOLAND
-            | op == 0x9b = return OP_BOOLOR
-            | op == 0x9c = return OP_NUMEQUAL
-            | op == 0x9d = return OP_NUMEQUALVERIFY
-            | op == 0x9e = return OP_NUMNOTEQUAL
-            | op == 0x9f = return OP_LESSTHAN
-            | op == 0xa0 = return OP_GREATERTHAN
-            | op == 0xa1 = return OP_LESSTHANOREQUAL
-            | op == 0xa2 = return OP_GREATERTHANOREQUAL
-            | op == 0xa3 = return OP_MIN
-            | op == 0xa4 = return OP_MAX
-            | op == 0xa5 = return OP_WITHIN
-
-            -- Crypto
-            | op == 0xa6 = return OP_RIPEMD160
-            | op == 0xa7 = return OP_SHA1
-            | op == 0xa8 = return OP_SHA256
-            | op == 0xa9 = return OP_HASH160
-            | op == 0xaa = return OP_HASH256
-            | op == 0xab = return OP_CODESEPARATOR
-            | op == 0xac = return OP_CHECKSIG
-            | op == 0xad = return OP_CHECKSIGVERIFY
-            | op == 0xae = return OP_CHECKMULTISIG
-            | op == 0xaf = return OP_CHECKMULTISIGVERIFY
-
-            -- More NOPs
-            | op == 0xb0 = return OP_NOP1
-            | op == 0xb1 = return OP_NOP2
-            | op == 0xb2 = return OP_NOP3
-            | op == 0xb3 = return OP_NOP4
-            | op == 0xb4 = return OP_NOP5
-            | op == 0xb5 = return OP_NOP6
-            | op == 0xb6 = return OP_NOP7
-            | op == 0xb7 = return OP_NOP8
-            | op == 0xb8 = return OP_NOP9
-            | op == 0xb9 = return OP_NOP10
-
-            -- Constants
-            | op == 0xfd = return OP_PUBKEYHASH
-            | op == 0xfe = return OP_PUBKEY
-
-            | otherwise = return $ OP_INVALIDOPCODE op
-
-    put op = case op of
-
-        (OP_PUSHDATA payload optype)-> do
-            let len = BS.length payload
-            case optype of
-                OPCODE -> do
-                    unless (len <= 0x4b) $ fail
-                        "OP_PUSHDATA OPCODE: Payload size too big"
-                    putWord8 $ fromIntegral len
-                OPDATA1 -> do
-                    unless (len <= 0xff) $ fail
-                        "OP_PUSHDATA OPDATA1: Payload size too big"
-                    putWord8 0x4c
-                    putWord8 $ fromIntegral len
-                OPDATA2 -> do
-                    unless (len <= 0xffff) $ fail
-                        "OP_PUSHDATA OPDATA2: Payload size too big"
-                    putWord8 0x4d
-                    putWord16le $ fromIntegral len
-                OPDATA4 -> do
-                    unless (len <= 0x7fffffff) $ fail
-                        "OP_PUSHDATA OPDATA4: Payload size too big"
-                    putWord8 0x4e
-                    putWord32le $ fromIntegral len
-            putByteString payload
-
-        -- Constants
-        OP_0                 -> putWord8 0x00
-        OP_1NEGATE           -> putWord8 0x4f
-        OP_RESERVED          -> putWord8 0x50
-        OP_1                 -> putWord8 0x51
-        OP_2                 -> putWord8 0x52
-        OP_3                 -> putWord8 0x53
-        OP_4                 -> putWord8 0x54
-        OP_5                 -> putWord8 0x55
-        OP_6                 -> putWord8 0x56
-        OP_7                 -> putWord8 0x57
-        OP_8                 -> putWord8 0x58
-        OP_9                 -> putWord8 0x59
-        OP_10                -> putWord8 0x5a
-        OP_11                -> putWord8 0x5b
-        OP_12                -> putWord8 0x5c
-        OP_13                -> putWord8 0x5d
-        OP_14                -> putWord8 0x5e
-        OP_15                -> putWord8 0x5f
-        OP_16                -> putWord8 0x60
-
-        -- Crypto Constants
-        OP_PUBKEY            -> putWord8 0xfe
-        OP_PUBKEYHASH        -> putWord8 0xfd
-
-        -- Invalid Opcodes
-        (OP_INVALIDOPCODE x) -> putWord8 x
-
-        -- Flow Control
-        OP_NOP               -> putWord8 0x61
-        OP_VER               -> putWord8 0x62
-        OP_IF                -> putWord8 0x63
-        OP_NOTIF             -> putWord8 0x64
-        OP_VERIF             -> putWord8 0x65
-        OP_VERNOTIF          -> putWord8 0x66
-        OP_ELSE              -> putWord8 0x67
-        OP_ENDIF             -> putWord8 0x68
-        OP_VERIFY            -> putWord8 0x69
-        OP_RETURN            -> putWord8 0x6a
-
-        -- Stack Operations
-        OP_TOALTSTACK        -> putWord8 0x6b
-        OP_FROMALTSTACK      -> putWord8 0x6c
-        OP_2DROP             -> putWord8 0x6d
-        OP_2DUP              -> putWord8 0x6e
-        OP_3DUP              -> putWord8 0x6f
-        OP_2OVER             -> putWord8 0x70
-        OP_2ROT              -> putWord8 0x71
-        OP_2SWAP             -> putWord8 0x72
-        OP_IFDUP             -> putWord8 0x73
-        OP_DEPTH             -> putWord8 0x74
-        OP_DROP              -> putWord8 0x75
-        OP_DUP               -> putWord8 0x76
-        OP_NIP               -> putWord8 0x77
-        OP_OVER              -> putWord8 0x78
-        OP_PICK              -> putWord8 0x79
-        OP_ROLL              -> putWord8 0x7a
-        OP_ROT               -> putWord8 0x7b
-        OP_SWAP              -> putWord8 0x7c
-        OP_TUCK              -> putWord8 0x7d
-
-        -- Splice
-        OP_CAT               -> putWord8 0x7e
-        OP_SUBSTR            -> putWord8 0x7f
-        OP_LEFT              -> putWord8 0x80
-        OP_RIGHT             -> putWord8 0x81
-        OP_SIZE              -> putWord8 0x82
-
-        -- Bitwise Logic
-        OP_INVERT            -> putWord8 0x83
-        OP_AND               -> putWord8 0x84
-        OP_OR                -> putWord8 0x85
-        OP_XOR               -> putWord8 0x86
-        OP_EQUAL             -> putWord8 0x87
-        OP_EQUALVERIFY       -> putWord8 0x88
-        OP_RESERVED1         -> putWord8 0x89
-        OP_RESERVED2         -> putWord8 0x8a
-
-        -- Arithmetic
-        OP_1ADD              -> putWord8 0x8b
-        OP_1SUB              -> putWord8 0x8c
-        OP_2MUL              -> putWord8 0x8d
-        OP_2DIV              -> putWord8 0x8e
-        OP_NEGATE            -> putWord8 0x8f
-        OP_ABS               -> putWord8 0x90
-        OP_NOT               -> putWord8 0x91
-        OP_0NOTEQUAL         -> putWord8 0x92
-        OP_ADD               -> putWord8 0x93
-        OP_SUB               -> putWord8 0x94
-        OP_MUL               -> putWord8 0x95
-        OP_DIV               -> putWord8 0x96
-        OP_MOD               -> putWord8 0x97
-        OP_LSHIFT            -> putWord8 0x98
-        OP_RSHIFT            -> putWord8 0x99
-        OP_BOOLAND           -> putWord8 0x9a
-        OP_BOOLOR            -> putWord8 0x9b
-        OP_NUMEQUAL          -> putWord8 0x9c
-        OP_NUMEQUALVERIFY    -> putWord8 0x9d
-        OP_NUMNOTEQUAL       -> putWord8 0x9e
-        OP_LESSTHAN          -> putWord8 0x9f
-        OP_GREATERTHAN       -> putWord8 0xa0
-        OP_LESSTHANOREQUAL   -> putWord8 0xa1
-        OP_GREATERTHANOREQUAL-> putWord8 0xa2
-        OP_MIN               -> putWord8 0xa3
-        OP_MAX               -> putWord8 0xa4
-        OP_WITHIN            -> putWord8 0xa5
-
-        -- Crypto
-        OP_RIPEMD160         -> putWord8 0xa6
-        OP_SHA1              -> putWord8 0xa7
-        OP_SHA256            -> putWord8 0xa8
-        OP_HASH160           -> putWord8 0xa9
-        OP_HASH256           -> putWord8 0xaa
-        OP_CODESEPARATOR     -> putWord8 0xab
-        OP_CHECKSIG          -> putWord8 0xac
-        OP_CHECKSIGVERIFY    -> putWord8 0xad
-        OP_CHECKMULTISIG     -> putWord8 0xae
-        OP_CHECKMULTISIGVERIFY -> putWord8 0xaf
-
-        -- More NOPs
-        OP_NOP1              -> putWord8 0xb0
-        OP_NOP2              -> putWord8 0xb1
-        OP_NOP3              -> putWord8 0xb2
-        OP_NOP4              -> putWord8 0xb3
-        OP_NOP5              -> putWord8 0xb4
-        OP_NOP6              -> putWord8 0xb5
-        OP_NOP7              -> putWord8 0xb6
-        OP_NOP8              -> putWord8 0xb7
-        OP_NOP9              -> putWord8 0xb8
-        OP_NOP10             -> putWord8 0xb9
-
-
--- | Check whether opcode is only data.
-isPushOp :: ScriptOp -> Bool
-isPushOp op = case op of
-    OP_PUSHDATA _ _ -> True
-    OP_0            -> True
-    OP_1NEGATE      -> True
-    OP_1            -> True
-    OP_2            -> True
-    OP_3            -> True
-    OP_4            -> True
-    OP_5            -> True
-    OP_6            -> True
-    OP_7            -> True
-    OP_8            -> True
-    OP_9            -> True
-    OP_10           -> True
-    OP_11           -> True
-    OP_12           -> True
-    OP_13           -> True
-    OP_14           -> True
-    OP_15           -> True
-    OP_16           -> True
-    _               -> False
-
--- | Optimally encode data using one of the 4 types of data pushing opcodes
-opPushData :: BS.ByteString -> ScriptOp
-opPushData bs
-    | len <= 0x4b       = OP_PUSHDATA bs OPCODE
-    | len <= 0xff       = OP_PUSHDATA bs OPDATA1
-    | len <= 0xffff     = OP_PUSHDATA bs OPDATA2
-    | len <= 0xffffffff = OP_PUSHDATA bs OPDATA4
-    | otherwise         = error "opPushData: payload size too big"
-  where
-    len = BS.length bs
+ src/Network/Bitcoin/Script.hs view
@@ -0,0 +1,21 @@+module Network.Bitcoin.Script ( decode
+                              , encode
+                              , ScriptOp (..)
+                              , Script (..)
+                              , PushDataType (..) ) where
+
+import qualified Data.Binary                 as B
+import qualified Data.ByteString.Base16.Lazy as BS16L
+import qualified Data.ByteString.Lazy        as BSL
+
+import           Network.Bitcoin.Script.Types
+
+-- | Decodes a hex representation of a script into a 'Script' object.
+decode :: BSL.ByteString -> Script
+decode =
+  B.decode . fst . BS16L.decode
+
+-- | Encodes a 'Script' object into a hex representation
+encode :: Script -> BSL.ByteString
+encode =
+  BS16L.encode . B.encode
+ src/Network/Bitcoin/Script/Types.hs view
@@ -0,0 +1,528 @@+module Network.Bitcoin.Script.Types
+( ScriptOp(..)
+, Script(..)
+, PushDataType(..)
+, isPushOp
+, opPushData
+) where
+
+import Control.Monad (liftM2, unless, forM_)
+import Control.Applicative ((<$>))
+
+import Data.Word (Word8)
+import Data.Binary (Binary, get, put)
+import Data.Binary.Get
+    ( isEmpty
+    , getWord8
+    , getWord16le
+    , getWord32le
+    , getByteString
+    )
+import Data.Binary.Put
+    ( putWord8
+    , putWord16le
+    , putWord32le
+    , putByteString
+    )
+import qualified Data.ByteString as BS
+    ( ByteString
+    , length
+    )
+
+-- | 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 the spending signatures in the input of a transaction
+data Script =
+    Script {
+             -- | List of script operators defining this script
+             scriptOps :: ![ScriptOp]
+           }
+    deriving (Eq, Show, Read)
+
+instance Binary Script where
+    get =
+        Script <$> getScriptOps
+      where
+        getScriptOps = do
+            empty <- isEmpty
+            if empty
+                then return []
+                else liftM2 (:) get getScriptOps
+
+    put (Script ops) = forM_ ops put
+
+-- | Data type representing the type of an OP_PUSHDATA opcode.
+data PushDataType
+    =
+      -- | The next opcode bytes is data to be pushed onto the stack
+      OPCODE
+      -- | The next byte contains the number of bytes to be pushed onto
+      -- the stack
+    | OPDATA1
+      -- | The next two bytes contains the number of bytes to be pushed onto
+      -- the stack
+    | OPDATA2
+      -- | The next four bytes contains the number of bytes to be pushed onto
+      -- the stack
+    | OPDATA4
+    deriving (Show, Read, Eq)
+
+-- | Data type representing all of the operators allowed inside a 'Script'.
+data ScriptOp
+      -- Pushing Data
+    = OP_PUSHDATA !BS.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_NOP2 | OP_NOP3 | OP_NOP4 | OP_NOP5
+    | OP_NOP6 | OP_NOP7 | OP_NOP8 | OP_NOP9 | OP_NOP10
+
+
+      -- Other
+    | OP_PUBKEYHASH
+    | OP_PUBKEY
+    | OP_INVALIDOPCODE !Word8
+
+        deriving (Show, Read, Eq)
+
+instance Binary ScriptOp where
+
+    get = go =<< (fromIntegral <$> getWord8)
+      where
+        go op
+            | op == 0x00 = return OP_0
+            | op <= 0x4b = do
+                payload <- getByteString (fromIntegral op)
+                return $ OP_PUSHDATA payload OPCODE
+            | op == 0x4c = do
+                len  <- getWord8
+                payload <- getByteString (fromIntegral len)
+                return $ OP_PUSHDATA payload OPDATA1
+            | op == 0x4d = do
+                len  <- getWord16le
+                payload <- getByteString (fromIntegral len)
+                return $ OP_PUSHDATA payload OPDATA2
+            | op == 0x4e = do
+                len  <- getWord32le
+                payload <- getByteString (fromIntegral len)
+                return $ OP_PUSHDATA payload OPDATA4
+
+            | op == 0x4f = return OP_1NEGATE
+            | op == 0x50 = return OP_RESERVED
+            | op == 0x51 = return OP_1
+            | op == 0x52 = return OP_2
+            | op == 0x53 = return OP_3
+            | op == 0x54 = return OP_4
+            | op == 0x55 = return OP_5
+            | op == 0x56 = return OP_6
+            | op == 0x57 = return OP_7
+            | op == 0x58 = return OP_8
+            | op == 0x59 = return OP_9
+            | op == 0x5a = return OP_10
+            | op == 0x5b = return OP_11
+            | op == 0x5c = return OP_12
+            | op == 0x5d = return OP_13
+            | op == 0x5e = return OP_14
+            | op == 0x5f = return OP_15
+            | op == 0x60 = return OP_16
+            -- Flow control
+            | op == 0x61 = return OP_NOP
+            | op == 0x62 = return OP_VER        -- reserved
+            | op == 0x63 = return OP_IF
+            | op == 0x64 = return OP_NOTIF
+            | op == 0x65 = return OP_VERIF      -- reserved
+            | op == 0x66 = return OP_VERNOTIF   -- reserved
+            | op == 0x67 = return OP_ELSE
+            | op == 0x68 = return OP_ENDIF
+            | op == 0x69 = return OP_VERIFY
+            | op == 0x6a = return OP_RETURN
+
+            -- Stack
+            | op == 0x6b = return OP_TOALTSTACK
+            | op == 0x6c = return OP_FROMALTSTACK
+            | op == 0x6d = return OP_2DROP
+            | op == 0x6e = return OP_2DUP
+            | op == 0x6f = return OP_3DUP
+            | op == 0x70 = return OP_2OVER
+            | op == 0x71 = return OP_2ROT
+            | op == 0x72 = return OP_2SWAP
+            | op == 0x73 = return OP_IFDUP
+            | op == 0x74 = return OP_DEPTH
+            | op == 0x75 = return OP_DROP
+            | op == 0x76 = return OP_DUP
+            | op == 0x77 = return OP_NIP
+            | op == 0x78 = return OP_OVER
+            | op == 0x79 = return OP_PICK
+            | op == 0x7a = return OP_ROLL
+            | op == 0x7b = return OP_ROT
+            | op == 0x7c = return OP_SWAP
+            | op == 0x7d = return OP_TUCK
+
+            -- Splice
+            | op == 0x7e = return OP_CAT
+            | op == 0x7f = return OP_SUBSTR
+            | op == 0x80 = return OP_LEFT
+            | op == 0x81 = return OP_RIGHT
+            | op == 0x82 = return OP_SIZE
+
+            -- Bitwise logic
+            | op == 0x83 = return OP_INVERT
+            | op == 0x84 = return OP_AND
+            | op == 0x85 = return OP_OR
+            | op == 0x86 = return OP_XOR
+            | op == 0x87 = return OP_EQUAL
+            | op == 0x88 = return OP_EQUALVERIFY
+            | op == 0x89 = return OP_RESERVED1
+            | op == 0x8a = return OP_RESERVED2
+
+            -- Arithmetic
+            | op == 0x8b = return OP_1ADD
+            | op == 0x8c = return OP_1SUB
+            | op == 0x8d = return OP_2MUL
+            | op == 0x8e = return OP_2DIV
+            | op == 0x8f = return OP_NEGATE
+            | op == 0x90 = return OP_ABS
+            | op == 0x91 = return OP_NOT
+            | op == 0x92 = return OP_0NOTEQUAL
+            | op == 0x93 = return OP_ADD
+            | op == 0x94 = return OP_SUB
+            | op == 0x95 = return OP_MUL
+            | op == 0x96 = return OP_DIV
+            | op == 0x97 = return OP_MOD
+            | op == 0x98 = return OP_LSHIFT
+            | op == 0x99 = return OP_RSHIFT
+            | op == 0x9a = return OP_BOOLAND
+            | op == 0x9b = return OP_BOOLOR
+            | op == 0x9c = return OP_NUMEQUAL
+            | op == 0x9d = return OP_NUMEQUALVERIFY
+            | op == 0x9e = return OP_NUMNOTEQUAL
+            | op == 0x9f = return OP_LESSTHAN
+            | op == 0xa0 = return OP_GREATERTHAN
+            | op == 0xa1 = return OP_LESSTHANOREQUAL
+            | op == 0xa2 = return OP_GREATERTHANOREQUAL
+            | op == 0xa3 = return OP_MIN
+            | op == 0xa4 = return OP_MAX
+            | op == 0xa5 = return OP_WITHIN
+
+            -- Crypto
+            | op == 0xa6 = return OP_RIPEMD160
+            | op == 0xa7 = return OP_SHA1
+            | op == 0xa8 = return OP_SHA256
+            | op == 0xa9 = return OP_HASH160
+            | op == 0xaa = return OP_HASH256
+            | op == 0xab = return OP_CODESEPARATOR
+            | op == 0xac = return OP_CHECKSIG
+            | op == 0xad = return OP_CHECKSIGVERIFY
+            | op == 0xae = return OP_CHECKMULTISIG
+            | op == 0xaf = return OP_CHECKMULTISIGVERIFY
+
+            -- More NOPs
+            | op == 0xb0 = return OP_NOP1
+            | op == 0xb1 = return OP_NOP2
+            | op == 0xb2 = return OP_NOP3
+            | op == 0xb3 = return OP_NOP4
+            | op == 0xb4 = return OP_NOP5
+            | op == 0xb5 = return OP_NOP6
+            | op == 0xb6 = return OP_NOP7
+            | op == 0xb7 = return OP_NOP8
+            | op == 0xb8 = return OP_NOP9
+            | op == 0xb9 = return OP_NOP10
+
+            -- Constants
+            | op == 0xfd = return OP_PUBKEYHASH
+            | op == 0xfe = return OP_PUBKEY
+
+            | otherwise = return $ OP_INVALIDOPCODE op
+
+    put op = case op of
+
+        (OP_PUSHDATA payload optype)-> do
+            let len = BS.length payload
+            case optype of
+                OPCODE -> do
+                    unless (len <= 0x4b) $ fail
+                        "OP_PUSHDATA OPCODE: Payload size too big"
+                    putWord8 $ fromIntegral len
+                OPDATA1 -> do
+                    unless (len <= 0xff) $ fail
+                        "OP_PUSHDATA OPDATA1: Payload size too big"
+                    putWord8 0x4c
+                    putWord8 $ fromIntegral len
+                OPDATA2 -> do
+                    unless (len <= 0xffff) $ fail
+                        "OP_PUSHDATA OPDATA2: Payload size too big"
+                    putWord8 0x4d
+                    putWord16le $ fromIntegral len
+                OPDATA4 -> do
+                    unless (len <= 0x7fffffff) $ fail
+                        "OP_PUSHDATA OPDATA4: Payload size too big"
+                    putWord8 0x4e
+                    putWord32le $ fromIntegral len
+            putByteString payload
+
+        -- Constants
+        OP_0                 -> putWord8 0x00
+        OP_1NEGATE           -> putWord8 0x4f
+        OP_RESERVED          -> putWord8 0x50
+        OP_1                 -> putWord8 0x51
+        OP_2                 -> putWord8 0x52
+        OP_3                 -> putWord8 0x53
+        OP_4                 -> putWord8 0x54
+        OP_5                 -> putWord8 0x55
+        OP_6                 -> putWord8 0x56
+        OP_7                 -> putWord8 0x57
+        OP_8                 -> putWord8 0x58
+        OP_9                 -> putWord8 0x59
+        OP_10                -> putWord8 0x5a
+        OP_11                -> putWord8 0x5b
+        OP_12                -> putWord8 0x5c
+        OP_13                -> putWord8 0x5d
+        OP_14                -> putWord8 0x5e
+        OP_15                -> putWord8 0x5f
+        OP_16                -> putWord8 0x60
+
+        -- Crypto Constants
+        OP_PUBKEY            -> putWord8 0xfe
+        OP_PUBKEYHASH        -> putWord8 0xfd
+
+        -- Invalid Opcodes
+        (OP_INVALIDOPCODE x) -> putWord8 x
+
+        -- Flow Control
+        OP_NOP               -> putWord8 0x61
+        OP_VER               -> putWord8 0x62
+        OP_IF                -> putWord8 0x63
+        OP_NOTIF             -> putWord8 0x64
+        OP_VERIF             -> putWord8 0x65
+        OP_VERNOTIF          -> putWord8 0x66
+        OP_ELSE              -> putWord8 0x67
+        OP_ENDIF             -> putWord8 0x68
+        OP_VERIFY            -> putWord8 0x69
+        OP_RETURN            -> putWord8 0x6a
+
+        -- Stack Operations
+        OP_TOALTSTACK        -> putWord8 0x6b
+        OP_FROMALTSTACK      -> putWord8 0x6c
+        OP_2DROP             -> putWord8 0x6d
+        OP_2DUP              -> putWord8 0x6e
+        OP_3DUP              -> putWord8 0x6f
+        OP_2OVER             -> putWord8 0x70
+        OP_2ROT              -> putWord8 0x71
+        OP_2SWAP             -> putWord8 0x72
+        OP_IFDUP             -> putWord8 0x73
+        OP_DEPTH             -> putWord8 0x74
+        OP_DROP              -> putWord8 0x75
+        OP_DUP               -> putWord8 0x76
+        OP_NIP               -> putWord8 0x77
+        OP_OVER              -> putWord8 0x78
+        OP_PICK              -> putWord8 0x79
+        OP_ROLL              -> putWord8 0x7a
+        OP_ROT               -> putWord8 0x7b
+        OP_SWAP              -> putWord8 0x7c
+        OP_TUCK              -> putWord8 0x7d
+
+        -- Splice
+        OP_CAT               -> putWord8 0x7e
+        OP_SUBSTR            -> putWord8 0x7f
+        OP_LEFT              -> putWord8 0x80
+        OP_RIGHT             -> putWord8 0x81
+        OP_SIZE              -> putWord8 0x82
+
+        -- Bitwise Logic
+        OP_INVERT            -> putWord8 0x83
+        OP_AND               -> putWord8 0x84
+        OP_OR                -> putWord8 0x85
+        OP_XOR               -> putWord8 0x86
+        OP_EQUAL             -> putWord8 0x87
+        OP_EQUALVERIFY       -> putWord8 0x88
+        OP_RESERVED1         -> putWord8 0x89
+        OP_RESERVED2         -> putWord8 0x8a
+
+        -- Arithmetic
+        OP_1ADD              -> putWord8 0x8b
+        OP_1SUB              -> putWord8 0x8c
+        OP_2MUL              -> putWord8 0x8d
+        OP_2DIV              -> putWord8 0x8e
+        OP_NEGATE            -> putWord8 0x8f
+        OP_ABS               -> putWord8 0x90
+        OP_NOT               -> putWord8 0x91
+        OP_0NOTEQUAL         -> putWord8 0x92
+        OP_ADD               -> putWord8 0x93
+        OP_SUB               -> putWord8 0x94
+        OP_MUL               -> putWord8 0x95
+        OP_DIV               -> putWord8 0x96
+        OP_MOD               -> putWord8 0x97
+        OP_LSHIFT            -> putWord8 0x98
+        OP_RSHIFT            -> putWord8 0x99
+        OP_BOOLAND           -> putWord8 0x9a
+        OP_BOOLOR            -> putWord8 0x9b
+        OP_NUMEQUAL          -> putWord8 0x9c
+        OP_NUMEQUALVERIFY    -> putWord8 0x9d
+        OP_NUMNOTEQUAL       -> putWord8 0x9e
+        OP_LESSTHAN          -> putWord8 0x9f
+        OP_GREATERTHAN       -> putWord8 0xa0
+        OP_LESSTHANOREQUAL   -> putWord8 0xa1
+        OP_GREATERTHANOREQUAL-> putWord8 0xa2
+        OP_MIN               -> putWord8 0xa3
+        OP_MAX               -> putWord8 0xa4
+        OP_WITHIN            -> putWord8 0xa5
+
+        -- Crypto
+        OP_RIPEMD160         -> putWord8 0xa6
+        OP_SHA1              -> putWord8 0xa7
+        OP_SHA256            -> putWord8 0xa8
+        OP_HASH160           -> putWord8 0xa9
+        OP_HASH256           -> putWord8 0xaa
+        OP_CODESEPARATOR     -> putWord8 0xab
+        OP_CHECKSIG          -> putWord8 0xac
+        OP_CHECKSIGVERIFY    -> putWord8 0xad
+        OP_CHECKMULTISIG     -> putWord8 0xae
+        OP_CHECKMULTISIGVERIFY -> putWord8 0xaf
+
+        -- More NOPs
+        OP_NOP1              -> putWord8 0xb0
+        OP_NOP2              -> putWord8 0xb1
+        OP_NOP3              -> putWord8 0xb2
+        OP_NOP4              -> putWord8 0xb3
+        OP_NOP5              -> putWord8 0xb4
+        OP_NOP6              -> putWord8 0xb5
+        OP_NOP7              -> putWord8 0xb6
+        OP_NOP8              -> putWord8 0xb7
+        OP_NOP9              -> putWord8 0xb8
+        OP_NOP10             -> putWord8 0xb9
+
+
+-- | Check whether opcode is only data.
+isPushOp :: ScriptOp -> Bool
+isPushOp op = case op of
+    OP_PUSHDATA _ _ -> True
+    OP_0            -> True
+    OP_1NEGATE      -> True
+    OP_1            -> True
+    OP_2            -> True
+    OP_3            -> True
+    OP_4            -> True
+    OP_5            -> True
+    OP_6            -> True
+    OP_7            -> True
+    OP_8            -> True
+    OP_9            -> True
+    OP_10           -> True
+    OP_11           -> True
+    OP_12           -> True
+    OP_13           -> True
+    OP_14           -> True
+    OP_15           -> True
+    OP_16           -> True
+    _               -> False
+
+-- | Optimally encode data using one of the 4 types of data pushing opcodes
+opPushData :: BS.ByteString -> ScriptOp
+opPushData bs
+    | len <= 0x4b       = OP_PUSHDATA bs OPCODE
+    | len <= 0xff       = OP_PUSHDATA bs OPDATA1
+    | len <= 0xffff     = OP_PUSHDATA bs OPDATA2
+    | len <= 0xffffffff = OP_PUSHDATA bs OPDATA4
+    | otherwise         = error "opPushData: payload size too big"
+  where
+    len = BS.length bs
− test/Bitcoin/ScriptSpec.hs
@@ -1,24 +0,0 @@-module Bitcoin.ScriptSpec where
-
-import           Bitcoin.Script
-
-import qualified Data.ByteString.Lazy.Char8 as BSL8 (pack)
-
-import           Test.Hspec
-import           Test.Hspec.Expectations    (expectationFailure)
-
-spec :: Spec
-spec = do
-  describe "when decompiling a specific script" $ do
-    it "encoding a decoding a script results in the original hex" $ do
-      let hex = BSL8.pack "76a914975efcba1e058667594dc57146022ec46560a63c88ac"
-
-      (encode . decode) hex `shouldBe` hex
-
-    it "succesfully parses a transaction into a meaningful object" $ do
-      let hex     = BSL8.pack "76a914975efcba1e058667594dc57146022ec46560a63c88ac"
-          decoded = decode hex
-
-      case decoded of
-       (Script [OP_DUP, OP_HASH160, OP_PUSHDATA _ OPCODE, OP_EQUALVERIFY, OP_CHECKSIG]) -> return ()
-       _                 -> expectationFailure ("Result does not match expected: " ++ show decoded)
+ test/Network/Bitcoin/ScriptSpec.hs view
@@ -0,0 +1,23 @@+module Network.Bitcoin.ScriptSpec where
+
+import           Network.Bitcoin.Script
+
+import qualified Data.ByteString.Lazy.Char8 as BSL8 (pack)
+
+import           Test.Hspec
+
+spec :: Spec
+spec = do
+  describe "when decompiling a specific script" $ do
+    it "encoding a decoding a script results in the original hex" $ do
+      let hex = BSL8.pack "76a914975efcba1e058667594dc57146022ec46560a63c88ac"
+
+      (encode . decode) hex `shouldBe` hex
+
+    it "succesfully parses a transaction into a meaningful object" $ do
+      let hex     = BSL8.pack "76a914975efcba1e058667594dc57146022ec46560a63c88ac"
+          decoded = decode hex
+
+      case decoded of
+       (Script [OP_DUP, OP_HASH160, OP_PUSHDATA _ OPCODE, OP_EQUALVERIFY, OP_CHECKSIG]) -> return ()
+       _                 -> expectationFailure ("Result does not match expected: " ++ show decoded)