Replies: 2 comments
-
Super cool! I guess this is more of a question for @patrick-ogrady, but I wonder if there's a "Disneyland Fastpass" model where transactions don't specify all of the state keys they touch still get executed but with a lower priority (this feature would be off by default, of course). I know we've had discussions around this before, but to have such a high failure rate on transactions seems pretty limiting, especially in a world where all the fees are always consumed (I think this is the case; please correct me if I'm wrong). |
Beta Was this translation helpful? Give feedback.
-
Nice work! It would be interesting to support relaying the transaction envelopes and standards that are already supported on Ethereum like EIP-712, EIP-2771, or account abstraction standards like ERC-4337. I'm not sure which one would be best, but I'd imagine if we supported one instance of these there's an external team already running a relayer service that could integrate and handle all of the state tracing and populating the HyperSDK transaction format. |
Beta Was this translation helpful? Give feedback.
-
Intro
This writeup summarizes initial experimentation and provides an overview of proof-of-concept code for executing EVM bytecode as a hyperSDK
chain.Action
(implemented here).All feedback is welcome
Presumptions
EVM interface
At the core of this idea, the HyperVM interfaces with the EVM by implementing the "core/state.Database" interface. This is done using a shim layer that maps the hyperVM's state to the EVM's state. In other words, the hyperVM provides addresses for the EVM accounts and storage slots. The hyperVM must also provide storage for the EVM bytecode that contract creation transactions write to and contract execution and certain opcodes read.
This is the core logic:
core/vm
package, which is the EVM bytecode interpreter. Additionally, this implementation contains detailed logic (eg, EVM revert logic or empty account handling).This seems preferable to implementing the core/vm.StateDB interface, which would need to replicate much of
core/state.StateDB
.*core/state.StateDB
can then be passed to the NewEVM function, and we can call core.ApplyMessage to execute the EVM bytecode.state.Mutable
(in accordance with its mapping scheme), which can be used to continue processing the Action as any other hyperVM Action.EVM modifications
This commit makes the following minor modifications to
subnet-evm
for this integration:vm.Config
(EVM configuration) is expanded to allow setting custom precompiles (and other minor operational aspects of the EVM).NewVM
function incore/vm
is wrapped incore
here to set defaults for the expandedvm.Config
. The call-sites are updated to use this wrapper.core/vm
package only contains minor modifications compared to upstream. These use the expanded options fromvm.Config
instead of the current non-configurable implementation or hardcoded values.Note: The referenced commit reduces or improves maintainability of differences with upstream.
State key tracing
Unlike EVM transactions, which have an optional access list, hyperVM actions must specify the keys they will read, update, or allocate prior to execution.
EVM nodes can construct an access list by running the transaction against current state and recording the keys accessed via eth_createAccessList. This experiment uses a similar approach and adds a VM-specific API call traceTx to the hyperVM.
The API call constructs the needed arguments to run the Action and wraps the current state with a tracing layer so it can identify keys that are accessed at the database level (and returns them to the user so they can sign the final transaction, which includes the serialized set of keys that will be read/write by the Action). Although the API contains EVM specific outputs, this approach is generic enough for use with other Actions as well. This unit test demonstrates a simplified version of key tracing and executing the action.
Note that state may be modified by the time the transaction including the Action is executed, and it is possible the Action tries to access different keys than those traced. Since this results in failed execution, programming models built on top of hyperVMs may wish to provide domain-specific methods to specify the keys they will access to result in fewer failed transactions. This may be difficult in a turing-complete like environment such as the EVM.
Note: I decided against using the EVM's access list to encode this information, since it is not clear how to map the EVM's access list to the hyperVM's key space (eg, EVM's access list does not distinguish reads and writes for bytecode from accessing the account itself), and specifying the access list may alter gas usage and therefore the execution path.
HyperVM / EVM interoperability details and limitations of this experiment
uint64
and conversion between auint64
and the EVM'sbig.Int
is left as future work.Since the action is already paying for storage, it is likely that gas for storage opcodes should be significantly reduced so gas is a more effective proxy for compute. For example, custom opcodes or gas modification can be added to the current
vm.Config
expansion idea.Tested functionality
The experiment performs the following steps in a repeatable test as a demonstration of the EVM integration:
TokenA
andTokenB
, and add liquidity for to the Uniswap liquidity pool for this pair.TokenA
forTokenB
while half of the accounts tradesTokenB
forTokenA
via the Uniswap liquidity pool. To keep the pools balanced, the accounts will rotate their roles each round for 100 rounds of trading.This test used 1000 accounts and usually results in > 80% successful transactions (some transactions fail because they access different state keys at execution).
Addendum: EVM relayer
As an experiment in wallet compatibility, a simple EVM relayer was implemented. This relayer listens for EVM transactions, traces the state keys for the EVM transaction, signs the result, and finally submits each one to the hyperVM. This is a simple example of how a wallet could be used to interact with the hyperVM. The relayer is implemented here and can be invoked like:
This relayer involves sending zero values for many cases such as gas prices, block and transaction hashes, and in general should be considered a proof of concept which is not suitable for any type of use.
While it is possible to construct such a relayer in the future, it is likely to require ongoing maintenance and support. Some edge case examples encountered during this experiment:
eth_getFeeHistory
oreth_gasPrice
to determine whether EIPs have been activated.Beta Was this translation helpful? Give feedback.
All reactions