Safe Haskell | None |
---|---|
Language | Haskell98 |
Bitcoin script interpreter
- type Entry = ByteString
- data InterpreterConfig = Cfg {}
- data InterpreterState = St {
- _mainStack :: [Entry]
- _altStack :: [Entry]
- _opcodeStream :: Stream
- type ScriptMonad a = ExceptT String (StateT InterpreterState (ReaderT InterpreterConfig Identity)) a
- checkTransaction :: forall a. Tx (Tx a RawScript, RawScript) RawScript -> Either String Bool
- isDisabledOpcode :: Opcode -> Bool
- initialState :: InterpreterState
- executeScript :: [Opcode] -> ScriptMonad ()
- runScriptPre :: InterpreterConfig -> InterpreterState -> Script -> (Either String (), InterpreterState)
- runScriptFinal :: InterpreterConfig -> InterpreterState -> Script -> (Either String Bool, InterpreterState)
- scriptStep :: ScriptMonad Bool
- scriptStep' :: Opcode -> ScriptMonad ()
- isFalse :: Entry -> Bool
- isTrue :: Entry -> Bool
- data Stream = Stream {}
- data Context
- data Hole
- data IfBranch
- data IfType
- data IfBlock = IfBlock {}
- streamMoveRight :: Stream -> Either Stream (Opcode, Stream)
- fetchOpcode :: ScriptMonad (Maybe Opcode)
- fetchOpcodeWithinContext :: ScriptMonad (Maybe Opcode)
- fetchIfBlock :: IfType -> IfBranch -> ScriptMonad IfBlock
- reconstructIfBlock :: IfBlock -> [Opcode]
- invalid :: String -> ScriptMonad a
- getState :: ScriptMonad InterpreterState
- putState :: InterpreterState -> ScriptMonad ()
- pushData :: Entry -> ScriptMonad ()
- popData :: ScriptMonad Entry
- pushAltData :: Entry -> ScriptMonad ()
- popAltData :: ScriptMonad Entry
- pushInteger :: Integer -> ScriptMonad ()
- popInteger :: ScriptMonad Integer
- pushBool :: Bool -> ScriptMonad ()
- popBool :: ScriptMonad Bool
- parseTxScripts :: Tx RawScript RawScript -> Either String (Tx Script Script)
- parseTxInScripts :: Tx RawScript a -> Either String (Tx Script a)
- parseTxOutScripts :: Tx a RawScript -> Either String (Tx a Script)
- parseSingleTxOutScript :: Int -> Tx a RawScript -> Either String (Tx a (Either RawScript Script))
types
type Entry = ByteString Source #
Stack entry
data InterpreterConfig Source #
data InterpreterState Source #
Two stacks, an opcode stream (the latter necessary for the somewhat convoluted IF parsing, and also for OP_CHECKSIG)
St | |
|
type ScriptMonad a = ExceptT String (StateT InterpreterState (ReaderT InterpreterConfig Identity)) a Source #
Interpreter monad
high level functions
checkTransaction :: forall a. Tx (Tx a RawScript, RawScript) RawScript -> Either String Bool Source #
Given a transaction together with its inputs, we check if it is valid or not. This is done by combining the input scripts of this transaction with the output scripts of the previous transactions, and running the resulting scripts
If any of the scripts fails, the cause of failure is returned; if the scripts runs correctly,
the result is returned (which should be True
for valid transactions)
medium level functions
isDisabledOpcode :: Opcode -> Bool Source #
initialState :: InterpreterState Source #
Empty stacks, empty script
executeScript :: [Opcode] -> ScriptMonad () Source #
Executes a list of opcodes
runScriptPre :: InterpreterConfig -> InterpreterState -> Script -> (Either String (), InterpreterState) Source #
Runs the scriptSig
runScriptFinal :: InterpreterConfig -> InterpreterState -> Script -> (Either String Bool, InterpreterState) Source #
Runs the scriptPubKey
scriptStep :: ScriptMonad Bool Source #
Execute a single (except in case of conditionals) opcode
"The stacks hold byte vectors. Byte vectors are interpreted as little-endian variable-length integers with the most significant bit determining the sign of the integer. Thus 0x81 represents -1. 0x80 is another representation of zero (so called negative 0). Byte vectors are interpreted as Booleans where False is represented by any representation of zero, and True is represented by any representation of non-zero."
Returns True
if the script finished.
scriptStep' :: Opcode -> ScriptMonad () Source #
internal types
An opcode stream consist of a zipper of opcodes, and a Context which describes (possibly recursively) what is on the left and right side of this zipper. This is used for executing (possibly nested) OP_IF blocks.
This may be overly complicated :)
A context of opcodes and (nested) if blocks
some internal functions
streamMoveRight :: Stream -> Either Stream (Opcode, Stream) Source #
Even where there is nothing on the right, we can change the stream itself during the discovery of this fact!
fetchOpcode :: ScriptMonad (Maybe Opcode) Source #
Fetches an opcode, possibly exiting the current context
fetchOpcodeWithinContext :: ScriptMonad (Maybe Opcode) Source #
Fetches an opcode, but does not exit the current context
fetchIfBlock :: IfType -> IfBranch -> ScriptMonad IfBlock Source #
We fetch an if block *and* take the given branch (second argument)
Note: if blocks can be nested...
reconstructIfBlock :: IfBlock -> [Opcode] Source #
script monad
invalid :: String -> ScriptMonad a Source #
putState :: InterpreterState -> ScriptMonad () Source #
push/pop
pushData :: Entry -> ScriptMonad () Source #
pushAltData :: Entry -> ScriptMonad () Source #
pushInteger :: Integer -> ScriptMonad () Source #
pushBool :: Bool -> ScriptMonad () Source #
parsing (should be elsewhere)
parseTxScripts :: Tx RawScript RawScript -> Either String (Tx Script Script) Source #
Tries to parse all scripts, both input and output. Since the output scripts can fail to parse (see below), this may also fail.
parseTxInScripts :: Tx RawScript a -> Either String (Tx Script a) Source #
Tries to parse all input scripts. This shouldn't fail for a valid transaction.