Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add hello world example #12

Draft
wants to merge 31 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8ffe814
add example precompile
ceyonur Oct 2, 2023
052d93b
Merge branch 'main' into hello-world-example
ceyonur Oct 2, 2023
511d200
bump versions
ceyonur Oct 25, 2023
503de25
Merge branch 'release-v0.1.5' into hello-world-example
ceyonur Oct 25, 2023
e2b1e8c
bump subnet-evm and avago versions
ceyonur Oct 26, 2023
6a4dd26
Merge branch 'release-v0.1.5' into hello-world-example
ceyonur Oct 26, 2023
0a70b13
Merge branch 'main' into hello-world-example
ceyonur Nov 10, 2023
f1ca45a
bump versions
ceyonur Dec 7, 2023
dd4e681
Merge branch 'release-v0.1.7' into hello-world-example
ceyonur Dec 7, 2023
5f65080
update npm packages
ceyonur Jan 29, 2024
f50df39
bump versions
ceyonur Jan 29, 2024
b87a39f
Merge branch 'bump-subnet-evm-v0-5-11' into hello-world-example
ceyonur Jan 29, 2024
d3257dc
Merge branch 'main' into hello-world-example
ceyonur Feb 26, 2024
c22192c
update go mod
ceyonur Feb 26, 2024
cc441ad
add durango changes
ceyonur Feb 27, 2024
769c810
remove subnetEVM timestamp to enable defaults
ceyonur Feb 27, 2024
4599d48
add hardhat events test
ceyonur Feb 29, 2024
92eab0b
Merge branch 'main' into hello-world-example
ceyonur Feb 29, 2024
974b707
Merge branch 'main' into hello-world-example
ceyonur Mar 26, 2024
176eb9d
Merge branch 'hello-world-example' of github.com:ava-labs/precompile-…
ceyonur Mar 26, 2024
49785b3
Merge branch 'main' into hello-world-example
ceyonur Mar 28, 2024
4b8f323
update subnet-evm v0.6.4
ceyonur May 2, 2024
d81e707
update avago in devcontainer
ceyonur May 3, 2024
d95d9a2
remove shellcheck
ceyonur May 3, 2024
ba74e4c
Merge branch 'prepare-v0.2.2' into hello-world-example
ceyonur May 3, 2024
4d7ba80
run go mod tidy
ceyonur May 3, 2024
30d9ae8
update genesis
ceyonur May 3, 2024
cc779ec
Merge branch 'hello-world-example' of github.com:ava-labs/precompile-…
ceyonur May 3, 2024
6d53b08
update devcontainer genesis
ceyonur May 3, 2024
83a2843
Merge branch 'prepare-v0.2.2' into hello-world-example
ceyonur May 3, 2024
e4a091f
change helloworld genesis ts
ceyonur May 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions .devcontainer/devcontainer.json
Expand Up @@ -6,7 +6,7 @@
"build": {
"dockerfile": "Dockerfile",
"args": {
"AVALANCHEGO_VERSION": "v1.11.3"
"AVALANCHEGO_VERSION": "v1.11.5"
}
},
"runArgs": ["--network=host"],
Expand All @@ -21,7 +21,7 @@
},

// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {
"version": "latest"
},
Expand Down
11 changes: 1 addition & 10 deletions .devcontainer/genesis-example.json
@@ -1,15 +1,6 @@
{
"config": {
"chainId": 99999,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"muirGlacierBlock": 0,
"warpConfig": {
"blockTimestamp": 0,
"quorumNumerator": 67
Expand All @@ -32,7 +23,7 @@
}
},
"nonce": "0x0",
"timestamp": "0x0",
"timestamp": "0x66350B4E",
"extraData": "0x00",
"gasLimit": "0xe4e1c0",
"difficulty": "0x0",
Expand Down
24 changes: 24 additions & 0 deletions .github/workflows/sync.yml
@@ -0,0 +1,24 @@
name: Sync
on:
push:
branches:
- main

jobs:
sync-branches:
runs-on: ubuntu-latest
name: Syncing branches
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Node
uses: actions/setup-node@v1
with:
node-version: 12
- name: Opening pull request
id: pull
uses: tretuna/sync-branches@1.4.0
with:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
FROM_BRANCH: "main"
TO_BRANCH: "develop"
@@ -1,44 +1,58 @@
name: Build + test + release
name: Tests

on:
push:
branches:
- master
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- '*'
pull_request:

env:
min_go_version: '~1.21.9'

jobs:
lint_test:
name: Lint
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '~1.21.7'
go-version: ${{ env.min_go_version }}
check-latest: true
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.54
version: v1.56
working-directory: .
args: --timeout 10m
skip-pkg-cache: true

unit_test:
name: Golang Unit Tests
runs-on: ubuntu-20.04
name: Golang Unit Tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, ubuntu-20.04, ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '~1.21.7'
go-version: ${{ env.min_go_version }}
check-latest: true
- name: Set timeout on Windows # Windows UT run slower and need a longer timeout
shell: bash
if: matrix.os == 'windows-latest'
run: echo "TIMEOUT=1200s" >> $GITHUB_ENV
- run: go mod download
shell: bash
- run: ./scripts/build.sh ./build/precompile-evm
- run: ./scripts/build.sh ./build/subnetevm
shell: bash
- run: ./scripts/build_test.sh -race
- run: ./scripts/build_test.sh
env:
TIMEOUT: ${{ env.TIMEOUT }}
shell: bash
- run: ./scripts/coverage.sh
shell: bash
Expand All @@ -48,16 +62,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Git checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: '~1.21.7'
go-version: ${{ env.min_go_version }}
check-latest: true
- name: Use Node.js
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: "18.x"
- name: NPM Clean Install
Expand Down
104 changes: 103 additions & 1 deletion README.md
Expand Up @@ -35,10 +35,111 @@ To get a comprehensive introduction to Precompile-EVM, take the Avalanche Academ

There is an example branch [hello-world-example](https://github.com/ava-labs/precompile-evm/tree/hello-world-example) in this repository. You can check the example branch to see how to register precompiles and test them.

### Clone the Repo

```zsh
git clone https://github.com/ava-labs/precompile-evm.git
cd precompile-evm/ # change directory to the precompile-evm/ directory
```

### Checkout the `hello-world-example` Branch

```zsh
git checkout hello-world-example

branch 'hello-world-example' set up to track 'origin/hello-world-example'.
Switched to a new branch 'hello-world-example'
```

### Install NodeJS Dependencies

First you have to `cd contracts/` and run `npm install` to get the dependencies.

```zsh
cd contracts/ # change directory to the contracts/ directory
npm install
```

### Create a New Contract

`hello-world-example` branch has already a precompile contract called `HelloWorld.sol`. All necessary files were already created for you. You can check existing files and see how a fully implemented precompile should look like. If you'd like to redo steps to create a new precompile contract, you can follow the steps below.

Copy the existing `IHelloWorld.sol` interface to a new file called `IHolaMundo.sol`.

```zsh
cd .. # change directory back to the root of the repo
cp contracts/contracts/interfaces/IHelloWorld.sol contracts/contracts/interfaces/IHolaMundo.sol
```

### Install `solc` and Confirm Dependency Version

Install the `solc` dependency.

```zsh
brew install solidity
```

Confirm `solc` is >=0.8.8.

```zsh
solc --version

solc, the solidity compiler commandline interface
Version: 0.8.17+commit.8df45f5f.Darwin.appleclang
```

### Generate an `.abi`

Now generate a `.abi` from a `.sol` using `solc`.

Passing in the following flags

- `--abi`
- ABI specification of the contracts.
- `--base-path path`
- Use the given path as the root of the source tree instead of the root of the filesystem.
- `--include-path path`
- Make an additional source directory available to the default import callback. Use this option if you want to import contracts whose location is not fixed in relation to your main source tree, e.g. third-party libraries installed using a package manager. Can be used multiple times. Can only be used if base path has a non-empty value.
- `--output-dir path`
- If given, creates one file per output component and contract/file at the specified directory.
- `--overwrite`
- Overwrite existing files (used together with `--output-dir`).

```zsh
cd contracts/ # change directory to the contracts/ directory
solc --abi contracts/interfaces/IHolaMundo.sol --output-dir abis --base-path . --include-path ./node_modules --overwrite

Compiler run successful. Artifact(s) can be found in directory "abis".
```

### Generate Precompile Files

First, you need to create your precompile contract interface in the `contracts` directory and build the ABI. Then you can generate your precompile files with `./scripts/generate_precompile.sh --abi {abiPath} --out {outPath}`. This script installs the `precompilegen` tool from Subnet-EVM and runs it to generate your precompile.

```zsh
cd .. # change directory back to the root directory of the repo
./scripts/generate_precompile.sh --abi contracts/abis/IHolaMundo.abi --out holamundo/

Using branch: hello-world-example
installing precompilegen from Subnet-EVM v0.5.2
generating precompile with Subnet-EVM v0.5.2
Precompile files generated successfully at: holamundo/
```

Confirm that the new `holamundo/` directory has the appropriate files.

```zsh
ls -lh helloworld

-rw-r--r-- 1 user group 2.3K Jul 5 13:26 README.md
-rw-r--r-- 1 user group 2.3K Jul 5 13:26 config.go
-rw-r--r-- 1 user group 2.8K Jul 5 13:26 config_test.go
-rw-r--r-- 1 user group 963B Jul 5 13:26 contract.abi
-rw-r--r-- 1 user group 8.1K Jul 5 13:26 contract.go
-rw-r--r-- 1 user group 8.3K Jul 5 13:26 contract_test.go
-rw-r--r-- 1 user group 2.7K Jul 5 13:26 module.go
```

### Register Precompile

In `plugin/main.go` Subnet-EVM is already imported and ready to be Run from the main package. All you need to do is explicitly register your precompiles to Subnet-EVM in `plugin/main.go` and build it together with Subnet-EVM. Precompiles generated by `precompilegen` tool have a self-registering mechanism in their `module.go/init()` function. All you need to do is to force-import your precompile packprecompile package in `plugin/main.go`.
Expand Down Expand Up @@ -88,5 +189,6 @@ In order to upgrade the Subnet-EVM version, you need to change the version in `g
[v0.1.7] AvalancheGo@v1.10.15-v1.10.17 (Protocol Version: 30)
[v0.1.8] AvalancheGo@v1.10.18-v1.10.19 (Protocol Version: 31)
[v0.2.0] AvalancheGo@v1.11.0-v1.11.1 (Protocol Version: 33)
[v0.2.1] AvalancheGo@v1.11.3 (Protocol Version: 35)
[v0.2.1] AvalancheGo@v1.11.3-v1.11.5 (Protocol Version: 35)
[v0.2.2] AvalancheGo@v1.11.3-v1.11.5 (Protocol Version: 35)
```
1 change: 1 addition & 0 deletions compatibility.json
@@ -1,5 +1,6 @@
{
"rpcChainVMProtocolVersion": {
"v0.2.2": 35,
"v0.2.1": 35,
"v0.2.0": 33,
"v0.1.8": 31,
Expand Down
9 changes: 0 additions & 9 deletions contracts/README.md
Expand Up @@ -111,15 +111,6 @@ Subnet-EVM must activate any precompiles used in the test in the genesis:
{
"config": {
"chainId": 43214,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"muirGlacierBlock": 0,
"feeConfig": {
"gasLimit": 8000000,
"minBaseFee": 25000000000,
Expand Down
Empty file removed contracts/contracts/.gitkeep
Empty file.
19 changes: 19 additions & 0 deletions contracts/contracts/ExampleHelloWorld.sol
@@ -0,0 +1,19 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./interfaces/IHelloWorld.sol";

address constant HELLO_WORLD_ADDRESS = 0x0300000000000000000000000000000000000000;

// ExampleHelloWorld shows how the HelloWorld precompile can be used in a smart contract.
contract ExampleHelloWorld {
IHelloWorld helloWorld = IHelloWorld(HELLO_WORLD_ADDRESS);

function sayHello() public view returns (string memory) {
return helloWorld.sayHello();
}

function setGreeting(string calldata greeting) public {
helloWorld.setGreeting(greeting);
}
}
Empty file.
13 changes: 13 additions & 0 deletions contracts/contracts/interfaces/IHelloWorld.sol
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;
import "@avalabs/subnet-evm-contracts/contracts/interfaces/IAllowList.sol";

interface IHelloWorld is IAllowList {
event GreetingChanged(address indexed sender, string oldGreeting, string newGreeting);
// sayHello returns the stored greeting string
function sayHello() external view returns (string calldata result);

// setGreeting stores the greeting string
function setGreeting(string calldata response) external;
}
Empty file removed contracts/contracts/test/.gitkeep
Empty file.
42 changes: 42 additions & 0 deletions contracts/contracts/test/ExampleHelloWorldTest.sol
@@ -0,0 +1,42 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../ExampleHelloWorld.sol";
import "../interfaces/IHelloWorld.sol";
import "@avalabs/subnet-evm-contracts/contracts/test/AllowListTest.sol";

contract ExampleHelloWorldTest is AllowListTest {
IHelloWorld helloWorld = IHelloWorld(HELLO_WORLD_ADDRESS);

function step_getDefaultHelloWorld() public {
ExampleHelloWorld example = new ExampleHelloWorld();
address exampleAddress = address(example);

assertRole(helloWorld.readAllowList(exampleAddress), AllowList.Role.None);
assertEq(example.sayHello(), "Hello World!");
}

function step_doesNotSetGreetingBeforeEnabled() public {
ExampleHelloWorld example = new ExampleHelloWorld();
address exampleAddress = address(example);

assertRole(helloWorld.readAllowList(exampleAddress), AllowList.Role.None);

try example.setGreeting("testing") {
assertTrue(false, "setGreeting should fail");
} catch {} // TODO should match on an error to make sure that this is failing in the way that's expected
}

function step_setAndGetGreeting() public {
ExampleHelloWorld example = new ExampleHelloWorld();
address exampleAddress = address(example);

assertRole(helloWorld.readAllowList(exampleAddress), AllowList.Role.None);
helloWorld.setEnabled(exampleAddress);
assertRole(helloWorld.readAllowList(exampleAddress), AllowList.Role.Enabled);

string memory greeting = "testgreeting";
example.setGreeting(greeting);
assertEq(example.sayHello(), greeting);
}
}
Empty file removed contracts/scripts/.gitkeep
Empty file.