The range of the script node that was evaluated to produce the trace
An array of reduced nodes to parse
The vm.debug
result to map to these nodes
This method incrementally concatenates the reduced bytecode from each node, parsing the result into evaluation samples.
Each node can contain only a portion of an instruction (like a long push operation), or it can contain multiple instructions (like a long hex literal representing a string of bytecode or an evaluation that is not wrapped by a push).
If a node contains only a portion of an instruction, the bytecode from additional nodes are concatenated (and ranges merged) until an instruction can be created. If any bytecode remains after a sample has been created, the next sample begins in the same range. (For this reason, it's possible that samples overlap.)
If a node contains more than one instruction, the intermediate states
produced before the final state for that sample are saved to the sample's
intermediateStates
array.
If the program states in trace
are exhausted before the final instruction
in a sample (usually caused by an evaluation error), the last instruction
with a matching program state is used for the sample (with its program
state), and the unmatched instructions are ignored. (This allows the "last
known state" to be displayed for the sample that caused evaluation to halt.)
For example, the following script demonstrates many of these cases:
0x00 0x01 0xab01 0xcd9300 $(OP_3 <0x00> OP_SWAP OP_CAT) 0x010203
Which compiles to 0x0001ab01cd93000003010203
, disassembled:
OP_0 OP_PUSHBYTES_1 0xab OP_PUSHBYTES_1 0xcd OP_ADD OP_0 OP_0 OP_PUSHBYTES_3 0x010203
In the script, there are 6 top-level nodes (identified below within []
):
[0x00] [0x01] [0xab01] [0xcd9300] [$(OP_3 <0x00> OP_SWAP OP_CAT)] [0x010203]
These nodes together encode 7 instructions, some within a single node, and
some split between several nodes. Below we substitute the evaluation for its
result 0x0003
to group instructions by []
:
[0x00] [0x01 0xab][01 0xcd][93][00] [0x00][03 0x010203]
The "resolution" of samples is limited to the range of single nodes: nodes
cannot always be introspected to determine where contained instructions begin
and end. For example, it is ambiguous which portions of the evaluation are
responsible for the initial 0x00
and which are responsible for the 0x03
.
For this reason, the range of each sample is limited to the range(s) of one
or more adjacent nodes. Samples may overlap in the range of a node that is
responsible for both ending a previous sample and beginning a new sample.
(Though, only 2 samples can overlap. If a node is responsible for more than 2
instructions, the second sample includes internalStates
for instructions
that occur before the end of the second sample.)
In this case, there are 6 samples identified below within []
, where each
[
is closed by the closest following ]
(no nesting):
[0x00] [0x01 [0xab01] [0xcd9300]] [[$(OP_3 <0x00> OP_SWAP OP_CAT)] 0x010203]
The ranges for each sample (in terms of nodes) are as follows:
Note that the following samples overlap:
Finally, note that Sample 4 will have one internal state produced by the
OP_ADD
instruction. Sample 4 then ends with the OP_0
(0x00
) instruction
at the end of the 0xcd9300
node.
Note, this implementation relies on the expectation that trace
begins with
the initial program state, contains a single program state per instruction,
and ends with the final program state (as produced by vm.debug
). It also
expects the bytecode
provided by nodes to be parsable by
decodeAuthenticationInstructions.
Generated using TypeDoc
Extract a set of "evaluation samples" from the result of a CashAssembly compilation and a matching debug trace (from
vm.debug
), pairing program states with the source ranges that produced them – like a "source map" for complete evaluations. This is useful for omniscient debuggers like Bitauth IDE.Returns an array of samples and an array of unmatched program states remaining if
nodes
doesn't contain enough instructions to consume all program states provided intrace
. Returned samples are ordered by the ending position (line and column) of their range.If all program states are consumed before the available nodes are exhausted, the remaining nodes are ignored (the produced samples end at the last instruction for which a program state exists). This usually occurs when an error halts evaluation before the end of the script. (Note: if this occurs, the final trace state will not be used, as it is expected to be the duplicated final result produced by
vm.debug
, and should not be matched with the next instruction. The returnedunmatchedStates
will have a length of0
.)This method allows for samples to be extracted from a single evaluation; most applications should use extractEvaluationSamplesRecursive instead.