Recently I was experimenting with FuelVM - an optimistic rollup (in the default configuration, there are more options for setup - see below) working on top of Ethereum that provides Smart Contract functionality and is focused on delivering significantly higher transaction speeds and, as a side effect, lowering the transaction fees. You can learn more about the Fuel VM project on the Fuel Labs website.
The speed goals are delivered by a combination of techniques that FuelVM employs. First one being parallelization of the transaction execution thanks to the UTXO execution model. It allows leveraging OS multi-threading and CPU cores for parallel execution of transactions in a block which significantly reduces the execution time when compared to single-threaded execution.
Another aspect that speeds up the whole solution is the use of Rust language for implementing the node. Rust is a secure language in a sense that it prevents many types of weaknesses from being introduced into the program at the compilation time. Various strategies for memory management, variables lifetimes, concurrency etc.. are used to eliminate such weaknesses classes such as:
All of these weaknesses were often resulting in serious vulnerabilities identified in the final products that were written in C, C++, etc.
In contrast to languages that rely on runtime memory management solutions such as garbage collectors (e.g., Java, Golang), Rust prevents the programmer from introducing the weakness during the compilation time by enforcing some principles of secure variable and memory management. Such principles include e.g.:
This way, Rust applications can speed up execution by eliminating the need for GC while maintaining high level of application security.
At the heart of every Fuel network there is a FuelVM node. In its monolithic configuration It's responsible for a variety of functions, including joining the network, executing smart contract transactions, participating in the consensus protocol. But Fuel is designed as a modular solution, which means it can be deployed in different configurations in which some functions can be delegated to other solutions.
Therefore, according to the design, FuelVM will be able to function as:
Fuel toolchain consists of several tools for managing code units, building and deployment, Rust-style. The most important elements include:
At the time of writing this post, according to my understanding, no mainnet yet exists for Fuel. The current version of public testnet is the Beta3 testnet. Therefore, the smart contracts described below have been deployed to this testnet.
The build toolchain with its CLI tool for manipulating wallets is supplemented by a browser wallet plugin that allows for interacting with the applications frontend. You can use the beta3 testnet faucet to send some ETH to your wallet: https://faucet-beta-3.fuel.network/
The Fuel smart contracts are created with the use of new language - Sway. It's based on Rust language but brings concepts from Solidity as well. Similarly to Rust, it's statically typed, compiled language with type interface and traits. The authors are aiming at making Sway safe and well performing through the use of static analysis and rich compiler feedback.
Ok, now let's get back to the actual smart contract primer. The idea for this one came to me during my discussions with a friend. We enjoy comparing and discussing our worldviews and often, while we are focusing on a particular topic, we are reaching a level of details at which every logical operator in a sentence seems to be important and it's crucial to get all of the sentence correct in order to understand the other person's position on the topic. Especially when it comes to definitions.
We both faced this situation several times (especially if alcohol was involved): Either he or me felt that his words have been twisted but were unable to recall what has been said on sufficient detail level. Was it that "I like all cats" or "I like some cats". This kind of claims have of course profound impact on how we view the world :). Therefore, I felt that we should employ modern technology to end this mutual drunken gaslighting.
The idea for the application is the following:
In case of the Sway smart contracts, we are defining separately:
Let's start with a single hash of the claim being stored on-chain.
First we signal to the compiler that the file contains a contract. It the storage section we declare one variable said of type b256 stored on-chain that will be holding hash of the last claim made by the user.
Then we implement the contract ABI, two methods:
This variant allows us to store only the last thing said. But let's use it as a primer to go through the building and deployment.
Now let's use the forc (Fuel Orchestrator) to build the contract.
Looks good (please ignore the warning :))!
For this primer, I will skip unit tests for the contract for now and will proceed with the deployment. But let me just say that unit tests are an important part of every CI/CD pipeline and should be included when writing production applications.
In order to deploy the contract on the testnet we need to create and sign the transaction:
forc deploy --node-url beta-3.fuel.network/graphql --gas-price 1 --random-salt
Please note the address of deployed contract, we will use it in the frontend. Don't mix it with the block number as I often do :).
For the frontend we will create a simple React application:
npx create-react-app hesaid-frontend --template typescript
Then, let's install the Fuel SDK (don't forget to include it in tsconfig.json):
npm install fuels@0.38.0 @fuel-wallet/sdk --save
We need to convert the ABI of our contract to the form that can be used by the frontend:
We import the contract factory alongside the deployment address:
The application itself:
Couple of words of explanation. First, the application confirms that the Fuel wallet is connected to this application. If not, it requests the user to connect.
Once the fuel wallet is connected, the interface is displayed with two buttons: Say and Did say?, one input field for the claim and the second one for verdicts.
Upon clicking the Say button, the say function is called which in turn takes the claim X from the inputValue field, calculates the keccak256 hash and calls the backend contract for storing it on-chain:
Upon clicking the Did say? button, the did_say function is called which in turn takes the X' claim from the inputValue field, calculates the keccak256 hash and calls the backend contract for the verdict. The contract checks if the hash matches the value stored on-chain and displays the verdict.
Let's start the application and test it!
It's a little impractical to hold just the last claim on-chain. What if instead of only the last one, one of the previous claims came up during the discussion and was being challenged? Let's modify the smart contract to hold more values:
We are bringing the StorageVec type from the std::storage library into the scope. This type allows us to store many values on the chain via its push method. In the did_say method we are going over all of the vector's element and comparing them to the parameter passsed by the frontend.
Let's deploy it and test it!
As you see, now we can keep many claims on the chain and check the challenged claim against this list.
Many things can be improved in this application:
In this entry I summarized my initial experiences with Fuel network and available toolset. I think this is a very interesting solution, speeding up the transactions and lowering the fees are very much needed indeed. As an optimistic rollup, Fuel can diverge from the safe direction chosen by the Ethereum community and deliver new, exciting functionality. For a security professional, the threat model for such a rollup is also very interesting and I will probably investigate the fuel-core internals and create a separate entry on this subject.