-- | Bitcoin scripts {-# LANGUAGE PatternGuards #-} module Bitcoin.Script.Base where -------------------------------------------------------------------------------- import Data.Int import Data.Word import Text.Show import qualified Data.ByteString as B import Bitcoin.Misc.OctetStream import Bitcoin.Misc.HexString import Bitcoin.Protocol.Hash import Bitcoin.Script.Integer -------------------------------------------------------------------------------- -- | A raw script (octet stream) newtype RawScript = RawScript { fromRawScript :: B.ByteString } deriving Eq -- | A parsed script (opcode stream) newtype Script = Script { fromScript :: [Opcode] } deriving Eq -- | The 160-bit hash of a (raw) script newtype ScriptHash = ScriptHash { fromScriptHash :: Hash160 } deriving (Eq,Show) emptyRawScript :: RawScript emptyRawScript = RawScript (B.empty) emptyScript :: Script emptyScript = Script [] scriptHash :: RawScript -> ScriptHash scriptHash = ScriptHash . doHash160 . fromRawScript instance OctetStream ScriptHash where toByteString = toByteString . fromScriptHash fromByteString = ScriptHash . fromByteString instance OctetStream RawScript where toByteString = fromRawScript fromByteString = RawScript instance Show RawScript where showsPrec d (RawScript rs) = showParen (d>10) $ showString "rawScriptFromString " . shows (toHexStringChars rs) instance Show Script where showsPrec d (Script opcodes) = showParen (d>10) $ showString "Script " . (showOpcodeList opcodes) rawScriptFromString :: String -> RawScript rawScriptFromString s = if odd (length s) then error "rawScriptFromString: hex string should have even length" else RawScript $ fromHexString $ HexString s -------------------------------------------------------------------------------- -- * shorthands -- | @OP_FALSE@ = @OP_0@ = 0x00 = pushes an empty array to stack. op_FALSE :: Opcode op_FALSE = OP_SMALLNUM 0 -- | @OP_TRUE@ = @OP_1@ = 0x51 = pushes the number 1 onto the stack op_TRUE :: Opcode op_TRUE = OP_SMALLNUM 1 -- | Pushes the corresponding number to the stack (0 is represented by an empty array) op_0 :: Opcode op_0 = OP_SMALLNUM 0 op_1 :: Opcode op_1 = OP_SMALLNUM 1 op_2 :: Opcode op_2 = OP_SMALLNUM 2 op_3 :: Opcode op_3 = OP_SMALLNUM 3 -- | Handy shorthands for comparisons op_LT :: Opcode op_LT = OP_LESSTHAN op_GT :: Opcode op_GT = OP_GREATERTHAN op_LE :: Opcode op_LE = OP_LESSTHANOREQUAL op_GE :: Opcode op_GE = OP_GREATERTHANOREQUAL -- | Figures out which opcode to use op_PUSHDATA :: B.ByteString -> Opcode op_PUSHDATA bs = let l = B.length bs in case l of 0 -> OP_SMALLNUM 0 -- OP_0 = push empty array _ | l>=1 && l<=75 -> OP_PUSHDATA (fromIntegral l) bs _ | l<=255 -> OP_PUSHDATA 76 bs _ | l<=65536 -> OP_PUSHDATA 77 bs _ -> OP_PUSHDATA 78 bs -- | Pushes a (signed) integer onto the stack, -- never using OP_SMALLNUM (except for 0, which is represented by the empty array) op_BIGNUMBER :: Integer -> Opcode op_BIGNUMBER n = op_PUSHDATA (asByteString n) -------------------------------------------------------------------------------- -- * opcodes -- | See data Opcode -- data = OP_SMALLNUM !Int -- ^ OP_0, OP_1 .. OP_16 (bytes 0,81,82..96). Pushes the number to the stack (0 is represented by an empty array) | OP_1NEGATE -- ^ The number -1 is pushed onto the stack. | OP_PUSHDATA !Word8 !B.ByteString -- ^ Pushes data to the stack. The Word8 is the opcode: it can be 0, 1..75 and 76,77,78. -- control flow | OP_NOP !Word8 -- ^ Does nothing. The argument is the opcode, either 0x61 or 0xb0-0xb9 | OP_IF -- ^ If the top stack value is not 0, the statements are executed. The top stack value is removed. | OP_NOTIF -- ^ If the top stack value is 0, the statements are executed. The top stack value is removed. | OP_ELSE -- ^ If the preceding OP_IF or OP_NOTIF or OP_ELSE was not executed then these statements are and if the preceding OP_IF or OP_NOTIF or OP_ELSE was executed then these statements are not. | OP_ENDIF -- ^ Ends an if/else block. | OP_VERIFY -- ^ Marks transaction as invalid if top stack value is not true. True is removed, but false is not. | OP_RETURN -- ^ Marks transaction as invalid. -- stack | OP_TOALTSTACK -- ^ Puts the input onto the top of the alt stack. Removes it from the main stack. | OP_FROMALTSTACK -- ^ Puts the input onto the top of the main stack. Removes it from the alt stack. | OP_IFDUP -- ^ If the top stack value is not 0, duplicate it. | OP_DEPTH -- ^ Puts the number of stack items onto the stack. | OP_DROP -- ^ Removes the top stack item. | OP_DUP -- ^ Duplicates the top stack item. | OP_NIP -- ^ Removes the second-to-top stack item. | OP_OVER -- ^ Copies the second-to-top stack item to the top. | OP_PICK -- ^ The item n back in the stack is copied to the top. | OP_ROLL -- ^ The item n back in the stack is moved to the top. | OP_ROT -- ^ The top three items on the stack are rotated to the left. | OP_SWAP -- ^ The top two items on the stack are swapped. | OP_TUCK -- ^ The item at the top of the stack is copied and inserted before the second-to-top item. | OP_2DROP -- ^ Removes the top two stack items. | OP_2DUP -- ^ Duplicates the top two stack items. | OP_3DUP -- ^ Duplicates the top three stack items. | OP_2OVER -- ^ Copies the pair of items two spaces back in the stack to the front. | OP_2ROT -- ^ The fifth and sixth items back are moved to the top of the stack. | OP_2SWAP -- ^ Swaps the top two pairs of items. -- splice | OP_CAT -- ^ Concatenates two strings. Currently disabled. | OP_SUBSTR -- ^ Returns a section of a string. Currently disabled. | OP_LEFT -- ^ Keeps only characters left of the specified point in a string. Currently disabled. | OP_RIGHT -- ^ Keeps only characters right of the specified point in a string. Currently disabled. | OP_SIZE -- ^ Returns the length of the input string. -- bitwise logic | OP_INVERT -- ^ Flips all of the bits in the input. Currently disabled. | OP_AND -- ^ Boolean and between each bit in the inputs. Currently disabled. | OP_OR -- ^ Boolean or between each bit in the inputs. Currently disabled. | OP_XOR -- ^ Boolean exclusive or between each bit in the inputs. Currently disabled. | OP_EQUAL -- ^ Returns 1 if the inputs are exactly equal, 0 otherwise. | OP_EQUALVERIFY -- ^ Same as OP_EQUAL, but runs OP_VERIFY afterward. -- arithmetic | OP_1ADD -- ^ 1 is added to the input. | OP_1SUB -- ^ 1 is subtracted from the input. | OP_2MUL -- ^ The input is multiplied by 2. Currently disabled. | OP_2DIV -- ^ The input is divided by 2. Currently disabled. | OP_NEGATE -- ^ The sign of the input is flipped. | OP_ABS -- ^ The input is made positive. | OP_NOT -- ^ If the input is 0 or 1, it is flipped. Otherwise the output will be 0. | OP_0NOTEQUAL -- ^ Returns 0 if the input is 0. 1 otherwise. | OP_ADD -- ^ a is added to b. | OP_SUB -- ^ b is subtracted from a. | OP_MUL -- ^ a is multiplied by b. Currently disabled. | OP_DIV -- ^ a is divided by b. Currently disabled. | OP_MOD -- ^ Returns the remainder after dividing a by b. Currently disabled. | OP_LSHIFT -- ^ Shifts a left b bits, preserving sign. Currently disabled. | OP_RSHIFT -- ^ Shifts a right b bits, preserving sign. Currently disabled. | OP_BOOLAND -- ^ If both a and b are not 0, the output is 1. Otherwise 0. | OP_BOOLOR -- ^ If a or b is not 0, the output is 1. Otherwise 0. | OP_NUMEQUAL -- ^ Returns 1 if the numbers are equal, 0 otherwise. | OP_NUMEQUALVERIFY -- ^ Same as OP_NUMEQUAL, but runs OP_VERIFY afterward. | OP_NUMNOTEQUAL -- ^ Returns 1 if the numbers are not equal, 0 otherwise. | OP_LESSTHAN -- ^ Returns 1 if a is less than b, 0 otherwise. | OP_GREATERTHAN -- ^ Returns 1 if a is greater than b, 0 otherwise. | OP_LESSTHANOREQUAL -- ^ Returns 1 if a is less than or equal to b, 0 otherwise. | OP_GREATERTHANOREQUAL -- ^ Returns 1 if a is greater than or equal to b, 0 otherwise. | OP_MIN -- ^ Returns the smaller of a and b. | OP_MAX -- ^ Returns the larger of a and b. | OP_WITHIN -- ^ Returns 1 if x is within the specified range (left-inclusive), 0 otherwise -- crypto | OP_RIPEMD160 -- ^ The input is hashed using RIPEMD-160. | OP_SHA1 -- ^ The input is hashed using SHA-1. | OP_SHA256 -- ^ The input is hashed using SHA-256. | OP_HASH160 -- ^ The input is hashed twice: first with SHA-256 and then with RIPEMD-160. | OP_HASH256 -- ^ The input is hashed two times with SHA-256. | OP_CODESEPARATOR -- ^ All of the signature checking words will only match signatures to the data after the most recently-executed OP_CODESEPARATOR. | OP_CHECKSIG -- ^ The entire transaction's outputs, inputs, and script (from the most recently-executed OP_CODESEPARATOR to the end) are hashed. The signature used by OP_CHECKSIG must be a valid signature for this hash and public key. If it is, 1 is returned, 0 otherwise. | OP_CHECKSIGVERIFY -- ^ Same as OP_CHECKSIG, but OP_VERIFY is executed afterward. | OP_CHECKMULTISIG -- ^ For each signature and public key pair, OP_CHECKSIG is executed. If more public keys than signatures are listed, some key/sig pairs can fail. All signatures need to match a public key. If all signatures are valid, 1 is returned, 0 otherwise. Due to a bug, one extra unused value is removed from the stack. | OP_CHECKMULTISIGVERIFY -- ^ Same as OP_CHECKMULTISIG, but OP_VERIFY is executed afterward. -- reserved words | OP_RESERVED -- ^ Transaction is invalid unless occuring in an unexecuted OP_IF branch | OP_VER -- ^ Transaction is invalid unless occuring in an unexecuted OP_IF branch | OP_VERIF -- ^ Transaction is invalid even when occuring in an unexecuted OP_IF branch | OP_VERNOTIF -- ^ Transaction is invalid even when occuring in an unexecuted OP_IF branch | OP_RESERVED1 -- ^ Transaction is invalid unless occuring in an unexecuted OP_IF branch | OP_RESERVED2 -- ^ Transaction is invalid unless occuring in an unexecuted OP_IF branch -- pseudo | OP_INVALIDOPCODE -- ^ this is a pseudo opcode, but it appears in the testnet3 blockchain... | OP_UNKNOWN !Word8 -- ^ unknown opcodes also appear in the testnet, inside (unexecuted?) OP_IF branches... deriving (Eq,Show) -------------------------------------------------------------------------------- -- * helper functions -- | Note: this function returns 'Nothing' for @OP_0@ (which technically pushes an empty array to the stack). -- Also we don't check for validity (see 'is_valid_pushdata') is_op_pushdata :: Opcode -> Maybe B.ByteString is_op_pushdata op = case op of { OP_PUSHDATA _ bs -> Just bs ; _ -> Nothing } -- | Note that OP_0 = push empty array, so we accept that as a valid @OP_PUSHDATA@ is_valid_pushdata :: Word8 -> B.ByteString -> Bool is_valid_pushdata op bs | op>=0 && op<=75 = (n == fromIntegral op) | op==76 = (n <= 255) | op==77 = (n <= 65535) | op==78 = True | otherwise = False where n = B.length bs is_op_smallnum :: Opcode -> Maybe Int is_op_smallnum op = case op of { OP_SMALLNUM k -> Just k ; _ -> Nothing } is_nop :: Word8 -> Bool is_nop w8 = case w8 of 0x61 -> True -- OP_NOP _ | w8 >= 0xb0 && w8 <= 0xb9 -> True -- OP_NOP1 .. OP_NOP10 _ -> False -------------------------------------------------------------------------------- showOpcode :: Opcode -> (String -> String) showOpcode op = case op of OP_PUSHDATA w8 dat -> showString "OP_PUSHDATA <0x" . showString (showHexWord8 w8) . showString "> \"" . showString (toHexStringChars dat) . showChar '\"' _ -> shows op showList' :: (a -> (String -> String)) -> [a] -> (String -> String) showList' _ [] s = "[]" ++ s showList' showx (x:xs) s = '[' : showx x (showl xs) where showl [] = ']' : s showl (y:ys) = ',' : showx y (showl ys) showOpcodeList :: [Opcode] -> (String -> String) showOpcodeList list = showList' showOpcode list --------------------------------------------------------------------------------