From 283d9ca727b0acec48ec719ae84359ad6c2ef0b2 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Thu, 31 Aug 2023 00:17:50 +0300 Subject: [PATCH] add hello world precompile --- .github/workflows/sync.yml | 24 ++ README.md | 101 +++++++ contracts/abis/IAllowList.abi | 1 + contracts/abis/IHelloWorld.abi | 1 + contracts/contracts/.gitkeep | 0 contracts/contracts/ExampleHelloWorld.sol | 19 ++ contracts/contracts/interfaces/.gitkeep | 0 .../contracts/interfaces/IHelloWorld.sol | 12 + contracts/contracts/test/.gitkeep | 0 .../contracts/test/ExampleHelloWorldTest.sol | 42 +++ contracts/hardhat.config.ts | 2 +- contracts/package.json | 1 + contracts/scripts/.gitkeep | 0 contracts/scripts/deployExampleHelloWorld.ts | 20 ++ contracts/tasks.ts | 61 +++- contracts/test/.gitkeep | 0 contracts/test/hello_world.ts | 34 +++ go.mod | 13 +- go.sum | 59 ++++ helloworld/README.md | 28 ++ helloworld/config.go | 72 +++++ helloworld/config_test.go | 81 ++++++ helloworld/contract.abi | 1 + helloworld/contract.go | 201 +++++++++++++ helloworld/contract_test.go | 268 ++++++++++++++++++ helloworld/module.go | 71 +++++ plugin/main.go | 2 + tests/precompile/genesis/.gitkeep | 0 tests/precompile/genesis/hello_world.json | 47 +++ tests/precompile/solidity/suites.go | 20 +- 30 files changed, 1171 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/sync.yml create mode 100644 contracts/abis/IAllowList.abi create mode 100644 contracts/abis/IHelloWorld.abi delete mode 100644 contracts/contracts/.gitkeep create mode 100644 contracts/contracts/ExampleHelloWorld.sol delete mode 100644 contracts/contracts/interfaces/.gitkeep create mode 100644 contracts/contracts/interfaces/IHelloWorld.sol delete mode 100644 contracts/contracts/test/.gitkeep create mode 100644 contracts/contracts/test/ExampleHelloWorldTest.sol delete mode 100644 contracts/scripts/.gitkeep create mode 100644 contracts/scripts/deployExampleHelloWorld.ts delete mode 100644 contracts/test/.gitkeep create mode 100644 contracts/test/hello_world.ts create mode 100644 helloworld/README.md create mode 100644 helloworld/config.go create mode 100644 helloworld/config_test.go create mode 100644 helloworld/contract.abi create mode 100644 helloworld/contract.go create mode 100644 helloworld/contract_test.go create mode 100644 helloworld/module.go delete mode 100644 tests/precompile/genesis/.gitkeep create mode 100644 tests/precompile/genesis/hello_world.json diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml new file mode 100644 index 0000000..ee68f97 --- /dev/null +++ b/.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" diff --git a/README.md b/README.md index 21ad6b5..cae149a 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,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`. diff --git a/contracts/abis/IAllowList.abi b/contracts/abis/IAllowList.abi new file mode 100644 index 0000000..ea89cd6 --- /dev/null +++ b/contracts/abis/IAllowList.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"readAllowList","outputs":[{"internalType":"uint256","name":"role","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setNone","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/contracts/abis/IHelloWorld.abi b/contracts/abis/IHelloWorld.abi new file mode 100644 index 0000000..ba09c3c --- /dev/null +++ b/contracts/abis/IHelloWorld.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"readAllowList","outputs":[{"internalType":"uint256","name":"role","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sayHello","outputs":[{"internalType":"string","name":"result","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"response","type":"string"}],"name":"setGreeting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setNone","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/contracts/contracts/.gitkeep b/contracts/contracts/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/contracts/contracts/ExampleHelloWorld.sol b/contracts/contracts/ExampleHelloWorld.sol new file mode 100644 index 0000000..b64fd0a --- /dev/null +++ b/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); + } +} diff --git a/contracts/contracts/interfaces/.gitkeep b/contracts/contracts/interfaces/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/contracts/contracts/interfaces/IHelloWorld.sol b/contracts/contracts/interfaces/IHelloWorld.sol new file mode 100644 index 0000000..911763c --- /dev/null +++ b/contracts/contracts/interfaces/IHelloWorld.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.8.0; +import "@avalabs/subnet-evm-contracts/contracts/interfaces/IAllowList.sol"; + +interface IHelloWorld is IAllowList { + // 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; +} diff --git a/contracts/contracts/test/.gitkeep b/contracts/contracts/test/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/contracts/contracts/test/ExampleHelloWorldTest.sol b/contracts/contracts/test/ExampleHelloWorldTest.sol new file mode 100644 index 0000000..16d10a6 --- /dev/null +++ b/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); + } +} diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts index b8cb0d2..b881e7c 100644 --- a/contracts/hardhat.config.ts +++ b/contracts/hardhat.config.ts @@ -1,6 +1,6 @@ import "@nomiclabs/hardhat-waffle" import "@nomiclabs/hardhat-ethers" -import "./tasks.ts" +import "./tasks" // HardHat users must populate these environment variables in order to connect to their subnet-evm instance // Since the blockchainID is not known in advance, there's no good default to use and we use the C-Chain here. diff --git a/contracts/package.json b/contracts/package.json index fee0c19..f9589d6 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -32,6 +32,7 @@ }, "license": "BSD-3-Clause", "scripts": { + "build": "rm -rf dist/ && tsc -b", "compile": "npx hardhat compile", "console": "npx hardhat console", "test": "npx hardhat test", diff --git a/contracts/scripts/.gitkeep b/contracts/scripts/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/contracts/scripts/deployExampleHelloWorld.ts b/contracts/scripts/deployExampleHelloWorld.ts new file mode 100644 index 0000000..48f609a --- /dev/null +++ b/contracts/scripts/deployExampleHelloWorld.ts @@ -0,0 +1,20 @@ +import { + Contract, + ContractFactory +} from "ethers" +import { ethers } from "hardhat" + +const main = async (): Promise => { + const contractFactory: ContractFactory = await ethers.getContractFactory("ExampleHelloWorld") + const contract: Contract = await contractFactory.deploy() + + await contract.deployed() + console.log(`Contract deployed to: ${contract.address}`) +} + +main() + .then(() => process.exit(0)) + .catch(error => { + console.error(error) + process.exit(1) + }) diff --git a/contracts/tasks.ts b/contracts/tasks.ts index f5edf5b..a259c0b 100644 --- a/contracts/tasks.ts +++ b/contracts/tasks.ts @@ -2,6 +2,20 @@ import { task } from "hardhat/config" import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" import { BigNumber } from "ethers" +const HELLO_WORLD_ADDRESS = "0x0300000000000000000000000000000000000000" + +const ROLES = { + 0: "None", + 1: "Enabled", + 2: "Admin", +} + +const getRole = async (allowList, address) => { + const role = await allowList.readAllowList(address) + console.log(`${address} has role: ${ROLES[role.toNumber()]}`) +} + +// npx hardhat accounts --network local task("accounts", "Prints the list of accounts", async (args, hre): Promise => { const accounts: SignerWithAddress[] = await hre.ethers.getSigners() accounts.forEach((account: SignerWithAddress): void => { @@ -9,6 +23,7 @@ task("accounts", "Prints the list of accounts", async (args, hre): Promise }) }) +// npx hardhat balances --network local task("balances", "Prints the list of account balances", async (args, hre): Promise => { const accounts: SignerWithAddress[] = await hre.ethers.getSigners() for (const account of accounts) { @@ -19,7 +34,7 @@ task("balances", "Prints the list of account balances", async (args, hre): Promi } }) - +// npx hardhat balance --network local --address [address] task("balance", "get the balance") .addParam("address", "the address you want to know balance of") .setAction(async (args, hre) => { @@ -28,5 +43,49 @@ task("balance", "get the balance") console.log(`balance: ${balanceInCoin} Coin`) }) +// npx hardhat helloWorld:readRole --network local --address [address] +task("helloWorld:readRole", "Gets the network enabled allow list") + .addParam("address", "the address you want to know the allowlist role for") + .setAction(async (args, hre) => { + const allowList = await hre.ethers.getContractAt("IHelloWorld", HELLO_WORLD_ADDRESS) + await getRole(allowList, args.address) + }) + +// npx hardhat helloWorld:addEnabled --network local --address [address] +task("helloWorld:addEnabled", "Adds the enabled on the allow list") + .addParam("address", "the address you want to add as a enabled") + .setAction(async (args, hre) => { + const allowList = await hre.ethers.getContractAt("IHelloWorld", HELLO_WORLD_ADDRESS) + // ADD CODE BELOW + await allowList.setEnabled(args.address) + await getRole(allowList, args.address) + }) + +// npx hardhat helloWorld:addAdmin --network local --address [address] +task("helloWorld:addAdmin", "Adds an admin on the allowlist") + .addParam("address", "the address you want to add as a admin") + .setAction(async (args, hre) => { + const allowList = await hre.ethers.getContractAt("IHelloWorld", HELLO_WORLD_ADDRESS) + await allowList.setAdmin(args.address) + await getRole(allowList, args.address) + }) + +// npx hardhat helloWorld:sayHello --network local +task("helloWorld:sayHello", "Says hello") + .setAction(async (args, hre) => { + const helloWorld = await hre.ethers.getContractAt("IHelloWorld", HELLO_WORLD_ADDRESS) + const result = await helloWorld.sayHello() + console.log(result) + }) + +// npx hardhat helloWorld:setGreeting --network local --greeting [greeting] +task("helloWorld:setGreeting", "Says hello") + .addParam("greeting", "the greeting string you want to set") + .setAction(async (args, hre) => { + const helloWorld = await hre.ethers.getContractAt("IHelloWorld", HELLO_WORLD_ADDRESS) + const result = await helloWorld.setGreeting(args.greeting) + console.log(result) + }) + diff --git a/contracts/test/.gitkeep b/contracts/test/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/contracts/test/hello_world.ts b/contracts/test/hello_world.ts new file mode 100644 index 0000000..84b11ee --- /dev/null +++ b/contracts/test/hello_world.ts @@ -0,0 +1,34 @@ +// (c) 2019-2022, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +import { ethers } from "hardhat" +import { test } from "@avalabs/subnet-evm-contracts" + +// make sure this is always an admin for hello world precompile +const ADMIN_ADDRESS = "0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC" +const HELLO_WORLD_ADDRESS = "0x0300000000000000000000000000000000000000" + +describe("ExampleHelloWorldTest", function () { + this.timeout("30s") + + beforeEach('Setup DS-Test contract', async function () { + const signer = await ethers.getSigner(ADMIN_ADDRESS) + const helloWorldPromise = ethers.getContractAt("IHelloWorld", HELLO_WORLD_ADDRESS, signer) + + return ethers.getContractFactory("ExampleHelloWorldTest", { signer }) + .then(factory => factory.deploy()) + .then(contract => { + this.testContract = contract + return contract.deployed().then(() => contract) + }) + .then(() => Promise.all([helloWorldPromise])) + .then(([helloWorld]) => helloWorld.setAdmin(this.testContract.address)) + .then(tx => tx.wait()) + }) + + test("should gets default hello world", ["step_getDefaultHelloWorld"]) + + test("should not set greeting before enabled", "step_doesNotSetGreetingBeforeEnabled") + + test("should set and get greeting with enabled account", "step_setAndGetGreeting") +}); diff --git a/go.mod b/go.mod index b4ed191..3b59703 100644 --- a/go.mod +++ b/go.mod @@ -5,16 +5,21 @@ go 1.19 require ( github.com/ava-labs/avalanchego v1.10.9 github.com/ava-labs/subnet-evm v0.5.5 + github.com/ethereum/go-ethereum v1.12.0 github.com/onsi/ginkgo/v2 v2.8.1 github.com/onsi/gomega v1.26.0 github.com/stretchr/testify v1.8.3 + go.uber.org/mock v0.2.0 ) require ( github.com/DataDog/zstd v1.5.2 // indirect + github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/VictoriaMetrics/fastcache v1.10.0 // indirect + github.com/ava-labs/coreth v0.12.5-rc.3 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect + github.com/btcsuite/btcd/btcutil v1.1.3 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect @@ -27,11 +32,11 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3 // indirect - github.com/ethereum/go-ethereum v1.12.0 // indirect github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect github.com/getsentry/sentry-go v0.18.0 // indirect + github.com/go-cmd/cmd v1.4.1 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect @@ -40,9 +45,11 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect + github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect github.com/google/uuid v1.3.0 // indirect + github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/rpc v1.2.0 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect @@ -68,6 +75,7 @@ require ( github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect + github.com/pires/go-proxyproto v0.6.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.16.0 // indirect @@ -75,8 +83,10 @@ require ( github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/rs/cors v1.7.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.8.2 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -101,7 +111,6 @@ require ( go.opentelemetry.io/otel/trace v1.11.0 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect go.uber.org/atomic v1.10.0 // indirect - go.uber.org/mock v0.2.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/crypto v0.1.0 // indirect diff --git a/go.sum b/go.sum index 03f7a2a..8a1cde6 100644 --- a/go.sum +++ b/go.sum @@ -45,10 +45,13 @@ github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMd github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40woBZAUiKonXzY= github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= @@ -56,15 +59,38 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/ava-labs/avalanchego v1.10.9 h1:qxhp3YoD2Wm/iIKP6Wb1isbkUPWmIrJxWgivDoL0obM= github.com/ava-labs/avalanchego v1.10.9/go.mod h1:C8R5uiltpc8MQ62ixxgODR+15mesWF0aAw3H+Qrl9Iw= +github.com/ava-labs/coreth v0.12.5-rc.3 h1:cpmC+fSZMsO4gaFWqXHzAHrJACf05u5HPAYmwh7nmkU= +github.com/ava-labs/coreth v0.12.5-rc.3/go.mod h1:HI+jTIflnDFBd0bledgkgid1Uurwr8q1h7zb3LsFsSo= github.com/ava-labs/subnet-evm v0.5.5 h1:8loOWaEzmewRIon+Q2oTLrtV8nbwVfnv7cjsBajMC6E= github.com/ava-labs/subnet-evm v0.5.5/go.mod h1:PAyhfYnECzA17N62i7OAdKazjfSsN2l8KR5nOspg39I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= +github.com/btcsuite/btcd v0.23.0 h1:V2/ZgjfDFIygAX3ZapeigkVBoVUtOJKSwrhZdlpSvaA= +github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= +github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= +github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= +github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= +github.com/btcsuite/btcd/btcutil v1.1.3 h1:xfbtw8lwpp0G6NwSHb+UE67ryTFHJAiNuipusjXSohQ= +github.com/btcsuite/btcd/btcutil v1.1.3/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -108,14 +134,18 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= @@ -160,6 +190,8 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-cmd/cmd v1.4.1 h1:JUcEIE84v8DSy02XTZpUDeGKExk2oW3DA10hTjbQwmc= +github.com/go-cmd/cmd v1.4.1/go.mod h1:tbBenttXtZU4c5djS1o7PWL5pd2xAr5sIqH1kGdNiRc= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -178,6 +210,7 @@ github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5Nq github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= @@ -225,6 +258,8 @@ github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -264,6 +299,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/rpc v1.2.0 h1:WvvdC2lNeT1SP32zrIce5l0ECBfbAlmrmSBsuc57wfk= github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -302,6 +339,9 @@ github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/ github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -315,6 +355,7 @@ github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7 github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= @@ -333,6 +374,7 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= @@ -381,14 +423,18 @@ github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.8.1 h1:xFTEVwOFa1D/Ty24Ws1npBWkDYEV9BqZrsDxVrVkrrU= github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= @@ -402,6 +448,8 @@ github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwb github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8= +github.com/pires/go-proxyproto v0.6.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -424,6 +472,8 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -437,6 +487,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= @@ -471,6 +523,7 @@ github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/thepudds/fzgen v0.4.2 h1:HlEHl5hk2/cqEomf2uK5SA/FeJc12s/vIHmOG+FbACw= @@ -542,6 +595,7 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -594,6 +648,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -624,6 +679,7 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -695,8 +751,10 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -934,6 +992,7 @@ gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXL gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/helloworld/README.md b/helloworld/README.md new file mode 100644 index 0000000..0bf854a --- /dev/null +++ b/helloworld/README.md @@ -0,0 +1,28 @@ +# Hello World Precompile + +This is a example precompile to demonstrate how to develop a precompile for Precompile-EVM. This is mainly used by [Hello World Precompile Tutorial](https://docs.avax.network/subnets/hello-world-precompile-tutorial). + +On below you can find the original README.md of the precompile template: + +There are some must-be-done changes waiting in the generated file. Each area requiring you to add your code is marked with CUSTOM CODE to make them easy to find and modify. +Additionally there are other files you need to edit to activate your precompile. +These areas are highlighted with comments "ADD YOUR PRECOMPILE HERE". +For testing take a look at other precompile tests in contract_test.go and config_test.go in other precompile folders. +See the tutorial in for more information about precompile development. +General guidelines for precompile development: +1- Set a suitable config key in generated module.go. E.g: "yourPrecompileConfig" +2- Read the comment and set a suitable contract address in generated module.go. E.g: +ContractAddress = common.HexToAddress("ASUITABLEHEXADDRESS") +3- It is recommended to only modify code in the highlighted areas marked with "CUSTOM CODE STARTS HERE". Typically, custom codes are required in only those areas. +Modifying code outside of these areas should be done with caution and with a deep understanding of how these changes may impact the EVM. +4- Set gas costs in generated contract.go +5- Force import your precompile package in precompile/registry/registry.go +6- Add your config unit tests under generated package config_test.go +7- Add your contract unit tests under generated package contract_test.go +8- Additionally you can add a full-fledged VM test for your precompile under plugin/vm/vm_test.go. See existing precompile tests for examples. +9- Add your solidity interface and test contract to contracts/contracts +10- Write solidity contract tests for your precompile in contracts/contracts/test +11- Write TypeScript DS-Test counterparts for your solidity tests in contracts/test +12- Create your genesis with your precompile enabled in tests/precompile/genesis/ +13- Create e2e test for your solidity test in tests/precompile/solidity/suites.go +14- Run your e2e precompile Solidity tests with './scripts/run_ginkgo.sh` diff --git a/helloworld/config.go b/helloworld/config.go new file mode 100644 index 0000000..7d39734 --- /dev/null +++ b/helloworld/config.go @@ -0,0 +1,72 @@ +package helloworld + +import ( + "github.com/ava-labs/subnet-evm/precompile/allowlist" + "github.com/ava-labs/subnet-evm/precompile/precompileconfig" + + "github.com/ethereum/go-ethereum/common" +) + +var _ precompileconfig.Config = &Config{} + +// Config implements the precompileconfig.Config interface and +// adds specific configuration for HelloWorld. +type Config struct { + allowlist.AllowListConfig + precompileconfig.Upgrade + // CUSTOM CODE STARTS HERE + // Add your own custom fields for Config here +} + +// NewConfig returns a config for a network upgrade at [blockTimestamp] that enables +// HelloWorld with the given [admins] as members of the allowlist . +func NewConfig(blockTimestamp *uint64, admins []common.Address, enableds []common.Address) *Config { + return &Config{ + AllowListConfig: allowlist.AllowListConfig{ + AdminAddresses: admins, + EnabledAddresses: enableds, + }, + Upgrade: precompileconfig.Upgrade{BlockTimestamp: blockTimestamp}, + } +} + +// NewDisableConfig returns config for a network upgrade at [blockTimestamp] +// that disables HelloWorld. +func NewDisableConfig(blockTimestamp *uint64) *Config { + return &Config{ + Upgrade: precompileconfig.Upgrade{ + BlockTimestamp: blockTimestamp, + Disable: true, + }, + } +} + +// Key returns the key for the HelloWorld precompileconfig. +// This should be the same key as used in the precompile module. +func (*Config) Key() string { return ConfigKey } + +// Verify tries to verify Config and returns an error accordingly. +func (c *Config) Verify(p precompileconfig.ChainConfig) error { + // Verify AllowList first + if err := c.AllowListConfig.Verify(p); err != nil { + return err + } + // CUSTOM CODE STARTS HERE + // Add your own custom verify code for Config here + // and return an error accordingly + return nil +} + +// Equal returns true if [s] is a [*Config] and it has been configured identical to [c]. +func (c *Config) Equal(s precompileconfig.Config) bool { + // typecast before comparison + other, ok := (s).(*Config) + if !ok { + return false + } + // CUSTOM CODE STARTS HERE + // modify this boolean accordingly with your custom Config, to check if [other] and the current [c] are equal + // if Config contains only Upgrade and AllowListConfig you can skip modifying it. + equals := c.Upgrade.Equal(&other.Upgrade) && c.AllowListConfig.Equal(&other.AllowListConfig) + return equals +} diff --git a/helloworld/config_test.go b/helloworld/config_test.go new file mode 100644 index 0000000..c6ebdfb --- /dev/null +++ b/helloworld/config_test.go @@ -0,0 +1,81 @@ +package helloworld + +import ( + "testing" + + "github.com/ava-labs/subnet-evm/precompile/allowlist" + "github.com/ava-labs/subnet-evm/precompile/precompileconfig" + "github.com/ava-labs/subnet-evm/precompile/testutils" + "github.com/ava-labs/subnet-evm/utils" + "go.uber.org/mock/gomock" + + "github.com/ethereum/go-ethereum/common" +) + +// TestVerify tests the verification of Config. +func TestVerify(t *testing.T) { + admins := []common.Address{allowlist.TestAdminAddr} + enableds := []common.Address{allowlist.TestEnabledAddr} + tests := map[string]testutils.ConfigVerifyTest{ + "valid config": { + Config: NewConfig(utils.NewUint64(3), admins, enableds), + ExpectedError: "", + }, + // CUSTOM CODE STARTS HERE + // Add your own Verify tests here, e.g.: + // "your custom test name": { + // Config: NewConfig(utils.NewUint64(3), admins, enableds), + // ExpectedError: ErrYourCustomError.Error(), + // }, + // We don't have a custom verification logic for HelloWorld + // so we just test the allowlist verification logic with a nil custom verifyTests input. + // VerifyPrecompileWithAllowListTests will add the allowlist verification logic tests for us. + } + // Verify the precompile with the allowlist. + // This adds allowlist verify tests to your custom tests + // and runs them all together. + // Even if you don't add any custom tests, keep this. This will still + // run the default allowlist verify tests. + allowlist.VerifyPrecompileWithAllowListTests(t, Module, tests) +} + +// TestEqual tests the equality of Config with other precompile configs. +func TestEqual(t *testing.T) { + admins := []common.Address{allowlist.TestAdminAddr} + enableds := []common.Address{allowlist.TestEnabledAddr} + tests := map[string]testutils.ConfigEqualTest{ + "non-nil config and nil other": { + Config: NewConfig(utils.NewUint64(3), admins, enableds), + Other: nil, + Expected: false, + }, + "different type": { + Config: NewConfig(utils.NewUint64(3), admins, enableds), + Other: precompileconfig.NewMockConfig(gomock.NewController(t)), + Expected: false, + }, + "different timestamp": { + Config: NewConfig(utils.NewUint64(3), admins, enableds), + Other: NewConfig(utils.NewUint64(4), admins, enableds), + Expected: false, + }, + "same config": { + Config: NewConfig(utils.NewUint64(3), admins, enableds), + Other: NewConfig(utils.NewUint64(3), admins, enableds), + Expected: true, + }, + // CUSTOM CODE STARTS HERE + // Add your own Equal tests here + "different enabled": { + Config: NewConfig(utils.NewUint64(3), admins, nil), + Other: NewConfig(utils.NewUint64(3), admins, enableds), + Expected: false, + }, + } + // Run allow list equal tests. + // This adds allowlist equal tests to your custom tests + // and runs them all together. + // Even if you don't add any custom tests, keep this. This will still + // run the default allowlist equal tests. + allowlist.EqualPrecompileWithAllowListTests(t, Module, tests) +} diff --git a/helloworld/contract.abi b/helloworld/contract.abi new file mode 100644 index 0000000..ba09c3c --- /dev/null +++ b/helloworld/contract.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"readAllowList","outputs":[{"internalType":"uint256","name":"role","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sayHello","outputs":[{"internalType":"string","name":"result","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"response","type":"string"}],"name":"setGreeting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setNone","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/helloworld/contract.go b/helloworld/contract.go new file mode 100644 index 0000000..7bf231b --- /dev/null +++ b/helloworld/contract.go @@ -0,0 +1,201 @@ +package helloworld + +import ( + "errors" + "fmt" + + "github.com/ava-labs/subnet-evm/accounts/abi" + "github.com/ava-labs/subnet-evm/precompile/allowlist" + "github.com/ava-labs/subnet-evm/precompile/contract" + "github.com/ava-labs/subnet-evm/vmerrs" + + _ "embed" + + "github.com/ethereum/go-ethereum/common" +) + +const ( + // Gas costs for each function. These are set to 0 by default. + // You should set a gas cost for each function in your contract. + // Generally, you should not set gas costs very low as this may cause your network to be vulnerable to DoS attacks. + // There are some predefined gas costs in contract/utils.go that you can use. + // This contract also uses AllowList precompile. + // You should also increase gas costs of functions that read from AllowList storage.} + SayHelloGasCost uint64 = contract.ReadGasCostPerSlot + SetGreetingGasCost uint64 = contract.WriteGasCostPerSlot + allowlist.ReadAllowListGasCost +) + +// Singleton StatefulPrecompiledContract and signatures. +var ( + ErrCannotSetGreeting = errors.New("non-enabled cannot call setGreeting") + ErrInputExceedsLimit = errors.New("input string is longer than 32 bytes") + + // HelloWorldRawABI contains the raw ABI of HelloWorld contract. + //go:embed contract.abi + HelloWorldRawABI string + + HelloWorldABI = contract.ParseABI(HelloWorldRawABI) + + HelloWorldPrecompile = createHelloWorldPrecompile() + + // storageKeyHash is the hash of the storage key "storageKey" in the contract storage. + // This is used to store the value of the greeting in the contract storage. + // It is important to use a unique key here to avoid conflicts with other storage keys + // like addresses, AllowList, etc. + storageKeyHash = common.BytesToHash([]byte("storageKey")) +) + +// GetHelloWorldAllowListStatus returns the role of [address] for the HelloWorld list. +func GetHelloWorldAllowListStatus(stateDB contract.StateDB, address common.Address) allowlist.Role { + return allowlist.GetAllowListStatus(stateDB, ContractAddress, address) +} + +// SetHelloWorldAllowListStatus sets the permissions of [address] to [role] for the +// HelloWorld list. Assumes [role] has already been verified as valid. +// This stores the [role] in the contract storage with address [ContractAddress] +// and [address] hash. It means that any reusage of the [address] key for different value +// conflicts with the same slot [role] is stored. +// Precompile implementations must use a different key than [address] for their storage. +func SetHelloWorldAllowListStatus(stateDB contract.StateDB, address common.Address, role allowlist.Role) { + allowlist.SetAllowListRole(stateDB, ContractAddress, address, role) +} + +// PackSayHello packs the include selector (first 4 func signature bytes). +// This function is mostly used for tests. +func PackSayHello() ([]byte, error) { + return HelloWorldABI.Pack("sayHello") +} + +// PackSayHelloOutput attempts to pack given result of type string +// to conform the ABI outputs. +func PackSayHelloOutput(result string) ([]byte, error) { + return HelloWorldABI.PackOutput("sayHello", result) +} + +// GetGreeting returns the value of the storage key "storageKey" in the contract storage, +// with leading zeroes trimmed. +// This function is mostly used for tests. +func GetGreeting(stateDB contract.StateDB) string { + // Get the value set at recipient + value := stateDB.GetState(ContractAddress, storageKeyHash) + return string(common.TrimLeftZeroes(value.Bytes())) +} + +// sayHello is the reader fucntion that returns the value of greeting stored in the contract storage. +func sayHello(accessibleState contract.AccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = contract.DeductGas(suppliedGas, SayHelloGasCost); err != nil { + return nil, 0, err + } + // no input provided for this function + + // CUSTOM CODE STARTS HERE + + // Get the current state + currentState := accessibleState.GetStateDB() + // Get the value set at recipient + value := GetGreeting(currentState) + packedOutput, err := PackSayHelloOutput(value) + if err != nil { + return nil, remainingGas, err + } + + // Return the packed output and the remaining gas + return packedOutput, remainingGas, nil +} + +// UnpackSetGreetingInput attempts to unpack [input] into the string type argument +// assumes that [input] does not include selector (omits first 4 func signature bytes) +func UnpackSetGreetingInput(input []byte) (string, error) { + res, err := HelloWorldABI.UnpackInput("setGreeting", input) + if err != nil { + return "", err + } + unpacked := *abi.ConvertType(res[0], new(string)).(*string) + return unpacked, nil +} + +// PackSetGreeting packs [response] of type string into the appropriate arguments for setGreeting. +// the packed bytes include selector (first 4 func signature bytes). +// This function is mostly used for tests. +func PackSetGreeting(response string) ([]byte, error) { + return HelloWorldABI.Pack("setGreeting", response) +} + +// StoreGreeting sets the value of the storage key "storageKey" in the contract storage. +func StoreGreeting(stateDB contract.StateDB, input string) { + inputPadded := common.LeftPadBytes([]byte(input), common.HashLength) + inputHash := common.BytesToHash(inputPadded) + + stateDB.SetState(ContractAddress, storageKeyHash, inputHash) +} + +// setGreeting is a state-changer function that sets the value of the greeting in the contract storage. +func setGreeting(accessibleState contract.AccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = contract.DeductGas(suppliedGas, SetGreetingGasCost); err != nil { + return nil, 0, err + } + if readOnly { + return nil, remainingGas, vmerrs.ErrWriteProtection + } + // attempts to unpack [input] into the arguments to the SetGreetingInput. + // Assumes that [input] does not include selector + // You can use unpacked [inputStruct] variable in your code + inputStruct, err := UnpackSetGreetingInput(input) + if err != nil { + return nil, remainingGas, err + } + + // Allow list is enabled and SetGreeting is a state-changer function. + // This part of the code restricts the function to be called only by enabled/admin addresses in the allow list. + // You can modify/delete this code if you don't want this function to be restricted by the allow list. + stateDB := accessibleState.GetStateDB() + // Verify that the caller is in the allow list and therefore has the right to call this function. + callerStatus := allowlist.GetAllowListStatus(stateDB, ContractAddress, caller) + if !callerStatus.IsEnabled() { + return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotSetGreeting, caller) + } + // allow list code ends here. + + // CUSTOM CODE STARTS HERE + // Check if the input string is longer than HashLength + if len(inputStruct) > common.HashLength { + return nil, 0, ErrInputExceedsLimit + } + + // setGreeting is the execution function + // "SetGreeting(name string)" and sets the storageKey + // in the string returned by hello world + StoreGreeting(stateDB, inputStruct) + + // This function does not return an output, leave this one as is + packedOutput := []byte{} + + // Return the packed output and the remaining gas + return packedOutput, remainingGas, nil +} + +// createHelloWorldPrecompile returns a StatefulPrecompiledContract with getters and setters for the precompile. +// Access to the getters/setters is controlled by an allow list for ContractAddress. +func createHelloWorldPrecompile() contract.StatefulPrecompiledContract { + var functions []*contract.StatefulPrecompileFunction + functions = append(functions, allowlist.CreateAllowListFunctions(ContractAddress)...) + + abiFunctionMap := map[string]contract.RunStatefulPrecompileFunc{ + "sayHello": sayHello, + "setGreeting": setGreeting, + } + + for name, function := range abiFunctionMap { + method, ok := HelloWorldABI.Methods[name] + if !ok { + panic(fmt.Errorf("given method (%s) does not exist in the ABI", name)) + } + functions = append(functions, contract.NewStatefulPrecompileFunction(method.ID, function)) + } + // Construct the contract with no fallback function. + statefulContract, err := contract.NewStatefulPrecompileContract(nil, functions) + if err != nil { + panic(err) + } + return statefulContract +} diff --git a/helloworld/contract_test.go b/helloworld/contract_test.go new file mode 100644 index 0000000..2e64e50 --- /dev/null +++ b/helloworld/contract_test.go @@ -0,0 +1,268 @@ +package helloworld + +import ( + "testing" + + "github.com/ava-labs/subnet-evm/core/state" + "github.com/ava-labs/subnet-evm/precompile/allowlist" + "github.com/ava-labs/subnet-evm/precompile/contract" + "github.com/ava-labs/subnet-evm/precompile/testutils" + "github.com/ava-labs/subnet-evm/utils" + "github.com/ava-labs/subnet-evm/vmerrs" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +// These tests are run against the precompile contract directly with +// the given input and expected output. They're just a guide to +// help you write your own tests. These tests are for general cases like +// allowlist, readOnly behaviour, and gas cost. You should write your own +// tests for specific cases. +const testGreeting = "test" + +var tests = map[string]testutils.PrecompileTest{ + "calling sayHello from NoRole should succeed": { + Caller: allowlist.TestNoRoleAddr, + BeforeHook: allowlist.SetDefaultRoles(Module.Address), + InputFn: func(t testing.TB) []byte { + input, err := PackSayHello() + require.NoError(t, err) + return input + }, + // This test is for a successful call. You can set the expected output here. + // CUSTOM CODE STARTS HERE + ExpectedRes: func() []byte { + // by default we don't Configure initial state for + // the module since Config is empty. + // This means we don't apply default greeting to the state. + res, err := PackSayHelloOutput("") + if err != nil { + panic(err) + } + return res + }(), + SuppliedGas: SayHelloGasCost, + ReadOnly: false, + ExpectedErr: "", + }, + "calling sayHello from Enabled should succeed": { + Caller: allowlist.TestEnabledAddr, + BeforeHook: allowlist.SetDefaultRoles(Module.Address), + InputFn: func(t testing.TB) []byte { + input, err := PackSayHello() + require.NoError(t, err) + return input + }, + // This test is for a successful call. You can set the expected output here. + // CUSTOM CODE STARTS HERE + ExpectedRes: func() []byte { + // by default we don't Configure initial state for + // the module since Config is empty. + // This means we don't apply default greeting to the state. + res, err := PackSayHelloOutput("") + if err != nil { + panic(err) + } + return res + }(), + SuppliedGas: SayHelloGasCost, + ReadOnly: false, + ExpectedErr: "", + }, + "calling sayHello from Admin should succeed": { + Caller: allowlist.TestAdminAddr, + BeforeHook: allowlist.SetDefaultRoles(Module.Address), + InputFn: func(t testing.TB) []byte { + input, err := PackSayHello() + require.NoError(t, err) + return input + }, + // This test is for a successful call. You can set the expected output here. + // CUSTOM CODE STARTS HERE + ExpectedRes: func() []byte { + // by default we don't Configure initial state for + // the module since Config is empty. + // This means we don't apply default greeting to the state. + res, err := PackSayHelloOutput("") + if err != nil { + panic(err) + } + return res + }(), + SuppliedGas: SayHelloGasCost, + ReadOnly: false, + ExpectedErr: "", + }, + "calling sayHello from NoRole with a config should return default greeting": { + Caller: allowlist.TestNoRoleAddr, + BeforeHook: allowlist.SetDefaultRoles(Module.Address), + Config: NewConfig(utils.NewUint64(0), nil, nil), + InputFn: func(t testing.TB) []byte { + input, err := PackSayHello() + require.NoError(t, err) + return input + }, + // This test is for a successful call. You can set the expected output here. + // CUSTOM CODE STARTS HERE + ExpectedRes: func() []byte { + res, err := PackSayHelloOutput(defaultGreeting) + if err != nil { + panic(err) + } + return res + }(), + SuppliedGas: SayHelloGasCost, + ReadOnly: false, + ExpectedErr: "", + }, + "insufficient gas for sayHello should fail": { + Caller: common.Address{1}, + InputFn: func(t testing.TB) []byte { + input, err := PackSayHello() + require.NoError(t, err) + return input + }, + SuppliedGas: SayHelloGasCost - 1, + ReadOnly: false, + ExpectedErr: vmerrs.ErrOutOfGas.Error(), + }, + "calling setGreeting from NoRole should fail": { + Caller: allowlist.TestNoRoleAddr, + BeforeHook: allowlist.SetDefaultRoles(Module.Address), + InputFn: func(t testing.TB) []byte { + // CUSTOM CODE STARTS HERE + // set test input to a value here + input, err := PackSetGreeting(testGreeting) + require.NoError(t, err) + return input + }, + SuppliedGas: SetGreetingGasCost, + ReadOnly: false, + ExpectedErr: ErrCannotSetGreeting.Error(), + }, + "calling setGreeting from Enabled should succeed": { + Caller: allowlist.TestEnabledAddr, + BeforeHook: allowlist.SetDefaultRoles(Module.Address), + InputFn: func(t testing.TB) []byte { + // CUSTOM CODE STARTS HERE + // set test input to a value here + input, err := PackSetGreeting(testGreeting) + require.NoError(t, err) + return input + }, + // This test is for a successful call. You can set the expected output here. + // CUSTOM CODE STARTS HERE + ExpectedRes: []byte{}, + SuppliedGas: SetGreetingGasCost, + ReadOnly: false, + ExpectedErr: "", + AfterHook: func(t testing.TB, state contract.StateDB) { + greeting := GetGreeting(state) + require.Equal(t, greeting, testGreeting) + }, + }, + "calling setGreeting from Admin should succeed": { + Caller: allowlist.TestAdminAddr, + BeforeHook: allowlist.SetDefaultRoles(Module.Address), + InputFn: func(t testing.TB) []byte { + // CUSTOM CODE STARTS HERE + // set test input to a value here + input, err := PackSetGreeting(testGreeting) + require.NoError(t, err) + return input + }, + // This test is for a successful call. You can set the expected output here. + // CUSTOM CODE STARTS HERE + ExpectedRes: []byte{}, + SuppliedGas: SetGreetingGasCost, + ReadOnly: false, + ExpectedErr: "", + AfterHook: func(t testing.TB, state contract.StateDB) { + greeting := GetGreeting(state) + require.Equal(t, greeting, testGreeting) + }, + }, + "readOnly setGreeting should fail": { + Caller: common.Address{1}, + InputFn: func(t testing.TB) []byte { + // CUSTOM CODE STARTS HERE + // set test input to a value here + var testInput string + input, err := PackSetGreeting(testInput) + require.NoError(t, err) + return input + }, + SuppliedGas: SetGreetingGasCost, + ReadOnly: true, + ExpectedErr: vmerrs.ErrWriteProtection.Error(), + }, + "insufficient gas for setGreeting should fail": { + Caller: common.Address{1}, + InputFn: func(t testing.TB) []byte { + // CUSTOM CODE STARTS HERE + // set test input to a value here + var testInput string + input, err := PackSetGreeting(testInput) + require.NoError(t, err) + return input + }, + SuppliedGas: SetGreetingGasCost - 1, + ReadOnly: false, + ExpectedErr: vmerrs.ErrOutOfGas.Error(), + }, + // more custom tests + "store greeting then say hello from non-enabled address": { + Caller: allowlist.TestNoRoleAddr, + BeforeHook: func(t testing.TB, state contract.StateDB) { + allowlist.SetDefaultRoles(Module.Address)(t, state) + StoreGreeting(state, testGreeting) + }, + InputFn: func(t testing.TB) []byte { + input, err := PackSayHello() + require.NoError(t, err) + return input + }, + SuppliedGas: SayHelloGasCost, + ReadOnly: true, + ExpectedRes: func() []byte { + res, err := PackSayHelloOutput(testGreeting) + if err != nil { + panic(err) + } + return res + }(), + }, + "set a very long greeting from enabled address": { + Caller: allowlist.TestEnabledAddr, + BeforeHook: allowlist.SetDefaultRoles(Module.Address), + InputFn: func(t testing.TB) []byte { + longString := "a very long string that is longer than 32 bytes and will cause an error" + input, err := PackSetGreeting(longString) + require.NoError(t, err) + + return input + }, + SuppliedGas: SetGreetingGasCost, + ReadOnly: false, + ExpectedErr: ErrInputExceedsLimit.Error(), + }, +} + +// TestHelloWorldRun tests the Run function of the precompile contract. +func TestHelloWorldRun(t *testing.T) { + // Run tests with allowlist tests. + // This adds allowlist run tests to your custom tests + // and runs them all together. + // Even if you don't add any custom tests, keep this. This will still + // run the default allowlist tests. + allowlist.RunPrecompileWithAllowListTests(t, Module, state.NewTestStateDB, tests) +} + +func BenchmarkHelloWorld(b *testing.B) { + // Benchmark tests with allowlist tests. + // This adds allowlist run tests to your custom tests + // and benchmarks them all together. + // Even if you don't add any custom tests, keep this. This will still + // run the default allowlist tests. + allowlist.BenchPrecompileWithAllowList(b, Module, state.NewTestStateDB, tests) +} diff --git a/helloworld/module.go b/helloworld/module.go new file mode 100644 index 0000000..20f6a26 --- /dev/null +++ b/helloworld/module.go @@ -0,0 +1,71 @@ +package helloworld + +import ( + "fmt" + + "github.com/ava-labs/subnet-evm/precompile/contract" + "github.com/ava-labs/subnet-evm/precompile/modules" + "github.com/ava-labs/subnet-evm/precompile/precompileconfig" + + "github.com/ethereum/go-ethereum/common" +) + +var _ contract.Configurator = &configurator{} + +// ConfigKey is the key used in json config files to specify this precompile precompileconfig. +// must be unique across all precompiles. +const ConfigKey = "helloWorldConfig" + +// ContractAddress is the defined address of the precompile contract. +// This should be unique across all precompile contracts. +// See precompile/registry/registry.go for registered precompile contracts and more information. +var ContractAddress = common.HexToAddress("0x0300000000000000000000000000000000000000") // SET A SUITABLE HEX ADDRESS HERE + +// Module is the precompile module. It is used to register the precompile contract. +var Module = modules.Module{ + ConfigKey: ConfigKey, + Address: ContractAddress, + Contract: HelloWorldPrecompile, + Configurator: &configurator{}, +} + +const defaultGreeting = "Hello World!" + +type configurator struct{} + +func init() { + // Register the precompile module. + // Each precompile contract registers itself through [RegisterModule] function. + if err := modules.RegisterModule(Module); err != nil { + panic(err) + } +} + +// MakeConfig returns a new precompile config instance. +// This is required for Marshal/Unmarshal the precompile config. +func (*configurator) MakeConfig() precompileconfig.Config { + return new(Config) +} + +// Configure configures [state] with the given [cfg] precompileconfig. +// This function is called by the EVM once per precompile contract activation. +// You can use this function to set up your precompile contract's initial state, +// by using the [cfg] config and [state] stateDB. +func (*configurator) Configure(chainConfig precompileconfig.ChainConfig, cfg precompileconfig.Config, state contract.StateDB, blockContext contract.BlockContext) error { + config, ok := cfg.(*Config) + if !ok { + return fmt.Errorf("incorrect config %T: %v", config, config) + } + // CUSTOM CODE STARTS HERE + + // This will be called in the first block where HelloWorld stateful precompile is enabled. + // 1) If BlockTimestamp is nil, this will not be called + // 2) If BlockTimestamp is 0, this will be called while setting up the genesis block + // 3) If BlockTimestamp is 1000, this will be called while processing the first block + // whose timestamp is >= 1000 + // + // Set the initial value under [common.BytesToHash([]byte("storageKey")] to "Hello World!" + StoreGreeting(state, defaultGreeting) + // AllowList is activated for this precompile. Configuring allowlist addresses here. + return config.AllowListConfig.Configure(chainConfig, ContractAddress, state, blockContext) +} diff --git a/plugin/main.go b/plugin/main.go index 112ea14..f92eebe 100644 --- a/plugin/main.go +++ b/plugin/main.go @@ -9,9 +9,11 @@ import ( "github.com/ava-labs/avalanchego/version" "github.com/ava-labs/subnet-evm/plugin/evm" "github.com/ava-labs/subnet-evm/plugin/runner" + // Each precompile generated by the precompilegen tool has a self-registering init function // that registers the precompile with the subnet-evm. Importing the precompile package here // will cause the precompile to be registered with the subnet-evm. + _ "github.com/ava-labs/precompile-evm/helloworld" // ADD YOUR PRECOMPILE HERE //_ "github.com/ava-labs/precompile-evm/{yourprecompilepkg}" ) diff --git a/tests/precompile/genesis/.gitkeep b/tests/precompile/genesis/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/tests/precompile/genesis/hello_world.json b/tests/precompile/genesis/hello_world.json new file mode 100644 index 0000000..3588e9d --- /dev/null +++ b/tests/precompile/genesis/hello_world.json @@ -0,0 +1,47 @@ +{ + "config": { + "chainId": 99999, + "homesteadBlock": 0, + "eip150Block": 0, + "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "subnetEVMTimestamp": 0, + "feeConfig": { + "gasLimit": 20000000, + "minBaseFee": 1000000000, + "targetGas": 100000000, + "baseFeeChangeDenominator": 48, + "minBlockGasCost": 0, + "maxBlockGasCost": 10000000, + "targetBlockRate": 2, + "blockGasCostStep": 500000 + }, + "helloWorldConfig": { + "blockTimestamp": 0, + "adminAddresses": [ + "0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC" + ] + } + }, + "alloc": { + "8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC": { + "balance": "0x52B7D2DCC80CD2E4000000" + } + }, + "nonce": "0x0", + "timestamp": "0x0", + "extraData": "0x00", + "gasLimit": "0x1312D00", + "difficulty": "0x0", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" +} diff --git a/tests/precompile/solidity/suites.go b/tests/precompile/solidity/suites.go index a0e37fc..139e0ac 100644 --- a/tests/precompile/solidity/suites.go +++ b/tests/precompile/solidity/suites.go @@ -5,6 +5,11 @@ package solidity import ( + "context" + "fmt" + "time" + + "github.com/ava-labs/subnet-evm/tests/utils" "github.com/onsi/ginkgo/v2" ) @@ -12,7 +17,6 @@ import ( // Before running the tests, this function creates all subnets given in the genesis files // and then runs the hardhat tests for each one asynchronously if called with `ginkgo run -procs=`. func RegisterAsyncTests() { - /* Uncomment these if you want to use default hardhat tests // Tests here assumes that the genesis files are in ./tests/precompile/genesis/ // with the name {precompile_name}.json genesisFiles, err := utils.GetFilesAndAliases("./tests/precompile/genesis/*.json") @@ -23,11 +27,17 @@ func RegisterAsyncTests() { ginkgo.AbortSuite("No genesis files found") } subnetsSuite := utils.CreateSubnetsSuite(genesisFiles) - */ + _ = ginkgo.Describe("[Asynchronized Precompile Tests]", func() { - // Uncomment below and register the ping test first - // utils.RegisterPingTest() + // Register the ping test first + utils.RegisterPingTest() + ginkgo.It("hello world", ginkgo.Label("Precompile"), ginkgo.Label("HelloWorld"), func() { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + blockchainID := subnetsSuite.GetBlockchainID("hello_world") + runDefaultHardhatTests(ctx, blockchainID, "hello_world") + }) // ADD YOUR PRECOMPILE HERE /* ginkgo.It("your precompile", ginkgo.Label("Precompile"), ginkgo.Label("YourPrecompile"), func() { @@ -43,7 +53,6 @@ func RegisterAsyncTests() { }) } -/* Uncomment this if you want to use default hardhat tests // Default parameters are: // // 1. Hardhat contract environment is located at ./contracts @@ -55,4 +64,3 @@ func runDefaultHardhatTests(ctx context.Context, blockchainID, testName string) testPath := fmt.Sprintf("./test/%s.ts", testName) utils.RunHardhatTests(ctx, blockchainID, cmdPath, testPath) } -*/