Getting Rust Contract in Wasm Working
Introduction
Here are the steps to run the basic_contract_rs
.
- Rust Smart Contract hosted within a Wasm engine
- Hyperledger Fabric v2
This guide will start up a 1 Organization, 1 Peer Fabric Network and start the contract.
Creating a working directory to hold the github repos we’ll clone. (examples assume that this is ~/github.com) A lot of the steps need only to be done once.
Getting setup
- Install the preqres for Rust and Wasm Development
- Stable Rust is sufficient, nightly is not required. Instructions at the rust-lang.org
- To build a Wasm binary you will need to have the wasm target. Note that wasm-pack is not required here as there is no JavaScript host.
rustup target add wasm32-unknown-unknown
- VSCode is our preferred editor, with the Rust Extension and the Rust Analyser
Hyperledger Fabric Docker images
We need Fabric Version 2, which you may already have so can skip this.
curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap.sh | bash -s -- 2.2.0 1.4.4 0.4.18 -s -b
Fabric Network
It’s perfectly possible to use the fabric-samples
test-network for this, that’s 2 Organization network. For these instructions, we want to use a smaller network purely for development purposes.
In your working directory clone the fabric-dev-networks
repo
git clone https://github.com/hyperledgendary/fabric-dev-networks.git
Then build the docker tools image that can be used to control it
docker build -t hyperledgendary/fabric-tools .
External builders
Fabric knows about the following languages implicitly. Java, Node, Go. However the peer is not really supposed to be the orchestrator of creating docker images. So this is where the external builder comes in.
To setup the external builder, you need to configure the peer and the easiest way to do that is by using the fabric-builders
project.
git clone https://github.com/hyperledgendary/fabric-builders
Next step is to build the updated peer docker image - we will need to use this to create a local Fabric network; the configuration of the external builder needs to modify the peers configuration file. This is easiest to do by creating a new docker image with the updated config file.
Change into the fabric-builder-peer
repo and build the docker image
docker build -t hyperledgendary/fabric-builder-peer .
Creation
Now we’re going to create the various assets etc that we need
Fabric Network
From the fabric-builders
directory
Generate the small network config files
docker run --rm -v small_config:/etc/hyperledger/fabric -w /etc/hyperledger/fabric --entrypoint=/bin/bash hyperledgendary/fabric-tools -c "setnet.sh"
Replace core.yaml
file with one from fabric-builders
docker run --rm -v ${PWD}:/local:ro -v small_config:/etc/hyperledger/fabric -w /etc/hyperledger/fabric --entrypoint=/bin/bash hyperledgendary/fabric-tools -c "cp /local/core.yaml ."
Update the small network docker-compose.yaml
file to use hyperledgendary/fabric-builder-peer
images
cd ~/github.com/fabric-dev-networks/networks/small/
sed -i.bak 's|hyperledger/fabric-peer|hyperledgendary/fabric-builder-peer|g' docker-compose.yaml
Bring up the docker compose network
docker-compose -f docker-compose.yaml up -d orderer.example.com peer0.humboldt.example.com couchdb cli
Create the Fabric network
docker exec humboldt.cli mknet.sh
Smart Contract
- In your working directory, clone this repo
git clone https://github.com/hyperledgendary/fabric-contract-api-rust.git
- Ensure it can be built correctly, cd into the
fabric-contract-api-rust
- Using make:
make -f justfile wasm
- Using just:
just wasm
- Using cargo:
cargo build --target wasm32-unknown-unknown
- Using make:
This will have built a Wasm binary to fabric-contract-api-rust/target/wasm32-unknown-unknown/debug/basic_contract_rs.wasm
External chaincode container
One final git repo to clone
git clone git@github.com:hyperledgendary/fabric-chaincode-wasm.git
docker build -t hyperledgendary/fabric-chaincode-wasm .
Copy the chaincode.env.sample
to chaincode.env
. This will need to be editted shortly, so it’s good to keep a copy of the original
It’s also worth copying the wasm binary file created previously, for example if you’re following the same directory structure run this command
cp ../fabric-contract-api-rust/target/wasm32-unknown-unknown/debug/basic_contract_rs.wasm ./contracts
Contract Deploy
Package and install Wasm chaincode
Create a connection.json
file with details of how Fabric will connect to the external service chaincode
{
"address": "wasmcc.example.com:9999",
"dial_timeout": "10s",
"tls_required": false
}
Package the connection.json
file using the pkgcc.sh script
Again if you have the same directory structure, this command
../fabric-builders/tools/pkgcc.sh -l wasmftw -t external connection.json
A wasmftw.tgz
file will be created. This is the chaincode package that will be installed on the peer - as the proxy for the real chaincode. Feel free to unpack and investigate it’s contents.
Copy the chaincode package to a docker volume for installing
docker run --rm -v ${PWD}:/local:ro -v small_cli:/var/hyperledgendary/fdn -w /var/hyperledgendary/fdn --entrypoint=/bin/bash hyperledgendary/fabric-tools -c "cp /local/wasmftw.tgz ."
Install the new chaincode package
docker exec humboldt.cli peer lifecycle chaincode install /var/hyperledgendary/fdn/wasmftw.tgz
It’s important to keep the output from this command as it will be needed in the next step
Run Wasm chaincode
Create a chaincode.env
file, making sure the CHAINCODE_ID matches the chaincode code package identifier from the install command
CHAINCODE_SERVER_ADDRESS=wasmcc.example.com:9999
CHAINCODE_ID=wasmftw:a5ceee0db53cdb4b50975c2379cc346075697873341af71a7440b5d4d7f1ca0c
CHAINCODE_WASM_FILE=/local/basic_contract_rs.wasm
Run the chaincode: note that this docker command runs it in foreground so you can watch what happens. Worth opening another terminal at this point.
docker run -it --rm -v ${PWD}/contracts:/local:ro --name wasmcc.example.com --hostname wasmcc.example.com --env-file chaincode.env --network=small_fabricdev hyperledgendary/fabric-chaincode-wasm
Approve and commit the Wasm chaincode
Approve the chaincode, making sure the package-id
matches the chaincode code package identifier from the install command
docker exec humboldt.cli peer lifecycle chaincode approveformyorg -o orderer.example.com:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --cafile /etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID smallchannel --name wasmftw --version 1 --sequence 1 --waitForEvent --package-id wasmftw:eeae07c6e9455f329e28f9a0eed977ae3549be68e68247018f71dc5a5f511c0d
Commit the chaincode
docker exec humboldt.cli peer lifecycle chaincode commit -o orderer.example.com:7050 --tls true --cafile /etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID smallchannel --name wasmftw --version 1 --sequence 1
Run a transaction!
Create an asset….
docker exec humboldt.cli peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C smallchannel -n wasmftw -c '{"function":"AssetContract:create_asset","Args":["007","Bond"]}'
docker exec humboldt.cli peer chaincode query -o orderer.example.com:7050 --tls true --cafile /etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C smallchannel -n wasmftw -c '{"function":"AssetContract:read_asset_value","Args":["007"]}'