Skip to content

Commit

Permalink
Stateful Precompile Improvements (#389)
Browse files Browse the repository at this point in the history
* move inline string ABIs to separate files and embed them (#383)

* move inline string ABIs to separate files and embed them

* fix tests

* fix tests

* unexport function

* Update accounts/abi/bind/bind.go

Co-authored-by: Darioush Jalali <darioush.jalali@avalabs.org>

* fix func name

Co-authored-by: Darioush Jalali <darioush.jalali@avalabs.org>

* replace getByKey with getByAddress (#395)

* rework on panics in precompiles (#418)

* rework on panics in precompiles

* Update precompile/allow_list.go

Co-authored-by: aaronbuchwald <aaron.buchwald56@gmail.com>

* Update precompile/fee_config_manager.go

Co-authored-by: aaronbuchwald <aaron.buchwald56@gmail.com>

* Update precompile/fee_config_manager.go

Co-authored-by: aaronbuchwald <aaron.buchwald56@gmail.com>

* fix reviews

* wrap errors in ConfigurePrecompiles

* cleaner errors

* Update utils.go

* Update miner/worker.go

Co-authored-by: aaronbuchwald <aaron.buchwald56@gmail.com>

* Update core/state_processor.go

Co-authored-by: aaronbuchwald <aaron.buchwald56@gmail.com>

Co-authored-by: aaronbuchwald <aaron.buchwald56@gmail.com>

* Precompile Specific Packages (#420)

* rework on panics in precompiles

* Update precompile/allow_list.go

Co-authored-by: aaronbuchwald <aaron.buchwald56@gmail.com>

* Update precompile/fee_config_manager.go

Co-authored-by: aaronbuchwald <aaron.buchwald56@gmail.com>

* Update precompile/fee_config_manager.go

Co-authored-by: aaronbuchwald <aaron.buchwald56@gmail.com>

* fix reviews

* wrap errors in ConfigurePrecompiles

* cleaner errors

* move reward manager precompile to package (WIP)

* rename files

* fix abi path

* move typecheck

* move precompiles to their own packages

* refactor precompile template

* remove test file

* upate comments

* rm test files

* new allowlist package

* Update precompile/utils.go

Co-authored-by: Darioush Jalali <darioush.jalali@avalabs.org>

* Update precompile/nativeminter/contract_native_minter.go

Co-authored-by: Darioush Jalali <darioush.jalali@avalabs.org>

* Update precompile/nativeminter/contract_native_minter.go

Co-authored-by: Darioush Jalali <darioush.jalali@avalabs.org>

* Update precompile/utils.go

Co-authored-by: Darioush Jalali <darioush.jalali@avalabs.org>

* Update precompile/nativeminter/contract_native_minter.go

Co-authored-by: Darioush Jalali <darioush.jalali@avalabs.org>

* fix nits

Co-authored-by: aaronbuchwald <aaron.buchwald56@gmail.com>
Co-authored-by: Darioush Jalali <darioush.jalali@avalabs.org>

* rename fee manager config struct (#427)

* rename struct

* rename fee config managers to fee managers

* fix comments

* Generalized upgrades rb (#434)

* introduce precompiles as registrable modules

* add precompile specific contract tests

* remove print debug

* add unmarshal tests

* remove unnecessary func

* fix initial disabled value

* register all modules in core/evm/contract_stateful

* more refactor & test fix

* sync template

* fix more tests

* rename file

* add comment

* rename

* fix linter

* use require error contains

* remove whitespace

* trim mock interface

* sort steps

* reviews

* Update precompile/stateful_precompile_module.go

* Update params/precompile_config.go

* Update params/precompile_config.go

* fix reviews

* add new module to configs and group module functions

* generalized-upgrades-rb review (#474)

* keep genesis disabled fix

* nits

* nits

* nit

* review fixes

* Update precompile/allowlist/allowlist.go

* use address in map

* fix linter for embedded keys

* update err messages

* more err update

* remove unnecessary function (#478)

* Start work on breaking cyclic dependency (#496)

* Update core/state_processor.go

* fix reviews

* Update precompile/contracts/txallowlist/contract_test.go

* Generalized upgrades rb nits0 (#512)

* Minor improvements

* restore readOnly

* more updates

* Add back readOnly to allow list tests

* Precompile improvements merge (#513)

Co-authored-by: aaronbuchwald <aaron.buchwald56@gmail.com>
Co-authored-by: Ceyhun Onur <ceyhun.onur@avalabs.org>
Co-authored-by: Darioush Jalali <darioush.jalali@avalabs.org>
Co-authored-by: cam-schultz <78878559+cam-schultz@users.noreply.github.com>
Co-authored-by: Matthew Lam <matthew.lam@avalabs.org>
Co-authored-by: cam-schultz <camschultz32@gmail.com>
Co-authored-by: omahs <73983677+omahs@users.noreply.github.com>
Co-authored-by: Anusha <63559942+anusha-ctrl@users.noreply.github.com>
Co-authored-by: Hagen Hübel <hhuebel@itinance.com>
Co-authored-by: minghinmatthewlam <matthew.lam@avalabs.org>
Fix: typos (#428)
fix allow list comments (#469)
fix CGO flags issue (#489)
fix lint job (#499)

* review fixes

* minor nits

* fix precompile generator

* fix fee manager config test

* remove debug files

* Update core/state_processor.go

Co-authored-by: aaronbuchwald <aaron.buchwald56@gmail.com>

* fix comments

* restore statedb ordering

* fix configure in reward manager

* precompiles: adds a regression test for the IsDisabled case in AvalancheRules (#515)

* Rename configs: alternative (#520)

* alternative renaming for precompile configs

* fixes

* update naming

* rename to AllowListConfig

* simplify

* move blackhole check to module registerer (#523)

* move blackhole check to module registerer

* check blackhole first

* add unit test

* Add test case for registering module outside of reserved range

---------

Co-authored-by: Aaron Buchwald <aaron.buchwald56@gmail.com>

* precompile: improve test structure (#517)

* refactor precompile tests

* minor improvements

* nit

* fix merge

* rename package

* pr comments

* rm file

* merge AllowListTests

* pr comments

* explicit BeforeHook

* wspace

* Mark TestTransactionIndices flaky

---------

Co-authored-by: Aaron Buchwald <aaron.buchwald56@gmail.com>

* nit improvements (#529)

* nit improvements

* move comments to README

* Update cmd/precompilegen/template-readme.md

* Rename new config (#528)

* rename configurator's new config to make config

* use new built-in to create new config instance

* precompile: just nits (#534)
  • Loading branch information
ceyonur committed Feb 22, 2023
1 parent 9e47da2 commit c1115ed
Show file tree
Hide file tree
Showing 102 changed files with 5,438 additions and 4,330 deletions.
126 changes: 37 additions & 89 deletions accounts/abi/bind/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,8 @@ import (
"github.com/ethereum/go-ethereum/log"
)

const (
setAdminFuncKey = "setAdmin"
setEnabledFuncKey = "setEnabled"
setNoneFuncKey = "setNone"
readAllowListFuncKey = "readAllowList"
)
// BindHook is a callback function that can be used to customize the binding.
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 @@ -101,13 +97,17 @@ func isKeyWord(arg string) bool {
// to be used as is in client code, but rather as an intermediate struct which
// enforces compile time type safety and naming convention opposed to having to
// manually maintain hard coded strings that break on runtime.
func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, lang Lang, libs map[string]string, aliases map[string]string, isPrecompile bool) (string, error) {
func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, lang Lang, libs map[string]string, aliases map[string]string) (string, error) {
return BindHelper(types, abis, bytecodes, fsigs, pkg, lang, libs, aliases, nil)
}

func BindHelper(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, lang Lang, libs map[string]string, aliases map[string]string, bindHook BindHook) (string, error) {
var (
// contracts is the map of each individual contract requested binding
contracts = make(map[string]*tmplContract)
contracts = make(map[string]*TmplContract)

// structs is the map of all redeclared structs shared by passed contracts.
structs = make(map[string]*tmplStruct)
structs = make(map[string]*TmplStruct)

// isLib is the map used to flag each encountered library as such
isLib = make(map[string]struct{})
Expand All @@ -128,11 +128,11 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]

// Extract the call and transact methods; events, struct definitions; and sort them alphabetically
var (
calls = make(map[string]*tmplMethod)
transacts = make(map[string]*tmplMethod)
calls = make(map[string]*TmplMethod)
transacts = make(map[string]*TmplMethod)
events = make(map[string]*tmplEvent)
fallback *tmplMethod
receive *tmplMethod
fallback *TmplMethod
receive *TmplMethod

// identifiers are used to detect duplicated identifiers of functions
// and events. For all calls, transacts and events, abigen will generate
Expand All @@ -155,7 +155,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
normalizedName := methodNormalizer[lang](alias(aliases, original.Name))

// Ensure there is no duplicated identifier
var identifiers = callIdentifiers
identifiers := callIdentifiers
if !original.IsConstant() {
identifiers = transactIdentifiers
}
Expand All @@ -178,11 +178,6 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
normalized.Outputs = make([]abi.Argument, len(original.Outputs))
copy(normalized.Outputs, original.Outputs)
for j, output := range normalized.Outputs {
if isPrecompile {
if output.Name == "" {
return "", fmt.Errorf("ABI outputs for %s require a name to generate the precompile binding, re-generate the ABI from a Solidity source file with all named outputs", normalized.Name)
}
}
if output.Name != "" {
normalized.Outputs[j].Name = capitalise(output.Name)
}
Expand All @@ -192,9 +187,9 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
}
// Append the methods to the call or transact lists
if original.IsConstant() {
calls[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original.Outputs)}
calls[original.Name] = &TmplMethod{Original: original, Normalized: normalized, Structured: structured(original.Outputs)}
} else {
transacts[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original.Outputs)}
transacts[original.Name] = &TmplMethod{Original: original, Normalized: normalized, Structured: structured(original.Outputs)}
}
}
for _, original := range evmABI.Events {
Expand Down Expand Up @@ -238,17 +233,17 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
}
// Add two special fallback functions if they exist
if evmABI.HasFallback() {
fallback = &tmplMethod{Original: evmABI.Fallback}
fallback = &TmplMethod{Original: evmABI.Fallback}
}
if evmABI.HasReceive() {
receive = &tmplMethod{Original: evmABI.Receive}
receive = &TmplMethod{Original: evmABI.Receive}
}
// There is no easy way to pass arbitrary java objects to the Go side.
if len(structs) > 0 && lang == LangJava {
return "", errors.New("java binding for tuple arguments is not supported yet")
}

contracts[types[i]] = &tmplContract{
contracts[types[i]] = &TmplContract{
Type: capitalise(types[i]),
InputABI: strings.ReplaceAll(strippedABI, "\"", "\\\""),
InputBin: strings.TrimPrefix(strings.TrimSpace(bytecodes[i]), "0x"),
Expand Down Expand Up @@ -291,19 +286,14 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
templateSource string
)

// Generate the contract template data according to contract type (precompile/non)
if isPrecompile {
if lang != LangGo {
return "", errors.New("only GoLang binding for precompiled contracts is supported yet")
}

if len(contracts) != 1 {
return "", errors.New("cannot generate more than 1 contract")
// Generate the contract template data according to hook
if bindHook != nil {
var err error
data, templateSource, err = bindHook(lang, pkg, types, contracts, structs)
if err != nil {
return "", err
}
precompileType := types[0]
firstContract := contracts[precompileType]
data, templateSource = createPrecompileDataAndTemplate(firstContract, structs)
} else {
} else { // default to generate contract binding
templateSource = tmplSource[lang]
data = &tmplData{
Package: pkg,
Expand Down Expand Up @@ -342,7 +332,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]

// bindType is a set of type binders that convert Solidity types to some supported
// programming language types.
var bindType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct) string{
var bindType = map[Lang]func(kind abi.Type, structs map[string]*TmplStruct) string{
LangGo: bindTypeGo,
LangJava: bindTypeJava,
}
Expand Down Expand Up @@ -374,7 +364,7 @@ func bindBasicTypeGo(kind abi.Type) string {
// bindTypeGo converts solidity types to Go ones. Since there is no clear mapping
// from all Solidity types to Go ones (e.g. uint17), those that cannot be exactly
// mapped will use an upscaled type (e.g. BigDecimal).
func bindTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
func bindTypeGo(kind abi.Type, structs map[string]*TmplStruct) string {
switch kind.T {
case abi.TupleTy:
return structs[kind.TupleRawName+kind.String()].Name
Expand Down Expand Up @@ -451,7 +441,7 @@ func pluralizeJavaType(typ string) string {
// bindTypeJava converts a Solidity type to a Java one. Since there is no clear mapping
// from all Solidity types to Java ones (e.g. uint17), those that cannot be exactly
// mapped will use an upscaled type (e.g. BigDecimal).
func bindTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {
func bindTypeJava(kind abi.Type, structs map[string]*TmplStruct) string {
switch kind.T {
case abi.TupleTy:
return structs[kind.TupleRawName+kind.String()].Name
Expand All @@ -464,14 +454,14 @@ func bindTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {

// bindTopicType is a set of type binders that convert Solidity types to some
// supported programming language topic types.
var bindTopicType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct) string{
var bindTopicType = map[Lang]func(kind abi.Type, structs map[string]*TmplStruct) string{
LangGo: bindTopicTypeGo,
LangJava: bindTopicTypeJava,
}

// bindTopicTypeGo converts a Solidity topic type to a Go one. It is almost the same
// functionality as for simple types, but dynamic types get converted to hashes.
func bindTopicTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
func bindTopicTypeGo(kind abi.Type, structs map[string]*TmplStruct) string {
bound := bindTypeGo(kind, structs)

// todo(rjl493456442) according solidity documentation, indexed event
Expand All @@ -488,7 +478,7 @@ func bindTopicTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {

// bindTopicTypeJava converts a Solidity topic type to a Java one. It is almost the same
// functionality as for simple types, but dynamic types get converted to hashes.
func bindTopicTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {
func bindTopicTypeJava(kind abi.Type, structs map[string]*TmplStruct) string {
bound := bindTypeJava(kind, structs)

// todo(rjl493456442) according solidity documentation, indexed event
Expand All @@ -505,15 +495,15 @@ func bindTopicTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {

// bindStructType is a set of type binders that convert Solidity tuple types to some supported
// programming language struct definition.
var bindStructType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct) string{
var bindStructType = map[Lang]func(kind abi.Type, structs map[string]*TmplStruct) string{
LangGo: bindStructTypeGo,
LangJava: bindStructTypeJava,
}

// bindStructTypeGo converts a Solidity tuple type to a Go one and records the mapping
// in the given map.
// Notably, this function will resolve and record nested struct recursively.
func bindStructTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
func bindStructTypeGo(kind abi.Type, structs map[string]*TmplStruct) string {
switch kind.T {
case abi.TupleTy:
// We compose a raw struct name and a canonical parameter expression
Expand Down Expand Up @@ -542,7 +532,7 @@ func bindStructTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
}
name = capitalise(name)

structs[id] = &tmplStruct{
structs[id] = &TmplStruct{
Name: name,
Fields: fields,
}
Expand All @@ -559,7 +549,7 @@ func bindStructTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
// bindStructTypeJava converts a Solidity tuple type to a Java one and records the mapping
// in the given map.
// Notably, this function will resolve and record nested struct recursively.
func bindStructTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {
func bindStructTypeJava(kind abi.Type, structs map[string]*TmplStruct) string {
switch kind.T {
case abi.TupleTy:
// We compose a raw struct name and a canonical parameter expression
Expand All @@ -581,7 +571,7 @@ func bindStructTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {
if name == "" {
name = fmt.Sprintf("Class%d", len(structs))
}
structs[id] = &tmplStruct{
structs[id] = &TmplStruct{
Name: name,
Fields: fields,
}
Expand Down Expand Up @@ -710,45 +700,3 @@ func hasStruct(t abi.Type) bool {
return false
}
}

func createPrecompileDataAndTemplate(contract *tmplContract, structs map[string]*tmplStruct) (interface{}, string) {
funcs := make(map[string]*tmplMethod)

for k, v := range contract.Transacts {
funcs[k] = v
}

for k, v := range contract.Calls {
funcs[k] = v
}
isAllowList := allowListEnabled(funcs)
if isAllowList {
// remove these functions as we will directly inherit AllowList
delete(funcs, readAllowListFuncKey)
delete(funcs, setAdminFuncKey)
delete(funcs, setEnabledFuncKey)
delete(funcs, setNoneFuncKey)
}

precompileContract := &tmplPrecompileContract{
tmplContract: contract,
AllowList: isAllowList,
Funcs: funcs,
}

data := &tmplPrecompileData{
Contract: precompileContract,
Structs: structs,
}
return data, tmplSourcePrecompileGo
}

func allowListEnabled(funcs map[string]*tmplMethod) bool {
keys := []string{readAllowListFuncKey, setAdminFuncKey, setEnabledFuncKey, setNoneFuncKey}
for _, key := range keys {
if _, ok := funcs[key]; !ok {
return false
}
}
return true
}
4 changes: 2 additions & 2 deletions accounts/abi/bind/bind_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2099,7 +2099,7 @@ func golangBindings(t *testing.T, overload bool) {
types = []string{tt.name}
}
// Generate the binding and create a Go source file in the workspace
bind, err := Bind(types, tt.abi, tt.bytecode, tt.fsigs, "bindtest", LangGo, tt.libs, tt.aliases, false)
bind, err := Bind(types, tt.abi, tt.bytecode, tt.fsigs, "bindtest", LangGo, tt.libs, tt.aliases)
if err != nil {
t.Fatalf("test %d: failed to generate binding: %v", i, err)
}
Expand Down Expand Up @@ -2529,7 +2529,7 @@ public class Test {
},
}
for i, c := range cases {
binding, err := Bind([]string{c.name}, []string{c.abi}, []string{c.bytecode}, nil, "bindtest", LangJava, nil, nil, false)
binding, err := Bind([]string{c.name}, []string{c.abi}, []string{c.bytecode}, nil, "bindtest", LangJava, nil, nil)
if err != nil {
t.Fatalf("test %d: failed to generate binding: %v", i, err)
}
Expand Down
Loading

0 comments on commit c1115ed

Please sign in to comment.