ishish.io
ishish.io

What is now proved
was once, only imagin'd

- William Blake

Fuel primer - HeSaidSheSaid

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:

  • race conditions
  • double free
  • Use-After-Free
  • wild pointer dereference
  • etc.

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.:

  • Ownership: Every value in Rust has a variable that’s called its owner. There can only be one owner at a time. When the owner goes out of scope, the value will be dropped.
  • Borrowing: Instead of transferring ownership, you can have references to a resource as either mutable or immutable. However, Rust enforces that at any given time, you can have either one mutable reference or any number of immutable references.
  • References: At any given time, you can have either one mutable reference or any number of immutable references. References must always be valid.
  • etc.

This way, Rust applications can speed up execution by eliminating the need for GC while maintaining high level of application security.

Fuel Components

FuelVM node

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.

Picture source: fuel.network

Therefore, according to the design, FuelVM will be able to function as:

  • Complete layer 1 solution
  • Layer 2 rollup
  • State channel
  • Sidechain

Build toolchain

Fuel toolchain consists of several tools for managing code units, building and deployment, Rust-style. The most important elements include:

  • fuel-core - the node, see above
  • fuelup - allows managing the versions of the toolchain
  • forc - compiler for Sway smart contracts
  • forc-client - deploying the contracts on the network
  • fuel-wallet - wallet manipulation
Network

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.

fuellabs.github.io/block-explorer-v2/beta-3/#/
Fuel Wallet

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/

Smart Contracts and Sway Language

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.

HeSaidSheSaid - concept

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:

  1. User A formulates her claim X and requests the application to store it on-chain
  2. The frontend component calculates the keccak256 hash of the claim
  3. The frontend calls web3 component to store the hash on-chain
  4. The discussion continues
  5. User B implies user A made a claim X' earlier in the discussion
  6. Challenged user A asks the frontend component to verify if the claim X' has been in fact made by her
  7. Frontend component calculates keccak256 hash of the X' claim and requests web3 component to verify if claim X' has in fact been made
  8. The result is displayed in the fontend

HeSaidSheSaid - Smart Contract Implementation

In case of the Sway smart contracts, we are defining separately:

  • the storage part - values that will be stored on-chain
  • the ABI of the contract
  • implementation of the ABI

Variant 1 - Single claim

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:

  • say - takes the hash calculated by the frontend and stores it in the contract
  • did_say - compares the hash passed by the frontend as a parameter and returns bool

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 :).

Variant 1 - Frontend

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!

Variant 2 - Multiple claims by a single wallet

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.

Variant 3 (WIP) - Many things said by many wallets

Many things can be improved in this application:

  • multi-wallet - we should assign claims to individual wallets, since user A might've made a claim that user B never made. We want to challenge claims of individual user wallets
  • testing claim variants - it's often not enough to understand that claim X has never been made. It would be very useful to know which claim X' has been made that is similar to the claim X that has not been made. For this I am considering interacting with a language model that would create a set of variants that would be later tested with the contract
  • code style - I'm sure that these could be improved in terms of style, e.g.. use of match and patterns, including some assertions
  • unit tests - yup

Summary

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.

ishish.io Copyright 2024