Simulating a blockchain
In case you missed the note on this section's first page, the functionality described in this page uses the unmaintained Ganache software library for simulating the EVM. See note for rationale and risk expectations.
This reference implemention relies heavily on the
Machine
interface it defines for reading the state of a running EVM; this page describes
how this implementation's integration tests adapt an
EIP-1193 JavaScript provider object
to this interface.
Since the primary purpose of Machine is to represent a series of code
execution steps, the adapter described here simplifies the concept of an
execution trace by restricting it to mean that which happens within the course
of an Ethereum transaction. The tests thus define a machineForProvider
function to adapt a provider object for a particular transaction hash.
As a result, this code only functions in the context of a provider to a
blockchain whose JSON-RPC exposes the original
go-ethereum's
"debug_traceTransaction" method, which exposes the state of the EVM at each
step of code execution for a particular transaction. Other kinds of traces (such
as tracing the execution of an "eth_call" request) are left to remain
intentionally out-of-scope for the purposes of testing this implementation.
Other implementations of the Machine interface need not make this restriction.
Implementing machineForProvider()
The machineForProvider() function takes two arguments and returns an object
adhering to the Machine interface. See the code listing for this function:
export function machineForProvider(
provider: EthereumProvider,
transactionHash: Data,
): Machine {
return {
trace(): AsyncIterable<Machine.State> {
return {
async *[Symbol.asyncIterator]() {
const structLogs = await requestStructLogs(
`0x${transactionHash.asUint().toString(16)}`,
provider,
);
for (const [index, structLog] of structLogs.entries()) {
yield toMachineState(structLog, index);
}
},
};
},
};
}
This function is written to return an object whose trace() method matches that
which is defined by Machine: a method to asynchronously produce an iterable
list of Machine.States. This function leverages two other helper functions as
part of the behavior of this method: requestStructLogs() and
toMachineState().