Files
pezkuwi-runtime-templates/docs/modules/ROOT/pages/guides/testing_with_zombienet.adoc
T
Özgün Özerk 033cf12f34 merge changes/fixes from v2 back into main (#333)
* update version for antora

* improving zombienet guide (#280)

* update docs version to 2.0.1 (#315)

* Change all references from rococo to paseo (#330)

* remove rococo-native featire from cargo.toml and other doc changes

* use evm compatible accounts, and fix properties for chain spec (#326)

* doc changes

* bump node and docs versions

* impl_runtime_apis need to be in the same file with construct runtime for the moment

* account type fix

* zombienet script update

* slot duration fix

---------

Co-authored-by: Nikita Khateev <nikita.khateev@gmail.com>
Co-authored-by: Özgün Özerk <ozgunozerk.elo@gmail.com>
Co-authored-by: Gustavo Gonzalez <gustavo.gonzalez@openzeppelin.com>

---------
2024-10-24 09:36:38 +03:00

317 lines
9.2 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
:source-highlighter: highlight.js
:highlightjs-languages: rust
:github-icon: pass:[<svg class="icon"><use href="#github-icon"/></svg>]
= Testing Solidity Smart Contracts with Zombienet
In this tutorial, we will demonstrate how to deploy your parachain using Zombienet, and test the functionalities of your parachain.
Below are the main steps of this demo:
. Deploy our parachain against the locally simulated Paseo testnet by Zombienet.
. Deploy a Solidity smart contract on our parachain.
. Successfully invoke the Solidity smart contract deployed on our parachain.
== Step 1: Deploy The Parachain
. git clone https://github.com/OpenZeppelin/polkadot-runtime-templates
. move to evm template directory
+
```bash
cd evm-template
```
. replace the content of `zombinet-config/devnet.toml` with:
+
```rust
[relaychain]
chain = "paseo-local"
default_command = "./bin-v1.6.0/polkadot"
[[relaychain.nodes]]
name = "alice"
validator = true
[[relaychain.nodes]]
name = "bob"
validator = true
[relaychain.genesis.runtimeGenesis.patch.configuration.config]
scheduling_lookahead = 2
[relaychain.genesis.runtimeGenesis.patch.configuration.config.async_backing_params]
max_candidate_depth = 3
allowed_ancestry_len = 2
```
. build the zombienet:
+
```bash
./scripts/zombienet.sh build
```
+
.if you came across this error (click to expand):
[%collapsible]
====
```bash
error[E0635]: unknown feature `stdsimd`
--> /Users/ozgunozerk/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ahash-0.7.6/src/lib.rs:33:42
|
33 | #![cfg_attr(feature = "stdsimd", feature(stdsimd))]
```
`Cd` into the `polkadot-sdk` directory (the path should be visible on the error message), and run the below command to update `ahash`:
```bash
cargo update -p ahash@0.7.6
```
====
+
.or if you came across this error (click to expand):
[%collapsible]
====
```rust
assertion failed [block != nullptr]: BasicBlock requested for unrecognized address
```
just re-run 🙂
====
. run the zombinet:
+
```bash
./scripts/zombienet.sh devnet
```
. build it with `async-backing` feature:
+
```bash
cargo build --release --features="async-backing"
```
. copy the `Direct Link` from `Alice's` tab from Zombienet TUI:
+
image::alice-direct-link.png[Alice Direct Link]
. Open the link with Chrome: link:https://polkadot.js.org/apps[PolkadotJS]. As of 2024 July, it doesnt work on Safari and Brave, and it is buggy on Firefox.
. Reserve a `ParaId` on Zombienet:
.. Go to `Network` > `Parachains`
.. Go to `Parathreads` tab
.. Click the `+ ParaId` button
.. Save a `parachain id` for the further usage.
.. Click `Submit` and `Sign and Submit` (you can use `Alice` as the account).
. Preparing necessary files to become a Parachain:
.. Generate a plain chainspec:
+
```bash
./target/release/evm-template-node build-spec --disable-default-bootnode > plain-parachain-chainspec.json
```
.. Edit the chainspec:
... Update `name`, `id` and `protocolId` to unique values (optional).
... Change `para_id` and `parachainInfo.parachainId` from `1000` to the previously saved parachain id (probably 2000 if thats your first time ;) ).
... Edit the `evmChainId.chainId` to the value of your choice. Try to select a value that has no existing EVM chain assigned to it (should be ok to leave as is for the most cases).
.. Generate a raw chainspec:
+
```bash
./target/release/evm-template-node build-spec --chain plain-parachain-chainspec.json --disable-default-bootnode --raw > raw-parachain-chainspec.json
```
.. Generate the genesis state:
+
```bash
./target/release/evm-template-node export-genesis-state --chain raw-parachain-chainspec.json > genesis-state
```
.. Generate the validation code:
+
```bash
./target/release/evm-template-node export-genesis-wasm --chain raw-parachain-chainspec.json > genesis-wasm
```
. Registering the Parachain:
.. Go back to `polkadot.js.org/apps` (remember Chrome). Go to `Developer/Sudo`.
.. select `pasasSudoWrapper` and `sudoScheduleParaInitialize(id, genesis)`
.. enter the reserved id (2000) to `id` field
.. enable `file upload` for both `genesisHead` and `validationCode` → because we will upload files for these.
.. select `Yes` for `paraKind` → meaning when we register our parachain, it will be a parachain rather than a parathread.
.. drag&drop your `genesis-state` file generated in step `10.d` into `genesisHead` field (good luck with the aiming)
.. drag&drop your `genesis-wasm` file generated in `10.e` into `validationCode` field
.. It should look like below:
+
image::register-parachain.png[Register Parachain]
.. `Submit Sudo`!
. copy the path to `chain-spec` from zombienet terminal from `Bob` (beware, this file is changing every time you spin up a new zombienet):
+
image::zombie-chain-spec.png[Zombie Chain Spec]
. run the node, and provide the `chain-spec` you copied from the last step into `--chain` part:
* be sure to clear your storage if you were running a node before
+
```rust
./target/release/evm-template-node \
--alice \
--collator \
--force-authoring \
--chain raw-parachain-chainspec.json \
--base-path storage/alice \
--port 40333 \
--rpc-port 8844 \
-- \
--execution wasm \
--chain /var/folders/...{redacted}.../paseo-local.json \
--port 30343 \
--rpc-port 9977
```
. your node should be running without any problem, and should see block production in your node terminal!
+
image::node-success.png[Node Success]
== Step 2: Deploy a Solidity Smart Contract
. Install Foundry with: `curl -L [https://foundry.paradigm.xyz](https://foundry.paradigm.xyz/) | bash`
. have a smart contract file ready, any smart contract of your choice! We will go with a cute `HelloWorld.sol` smart contract for this tutorial:
+
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract HelloWorld {
string public greeting = "Hello, World!";
function getGreeting() public view returns (string memory) {
return greeting;
}
}
```
. Create a new javascript project with the below files:
.. `package.json`:
+
```solidity
{
"name": "ts-wallet",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"exec": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"web3": "^4.8.0"
}
}
```
.. `sanity_check.js`:
+
```solidity
import { Web3 } from "web3";
const web3 = new Web3("ws://127.0.0.1:8844");
console.log("Balance:");
// this is the address of `Alith` in our chainspec
web3.eth.getBalance("0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac").then(console.log);
let raw = await web3.eth.accounts.signTransaction({
gas: 21000,
gasPrice: 10000000000,
from: "0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac", // Alith's address
to: "0x7c98a1801f0B28dF559bCd828fc67Bd6ab558074", // Baltathar's address
value: '100000000000000000'
}, "0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133"); // Alith's private key
let res = await web3.eth.sendSignedTransaction(raw.rawTransaction);
console.log("Transaction details:");
console.log(res);
```
.. `invoke_smart_contract.js`:
+
```solidity
import { Web3 } from "web3";
import { MyAbi } from "./abi.js";
const web3 = new Web3("ws://127.0.0.1:8844");
let contract = new web3.eth.Contract(MyAbi, "0x4045F03B68919da2c440F023Fd7cE2982BfD3C03");
let s = await contract.methods.getGreeting().call();
console.log(s);
```
.. `abi.js`:
+
```solidity
export var MyAbi = [
{
"type": "function",
"name": "getGreeting",
"inputs": [],
"outputs": [
{
"name": "",
"type": "string",
"internalType": "string"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "greeting",
"inputs": [],
"outputs": [
{
"name": "",
"type": "string",
"internalType": "string"
}
],
"stateMutability": "view"
}
];
```
. run the below command, and you should see the balance, and then the transaction details printed, proving everything works so far!
+
```solidity
node sanity_check.js
```
. open a terminal instance where the current directory has the `HelloWorld.sol` file, and run the below command to deploy the contract with Alith's private key:
+
```solidity
forge create --rpc-url http://localhost:9933 --private-key 0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133 HelloWorld.sol:HelloWorld
```
+
* dont forget to copy the address this contract deployed to (shown in the output of the command)!
== Step 3: Invoke The Solidity Smart Contract
. replace the contract address in `invoke_smart_contract.js` with the address you copied!
. build the `abi` of the smart contract with:
+
```solidity
forge build --silent && jq '.abi' ./out/HelloWorld.sol/HelloWorld.json
```
. Surprise! We already give you the abi of this in `abi.js` file in step `3`. If you used another contract than `HelloWorld`, replace that `abi.js` files content with your contracts `abi`.
. run the below command, and you should see your smart contract in action:
+
```solidity
node invoke_smart_contract.js
```