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

Stateful Precompile Improvements #389

Merged
merged 32 commits into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
2d47fde
move inline string ABIs to separate files and embed them (#383)
ceyonur Dec 2, 2022
557d1f4
Merge branch 'master' into precompile-improvements-main
ceyonur Dec 16, 2022
77ce3c3
replace getByKey with getByAddress (#395)
ceyonur Dec 22, 2022
e3b7ff3
Merge branch 'master' into precompile-improvements-main
ceyonur Dec 27, 2022
9e5c8c4
rework on panics in precompiles (#418)
ceyonur Dec 27, 2022
8868a99
Precompile Specific Packages (#420)
ceyonur Jan 6, 2023
357d9e6
rename fee manager config struct (#427)
ceyonur Jan 12, 2023
1add41a
Generalized upgrades rb (#434)
ceyonur Feb 16, 2023
6770536
Precompile improvements merge (#513)
aaronbuchwald Feb 16, 2023
7f4c66b
review fixes
ceyonur Feb 16, 2023
aa152c9
merge
darioush Feb 16, 2023
77751e4
minor nits
darioush Feb 16, 2023
ce23fca
fix precompile generator
ceyonur Feb 16, 2023
4bd2442
Merge branch 'precompile-improvements-main' of github.com:ava-labs/su…
ceyonur Feb 16, 2023
f806ad4
fix fee manager config test
ceyonur Feb 16, 2023
ea3c13b
remove debug files
ceyonur Feb 16, 2023
39e16d8
Update core/state_processor.go
ceyonur Feb 17, 2023
9a63a87
fix comments
ceyonur Feb 17, 2023
c9a5811
restore statedb ordering
ceyonur Feb 17, 2023
9868f4e
Merge branch 'precompile-improvements-main' of github.com:ava-labs/su…
ceyonur Feb 17, 2023
81fb4a9
fix configure in reward manager
ceyonur Feb 17, 2023
d518651
precompiles: adds a regression test for the IsDisabled case in Avalan…
darioush Feb 17, 2023
c81b44b
Rename configs: alternative (#520)
darioush Feb 17, 2023
7f13c45
Merge branch 'master' into precompile-improvements-main
aaronbuchwald Feb 17, 2023
aa6842d
move blackhole check to module registerer (#523)
ceyonur Feb 17, 2023
8ca09a3
precompile: improve test structure (#517)
darioush Feb 18, 2023
1b995e2
Merge branch 'master' into precompile-improvements-main
aaronbuchwald Feb 21, 2023
e8b55cf
Merge branch 'master' into precompile-improvements-main
aaronbuchwald Feb 21, 2023
c5c1017
nit improvements (#529)
ceyonur Feb 21, 2023
9059a09
Rename new config (#528)
ceyonur Feb 21, 2023
9a8a85d
precompile: just nits (#534)
darioush Feb 22, 2023
c004080
Merge branch 'master' into precompile-improvements-main
ceyonur Feb 22, 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
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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: undo unneeded change

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