mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-10 14:03:46 +00:00
accounts/abi: attempt to improve documentation throughout the PR. Make the method docs in generated bindings consistent.
This commit is contained in:
parent
6868cd49d9
commit
c88e3874bb
5 changed files with 69 additions and 46 deletions
|
|
@ -31,8 +31,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
)
|
)
|
||||||
|
|
||||||
// underlyingBindType returns the underlying Go type represented by the given
|
// underlyingBindType returns a string representation of the Go type
|
||||||
// type, panicking if it is not a pointer type.
|
// that corresponds to the given ABI type, panicking if it is not a
|
||||||
|
// pointer.
|
||||||
func underlyingBindType(typ abi.Type) string {
|
func underlyingBindType(typ abi.Type) string {
|
||||||
goType := typ.GetType()
|
goType := typ.GetType()
|
||||||
if goType.Kind() != reflect.Pointer {
|
if goType.Kind() != reflect.Pointer {
|
||||||
|
|
@ -41,11 +42,12 @@ func underlyingBindType(typ abi.Type) string {
|
||||||
return goType.Elem().String()
|
return goType.Elem().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// isPointerType returns true if the
|
// isPointerType returns true if the underlying type is a pointer.
|
||||||
func isPointerType(typ abi.Type) bool {
|
func isPointerType(typ abi.Type) bool {
|
||||||
return typ.GetType().Kind() == reflect.Pointer
|
return typ.GetType().Kind() == reflect.Pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OLD:
|
||||||
// binder is used during the conversion of an ABI definition into Go bindings
|
// binder is used during the conversion of an ABI definition into Go bindings
|
||||||
// (as part of the execution of BindV2). In contrast to contractBinder, binder
|
// (as part of the execution of BindV2). In contrast to contractBinder, binder
|
||||||
// contains binding-generation-state that is shared between contracts:
|
// contains binding-generation-state that is shared between contracts:
|
||||||
|
|
@ -63,6 +65,18 @@ func isPointerType(typ abi.Type) bool {
|
||||||
// instantiated to produce a set of tmplContractV2 and tmplStruct objects from
|
// instantiated to produce a set of tmplContractV2 and tmplStruct objects from
|
||||||
// the provided ABI definition. These are used as part of the input to rendering
|
// the provided ABI definition. These are used as part of the input to rendering
|
||||||
// the binding template.
|
// the binding template.
|
||||||
|
|
||||||
|
// NEW:
|
||||||
|
// binder is used to translate an ABI definition into a set of data-structures
|
||||||
|
// that will be used to render the template and produce Go bindings. This can
|
||||||
|
// be thought of as the "backend" that sanitizes the ABI definition to a format
|
||||||
|
// that can be directly rendered with minimal complexity in the template.
|
||||||
|
//
|
||||||
|
// The input data to the template rendering consists of:
|
||||||
|
// - the set of all contracts requested for binding, each containing
|
||||||
|
// methods/events/errors to emit pack/unpack methods for.
|
||||||
|
// - the set of structures defined by the contracts, and created
|
||||||
|
// as part of the binding process.
|
||||||
type binder struct {
|
type binder struct {
|
||||||
// contracts is the map of each individual contract requested binding.
|
// contracts is the map of each individual contract requested binding.
|
||||||
// It is keyed by the contract name provided in the ABI definition.
|
// It is keyed by the contract name provided in the ABI definition.
|
||||||
|
|
@ -79,7 +93,7 @@ type binder struct {
|
||||||
aliases map[string]string
|
aliases map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// BindStructType register the type to be emitted as a struct in the
|
// BindStructType registers the type to be emitted as a struct in the
|
||||||
// bindings.
|
// bindings.
|
||||||
func (b *binder) BindStructType(typ abi.Type) {
|
func (b *binder) BindStructType(typ abi.Type) {
|
||||||
bindStructType(typ, b.structs)
|
bindStructType(typ, b.structs)
|
||||||
|
|
@ -87,8 +101,7 @@ func (b *binder) BindStructType(typ abi.Type) {
|
||||||
|
|
||||||
// contractBinder holds state for binding of a single contract. It is a type
|
// contractBinder holds state for binding of a single contract. It is a type
|
||||||
// registry for compiling maps of identifiers that will be emitted in generated
|
// registry for compiling maps of identifiers that will be emitted in generated
|
||||||
// bindings. It also sanitizes/converts information contained in the ABI
|
// bindings.
|
||||||
// definition into a data-format that is amenable for rendering the templates.
|
|
||||||
type contractBinder struct {
|
type contractBinder struct {
|
||||||
binder *binder
|
binder *binder
|
||||||
|
|
||||||
|
|
@ -114,8 +127,8 @@ func newContractBinder(binder *binder) *contractBinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// registerIdentifier applies alias renaming, name normalization (conversion to
|
// registerIdentifier applies alias renaming, name normalization (conversion
|
||||||
// camel case), and registers the normalized name in the specified identifier map.
|
// from snake to camel-case), and registers the normalized name in the specified identifier map.
|
||||||
// It returns an error if the normalized name already exists in the map.
|
// It returns an error if the normalized name already exists in the map.
|
||||||
func (cb *contractBinder) registerIdentifier(identifiers map[string]bool, original string) (normalized string, err error) {
|
func (cb *contractBinder) registerIdentifier(identifiers map[string]bool, original string) (normalized string, err error) {
|
||||||
normalized = abi.ToCamelCase(alias(cb.binder.aliases, original))
|
normalized = abi.ToCamelCase(alias(cb.binder.aliases, original))
|
||||||
|
|
@ -138,7 +151,7 @@ func (cb *contractBinder) registerIdentifier(identifiers map[string]bool, origin
|
||||||
// bindMethod registers a method to be emitted in the bindings. The name, inputs
|
// bindMethod registers a method to be emitted in the bindings. The name, inputs
|
||||||
// and outputs are normalized. If any inputs are struct-type their structs are
|
// and outputs are normalized. If any inputs are struct-type their structs are
|
||||||
// registered to be emitted in the bindings. Any methods that return more than
|
// registered to be emitted in the bindings. Any methods that return more than
|
||||||
// one output have their result coalesced into a struct.
|
// one output have their results gathered into a struct.
|
||||||
func (cb *contractBinder) bindMethod(original abi.Method) error {
|
func (cb *contractBinder) bindMethod(original abi.Method) error {
|
||||||
normalized := original
|
normalized := original
|
||||||
normalizedName, err := cb.registerIdentifier(cb.callIdentifiers, original.Name)
|
normalizedName, err := cb.registerIdentifier(cb.callIdentifiers, original.Name)
|
||||||
|
|
@ -164,7 +177,7 @@ func (cb *contractBinder) bindMethod(original abi.Method) error {
|
||||||
}
|
}
|
||||||
isStructured := structured(original.Outputs)
|
isStructured := structured(original.Outputs)
|
||||||
|
|
||||||
// If the call returns multiple values, coalesced them into a struct
|
// If the call returns multiple values, gather them into a struct
|
||||||
if len(normalized.Outputs) > 1 {
|
if len(normalized.Outputs) > 1 {
|
||||||
isStructured = true
|
isStructured = true
|
||||||
}
|
}
|
||||||
|
|
@ -202,8 +215,8 @@ func normalizeArgs(args abi.Arguments) abi.Arguments {
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalizeErrorOrEventFields normalizes errors/events for emitting through bindings:
|
// normalizeErrorOrEventFields normalizes errors/events for emitting through
|
||||||
// Any anonymous fields are given generated names.
|
// bindings: Any anonymous fields are given generated names.
|
||||||
func (cb *contractBinder) normalizeErrorOrEventFields(originalInputs abi.Arguments) abi.Arguments {
|
func (cb *contractBinder) normalizeErrorOrEventFields(originalInputs abi.Arguments) abi.Arguments {
|
||||||
normalizedArguments := normalizeArgs(originalInputs)
|
normalizedArguments := normalizeArgs(originalInputs)
|
||||||
for _, input := range normalizedArguments {
|
for _, input := range normalizedArguments {
|
||||||
|
|
@ -246,6 +259,8 @@ func (cb *contractBinder) bindError(original abi.Error) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseLibraryDeps extracts references to library dependencies from the unlinked
|
||||||
|
// hex string deployment bytecode.
|
||||||
func parseLibraryDeps(unlinkedCode string) (res []string) {
|
func parseLibraryDeps(unlinkedCode string) (res []string) {
|
||||||
reMatchSpecificPattern, err := regexp.Compile(`__\$([a-f0-9]+)\$__`)
|
reMatchSpecificPattern, err := regexp.Compile(`__\$([a-f0-9]+)\$__`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -89,8 +89,8 @@ var (
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
{{range .Calls}}
|
{{range .Calls}}
|
||||||
// {{.Normalized.Name}} is the Go binding used to pack the parameters required for calling
|
// Pack{{.Normalized.Name}} is the Go binding used to pack the parameters required for calling
|
||||||
// the contract method 0x{{printf "%x" .Original.ID}}.
|
// the contract method with ID 0x{{printf "%x" .Original.ID}}.
|
||||||
//
|
//
|
||||||
// Solidity: {{.Original.String}}
|
// Solidity: {{.Original.String}}
|
||||||
func ({{ decapitalise $contract.Type}} *{{$contract.Type}}) Pack{{.Normalized.Name}}({{range .Normalized.Inputs}} {{.Name}} {{bindtype .Type $structs}}, {{end}}) []byte {
|
func ({{ decapitalise $contract.Type}} *{{$contract.Type}}) Pack{{.Normalized.Name}}({{range .Normalized.Inputs}} {{.Name}} {{bindtype .Type $structs}}, {{end}}) []byte {
|
||||||
|
|
@ -152,7 +152,7 @@ var (
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{range .Events}}
|
{{range .Events}}
|
||||||
// {{$contract.Type}}{{.Normalized.Name}} represents a {{.Normalized.Name}} event raised by the {{$contract.Type}} contract.
|
// {{$contract.Type}}{{.Normalized.Name}} represents a {{.Original.Name}} event raised by the {{$contract.Type}} contract.
|
||||||
type {{$contract.Type}}{{.Normalized.Name}} struct {
|
type {{$contract.Type}}{{.Normalized.Name}} struct {
|
||||||
{{- range .Normalized.Inputs}}
|
{{- range .Normalized.Inputs}}
|
||||||
{{ capitalise .Name}}
|
{{ capitalise .Name}}
|
||||||
|
|
@ -211,7 +211,7 @@ var (
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
{{range .Errors}}
|
{{range .Errors}}
|
||||||
// {{$contract.Type}}{{.Normalized.Name}} represents a {{.Normalized.Name}} error raised by the {{$contract.Type}} contract.
|
// {{$contract.Type}}{{.Normalized.Name}} represents a {{.Original.Name}} error raised by the {{$contract.Type}} contract.
|
||||||
type {{$contract.Type}}{{.Normalized.Name}} struct { {{range .Normalized.Inputs}}
|
type {{$contract.Type}}{{.Normalized.Name}} struct { {{range .Normalized.Inputs}}
|
||||||
{{capitalise .Name}} {{if .Indexed}}{{bindtopictype .Type $structs}}{{else}}{{bindtype .Type $structs}}{{end}}; {{end}}
|
{{capitalise .Name}} {{if .Indexed}}{{bindtopictype .Type $structs}}{{else}}{{bindtype .Type $structs}}{{end}}; {{end}}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,8 +80,8 @@ func newTmplContractV2(typ string, abiStr string, bytecode string, constructor a
|
||||||
}
|
}
|
||||||
|
|
||||||
type tmplDataV2 struct {
|
type tmplDataV2 struct {
|
||||||
Package string // Name of the package to place the generated file in
|
Package string // Name of the package to use for the generated bindings
|
||||||
Contracts map[string]*tmplContractV2 // List of contracts to generate into this file
|
Contracts map[string]*tmplContractV2 // Contracts that will be emitted in the bindings (keyed by contract name)
|
||||||
Libraries map[string]string // Map of the contract's name to link pattern
|
Libraries map[string]string // Map of the contract's name to link pattern
|
||||||
Structs map[string]*tmplStruct // Contract struct type definitions
|
Structs map[string]*tmplStruct // Contract struct type definitions
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ type WatchOpts struct {
|
||||||
|
|
||||||
// MetaData collects all metadata for a bound contract.
|
// MetaData collects all metadata for a bound contract.
|
||||||
type MetaData struct {
|
type MetaData struct {
|
||||||
Bin string // runtime bytecode (as a hex string)
|
Bin string // deployer bytecode (as a hex string)
|
||||||
ABI string // the raw ABI definition (JSON)
|
ABI string // the raw ABI definition (JSON)
|
||||||
Deps []*MetaData // library dependencies of the contract
|
Deps []*MetaData // library dependencies of the contract
|
||||||
|
|
||||||
|
|
@ -110,7 +110,8 @@ type MetaData struct {
|
||||||
parsedABI *abi.ABI
|
parsedABI *abi.ABI
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseABI returns the parsed ABI specification.
|
// ParseABI returns the parsed ABI specification, or an error if the string
|
||||||
|
// representation of the ABI set in the MetaData instance could not be parsed.
|
||||||
func (m *MetaData) ParseABI() (*abi.ABI, error) {
|
func (m *MetaData) ParseABI() (*abi.ABI, error) {
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
defer m.mu.Unlock()
|
defer m.mu.Unlock()
|
||||||
|
|
@ -262,7 +263,8 @@ func (c *BoundContract) RawTransact(opts *TransactOpts, calldata []byte) (*types
|
||||||
return c.transact(opts, &c.address, calldata)
|
return c.transact(opts, &c.address, calldata)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RawTransact initiates a contract-creation transaction with the given raw calldata as the input.
|
// RawCreationTransact creates and submits a contract-creation transaction with
|
||||||
|
// the given calldata as the input.
|
||||||
func (c *BoundContract) RawCreationTransact(opts *TransactOpts, calldata []byte) (*types.Transaction, error) {
|
func (c *BoundContract) RawCreationTransact(opts *TransactOpts, calldata []byte) (*types.Transaction, error) {
|
||||||
return c.transact(opts, nil, calldata)
|
return c.transact(opts, nil, calldata)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,23 +26,21 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeploymentParams represents parameters needed to deploy a set of contracts.
|
// DeploymentParams contains parameters needed to deploy one or more contracts via LinkAndDeploy
|
||||||
// It takes an optional override list to specify contracts/libraries that have
|
|
||||||
// already been deployed on-chain.
|
|
||||||
type DeploymentParams struct {
|
type DeploymentParams struct {
|
||||||
|
// list of all contracts targeted for the deployment
|
||||||
Contracts []*MetaData
|
Contracts []*MetaData
|
||||||
|
|
||||||
// Map of solidity library pattern to constructor input.
|
// optional map of ABI-encoded constructor inputs keyed by the MetaData.ID.
|
||||||
Inputs map[string][]byte
|
Inputs map[string][]byte
|
||||||
|
|
||||||
// Overrides is an optional map of pattern to deployment address.
|
// optional map of override addresses for specifying already-deployed
|
||||||
// Contracts/libraries that refer to dependencies in the override
|
// contracts. It is keyed by the MetaData.ID.
|
||||||
// set are linked to the provided address (an already-deployed contract).
|
|
||||||
Overrides map[string]common.Address
|
Overrides map[string]common.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate determines whether the contracts specified in the DeploymentParams
|
// validate determines whether the contracts specified in the DeploymentParams
|
||||||
// instance have provided deployer bytecode.
|
// instance have embedded deployer code in their provided MetaData instances.
|
||||||
func (d *DeploymentParams) validate() error {
|
func (d *DeploymentParams) validate() error {
|
||||||
for _, meta := range d.Contracts {
|
for _, meta := range d.Contracts {
|
||||||
if meta.Bin == "" {
|
if meta.Bin == "" {
|
||||||
|
|
@ -52,14 +50,13 @@ func (d *DeploymentParams) validate() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeploymentResult encapsulates information about the result of the deployment
|
// DeploymentResult contains information about the result of a pending
|
||||||
// of a set of contracts: the pending deployment transactions, and the addresses
|
// deployment made by LinkAndDeploy.
|
||||||
// where the contracts will be deployed at.
|
|
||||||
type DeploymentResult struct {
|
type DeploymentResult struct {
|
||||||
// Map of contract MetaData Id to deploy transaction
|
// Map of contract MetaData.ID to pending deployment transaction
|
||||||
Txs map[string]*types.Transaction
|
Txs map[string]*types.Transaction
|
||||||
|
|
||||||
// Map of contract MetaData Id to deployed contract address
|
// Map of contract MetaData.ID to the address where it will be deployed
|
||||||
Addresses map[string]common.Address
|
Addresses map[string]common.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,11 +91,12 @@ func newDepTreeDeployer(deployParams *DeploymentParams, deployFn DeployFn) *depT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// linkAndDeploy recursively deploys a contract and its dependencies: starting by
|
// linkAndDeploy deploys a contract and it's dependencies. Because libraries
|
||||||
// linking/deploying its dependencies. The deployment result (deploy addresses/txs
|
// can in-turn have their own library dependencies, linkAndDeploy performs
|
||||||
// or an error) is stored in the depTreeDeployer object.
|
// deployment recursively (deepest-dependency first). The address of the
|
||||||
|
// pending contract deployment for the top-level contract is returned.
|
||||||
func (d *depTreeDeployer) linkAndDeploy(metadata *MetaData) (common.Address, error) {
|
func (d *depTreeDeployer) linkAndDeploy(metadata *MetaData) (common.Address, error) {
|
||||||
// Don't deploy already deployed contracts
|
// Don't re-deploy aliased or previously-deployed contracts
|
||||||
if addr, ok := d.deployedAddrs[metadata.ID]; ok {
|
if addr, ok := d.deployedAddrs[metadata.ID]; ok {
|
||||||
return addr, nil
|
return addr, nil
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +111,7 @@ func (d *depTreeDeployer) linkAndDeploy(metadata *MetaData) (common.Address, err
|
||||||
// Link their deployed addresses into the bytecode to produce
|
// Link their deployed addresses into the bytecode to produce
|
||||||
deployerCode = strings.ReplaceAll(deployerCode, "__$"+dep.ID+"$__", strings.ToLower(addr.String()[2:]))
|
deployerCode = strings.ReplaceAll(deployerCode, "__$"+dep.ID+"$__", strings.ToLower(addr.String()[2:]))
|
||||||
}
|
}
|
||||||
// Finally, deploy the contract.
|
// Finally, deploy the top-level contract.
|
||||||
code, err := hex.DecodeString(deployerCode[2:])
|
code, err := hex.DecodeString(deployerCode[2:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("error decoding contract deployer hex %s:\n%v", deployerCode[2:], err))
|
panic(fmt.Sprintf("error decoding contract deployer hex %s:\n%v", deployerCode[2:], err))
|
||||||
|
|
@ -127,9 +125,10 @@ func (d *depTreeDeployer) linkAndDeploy(metadata *MetaData) (common.Address, err
|
||||||
return addr, nil
|
return addr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// result returns a result for this deployment, or an error if it failed.
|
// result returns a DeploymentResult instance referencing contracts deployed
|
||||||
|
// and not including any overrides specified for this deployment.
|
||||||
func (d *depTreeDeployer) result() *DeploymentResult {
|
func (d *depTreeDeployer) result() *DeploymentResult {
|
||||||
// remove the override addresses from the resulting deployed addresses
|
// filter the override addresses from the deployed address set.
|
||||||
for pattern := range d.deployedAddrs {
|
for pattern := range d.deployedAddrs {
|
||||||
if _, ok := d.deployerTxs[pattern]; !ok {
|
if _, ok := d.deployerTxs[pattern]; !ok {
|
||||||
delete(d.deployedAddrs, pattern)
|
delete(d.deployedAddrs, pattern)
|
||||||
|
|
@ -141,12 +140,19 @@ func (d *depTreeDeployer) result() *DeploymentResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LinkAndDeploy deploys a specified set of contracts and their dependent
|
// LinkAndDeploy performs the contract deployment specified by params using the
|
||||||
// libraries. If an error occurs, only contracts which were successfully
|
// provided DeployFn to create, sign and submit transactions.
|
||||||
// deployed are returned in the result.
|
|
||||||
//
|
//
|
||||||
// In the case where multiple contracts share a common dependency: the shared
|
// Contracts can depend on libraries, which in-turn can have their own library
|
||||||
// dependency will only be deployed once.
|
// dependencies. Therefore, LinkAndDeploy performs the deployment recursively,
|
||||||
|
// starting with libraries (and contracts) that don't have dependencies, and
|
||||||
|
// progressing through the contracts that depend upon them.
|
||||||
|
//
|
||||||
|
// If an error is encountered, the returned DeploymentResult only contains
|
||||||
|
// entries for the contracts whose deployment submission succeeded.
|
||||||
|
//
|
||||||
|
// LinkAndDeploy performs creation and submission of creation transactions,
|
||||||
|
// but does not ensure that the contracts are included in the chain.
|
||||||
func LinkAndDeploy(params *DeploymentParams, deploy DeployFn) (*DeploymentResult, error) {
|
func LinkAndDeploy(params *DeploymentParams, deploy DeployFn) (*DeploymentResult, error) {
|
||||||
if err := params.validate(); err != nil {
|
if err := params.validate(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue