Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Precompile Specific Packages #420

Merged
merged 26 commits into from
Jan 6, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1fdc23e
rework on panics in precompiles
ceyonur Dec 20, 2022
4d011d9
Update precompile/allow_list.go
ceyonur Dec 21, 2022
2f90260
Update precompile/fee_config_manager.go
ceyonur Dec 21, 2022
5991c6e
Update precompile/fee_config_manager.go
ceyonur Dec 21, 2022
8f83fe5
fix reviews
ceyonur Dec 22, 2022
a4f8b28
Merge branch 'precompile-improvements-main' into reduce-precompile-pa…
ceyonur Dec 23, 2022
ccc7810
wrap errors in ConfigurePrecompiles
ceyonur Dec 23, 2022
93296c6
cleaner errors
ceyonur Dec 23, 2022
50bad39
move reward manager precompile to package (WIP)
ceyonur Dec 23, 2022
859b2b5
rename files
ceyonur Dec 23, 2022
b9f8486
fix abi path
ceyonur Dec 23, 2022
af8899f
move typecheck
ceyonur Dec 23, 2022
aab1239
move precompiles to their own packages
ceyonur Dec 26, 2022
6adb71b
refactor precompile template
ceyonur Dec 29, 2022
02a423f
Merge branch 'precompile-improvements-main' into precompile-specific-…
ceyonur Dec 29, 2022
00dc16d
remove test file
ceyonur Dec 29, 2022
535f1c6
upate comments
ceyonur Dec 29, 2022
2ef3587
rm test files
ceyonur Dec 29, 2022
af5bc81
new allowlist package
ceyonur Jan 3, 2023
0aae074
Update precompile/utils.go
ceyonur Jan 4, 2023
79bba2a
Update precompile/nativeminter/contract_native_minter.go
ceyonur Jan 4, 2023
1bd589f
Update precompile/nativeminter/contract_native_minter.go
ceyonur Jan 4, 2023
bd0c54e
Update precompile/utils.go
ceyonur Jan 4, 2023
f4c399e
Update precompile/nativeminter/contract_native_minter.go
ceyonur Jan 4, 2023
988439c
fix nits
ceyonur Jan 4, 2023
bdbfbb1
Merge branch 'precompile-specific-packages' of github.com:ava-labs/su…
ceyonur Jan 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions accounts/abi/bind/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const (
readAllowListFuncKey = "readAllowList"
)

type BindHook func(lang Lang, types []string, contracts map[string]*tmplContract, structs map[string]*tmplStruct) (data interface{}, templateSource string, err error)
type BindHook func(lang Lang, pkg string, types []string, contracts map[string]*tmplContract, structs map[string]*tmplStruct) (data interface{}, templateSource string, err error)

// Lang is a target programming language selector to generate bindings for.
type Lang int
Expand Down Expand Up @@ -295,7 +295,7 @@ func bindHelper(types []string, abis []string, bytecodes []string, fsigs []map[s
// Generate the contract template data according to hook
if bindHook != nil {
var err error
data, templateSource, err = bindHook(lang, types, contracts, structs)
data, templateSource, err = bindHook(lang, pkg, types, contracts, structs)
if err != nil {
return "", err
}
Expand Down
26 changes: 20 additions & 6 deletions accounts/abi/bind/precompile_bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,23 @@ import (
"fmt"
)

func PrecompileBind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, lang Lang, libs map[string]string, aliases map[string]string, abifilename string) (string, error) {
// create hook
var createPrecompileFunc BindHook = func(lang Lang, types []string, contracts map[string]*tmplContract, structs map[string]*tmplStruct) (interface{}, string, error) {
// PrecompileBind generates a Go binding for a precompiled contract. It returns config binding and contract binding.
func PrecompileBind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, lang Lang, libs map[string]string, aliases map[string]string, abifilename string) (string, string, error) {
// create hooks
configHook := createPrecompileHook(abifilename, tmplSourcePrecompileConfigGo)
contractHook := createPrecompileHook(abifilename, tmplSourcePrecompileContractGo)

configBind, err := bindHelper(types, abis, bytecodes, fsigs, pkg, lang, libs, aliases, configHook)
if err != nil {
return "", "", err
}
contractBind, err := bindHelper(types, abis, bytecodes, fsigs, pkg, lang, libs, aliases, contractHook)

return configBind, contractBind, err
}

func createPrecompileHook(abifilename string, template string) BindHook {
var bindHook BindHook = func(lang Lang, pkg string, types []string, contracts map[string]*tmplContract, structs map[string]*tmplStruct) (interface{}, string, error) {
// verify first
if lang != LangGo {
return nil, "", errors.New("only GoLang binding for precompiled contracts is supported yet")
Expand Down Expand Up @@ -82,11 +96,11 @@ func PrecompileBind(types []string, abis []string, bytecodes []string, fsigs []m
data := &tmplPrecompileData{
Contract: precompileContract,
Structs: structs,
Package: pkg,
}
return data, tmplSourcePrecompileGo, nil
return data, template, nil
}

return bindHelper(types, abis, bytecodes, fsigs, pkg, lang, libs, aliases, createPrecompileFunc)
return bindHook
}

func allowListEnabled(funcs map[string]*tmplMethod) bool {
Expand Down
2 changes: 1 addition & 1 deletion accounts/abi/bind/precompile_bind_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func golangBindingsFailure(t *testing.T) {
for i, tt := range bindFailedTests {
t.Run(tt.name, func(t *testing.T) {
// Generate the binding
_, err := PrecompileBind([]string{tt.name}, tt.abi, tt.bytecode, tt.fsigs, "bindtest", LangGo, tt.libs, tt.aliases, "")
_, _, err := PrecompileBind([]string{tt.name}, tt.abi, tt.bytecode, tt.fsigs, "bindtest", LangGo, tt.libs, tt.aliases, "")
if err == nil {
t.Fatalf("test %d: no error occurred but was expected", i)
}
Expand Down
151 changes: 151 additions & 0 deletions accounts/abi/bind/precompile_config_template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// (c) 2019-2022, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package bind

// tmplSourcePrecompileConfigGo is the Go precompiled config source template.
const tmplSourcePrecompileConfigGo = `
// 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.

// There are some must-be-done changes waiting in the file. Each area requiring you to add your code is marked with CUSTOM CODE to make them easy to find and modify.
// Additionally there are other files you need to edit to activate your precompile.
// These areas are highlighted with comments "ADD YOUR PRECOMPILE HERE".
// For testing take a look at other precompile tests in core/stateful_precompile_test.go and config_test.go in other precompile folders.

/* General guidelines for precompile development:
1- Read the comment and set a suitable contract address in precompile/params.go. E.g:
{{.Contract.Type}}Address = common.HexToAddress("ASUITABLEHEXADDRESS")
2- Set gas costs in contract.go
3- It is recommended to only modify code in the highlighted areas marked with "CUSTOM CODE STARTS HERE". Modifying code outside of these areas should be done with caution and with a deep understanding of how these changes may impact the EVM.
Typically, custom codes are required in only those areas.
4- Add your upgradable config in params/precompile_config.go
5- Add your precompile upgrade in params/config.go
6- Add your config unit test in {generatedpkg}/config_test.go
7- Add your solidity interface and test contract to contract-examples/contracts
8- Write solidity tests for your precompile in contract-examples/test
9- Create your genesis with your precompile enabled in tests/e2e/genesis/
10- Create e2e test for your solidity test in tests/e2e/solidity/suites.go
11- Run your e2e precompile Solidity tests with 'E2E=true ./scripts/run.sh'

*/

package {{.Package}}

import (
"encoding/json"
"math/big"

"github.com/ava-labs/subnet-evm/precompile"

"github.com/ethereum/go-ethereum/common"
)

{{$contract := .Contract}}
var (
_ precompile.StatefulPrecompileConfig = &{{.Contract.Type}}Config{}
)

// {{.Contract.Type}}Config implements the StatefulPrecompileConfig
// interface while adding in the {{.Contract.Type}} specific precompile address.
type {{.Contract.Type}}Config struct {
{{- if .Contract.AllowList}}
precompile.AllowListConfig
{{- end}}
precompile.UpgradeableConfig
}

{{$structs := .Structs}}
{{range $structs}}
// {{.Name}} is an auto generated low-level Go binding around an user-defined struct.
type {{.Name}} struct {
{{range $field := .Fields}}
{{$field.Name}} {{$field.Type}}{{end}}
}
{{- end}}

{{- range .Contract.Funcs}}
{{ if len .Normalized.Inputs | lt 1}}
type {{capitalise .Normalized.Name}}Input struct{
{{range .Normalized.Inputs}} {{capitalise .Name}} {{bindtype .Type $structs}}; {{end}}
}
{{- end}}
{{ if len .Normalized.Outputs | lt 1}}
type {{capitalise .Normalized.Name}}Output struct{
{{range .Normalized.Outputs}} {{capitalise .Name}} {{bindtype .Type $structs}}; {{end}}
}
{{- end}}
{{- end}}

// New{{.Contract.Type}}Config returns a config for a network upgrade at [blockTimestamp] that enables
// {{.Contract.Type}} {{if .Contract.AllowList}} with the given [admins] as members of the allowlist {{end}}.
func New{{.Contract.Type}}Config(blockTimestamp *big.Int{{if .Contract.AllowList}}, admins []common.Address{{end}}) *{{.Contract.Type}}Config {
return &{{.Contract.Type}}Config{
{{if .Contract.AllowList}}AllowListConfig: precompile.AllowListConfig{AllowListAdmins: admins},{{end}}
UpgradeableConfig: precompile.UpgradeableConfig{BlockTimestamp: blockTimestamp},
}
}

// NewDisable{{.Contract.Type}}Config returns config for a network upgrade at [blockTimestamp]
// that disables {{.Contract.Type}}.
func NewDisable{{.Contract.Type}}Config(blockTimestamp *big.Int) *{{.Contract.Type}}Config {
return &{{.Contract.Type}}Config{
UpgradeableConfig: precompile.UpgradeableConfig{
BlockTimestamp: blockTimestamp,
Disable: true,
},
}
}

// Verify tries to verify {{.Contract.Type}}Config and returns an error accordingly.
func (c *{{.Contract.Type}}Config) Verify() error {
{{if .Contract.AllowList}}
// Verify AllowList first
if err := c.AllowListConfig.Verify(); err != nil {
return err
}
{{end}}
// CUSTOM CODE STARTS HERE
// Add your own custom verify code for {{.Contract.Type}}Config here
// and return an error accordingly
return nil
}

// Equal returns true if [s] is a [*{{.Contract.Type}}Config] and it has been configured identical to [c].
func (c *{{.Contract.Type}}Config) Equal(s precompile.StatefulPrecompileConfig) bool {
// typecast before comparison
other, ok := (s).(*{{.Contract.Type}}Config)
if !ok {
return false
}
// CUSTOM CODE STARTS HERE
// modify this boolean accordingly with your custom {{.Contract.Type}}Config, to check if [other] and the current [c] are equal
// if {{.Contract.Type}}Config contains only UpgradeableConfig {{if .Contract.AllowList}} and AllowListConfig {{end}} you can skip modifying it.
equals := c.UpgradeableConfig.Equal(&other.UpgradeableConfig) {{if .Contract.AllowList}} && c.AllowListConfig.Equal(&other.AllowListConfig) {{end}}
return equals
}

// Address returns the address of the {{.Contract.Type}}. Addresses reside under the precompile/params.go
// Select a non-conflicting address and set it in the params.go.
func (c *{{.Contract.Type}}Config) Address() common.Address {
return {{.Contract.Type}}Address
}

// Configure configures [state] with the initial configuration.
func (c *{{.Contract.Type}}Config) Configure(_ precompile.ChainConfig, state precompile.StateDB, _ precompile.BlockContext) error {
{{if .Contract.AllowList}}c.AllowListConfig.Configure(state, {{.Contract.Type}}Address){{end}}
// CUSTOM CODE STARTS HERE
return nil
}

// Contract returns the singleton stateful precompiled contract to be used for {{.Contract.Type}}.
func (c *{{.Contract.Type}}Config) Contract() precompile.StatefulPrecompiledContract {
return {{.Contract.Type}}Precompile
}

// String returns a string representation of the {{.Contract.Type}}Config.
func (c *{{.Contract.Type}}Config) String() string {
bytes, _ := json.Marshal(c)
return string(bytes)
}
`
Loading