diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index e9950f0..09e9a6c 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -6,8 +6,3 @@ FROM mcr.microsoft.com/devcontainers/base COPY --from=avalanchego /avalanchego/build /go/src/github.com/ava-labs/avalanchego/build COPY --from=avalanche-cli /avalanche /usr/local/bin/avalanche - -COPY --from=foundry /usr/local/bin/forge /usr/local/bin/forge -COPY --from=foundry /usr/local/bin/cast /usr/local/bin/cast -COPY --from=foundry /usr/local/bin/anvil /usr/local/bin/anvil -COPY --from=foundry /usr/local/bin/chisel /usr/local/bin/chisel diff --git a/README.md b/README.md index 23c8837..f35f344 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,6 @@ To get a comprehensive introduction to Precompile-EVM, take the Avalanche Academ ## How to use -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. - ### 1. 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 as such: @@ -63,6 +61,8 @@ First, create the configuration for your subnet. avalanche blockchain create myblockchain --custom --vm $AVALANCHEGO_PLUGIN_PATH/srEXiWaHuhNyGwPUi444Tu47ZEDwxTWrbQiuD7FmgSAQ6X7Dy --genesis ./.devcontainer/genesis-example.json ``` +Confirm that the new `holamundo/` directory has the appropriate files. + Next, launch the Subnet with your custom VM: ```bash diff --git a/contracts/README.md b/contracts/README.md index 98322d3..b62dffe 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -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, 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..d7c220f --- /dev/null +++ b/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; +} 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/package-lock.json b/contracts/package-lock.json index a5a2ba3..0a951d8 100644 --- a/contracts/package-lock.json +++ b/contracts/package-lock.json @@ -9,7 +9,8 @@ "version": "1.0.0", "license": "BSD-3-Clause", "dependencies": { - "@openzeppelin/contracts": "^4.9.6" + "@openzeppelin/contracts": "^4.9.6", + "solc": "^0.8.27" }, "devDependencies": { "@avalabs/subnet-evm-contracts": "^1.2.2", @@ -2747,8 +2748,7 @@ "node_modules/command-exists": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", - "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", - "dev": true + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==" }, "node_modules/command-line-args": { "version": "5.2.1", @@ -2881,10 +2881,13 @@ } }, "node_modules/commander": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", - "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", - "dev": true + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } }, "node_modules/concat-map": { "version": "0.0.1", @@ -3747,7 +3750,6 @@ "version": "1.15.6", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "dev": true, "funding": [ { "type": "individual", @@ -4287,6 +4289,13 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "node_modules/hardhat/node_modules/commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true, + "license": "MIT" + }, "node_modules/hardhat/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -4340,6 +4349,64 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/hardhat/node_modules/solc": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", + "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "follow-redirects": "^1.12.1", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solcjs" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/hardhat/node_modules/solc/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/hardhat/node_modules/solc/node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/hardhat/node_modules/solc/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/hardhat/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -4746,8 +4813,7 @@ "node_modules/js-sha3": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", - "dev": true + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" }, "node_modules/js-yaml": { "version": "4.1.0", @@ -4828,6 +4894,7 @@ "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", "dev": true, + "license": "MIT", "optionalDependencies": { "graceful-fs": "^4.1.9" } @@ -4962,7 +5029,6 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", - "dev": true, "engines": { "node": ">= 0.10.0" } @@ -5482,7 +5548,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -5937,6 +6002,7 @@ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -6297,55 +6363,30 @@ } }, "node_modules/solc": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", - "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", - "dev": true, + "version": "0.8.27", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.27.tgz", + "integrity": "sha512-BNxMol2tUAbkH7HKlXBcBqrGi2aqgv+uMHz26mJyTtlVgWmBA4ktiw0qVKHfkjf2oaHbwtbtaSeE2dhn/gTAKw==", + "license": "MIT", "dependencies": { "command-exists": "^1.2.8", - "commander": "3.0.2", + "commander": "^8.1.0", "follow-redirects": "^1.12.1", - "fs-extra": "^0.30.0", "js-sha3": "0.8.0", "memorystream": "^0.3.1", - "require-from-string": "^2.0.0", "semver": "^5.5.0", "tmp": "0.0.33" }, "bin": { - "solcjs": "solcjs" + "solcjs": "solc.js" }, "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/solc/node_modules/fs-extra": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", - "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0", - "path-is-absolute": "^1.0.0", - "rimraf": "^2.2.8" - } - }, - "node_modules/solc/node_modules/jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "node": ">=10.0.0" } }, "node_modules/solc/node_modules/semver": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, "bin": { "semver": "bin/semver" } @@ -6819,7 +6860,6 @@ "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, "dependencies": { "os-tmpdir": "~1.0.2" }, diff --git a/contracts/package.json b/contracts/package.json index 678be0e..2bd1978 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -35,7 +35,8 @@ "release:prepare": "rm -rf ./node_modules && npm install && npm run build" }, "dependencies": { - "@openzeppelin/contracts": "^4.9.6" + "@openzeppelin/contracts": "^4.9.6", + "solc": "^0.8.27" }, "engines": { "npm": ">7.0.0", 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..9189a1f --- /dev/null +++ b/contracts/scripts/deployExampleHelloWorld.ts @@ -0,0 +1,15 @@ +import { ethers } from "hardhat" +import { ExampleHelloWorld } from "typechain-types" + +const main = async (): Promise => { + const contract: ExampleHelloWorld = await ethers.deployContract("ExampleHelloWorld") + await contract.waitForDeployment() + console.log(`Contract deployed to: ${contract.target}`) +} + +main() + .then(() => process.exit(0)) + .catch(error => { + console.error(error) + process.exit(1) + }) diff --git a/contracts/tasks.ts b/contracts/tasks.ts index 03ceff1..f2a7694 100644 --- a/contracts/tasks.ts +++ b/contracts/tasks.ts @@ -1,6 +1,20 @@ import { task } from "hardhat/config" +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 = await hre.ethers.getSigners() accounts.forEach((account): void => { @@ -8,6 +22,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 = await hre.ethers.getSigners() for (const account of accounts) { @@ -18,7 +33,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) => { @@ -27,3 +42,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/hello_world.ts b/contracts/test/hello_world.ts new file mode 100644 index 0000000..0dafbdc --- /dev/null +++ b/contracts/test/hello_world.ts @@ -0,0 +1,68 @@ +// (c) 2019-2022, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + + +import { expect } from "chai" +import { Signer } from "ethers" +import { ethers } from "hardhat" +import { test } from "@avalabs/subnet-evm-contracts" +import { IHelloWorld } from "typechain-types" + +// 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.waitForDeployment().then(() => contract) + }) + .then(() => Promise.all([helloWorldPromise])) + .then(([helloWorld]) => helloWorld.setAdmin(this.testContract.target)) + .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") +}); + +describe("IHelloWorld events", function () { + let owner: Signer + let ownerAddress: string + let contract: IHelloWorld + let defaultGreeting = "Hello, World!" + before(async function () { + owner = await ethers.getSigner(ADMIN_ADDRESS); + ownerAddress = await owner.getAddress() + contract = await ethers.getContractAt("IHelloWorld", HELLO_WORLD_ADDRESS, owner) + + // reset greeting + let tx = await contract.setGreeting(defaultGreeting) + await tx.wait() + }); + + it("should emit GreetingChanged event", async function () { + let newGreeting = "helloprecompile" + let tx = await contract.setGreeting(newGreeting) + let receipt = await tx.wait() + await expect(receipt) + .to.emit(contract, "GreetingChanged").withArgs( + ownerAddress, + // old greeting + defaultGreeting, + // new greeting + newGreeting + ) + }) +}) diff --git a/go.mod b/go.mod index 31d12d8..4a59ed1 100644 --- a/go.mod +++ b/go.mod @@ -4,23 +4,28 @@ go 1.24.11 require ( github.com/ava-labs/avalanchego v1.14.0 + github.com/ava-labs/libevm v1.13.15-0.20251016142715-1bccf4f2ddb2 github.com/ava-labs/subnet-evm v0.8.0 github.com/onsi/ginkgo/v2 v2.25.3 github.com/onsi/gomega v1.38.2 github.com/stretchr/testify v1.11.1 + go.uber.org/mock v0.5.0 ) require ( + connectrpc.com/connect v1.18.1 // indirect + connectrpc.com/grpcreflect v1.3.0 // indirect github.com/DataDog/zstd v1.5.2 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/StephenButtolph/canoto v0.17.2 // indirect github.com/VictoriaMetrics/fastcache v1.12.1 // indirect + github.com/ava-labs/coreth v0.16.0-rc.0 // indirect github.com/ava-labs/firewood-go-ethhash/ffi v0.0.13 // indirect - github.com/ava-labs/libevm v1.13.15-0.20251016142715-1bccf4f2ddb2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.20.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.5 // indirect + github.com/btcsuite/btcd/btcutil v1.1.3 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cenkalti/backoff/v5 v5.0.2 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -38,24 +43,34 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/ethereum/c-kzg-4844 v1.0.0 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect github.com/getsentry/sentry-go v0.35.0 // indirect + github.com/go-cmd/cmd v1.4.3 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.22.3 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect + github.com/google/btree v1.1.2 // indirect + github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.7.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect github.com/google/renameio/v2 v2.0.0 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/rpc v1.2.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect @@ -66,19 +81,28 @@ require ( github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/uint256 v1.2.4 // indirect github.com/huin/goupnp v1.3.0 // indirect + github.com/imdario/mergo v0.3.16 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/pointerstructure v1.2.0 // indirect + github.com/moby/spdystream v0.2.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // 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.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.0 // indirect @@ -87,6 +111,7 @@ require ( github.com/prometheus/procfs v0.16.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect + github.com/rs/cors v1.7.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.9.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect @@ -115,7 +140,6 @@ require ( go.opentelemetry.io/otel/trace v1.37.0 // indirect go.opentelemetry.io/proto/otlp v1.7.0 // indirect go.uber.org/automaxprocs v1.6.0 // indirect - go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect @@ -123,6 +147,7 @@ require ( golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect golang.org/x/mod v0.29.0 // indirect golang.org/x/net v0.46.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect golang.org/x/term v0.36.0 // indirect @@ -134,6 +159,17 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect google.golang.org/grpc v1.75.0 // indirect google.golang.org/protobuf v1.36.8 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.29.0 // indirect + k8s.io/apimachinery v0.29.0 // indirect + k8s.io/client-go v0.29.0 // indirect + k8s.io/klog/v2 v2.110.1 // indirect + k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect + k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index b2230b5..cd6ea59 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,12 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw= +connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= +connectrpc.com/grpcreflect v1.3.0 h1:Y4V+ACf8/vOb1XOc251Qun7jMB75gCUNw6llvB9csXc= +connectrpc.com/grpcreflect v1.3.0/go.mod h1:nfloOtCS8VUQOQ1+GTdFzVg2CJo4ZGaat8JIovCtDYs= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= -github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= @@ -17,12 +21,17 @@ github.com/StephenButtolph/canoto v0.17.2 h1:kRLJwtYk0bzdGEeEvwHaVmmDm0HFHxrS0Vl github.com/StephenButtolph/canoto v0.17.2/go.mod h1:IcnAHC6nJUfQFVR9y60ko2ecUqqHHSB6UwI9NnBFZnE= github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= +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= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/ava-labs/avalanchego v1.14.0 h1:0j314N1fEwstKSymvyhvvxi8Hr752xc6MQvjq6kGIJY= github.com/ava-labs/avalanchego v1.14.0/go.mod h1:7sYTcQknONY5x5qzS+GrN+UtyB8kX7Q5ClHhGj1DgXg= +github.com/ava-labs/coreth v0.16.0-rc.0 h1:nPvkDbxaH8N9f/wQe7B+IGMhPISMuW5CU0cDYuU8iCw= +github.com/ava-labs/coreth v0.16.0-rc.0/go.mod h1:uGr1C7BP0+dWhvsIouhuH0yCyI8YDgS6sfEFIExs0iI= github.com/ava-labs/firewood-go-ethhash/ffi v0.0.13 h1:obPwnVCkF5+B2f8WbTepHj0ZgiW21vKUgFCtATuAYNY= github.com/ava-labs/firewood-go-ethhash/ffi v0.0.13/go.mod h1:gsGr1ICjokI9CyPaaRHMqDoDCaT1VguC/IyOTx6rJ14= github.com/ava-labs/libevm v1.13.15-0.20251016142715-1bccf4f2ddb2 h1:hQ15IJxY7WOKqeJqCXawsiXh0NZTzmoQOemkWHz7rr4= @@ -34,10 +43,31 @@ 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/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +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.5 h1:dpAlnAwmT1yIBm3exhT1/8iUSD98RDJM5vqJVQDQLiU= github.com/btcsuite/btcd/btcec/v2 v2.3.5/go.mod h1:m22FrOAiuxl/tht9wIqAoGHcbnCCaPWyauO8y2LGGtQ= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +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/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/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.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= @@ -84,16 +114,20 @@ github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJ github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks= 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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/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/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= +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= @@ -106,6 +140,8 @@ github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= @@ -133,10 +169,13 @@ github.com/getsentry/sentry-go v0.35.0/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvN 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.3 h1:6y3G+3UqPerXvPcXvj+5QNPHT02BUw7p6PsqRxLNA7Y= +github.com/go-cmd/cmd v1.4.3/go.mod h1:u3hxg/ry+D5kwh8WvUkHLAMe2zQCaXd00t35WfQaOFk= 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-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -145,11 +184,19 @@ github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AE github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= @@ -184,12 +231,17 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +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/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= 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= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -206,9 +258,12 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= @@ -233,6 +288,8 @@ github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFck github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= @@ -242,8 +299,17 @@ github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0Gqw github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +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/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +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/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= @@ -253,6 +319,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.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= @@ -274,6 +341,8 @@ github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= @@ -300,15 +369,24 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= @@ -319,14 +397,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.25.3 h1:Ty8+Yi/ayDAGtk4XxmmfUy4GabvM+MegeB4cDLRi6nw= github.com/onsi/ginkgo/v2 v2.25.3/go.mod h1:43uiyQC4Ed2tkOzLsEYm7hnrb7UJTWHYNsuy3bG/snE= +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= @@ -338,6 +420,8 @@ github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0 github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= 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= @@ -363,6 +447,8 @@ github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4 github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +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= @@ -397,18 +483,24 @@ github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqj github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/supranational/blst v0.3.14 h1:xNMoHRJOTwMn63ip6qoWJ2Ymgvj7E2b9jY2FAwY+qRo= github.com/supranational/blst v0.3.14/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.3 h1:srUP/34BulQaEwPP/uHZkdjUcUjIzL7Jkf4CBVryiP8= @@ -479,6 +571,7 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +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-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -503,6 +596,7 @@ 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/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +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= @@ -517,6 +611,7 @@ golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= @@ -528,6 +623,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -554,6 +651,8 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/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= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -657,14 +756,18 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= 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.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= @@ -675,3 +778,21 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= +k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= +k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= +k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= +k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= +k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= +k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= +k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/helloworld/README.md b/helloworld/README.md new file mode 100644 index 0000000..ae18120 --- /dev/null +++ b/helloworld/README.md @@ -0,0 +1,59 @@ +# Helloworld + +There are some must-be-done changes waiting in the generated file. + +- Each place requiring you to add your code is marked with `// CUSTOM CODE` +- Add your precompile where the comment `// ADD YOUR PRECOMPILE HERE` is present, to activate your precompile. + +For testing, you can refer to other precompile tests in [contract_test.go](contract_test.go) and [config_test.go](config_test.go). + +The [hello world precompile tutorial](https://docs.avax.network/subnets/hello-world-precompile-tutorial) should guide you on precompile development. + +## General guidelines for precompile development + +- In the generated [`module.go`](module.go): + - Set a suitable config key, for example + + ```go + const ConfigKey = "yourPrecompileConfig" + ``` + + - Set a suitable contract address, for example: + + ```go + var ContractAddress = common.HexToAddress("ASUITABLEHEXADDRESS") + ``` + +- Only modify code after `// CUSTOM CODE STARTS HERE`. Modifying code outside of these areas should be done with caution and with a good understanding of how changes may impact the EVM. +- Set gas costs in the generated [`contract.go`](contract.go) file, for example: + + ```go + const ( + // Gas costs for each function. These are set to 1 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 + ) + ``` + +- Force import your precompile package in `precompile/registry/registry.go`, for example with: + + ```go + import ( + _ "github.com/ava-labs/precompile-evm/helloworld" + ) + ``` + +- Add your config unit tests in [`config_test.go`](config_test.go) +- Add your contract unit tests in [`contract_test.go`](contract_test.go) +- You can add a full-fledged VM test for your precompile in [`plugin/vm/vm_test.go`](plugin/vm/vm_test.go). See existing precompile tests for examples. +- Add your Solidity interface and test contract to [`contracts/contracts`](../contracts/contracts/) +- Write Solidity contract tests for your precompile in [`contracts/contracts/test`](../contracts/contracts/test) +- Write TypeScript DS-Test counterparts for your Solidity tests in [`contracts/test`](../contracts/test) +- Create your genesis with your precompile enabled in [`tests/precompile/genesis/`](../tests/precompile/genesis) +- Create e2e test for your Solidity test in [`tests/precompile/solidity/suites.go`](../tests/precompile/solidity/suites.go) +- 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..1459840 --- /dev/null +++ b/helloworld/config.go @@ -0,0 +1,77 @@ +// Code generated +// This file is a generated precompile contract config with stubbed abstract functions. +// The file is generated by a template. Please inspect every code and comment in this file before use. + +package helloworld + +import ( + "github.com/ava-labs/subnet-evm/precompile/allowlist" + "github.com/ava-labs/subnet-evm/precompile/precompileconfig" + + "github.com/ava-labs/libevm/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], [enableds] and [managers] members of the allowlist . +func NewConfig(blockTimestamp *uint64, admins []common.Address, enableds []common.Address, managers []common.Address) *Config { + return &Config{ + AllowListConfig: allowlist.AllowListConfig{ + AdminAddresses: admins, + EnabledAddresses: enableds, + ManagerAddresses: managers, + }, + 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(chainConfig precompileconfig.ChainConfig) error { + // Verify AllowList first + if err := c.AllowListConfig.Verify(chainConfig, c.Upgrade); 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..4cc376b --- /dev/null +++ b/helloworld/config_test.go @@ -0,0 +1,87 @@ +// Code generated +// This file is a generated precompile config test with the skeleton of test functions. +// The file is generated by a template. Please inspect every code and comment in this file before use. + +package helloworld + +import ( + "testing" + + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/subnet-evm/precompile/allowlist/allowlisttest" + "github.com/ava-labs/subnet-evm/precompile/precompileconfig" + "github.com/ava-labs/subnet-evm/precompile/precompiletest" + "github.com/ava-labs/subnet-evm/utils" + "go.uber.org/mock/gomock" +) + +// TestVerify tests the verification of Config. +func TestVerify(t *testing.T) { + admins := []common.Address{allowlisttest.TestAdminAddr} + enableds := []common.Address{allowlisttest.TestEnabledAddr} + managers := []common.Address{allowlisttest.TestManagerAddr} + tests := map[string]precompiletest.ConfigVerifyTest{ + "valid config": { + Config: NewConfig(utils.NewUint64(3), admins, enableds, managers), + ChainConfig: func() precompileconfig.ChainConfig { + config := precompileconfig.NewMockChainConfig(gomock.NewController(t)) + config.EXPECT().IsDurango(gomock.Any()).Return(true).AnyTimes() + return config + }(), + ExpectedError: "", + }, + // CUSTOM CODE STARTS HERE + // Add your own Verify tests here, e.g.: + // "your custom test name": { + // Config: NewConfig(utils.NewUint64(3), admins, enableds, managers), + // ExpectedError: ErrYourCustomError.Error(), + // }, + "invalid allow list config in hello world allowlist": { + Config: NewConfig(utils.NewUint64(3), admins, admins, nil), + ExpectedError: "cannot set address", + }, + } + // 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. + allowlisttest.VerifyPrecompileWithAllowListTests(t, Module, tests) +} + +// TestEqual tests the equality of Config with other precompile configs. +func TestEqual(t *testing.T) { + admins := []common.Address{allowlisttest.TestAdminAddr} + enableds := []common.Address{allowlisttest.TestEnabledAddr} + managers := []common.Address{allowlisttest.TestManagerAddr} + tests := map[string]precompiletest.ConfigEqualTest{ + "non-nil config and nil other": { + Config: NewConfig(utils.NewUint64(3), admins, enableds, managers), + Other: nil, + Expected: false, + }, + "different type": { + Config: NewConfig(utils.NewUint64(3), admins, enableds, managers), + Other: precompileconfig.NewMockConfig(gomock.NewController(t)), + Expected: false, + }, + "different timestamp": { + Config: NewConfig(utils.NewUint64(3), admins, enableds, managers), + Other: NewConfig(utils.NewUint64(4), admins, enableds, managers), + Expected: false, + }, + "same config": { + Config: NewConfig(utils.NewUint64(3), admins, enableds, managers), + Other: NewConfig(utils.NewUint64(3), admins, enableds, managers), + Expected: true, + }, + // CUSTOM CODE STARTS HERE + // Add your own Equal tests here + } + // 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. + allowlisttest.EqualPrecompileWithAllowListTests(t, Module, tests) +} diff --git a/helloworld/contract.abi b/helloworld/contract.abi new file mode 100644 index 0000000..94b0074 --- /dev/null +++ b/helloworld/contract.abi @@ -0,0 +1 @@ +[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"string","name":"oldGreeting","type":"string"},{"indexed":false,"internalType":"string","name":"newGreeting","type":"string"}],"name":"GreetingChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"role","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldRole","type":"uint256"}],"name":"RoleSet","type":"event"},{"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":"setManager","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..f5b7aa5 --- /dev/null +++ b/helloworld/contract.go @@ -0,0 +1,254 @@ +// Code generated +// This file is a generated precompile contract config with stubbed abstract functions. +// The file is generated by a template. Please inspect every code and comment in this file before use. + +package helloworld + +import ( + "errors" + "fmt" + + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/subnet-evm/accounts/abi" + "github.com/ava-labs/subnet-evm/precompile/allowlist" + "github.com/ava-labs/subnet-evm/precompile/contract" + + _ "embed" + + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/types" +) + +const ( + // Gas costs for each function. These are set to 1 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 = 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) +} + +// UnpackSayHelloOutput attempts to unpack given [output] into the string type output +// assumes that [output] does not include selector (omits first 4 func signature bytes) +func UnpackSayHelloOutput(output []byte) (string, error) { + res, err := HelloWorldABI.Unpack("sayHello", output) + if err != nil { + return "", err + } + unpacked := *abi.ConvertType(res[0], new(string)).(*string) + return unpacked, nil +} + +// 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) +// if [useStrictMode] is true, it will return an error if the length of [input] is not [common.HashLength] +func UnpackSetGreetingInput(input []byte, useStrictMode bool) (string, error) { + // Initially we had this check to ensure that the input was the correct length. + // However solidity does not always pack the input to the correct length, and allows + // for extra padding bytes to be added to the end of the input. Therefore, we have removed + // this check with the Durango. We still need to keep this check for backwards compatibility. + if useStrictMode && len(input) > common.HashLength { + return "", ErrInputExceedsLimit + } + res, err := HelloWorldABI.UnpackInput("setGreeting", input, useStrictMode) + 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, vm.ErrWriteProtection + } + // do not use strict mode after Durango + useStrictMode := !contract.IsDurangoActivated(accessibleState) + // 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, useStrictMode) + 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 + // With Durango, you can emit an event in your state-changing precompile functions. + // Note: If you have been using the precompile before Durango, you should activate it only after Durango. + // Activating this code before Durango will result in a consensus failure. + // If this is a new precompile and never deployed before Durango, you can activate it immediately by removing + // the if condition. + // This example assumes that the HelloWorld precompile contract has been deployed before Durango. + if contract.IsDurangoActivated(accessibleState) { + // We will first read the old greeting. So we should charge the gas for reading the storage. + if remainingGas, err = contract.DeductGas(remainingGas, contract.ReadGasCostPerSlot); err != nil { + return nil, 0, err + } + oldGreeting := GetGreeting(stateDB) + + eventData := GreetingChangedEventData{ + OldGreeting: oldGreeting, + NewGreeting: inputStruct, + } + topics, data, err := PackGreetingChangedEvent(caller, eventData) + if err != nil { + return nil, remainingGas, err + } + // Charge the gas for emitting the event. + eventGasCost := GetGreetingChangedEventGasCost(eventData) + if remainingGas, err = contract.DeductGas(remainingGas, eventGasCost); err != nil { + return nil, 0, err + } + + // Emit the event + stateDB.AddLog(&types.Log{ + Address: ContractAddress, + Topics: topics, + Data: data, + BlockNumber: accessibleState.GetBlockContext().Number().Uint64(), + }) + } + + // 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..af5a2b7 --- /dev/null +++ b/helloworld/contract_test.go @@ -0,0 +1,385 @@ +// Code generated +// This file is a generated precompile contract test with the skeleton of test functions. +// The file is generated by a template. Please inspect every code and comment in this file before use. + +package helloworld + +import ( + "testing" + + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/subnet-evm/core/extstate" + "github.com/ava-labs/subnet-evm/precompile/allowlist/allowlisttest" + "github.com/ava-labs/subnet-evm/precompile/contract" + "github.com/ava-labs/subnet-evm/precompile/precompileconfig" + "github.com/ava-labs/subnet-evm/precompile/precompiletest" + "github.com/ava-labs/subnet-evm/utils" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +// 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" +const longString = "a very long string that is longer than 32 bytes and will cause an error" + +var ( + tests = []precompiletest.PrecompileTest{ + { + Name: "calling sayHello from NoRole should succeed", + Caller: allowlisttest.TestNoRoleAddr, + BeforeHook: allowlisttest.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: "", + }, + { + Name: "calling sayHello from Enabled should succeed", + Caller: allowlisttest.TestEnabledAddr, + BeforeHook: allowlisttest.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: "", + }, + { + Name: "calling sayHello from Manager should succeed", + Caller: allowlisttest.TestManagerAddr, + BeforeHook: allowlisttest.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: "", + }, + { + Name: "calling sayHello from Admin should succeed", + Caller: allowlisttest.TestAdminAddr, + BeforeHook: allowlisttest.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: "", + }, + { + Name: "calling sayHello from NoRole with a config should return default greeting", + Caller: allowlisttest.TestNoRoleAddr, + BeforeHook: allowlisttest.SetDefaultRoles(Module.Address), + Config: NewConfig(utils.NewUint64(0), nil, 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: "", + }, + { + Name: "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: vm.ErrOutOfGas.Error(), + }, + { + Name: "calling setGreeting from NoRole should fail", + Caller: allowlisttest.TestNoRoleAddr, + BeforeHook: allowlisttest.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(), + }, + { + Name: "calling setGreeting from Enabled should succeed", + Caller: allowlisttest.TestEnabledAddr, + BeforeHook: allowlisttest.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 + contract.ReadGasCostPerSlot + GetGreetingChangedEventGasCost(GreetingChangedEventData{ + OldGreeting: "", + NewGreeting: testGreeting, + }), + ReadOnly: false, + ExpectedErr: "", + AfterHook: func(t testing.TB, state *extstate.StateDB) { + greeting := GetGreeting(state) + require.Equal(t, greeting, testGreeting) + }, + }, + { + Name: "calling setGreeting from Manager should succeed", + Caller: allowlisttest.TestManagerAddr, + BeforeHook: allowlisttest.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 + contract.ReadGasCostPerSlot + GetGreetingChangedEventGasCost(GreetingChangedEventData{ + OldGreeting: "", + NewGreeting: testGreeting, + }), + ReadOnly: false, + ExpectedErr: "", + AfterHook: func(t testing.TB, state *extstate.StateDB) { + greeting := GetGreeting(state) + require.Equal(t, greeting, testGreeting) + }, + }, + { + Name: "calling setGreeting from Admin should succeed", + Caller: allowlisttest.TestAdminAddr, + BeforeHook: allowlisttest.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 + contract.ReadGasCostPerSlot + GetGreetingChangedEventGasCost(GreetingChangedEventData{ + OldGreeting: "", + NewGreeting: testGreeting, + }), + ReadOnly: false, + ExpectedErr: "", + AfterHook: func(t testing.TB, state *extstate.StateDB) { + greeting := GetGreeting(state) + require.Equal(t, greeting, testGreeting) + }, + }, + { + Name: "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: vm.ErrWriteProtection.Error(), + }, + { + Name: "insufficient gas for setGreeting should fail", + Caller: allowlisttest.TestEnabledAddr, + BeforeHook: allowlisttest.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 + contract.ReadGasCostPerSlot + GetGreetingChangedEventGasCost(GreetingChangedEventData{ + OldGreeting: "", + NewGreeting: testGreeting, + }) - 1, + ReadOnly: false, + ExpectedErr: vm.ErrOutOfGas.Error(), + }, + // more custom tests + { + Name: "store greeting then say hello from non-enabled address", + Caller: allowlisttest.TestNoRoleAddr, + BeforeHook: func(t testing.TB, state *extstate.StateDB) { + allowlisttest.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 + }(), + }, + { + Name: "set a very long greeting from enabled address before Durango", + Caller: allowlisttest.TestEnabledAddr, + BeforeHook: allowlisttest.SetDefaultRoles(Module.Address), + // By default Durango is enabled in the tests. + ChainConfigFn: func(ctrl *gomock.Controller) precompileconfig.ChainConfig { + config := precompileconfig.NewMockChainConfig(ctrl) + config.EXPECT().IsDurango(gomock.Any()).Return(false).AnyTimes() + return config + }, + 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(), + }, + { + Name: "set a very long greeting from enabled address after Durango", + Caller: allowlisttest.TestEnabledAddr, + BeforeHook: allowlisttest.SetDefaultRoles(Module.Address), + InputFn: func(t testing.TB) []byte { + input, err := PackSetGreeting(longString) + require.NoError(t, err) + + return input + }, + SuppliedGas: SetGreetingGasCost + contract.ReadGasCostPerSlot + GetGreetingChangedEventGasCost(GreetingChangedEventData{ + OldGreeting: "", + NewGreeting: longString, + }), + ReadOnly: false, + ExpectedErr: "", + ExpectedRes: []byte{}, + }, + } +) + +// 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. + allowlisttest.RunPrecompileWithAllowListTests(t, Module, tests) +} + +// TestPackUnpackGreetingChangedEventData tests the Pack/UnpackGreetingChangedEventData. +func TestPackUnpackGreetingChangedEventData(t *testing.T) { + // CUSTOM CODE STARTS HERE + // set test inputs with proper values here + senderInput := common.Address{} + + dataInput := GreetingChangedEventData{ + OldGreeting: "", + NewGreeting: "", + } + + _, data, err := PackGreetingChangedEvent( + senderInput, + dataInput, + ) + require.NoError(t, err) + + unpacked, err := UnpackGreetingChangedEventData(data) + require.NoError(t, err) + require.Equal(t, dataInput, unpacked) +} diff --git a/helloworld/event.go b/helloworld/event.go new file mode 100644 index 0000000..5709a79 --- /dev/null +++ b/helloworld/event.go @@ -0,0 +1,90 @@ +// Code generated +// This file is a generated precompile contract config with stubbed abstract functions. +// The file is generated by a template. Please inspect every code and comment in this file before use. + +package helloworld + +import ( + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/subnet-evm/precompile/contract" +) + +/* NOTE: Events can only be emitted in state-changing functions. So you cannot use events in read-only (view) functions. +Events are generally emitted at the end of a state-changing function with AddLog method of the StateDB. The AddLog method takes 4 arguments: + 1. Address of the contract that emitted the event. + 2. Topic hashes of the event. + 3. Encoded non-indexed data of the event. + 4. Block number at which the event was emitted. +The first argument is the address of the contract that emitted the event. +Topics can be at most 4 elements, the first topic is the hash of the event signature and the rest are the indexed event arguments. There can be at most 3 indexed arguments. +Topics cannot be fully unpacked into their original values since they're 32-bytes hashes. +The non-indexed arguments are encoded using the ABI encoding scheme. The non-indexed arguments can be unpacked into their original values. +Before packing the event, you need to calculate the gas cost of the event. The gas cost of an event is the base gas cost + the gas cost of the topics + the gas cost of the non-indexed data. +See Get{EvetName}EventGasCost functions for more details. +You can use the following code to emit an event in your state-changing precompile functions (generated packer might be different)): +topics, data, err := PackMyEvent( + topic1, + topic2, + data1, + data2, +) +if err != nil { + return nil, remainingGas, err +} +accessibleState.GetStateDB().AddLog( + ContractAddress, + topics, + data, + accessibleState.GetBlockContext().Number().Uint64(), +) +*/ + +// HelloWorldGreetingChanged represents a GreetingChanged non-indexed event data raised by the HelloWorld contract. +type GreetingChangedEventData struct { + OldGreeting string + NewGreeting string +} + +// GetGreetingChangedEventGasCost returns the gas cost of the event. +// The gas cost of an event is the base gas cost + the gas cost of the topics + the gas cost of the non-indexed data. +// The base gas cost and the gas cost of per topics are fixed and can be found in the contract package. +// The gas cost of the non-indexed data depends on the data type and the data size. +func GetGreetingChangedEventGasCost(data GreetingChangedEventData) uint64 { + gas := contract.LogGas // base gas cost + + // Add topics gas cost (2 topics) + // Topics always include the signature hash of the event. The rest are the indexed event arguments. + gas += contract.LogTopicGas * 2 + + // CUSTOM CODE STARTS HERE + // TODO: calculate gas cost for packing the data.oldGreeting according to the type. + // Keep in mind that the data here will be encoded using the ABI encoding scheme. + // So the computation cost might change according to the data type + data size and should be charged accordingly. + // i.e gas += LogDataGas * uint64(len(data.oldGreeting)) + gas += contract.LogDataGas * uint64(len(data.OldGreeting)) // * ... + // CUSTOM CODE ENDS HERE + // CUSTOM CODE STARTS HERE + // TODO: calculate gas cost for packing the data.newGreeting according to the type. + // Keep in mind that the data here will be encoded using the ABI encoding scheme. + // So the computation cost might change according to the data type + data size and should be charged accordingly. + // i.e gas += LogDataGas * uint64(len(data.newGreeting)) + gas += contract.LogDataGas * uint64(len(data.NewGreeting)) // * ... + // CUSTOM CODE ENDS HERE + + // CUSTOM CODE STARTS HERE + // TODO: do any additional gas cost calculation here (only if needed) + return gas +} + +// PackGreetingChangedEvent packs the event into the appropriate arguments for GreetingChanged. +// It returns topic hashes and the encoded non-indexed data. +func PackGreetingChangedEvent(sender common.Address, data GreetingChangedEventData) ([]common.Hash, []byte, error) { + return HelloWorldABI.PackEvent("GreetingChanged", sender, data.OldGreeting, data.NewGreeting) +} + +// UnpackGreetingChangedEventData attempts to unpack non-indexed [dataBytes]. +func UnpackGreetingChangedEventData(dataBytes []byte) (GreetingChangedEventData, error) { + eventData := GreetingChangedEventData{} + err := HelloWorldABI.UnpackIntoInterface(&eventData, "GreetingChanged", dataBytes) + return eventData, err +} diff --git a/helloworld/module.go b/helloworld/module.go new file mode 100644 index 0000000..5046771 --- /dev/null +++ b/helloworld/module.go @@ -0,0 +1,74 @@ +// Code generated +// This file is a generated precompile contract config with stubbed abstract functions. +// The file is generated by a template. Please inspect every code and comment in this file before use. + +package helloworld + +import ( + "fmt" + + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/subnet-evm/precompile/contract" + "github.com/ava-labs/subnet-evm/precompile/modules" + "github.com/ava-labs/subnet-evm/precompile/precompileconfig" +) + +var _ contract.Configurator = &configurator{} + +// ConfigKey is the key used in json config files to specify this precompile config. +// 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 to 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.ConfigurationBlockContext) 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.Configure(chainConfig, ContractAddress, state, blockContext) +} diff --git a/plugin/main.go b/plugin/main.go index 7f0aa19..3cb16d9 100644 --- a/plugin/main.go +++ b/plugin/main.go @@ -9,11 +9,12 @@ 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. // ADD YOUR PRECOMPILE HERE - //_ "github.com/ava-labs/precompile-evm/{yourprecompilepkg}" + _ "github.com/ava-labs/precompile-evm/helloworld" ) const Version = "v0.4.0" diff --git a/tests/precompile/genesis/hello_world.json b/tests/precompile/genesis/hello_world.json new file mode 100644 index 0000000..f1973d7 --- /dev/null +++ b/tests/precompile/genesis/hello_world.json @@ -0,0 +1,36 @@ +{ + "config": { + "chainId": 99999, + "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": "0x66350B4E", + "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) } -*/