mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-28 07:36:44 +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"
|
||||
)
|
||||
|
||||
// underlyingBindType returns the underlying Go type represented by the given
|
||||
// type, panicking if it is not a pointer type.
|
||||
// underlyingBindType returns a string representation of the Go type
|
||||
// that corresponds to the given ABI type, panicking if it is not a
|
||||
// pointer.
|
||||
func underlyingBindType(typ abi.Type) string {
|
||||
goType := typ.GetType()
|
||||
if goType.Kind() != reflect.Pointer {
|
||||
|
|
@ -41,11 +42,12 @@ func underlyingBindType(typ abi.Type) 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 {
|
||||
return typ.GetType().Kind() == reflect.Pointer
|
||||
}
|
||||
|
||||
// OLD:
|
||||
// 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
|
||||
// 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
|
||||
// the provided ABI definition. These are used as part of the input to rendering
|
||||
// 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 {
|
||||
// contracts is the map of each individual contract requested binding.
|
||||
// It is keyed by the contract name provided in the ABI definition.
|
||||
|
|
@ -79,7 +93,7 @@ type binder struct {
|
|||
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.
|
||||
func (b *binder) BindStructType(typ abi.Type) {
|
||||
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
|
||||
// registry for compiling maps of identifiers that will be emitted in generated
|
||||
// bindings. It also sanitizes/converts information contained in the ABI
|
||||
// definition into a data-format that is amenable for rendering the templates.
|
||||
// bindings.
|
||||
type contractBinder struct {
|
||||
binder *binder
|
||||
|
||||
|
|
@ -114,8 +127,8 @@ func newContractBinder(binder *binder) *contractBinder {
|
|||
}
|
||||
}
|
||||
|
||||
// registerIdentifier applies alias renaming, name normalization (conversion to
|
||||
// camel case), and registers the normalized name in the specified identifier map.
|
||||
// registerIdentifier applies alias renaming, name normalization (conversion
|
||||
// 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.
|
||||
func (cb *contractBinder) registerIdentifier(identifiers map[string]bool, original string) (normalized string, err error) {
|
||||
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
|
||||
// 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
|
||||
// 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 {
|
||||
normalized := original
|
||||
normalizedName, err := cb.registerIdentifier(cb.callIdentifiers, original.Name)
|
||||
|
|
@ -164,7 +177,7 @@ func (cb *contractBinder) bindMethod(original abi.Method) error {
|
|||
}
|
||||
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 {
|
||||
isStructured = true
|
||||
}
|
||||
|
|
@ -202,8 +215,8 @@ func normalizeArgs(args abi.Arguments) abi.Arguments {
|
|||
return args
|
||||
}
|
||||
|
||||
// normalizeErrorOrEventFields normalizes errors/events for emitting through bindings:
|
||||
// Any anonymous fields are given generated names.
|
||||
// normalizeErrorOrEventFields normalizes errors/events for emitting through
|
||||
// bindings: Any anonymous fields are given generated names.
|
||||
func (cb *contractBinder) normalizeErrorOrEventFields(originalInputs abi.Arguments) abi.Arguments {
|
||||
normalizedArguments := normalizeArgs(originalInputs)
|
||||
for _, input := range normalizedArguments {
|
||||
|
|
@ -246,6 +259,8 @@ func (cb *contractBinder) bindError(original abi.Error) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// parseLibraryDeps extracts references to library dependencies from the unlinked
|
||||
// hex string deployment bytecode.
|
||||
func parseLibraryDeps(unlinkedCode string) (res []string) {
|
||||
reMatchSpecificPattern, err := regexp.Compile(`__\$([a-f0-9]+)\$__`)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -89,8 +89,8 @@ var (
|
|||
{{ end }}
|
||||
|
||||
{{range .Calls}}
|
||||
// {{.Normalized.Name}} is the Go binding used to pack the parameters required for calling
|
||||
// the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
// Pack{{.Normalized.Name}} is the Go binding used to pack the parameters required for calling
|
||||
// the contract method with ID 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func ({{ decapitalise $contract.Type}} *{{$contract.Type}}) Pack{{.Normalized.Name}}({{range .Normalized.Inputs}} {{.Name}} {{bindtype .Type $structs}}, {{end}}) []byte {
|
||||
|
|
@ -152,7 +152,7 @@ var (
|
|||
{{end}}
|
||||
|
||||
{{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 {
|
||||
{{- range .Normalized.Inputs}}
|
||||
{{ capitalise .Name}}
|
||||
|
|
@ -211,7 +211,7 @@ var (
|
|||
{{ end }}
|
||||
|
||||
{{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}}
|
||||
{{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 {
|
||||
Package string // Name of the package to place the generated file in
|
||||
Contracts map[string]*tmplContractV2 // List of contracts to generate into this file
|
||||
Package string // Name of the package to use for the generated bindings
|
||||
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
|
||||
Structs map[string]*tmplStruct // Contract struct type definitions
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ type WatchOpts struct {
|
|||
|
||||
// MetaData collects all metadata for a bound contract.
|
||||
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)
|
||||
Deps []*MetaData // library dependencies of the contract
|
||||
|
||||
|
|
@ -110,7 +110,8 @@ type MetaData struct {
|
|||
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) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
|
@ -262,7 +263,8 @@ func (c *BoundContract) RawTransact(opts *TransactOpts, calldata []byte) (*types
|
|||
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) {
|
||||
return c.transact(opts, nil, calldata)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,23 +26,21 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// DeploymentParams represents parameters needed to deploy a set of contracts.
|
||||
// It takes an optional override list to specify contracts/libraries that have
|
||||
// already been deployed on-chain.
|
||||
// DeploymentParams contains parameters needed to deploy one or more contracts via LinkAndDeploy
|
||||
type DeploymentParams struct {
|
||||
// list of all contracts targeted for the deployment
|
||||
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
|
||||
|
||||
// Overrides is an optional map of pattern to deployment address.
|
||||
// Contracts/libraries that refer to dependencies in the override
|
||||
// set are linked to the provided address (an already-deployed contract).
|
||||
// optional map of override addresses for specifying already-deployed
|
||||
// contracts. It is keyed by the MetaData.ID.
|
||||
Overrides map[string]common.Address
|
||||
}
|
||||
|
||||
// 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 {
|
||||
for _, meta := range d.Contracts {
|
||||
if meta.Bin == "" {
|
||||
|
|
@ -52,14 +50,13 @@ func (d *DeploymentParams) validate() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// DeploymentResult encapsulates information about the result of the deployment
|
||||
// of a set of contracts: the pending deployment transactions, and the addresses
|
||||
// where the contracts will be deployed at.
|
||||
// DeploymentResult contains information about the result of a pending
|
||||
// deployment made by LinkAndDeploy.
|
||||
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
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
|
@ -94,11 +91,12 @@ func newDepTreeDeployer(deployParams *DeploymentParams, deployFn DeployFn) *depT
|
|||
}
|
||||
}
|
||||
|
||||
// linkAndDeploy recursively deploys a contract and its dependencies: starting by
|
||||
// linking/deploying its dependencies. The deployment result (deploy addresses/txs
|
||||
// or an error) is stored in the depTreeDeployer object.
|
||||
// linkAndDeploy deploys a contract and it's dependencies. Because libraries
|
||||
// can in-turn have their own library dependencies, linkAndDeploy performs
|
||||
// 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) {
|
||||
// Don't deploy already deployed contracts
|
||||
// Don't re-deploy aliased or previously-deployed contracts
|
||||
if addr, ok := d.deployedAddrs[metadata.ID]; ok {
|
||||
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
|
||||
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:])
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// remove the override addresses from the resulting deployed addresses
|
||||
// filter the override addresses from the deployed address set.
|
||||
for pattern := range d.deployedAddrs {
|
||||
if _, ok := d.deployerTxs[pattern]; !ok {
|
||||
delete(d.deployedAddrs, pattern)
|
||||
|
|
@ -141,12 +140,19 @@ func (d *depTreeDeployer) result() *DeploymentResult {
|
|||
}
|
||||
}
|
||||
|
||||
// LinkAndDeploy deploys a specified set of contracts and their dependent
|
||||
// libraries. If an error occurs, only contracts which were successfully
|
||||
// deployed are returned in the result.
|
||||
// LinkAndDeploy performs the contract deployment specified by params using the
|
||||
// provided DeployFn to create, sign and submit transactions.
|
||||
//
|
||||
// In the case where multiple contracts share a common dependency: the shared
|
||||
// dependency will only be deployed once.
|
||||
// Contracts can depend on libraries, which in-turn can have their own library
|
||||
// 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) {
|
||||
if err := params.validate(); err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
Loading…
Reference in a new issue