FuelVM learns from the EVM, Solana, WASM, Bitcoin, and Cosmos.
This page is meant to outline the ways the FuelVM differs compared to the EVM in simple terms.
The FuelVM has a globally shared memory architecture. Instead of every contract call having its own separate memory space, call data, and return data, all contract call frames share global memory. This chunk of memory is shared amongst all call frames and is globally readable. This allows you to pass data around between contracts without expensive storage and pass chunks of data without having to serialize, copy from call data to memory, etc. Read more about the FuelVM memory model here.
The EVM is a complicated machine to construct fraud proofs for. It usually requires a second layer such as WASM or MIPS to be interpreted into a fraud provable system. Check out User Sovereignty with Fraud Proofs and how fraud proofs unlock key functionality.
In Ethereum, the only native asset is Ether. It’s the only one that gets first-class treatment in terms of cost and ability to be pushed and pulled through a call. In Fuel, any contract can mint its UTXO-based native asset using a set of easy asset opcodes. All of which can gain the benefits of native-level call and optimization. Read more about support for multiple native assets in the Sway docs, and here.
Modern processors have 64-bit registers, and all of the instruction set operates on 64 bits. Those are the most efficient instructions, and when you deal with 256 bits, you’re dealing with big numbers, and since modern processors aren't made to handle those numbers natively, it means you have to do more in the software.
Register-based VMs typically require fewer instructions to do the same work than stack-based VMs. Because every operation is priced, optimizing to reduce the number of operations needed to do the same amount of work has outsized benefits.
Fuel uses a system of UTXOs which enable a more efficient system fo transfer and ownership of assets, where the accounts tree doesn't have to be rebuilt every time funds are transferred.
The FuelVM removes the need for approve/transferFrom UX with scripts. Unlike the EVM, the FuelVM has scripts, which allow many actions to happen from an origin sender without a contract being deployed. Read more in the Fuel Specification here.
The FuelVM implements several EIPs that have been suggested and supported by the community but couldn't be implemented due to the need to maintain backward compatibility. Check out a non-exhaustive list, also available here:
|Allow transactions in the EVM to be processed in parallel by specifying what addresses they can access.
|Fuel can execute transactions in parallel by using strict state access lists with our UTXO model. This allows Fuel to use of all the threads and cores of your CPU to validate transactions.
|EIP-2098: Compact Signature Representation
|Reduce signatures from 65 bytes to 64 bytes to simplify handling transactions in client code, reduce gas costs, and reduce transaction sizes.
|Fuel compresses signature data by a byte, from 65 to 64 bytes.
|Introduces two EVM instructions,
AUTHCALL, to enable batching capabilities, allowing for gas sponsoring, expirations, scripting, and beyond.
|Fuel has scripts and predicates that, when combined, allow the execution of multiple calls in a single batch.
|EIP-3102: Binary Trie Structure
|Introduces binary structure and merkelization rule for the account and storage tries, which are merged into a single “state” trie. Binary tries make for smaller (~4x) proofs than hexary tries, making it the design of choice for a stateless-friendly Ethereum.
|Fuel uses a binary Sparse Merkle Trie instead of a Patricia Merkle Trie, which makes for smaller proofs and results in better performance.
|EIP-4758: Deactivate SELFDESTRUCT
SELFDESTRUCT opcode to
SENDALL, and only immediately move all ETH in the account to the target; no longer destroying code or storage or alters the nonce. Disabling
SELFDESTRUCT will be a requirement for statelessness.
|The FuelVM doesn't have a
SELFDESTRUCT opcode which can complicate client implementations.
|EIP-5027: Remove the limit on contract code size
|Remove the limit on the code size so that users can deploy a large-code contract without worrying about splitting the contract into several sub-contracts. With the dramatic growth of decentralized applications, the functionalities of smart contracts are becoming more and more complicated, and thus, the sizes of newly developed contracts are steadily increasing. As a result, we are facing more issues with the 24576-bytes contract size limit.
|FuelVM doesn't have a limit on the size of a single contract below their physical limits. We have an instruction that allows you to load bytecode from another contract into the current execution context, allowing you to use it as a single contract even if you have to split bytecode across multiple transactions. It'll have a single monolithic bytecode and one state. In EVM, if you spit a contract across two transactions, it's two separate contracts, and you have to do things like delegate calls to share the state between the two contracts and can't do things like jump between bytecode on each contract.
|EIP-5065: Instruction for Transferring Ether
|Add a new instruction that transfers ether to a destination address without handing over the flow of execution to it. Ethereum currently has no ideal way to transfer ether without transferring the execution flow. People have come up with reentrancy guards and similar solutions to prevent some types of attacks, but it’s not an ideal solution.
|The FuelVM has an instruction called
TR, short for transfer, which transfers a native asset to a contract but doesn't allow the receiving contract to execute logic. You might want to do this to ensure the receiving contract cannot reenter. This doesn't exist as a native, first-class instruction in the EVM- you can do this by self-destructing a contract but it's a messy workaround that only works for ETH.
|EIP-86: Abstraction of Transaction Origin and Signature and EIP-2938: Account Abstraction
|Implements a set of changes that serve the combined purpose of “abstracting out” signature verification and nonce checking, allowing users to create “account contracts” that perform any desired signature/nonce checks instead of using the mechanism currently hard-coded into transaction processing.
|FuelVM has stateless account abstraction, enabling application-layer logic to configure validity rules of transactions. On Ethereum today, a transaction is valid if the user has enough Ether, the nonce is correct, and signature is valid. With account abstraction, the user can change the validity of the transaction logic without a hard fork. This could mean changes to the signature scheme or natively locking an account behind a multisig.
|EIP-1051: Overflow Checking for the EVM
|This EIP adds overflow checking for EVM arithmetic operations and two new opcodes that check and clear the overflow flags. Since the EVM operates on mod 2^256 integers and provides no built-in overflow detection or prevention, this requires manual checks on every arithmetic operation.
|Overflow checking is built into the FuelVM and can be optionally disabled.
|EIP-2803: Rich Transactions
|If a transaction has a to of address x, then the data of the transaction will be treated as EVM bytecode, and it will be executed from the context of the CALLER of the transaction (aka: the transaction signer). Many Ethereum DApps require users to approve multiple transactions to produce one effect. This results in a poor user experience and complicates the experience of interacting with DApps.
|The FuelVM has scripts that implement this.
|EIP-2926: Chunk-based Code Merkelization
|Bytecode is currently the second contributor to block witness size after the proof hashes. Transitioning the trie from hexary to binary reduces the hash section of the witness by 3x, thereby making code the first contributor. By breaking contract code into chunks and committing to those chunks in a Merkle tree, stateless clients would only need the chunks that were touched during a given transaction to execute it.
|To get a code hash on Ethereum, you hash together all the byte code. The problem is that if you want to do things with statelessness or fraud proofs, to show that this hash is valid, you have to provide all the byte code, up to 24KB per contract. This EIP suggests we should merkalize it instead of hashing. The FuelVM implements this by having code roots instead of code hashes.