-
Notifications
You must be signed in to change notification settings - Fork 376
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat!(precompile): Add registry and genesis tests (#1999)
* feat!(precompile): Add registry and genesis tests Based on evgeniy-scherbina's work, this adds a new precompile module which defines a contract moudule with an example noop contract that will be will be used for implementing test functions. In addition, it defines a registry module that instantiates stateful precompile contracts and associates them with an address in a global registry defined in kava-labs/go-ethereum. See precompile/README.md for more information. The kava-labs/go-ethereum and kava-labs/etheremint replace statements are updated to support these changes as well as an update to kvtool which includes genesis state for the registry.NoopContractAddress and initializes the contract's EthAccount with a non-zero sequence and codehash set to keccak256(0x01), and sets the contract code to 0x01. See tests/e2e/e2e_precompile_genesis_test.go for an overview of the expected genesis state for an enabled precompile. Co-authored-by: evgeniy-scherbina <[email protected]> * chore: Precompile readme improvements This fixes a typo (import -> important) and uses package terminology instead of unclear module terminology. This aligns best with golang terminology were modules and packages are distinctly different and modules are defined using go.mod. * chore: Improve noop contract godoc Add a more meaningful godoc where the noop contract is constructed. * chore(e2e): Improve comments around query checks Improve the clarity of comments around where the error is checked for accounts and why it is not checked directly. In addition, improve comment on why both grpc and rpc code is fetched and where they are used. --------- Co-authored-by: evgeniy-scherbina <[email protected]>
- Loading branch information
1 parent
33932e8
commit ab3cf7c
Showing
12 changed files
with
344 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Precompile | ||
|
||
The `precompile` package defines stateful precompile contracts used for creating precompile contracts that enhance the EVM, enable interactions between cosmos state and EVM state, or are used soley for testing purposes. | ||
|
||
This package is made of two subpackages: | ||
|
||
- `contracts` - Defines stateful precompiles and their constructors. | ||
- `registry` - Defines stateful precompile addresses and registers them with the global registry | ||
defined at `github.com/kava-labs/go-ethereum/precompile/modules`. | ||
|
||
This is architected to isolate the dependency on the global registry (`github.com/kava-labs/go-ethereum/precompile/modules` package) to as few places as possible, have one source of truth for address registration (see `./registry/registry.go`), and isolate registration testing to one package. | ||
|
||
In order to use the precompile registry, it must be imported for it's init function to run and register the precompiles. For the kava app, this is done in the `app.go` file with the import `_ "github.com/kava-labs/kava/precompile/registry"`. This is done in the `app.go` since this is the main file used for app dependencies and so all modules using the app cause the registry to be loaded. This is important for any consumers of the app outside of the kava cmd, as well as test code using the app for integration and unit testing. | ||
|
||
## Defining a new precompile | ||
|
||
1) Add the expected 0x address to the expected list in `./registry/registry_test.go`. | ||
2) Create a new sub-directory under `./contracts` with a `contract_test.go` and `contract.go` file. | ||
3) Implement `NewContract` function with associated tests in contract and contract test files. | ||
4) Add the contract registration to `./registry/registry.go`. | ||
|
||
## Contracts | ||
|
||
### Noop | ||
|
||
This contract is used for testing purposes only and should not be used on public chains. The functions of this contract (once implemented), will be used to exercise and test the various aspects of the EVM such as gas usage, argument parsing, events, etc. The specific operations tested under this contract are still to be determined. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package noop | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/ethereum/go-ethereum/precompile/contract" | ||
) | ||
|
||
// NewContract returns a new noop stateful precompiled contract. | ||
// | ||
// This contract is used for testing purposes only and should not be used on public chains. | ||
// The functions of this contract (once implemented), will be used to exercise and test the various aspects of | ||
// the EVM such as gas usage, argument parsing, events, etc. The specific operations tested under this contract are | ||
// still to be determined. | ||
func NewContract() (contract.StatefulPrecompiledContract, error) { | ||
precompile, err := contract.NewStatefulPrecompileContract([]*contract.StatefulPrecompileFunction{}) | ||
|
||
if err != nil { | ||
return nil, fmt.Errorf("failed to instantiate noop precompile: %w", err) | ||
} | ||
|
||
return precompile, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package noop_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/kava-labs/kava/precompile/contracts/noop" | ||
) | ||
|
||
// TestContractConstructor ensures we have a valid constructor. This will fail | ||
// if we attempt to define invalid or duplicate function selectors. | ||
func TestContractConstructor(t *testing.T) { | ||
precompile, err := noop.NewContract() | ||
require.NoError(t, err, "expected precompile not error when created") | ||
assert.NotNil(t, precompile, "expected precompile contract to be defined") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package registry | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/precompile/contract" | ||
"github.com/ethereum/go-ethereum/precompile/modules" | ||
|
||
"github.com/kava-labs/kava/precompile/contracts/noop" | ||
) | ||
|
||
const ( | ||
// NoopContractAddress the primary noop contract address for testing | ||
NoopContractAddress = "0x9000000000000000000000000000000000000001" | ||
// NoopContractAddress2 the secondary noop contract address for testing | ||
NoopContractAddress2 = "0x9000000000000000000000000000000000000002" | ||
) | ||
|
||
// init registers stateful precompile contracts with the global precompile registry | ||
// defined in kava-labs/go-ethereum/precompile/modules | ||
func init() { | ||
register(NoopContractAddress, noop.NewContract) | ||
register(NoopContractAddress2, noop.NewContract) | ||
} | ||
|
||
// register accepts a 0x address string and a stateful precompile contract constructor, instantiates the | ||
// precompile contract via the constructor, and registers it with the precompile module registry. | ||
// | ||
// This panics if the contract can not be created or the module can not be registered | ||
func register(address string, newContract func() (contract.StatefulPrecompiledContract, error)) { | ||
contract, err := newContract() | ||
if err != nil { | ||
panic(fmt.Errorf("error creating contract for address %s: %w", address, err)) | ||
} | ||
|
||
module := modules.Module{ | ||
Address: common.HexToAddress(address), | ||
Contract: contract, | ||
} | ||
|
||
err = modules.RegisterModule(module) | ||
if err != nil { | ||
panic(fmt.Errorf("error registering contract module for address %s: %w", address, err)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package registry_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/ethereum/go-ethereum/precompile/modules" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
// TestRegisteredPrecompiles asserts precompiles are registered | ||
// | ||
// In addition, this serves as an integration test to | ||
// 1. Ensure modules.RegisteredModules() is returning addresses in the correct ascending order | ||
// 2. Ensure that that the address defined in the module is correct. Since we use common.HexToAddress and | ||
// then back to 0x encoded string, we can be certain that the string defined in the module is the | ||
// expected length, not missing 0's, etc. | ||
func TestRegisteredPrecompilesAddresses(t *testing.T) { | ||
// build list of 0x addresses that are registered | ||
registeredModules := modules.RegisteredModules() | ||
registeredPrecompiles := make([]string, 0, len(registeredModules)) | ||
for _, rp := range registeredModules { | ||
registeredPrecompiles = append(registeredPrecompiles, rp.Address.String()) | ||
} | ||
|
||
expectedPrecompiles := []string{ | ||
// 0x9 address space used for e2e & integration tests | ||
"0x9000000000000000000000000000000000000001", // noop | ||
"0x9000000000000000000000000000000000000002", // noop (duplicated for testing) | ||
} | ||
|
||
assert.Equal(t, expectedPrecompiles, registeredPrecompiles, | ||
"expected registered precompile address list to match to match expected") | ||
} |
Oops, something went wrong.