NAME

Bitcoin::Crypto::Script::Runner - Bitcoin Script runner

SYNOPSIS

use Bitcoin::Crypto::Script::Runner;
use Data::Dumper;

my $runner = Bitcoin::Crypto::Script::Runner->new;

# provide an instance of Bitcoin::Crypto::Script
# runs the script all at once
$runner->execute($script);

# ... or: runs the script step by step
$runner->start($script);
while ($runner->step) {
	print 'runner step, stack: ';
	print Dumper($runner->stack);
}

print 'FAILURE' unless $runner->success;
print 'resulting stack: ';
print Dumper($runner->stack);

DESCRIPTION

This class instances can be used to execute Bitcoin scripts defined as instances of Bitcoin::Crypto::Script. Scripts can be executed in one go or step by step, and the execution stack is available through an accessor.

One runner can be used to execute scripts multiple times. Each time you call execute or start, the runner state is reset. Initial stack state can be provided to either one of those methods. This provides better control over execution than "run" in Bitcoin::Crypto::Script, which simply executes the script and returns its stack.

INTERFACE

Attributes

transaction

Instance of Bitcoin::Crypto::Transaction wrapped inside Bitcoin::Crypto::Script::Transaction for some extra data. It is optional, but some opcodes will refuse to function without it.

predicate: has_transaction

writer: set_transaction

flags

An instance of Bitcoin::Crypto::Transaction::Flags. If not passed, full set of consensus flags will be assumed (same as calling "new" in Bitcoin::Crypto::Transaction::Flags with no arguments).

writer: set_flags

script

The current script being executed. Will be set automatically in "start". set_script can be used to set it manually.

Not assignable in the constructor

stack

Not assignable in the constructor

Array reference - the stack which is used during script execution. Last item in this array is the stack top. Use $runner->stack->[-1] to examine the stack top.

Each item on the stack is a byte string. Use "to_int" and "to_bool" to transform it into an integer or boolean value in the same fashion bitcoin script interpreter does it.

alt_stack

Not assignable in the constructor

Array reference - alt stack, used by OP_TOALTSTACK and OP_FROMALTSTACK.

operations

Not assignable in the constructor

Array reference - An array of operations to be executed. Same as "operations" in Bitcoin::Crypto::Script and automatically obtained by calling it.

[
	[OP_XXX (Object), raw (String), ...],
	...
]

The first element of each subarray is the Bitcoin::Crypto::Script::Opcode object. The second element is the raw opcode string, usually single byte. The rest of elements are metadata and is dependant on the op type. This metadata is used during script execution.

pos

Not assignable in the constructor

Positive integer - the position of the operation to be run in the next step (from "operations").

codeseparator

Not assignable in the constructor

Positive integer - "pos" of the last encountered codeseparator, or undef if none was encountered.

Methods

new

$object = $class->new(%data)

This is a standard Moo constructor, which can be used to create the object. It takes arguments specified in "Attributes".

Returns class instance.

execute

$object = $object->execute($script, \@initial_stack = [])

Executes the script in one go. Returns runner instance (for chaining).

$script must be an instance of Bitcoin::Crypto::Script. If you only have a serialized script in a string, call "from_serialized" in Bitcoin::Crypto::Script first to get a proper script instance. $initial_stack will be used to pre-populate the stack before running the script.

After the method returns call "stack" to get execution stack. This can be done in a single line:

my $stack = $runner->execute($script)->stack;

If errors occur, they will be thrown as exceptions. See "EXCEPTIONS".

compile

$object->compile()

Fills "operations" based on the contents of "script". May throw an exception in case of both success and failure. Advanced use only.

start

$object = $object->start($script, \@initial_stack = [])

Same as "execute", but only sets initial runner state and does not actually execute any script opcodes. "step" must be called to continue the execution.

step

while ($runner->step) {
	# do something after each step
}

Executes the next script opcode. Returns a false value if the script finished the execution, and a true value otherwise.

"start" must be called before this method is called.

Note that not every opcode will take a step to execute. This means that this script:

OP_1 OP_IF OP_PUSHDATA1 1 0x1f OP_ENDIF

will take four steps to execute (OP_1 -> OP_IF -> 0x1f -> OP_ENDIF).

This one however:

OP_1 OP_IF OP_PUSHDATA1 1 0x1f OP_ELSE OP_PUSHDATA1 2 0xe15e OP_ENDIF

will also take four steps (OP_1 -> OP_IF -> 0x1f -> OP_ELSE). This happens because OP_ELSE performs a jump past OP_ENDIF. If the initial op was OP_0, the execution would be OP_0 -> OP_IF -> 0xe15e -> OP_ENDIF. No OP_ELSE since it was jumped over and reaching OP_ENDIF.

These details should not matter usually, but may be confusing if you would want to for example print your stack step by step. When in doubt, check $runner->pos, which contains the position of the next opcode to execute.

subscript

$subscript = $object->subscript()

Returns current subscript - part of the running script from after the last codeseparator, also known as scriptCode.

Depending on the input spending segwit, the subscript will behave differently:

  • pre-segwit

    Removes all codeseparators after the last executed codeseparator. Currently does not remove the signature (known as FindAndDelete).

  • segwit

    Only removes the part up to the last executed OP_CODESEPARATOR.

success

$boolean = $object->success()

Returns a boolean indicating whether the script execution was successful.

is_tapscript

$boolean = $object->is_tapscript()

Returns true if currently executed script is a tapscript.

Helper methods

to_int, from_int

my $int = $runner->to_int($byte_vector, $max_bytes = 4);
my $byte_vector = $runner->from_int($int);

These methods encode and decode numbers in format which is used on "stack".

BigInts are used. to_int will return an instance of Math::BigInt, while from_int can accept it (but it should also handle regular numbers just fine). to_int limits the size of an integer to $max_bytes.

to_bool, to_minimal_bool, from_bool

These methods encode and decode booleans in format which is used on "stack". to_minimal_bool variant is used to enforce MINIMALIF rule.

stack_serialized

Returns the serialized stack. Any null vectors will be transformed to 0x00.

EXCEPTIONS

This module throws an instance of Bitcoin::Crypto::Exception if it encounters an error. It can produce the following error types from the Bitcoin::Crypto::Exception namespace:

  • ScriptRuntime - script has encountered a runtime exception - the transaction is invalid

  • ScriptCompilation - script compilation has encountered a problem

SEE ALSO

Bitcoin::Crypto::Script