diff options
author | Determinant <[email protected]> | 2020-09-15 23:55:34 -0400 |
---|---|---|
committer | Determinant <[email protected]> | 2020-09-15 23:55:34 -0400 |
commit | 78745551c077bf54151202138c2629f288769561 (patch) | |
tree | 2b628e99fd110617089778fa91235ecd2888f4ef /accounts | |
parent | 7d1388c743b4ec8f4a86bea95bfada785dee83f7 (diff) |
WIP: geth-tavum
Diffstat (limited to 'accounts')
27 files changed, 85 insertions, 4456 deletions
diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go deleted file mode 100644 index 7af6685..0000000 --- a/accounts/abi/abi.go +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package abi - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - - "github.com/ava-labs/go-ethereum/common" -) - -// The ABI holds information about a contract's context and available -// invokable methods. It will allow you to type check function calls and -// packs data accordingly. -type ABI struct { - Constructor Method - Methods map[string]Method - Events map[string]Event -} - -// JSON returns a parsed ABI interface and error if it failed. -func JSON(reader io.Reader) (ABI, error) { - dec := json.NewDecoder(reader) - - var abi ABI - if err := dec.Decode(&abi); err != nil { - return ABI{}, err - } - - return abi, nil -} - -// Pack the given method name to conform the ABI. Method call's data -// will consist of method_id, args0, arg1, ... argN. Method id consists -// of 4 bytes and arguments are all 32 bytes. -// Method ids are created from the first 4 bytes of the hash of the -// methods string signature. (signature = baz(uint32,string32)) -func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) { - // Fetch the ABI of the requested method - if name == "" { - // constructor - arguments, err := abi.Constructor.Inputs.Pack(args...) - if err != nil { - return nil, err - } - return arguments, nil - } - method, exist := abi.Methods[name] - if !exist { - return nil, fmt.Errorf("method '%s' not found", name) - } - arguments, err := method.Inputs.Pack(args...) - if err != nil { - return nil, err - } - // Pack up the method ID too if not a constructor and return - return append(method.ID(), arguments...), nil -} - -// Unpack output in v according to the abi specification -func (abi ABI) Unpack(v interface{}, name string, data []byte) (err error) { - if len(data) == 0 { - return fmt.Errorf("abi: unmarshalling empty output") - } - // since there can't be naming collisions with contracts and events, - // we need to decide whether we're calling a method or an event - if method, ok := abi.Methods[name]; ok { - if len(data)%32 != 0 { - return fmt.Errorf("abi: improperly formatted output: %s - Bytes: [%+v]", string(data), data) - } - return method.Outputs.Unpack(v, data) - } - if event, ok := abi.Events[name]; ok { - return event.Inputs.Unpack(v, data) - } - return fmt.Errorf("abi: could not locate named method or event") -} - -// UnpackIntoMap unpacks a log into the provided map[string]interface{} -func (abi ABI) UnpackIntoMap(v map[string]interface{}, name string, data []byte) (err error) { - if len(data) == 0 { - return fmt.Errorf("abi: unmarshalling empty output") - } - // since there can't be naming collisions with contracts and events, - // we need to decide whether we're calling a method or an event - if method, ok := abi.Methods[name]; ok { - if len(data)%32 != 0 { - return fmt.Errorf("abi: improperly formatted output") - } - return method.Outputs.UnpackIntoMap(v, data) - } - if event, ok := abi.Events[name]; ok { - return event.Inputs.UnpackIntoMap(v, data) - } - return fmt.Errorf("abi: could not locate named method or event") -} - -// UnmarshalJSON implements json.Unmarshaler interface -func (abi *ABI) UnmarshalJSON(data []byte) error { - var fields []struct { - Type string - Name string - Constant bool - Anonymous bool - Inputs []Argument - Outputs []Argument - } - if err := json.Unmarshal(data, &fields); err != nil { - return err - } - abi.Methods = make(map[string]Method) - abi.Events = make(map[string]Event) - for _, field := range fields { - switch field.Type { - case "constructor": - abi.Constructor = Method{ - Inputs: field.Inputs, - } - // empty defaults to function according to the abi spec - case "function", "": - name := field.Name - _, ok := abi.Methods[name] - for idx := 0; ok; idx++ { - name = fmt.Sprintf("%s%d", field.Name, idx) - _, ok = abi.Methods[name] - } - abi.Methods[name] = Method{ - Name: name, - RawName: field.Name, - Const: field.Constant, - Inputs: field.Inputs, - Outputs: field.Outputs, - } - case "event": - name := field.Name - _, ok := abi.Events[name] - for idx := 0; ok; idx++ { - name = fmt.Sprintf("%s%d", field.Name, idx) - _, ok = abi.Events[name] - } - abi.Events[name] = Event{ - Name: name, - RawName: field.Name, - Anonymous: field.Anonymous, - Inputs: field.Inputs, - } - } - } - - return nil -} - -// MethodById looks up a method by the 4-byte id -// returns nil if none found -func (abi *ABI) MethodById(sigdata []byte) (*Method, error) { - if len(sigdata) < 4 { - return nil, fmt.Errorf("data too short (%d bytes) for abi method lookup", len(sigdata)) - } - for _, method := range abi.Methods { - if bytes.Equal(method.ID(), sigdata[:4]) { - return &method, nil - } - } - return nil, fmt.Errorf("no method with id: %#x", sigdata[:4]) -} - -// EventByID looks an event up by its topic hash in the -// ABI and returns nil if none found. -func (abi *ABI) EventByID(topic common.Hash) (*Event, error) { - for _, event := range abi.Events { - if bytes.Equal(event.ID().Bytes(), topic.Bytes()) { - return &event, nil - } - } - return nil, fmt.Errorf("no event with id: %#x", topic.Hex()) -} diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go deleted file mode 100644 index 4dae586..0000000 --- a/accounts/abi/argument.go +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package abi - -import ( - "encoding/json" - "fmt" - "reflect" - "strings" -) - -// Argument holds the name of the argument and the corresponding type. -// Types are used when packing and testing arguments. -type Argument struct { - Name string - Type Type - Indexed bool // indexed is only used by events -} - -type Arguments []Argument - -type ArgumentMarshaling struct { - Name string - Type string - Components []ArgumentMarshaling - Indexed bool -} - -// UnmarshalJSON implements json.Unmarshaler interface -func (argument *Argument) UnmarshalJSON(data []byte) error { - var arg ArgumentMarshaling - err := json.Unmarshal(data, &arg) - if err != nil { - return fmt.Errorf("argument json err: %v", err) - } - - argument.Type, err = NewType(arg.Type, arg.Components) - if err != nil { - return err - } - argument.Name = arg.Name - argument.Indexed = arg.Indexed - - return nil -} - -// LengthNonIndexed returns the number of arguments when not counting 'indexed' ones. Only events -// can ever have 'indexed' arguments, it should always be false on arguments for method input/output -func (arguments Arguments) LengthNonIndexed() int { - out := 0 - for _, arg := range arguments { - if !arg.Indexed { - out++ - } - } - return out -} - -// NonIndexed returns the arguments with indexed arguments filtered out -func (arguments Arguments) NonIndexed() Arguments { - var ret []Argument - for _, arg := range arguments { - if !arg.Indexed { - ret = append(ret, arg) - } - } - return ret -} - -// isTuple returns true for non-atomic constructs, like (uint,uint) or uint[] -func (arguments Arguments) isTuple() bool { - return len(arguments) > 1 -} - -// Unpack performs the operation hexdata -> Go format -func (arguments Arguments) Unpack(v interface{}, data []byte) error { - // make sure the passed value is arguments pointer - if reflect.Ptr != reflect.ValueOf(v).Kind() { - return fmt.Errorf("abi: Unpack(non-pointer %T)", v) - } - marshalledValues, err := arguments.UnpackValues(data) - if err != nil { - return err - } - if arguments.isTuple() { - return arguments.unpackTuple(v, marshalledValues) - } - return arguments.unpackAtomic(v, marshalledValues[0]) -} - -// UnpackIntoMap performs the operation hexdata -> mapping of argument name to argument value -func (arguments Arguments) UnpackIntoMap(v map[string]interface{}, data []byte) error { - marshalledValues, err := arguments.UnpackValues(data) - if err != nil { - return err - } - - return arguments.unpackIntoMap(v, marshalledValues) -} - -// unpack sets the unmarshalled value to go format. -// Note the dst here must be settable. -func unpack(t *Type, dst interface{}, src interface{}) error { - var ( - dstVal = reflect.ValueOf(dst).Elem() - srcVal = reflect.ValueOf(src) - ) - tuple, typ := false, t - for { - if typ.T == SliceTy || typ.T == ArrayTy { - typ = typ.Elem - continue - } - tuple = typ.T == TupleTy - break - } - if !tuple { - return set(dstVal, srcVal) - } - - // Dereferences interface or pointer wrapper - dstVal = indirectInterfaceOrPtr(dstVal) - - switch t.T { - case TupleTy: - if dstVal.Kind() != reflect.Struct { - return fmt.Errorf("abi: invalid dst value for unpack, want struct, got %s", dstVal.Kind()) - } - fieldmap, err := mapArgNamesToStructFields(t.TupleRawNames, dstVal) - if err != nil { - return err - } - for i, elem := range t.TupleElems { - fname := fieldmap[t.TupleRawNames[i]] - field := dstVal.FieldByName(fname) - if !field.IsValid() { - return fmt.Errorf("abi: field %s can't found in the given value", t.TupleRawNames[i]) - } - if err := unpack(elem, field.Addr().Interface(), srcVal.Field(i).Interface()); err != nil { - return err - } - } - return nil - case SliceTy: - if dstVal.Kind() != reflect.Slice { - return fmt.Errorf("abi: invalid dst value for unpack, want slice, got %s", dstVal.Kind()) - } - slice := reflect.MakeSlice(dstVal.Type(), srcVal.Len(), srcVal.Len()) - for i := 0; i < slice.Len(); i++ { - if err := unpack(t.Elem, slice.Index(i).Addr().Interface(), srcVal.Index(i).Interface()); err != nil { - return err - } - } - dstVal.Set(slice) - case ArrayTy: - if dstVal.Kind() != reflect.Array { - return fmt.Errorf("abi: invalid dst value for unpack, want array, got %s", dstVal.Kind()) - } - array := reflect.New(dstVal.Type()).Elem() - for i := 0; i < array.Len(); i++ { - if err := unpack(t.Elem, array.Index(i).Addr().Interface(), srcVal.Index(i).Interface()); err != nil { - return err - } - } - dstVal.Set(array) - } - return nil -} - -// unpackIntoMap unpacks marshalledValues into the provided map[string]interface{} -func (arguments Arguments) unpackIntoMap(v map[string]interface{}, marshalledValues []interface{}) error { - // Make sure map is not nil - if v == nil { - return fmt.Errorf("abi: cannot unpack into a nil map") - } - - for i, arg := range arguments.NonIndexed() { - v[arg.Name] = marshalledValues[i] - } - return nil -} - -// unpackAtomic unpacks ( hexdata -> go ) a single value -func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues interface{}) error { - if arguments.LengthNonIndexed() == 0 { - return nil - } - argument := arguments.NonIndexed()[0] - elem := reflect.ValueOf(v).Elem() - - if elem.Kind() == reflect.Struct && argument.Type.T != TupleTy { - fieldmap, err := mapArgNamesToStructFields([]string{argument.Name}, elem) - if err != nil { - return err - } - field := elem.FieldByName(fieldmap[argument.Name]) - if !field.IsValid() { - return fmt.Errorf("abi: field %s can't be found in the given value", argument.Name) - } - return unpack(&argument.Type, field.Addr().Interface(), marshalledValues) - } - return unpack(&argument.Type, elem.Addr().Interface(), marshalledValues) -} - -// unpackTuple unpacks ( hexdata -> go ) a batch of values. -func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error { - var ( - value = reflect.ValueOf(v).Elem() - typ = value.Type() - kind = value.Kind() - ) - if err := requireUnpackKind(value, typ, kind, arguments); err != nil { - return err - } - - // If the interface is a struct, get of abi->struct_field mapping - var abi2struct map[string]string - if kind == reflect.Struct { - var ( - argNames []string - err error - ) - for _, arg := range arguments.NonIndexed() { - argNames = append(argNames, arg.Name) - } - abi2struct, err = mapArgNamesToStructFields(argNames, value) - if err != nil { - return err - } - } - for i, arg := range arguments.NonIndexed() { - switch kind { - case reflect.Struct: - field := value.FieldByName(abi2struct[arg.Name]) - if !field.IsValid() { - return fmt.Errorf("abi: field %s can't be found in the given value", arg.Name) - } - if err := unpack(&arg.Type, field.Addr().Interface(), marshalledValues[i]); err != nil { - return err - } - case reflect.Slice, reflect.Array: - if value.Len() < i { - return fmt.Errorf("abi: insufficient number of arguments for unpack, want %d, got %d", len(arguments), value.Len()) - } - v := value.Index(i) - if err := requireAssignable(v, reflect.ValueOf(marshalledValues[i])); err != nil { - return err - } - if err := unpack(&arg.Type, v.Addr().Interface(), marshalledValues[i]); err != nil { - return err - } - default: - return fmt.Errorf("abi:[2] cannot unmarshal tuple in to %v", typ) - } - } - return nil - -} - -// UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification, -// without supplying a struct to unpack into. Instead, this method returns a list containing the -// values. An atomic argument will be a list with one element. -func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) { - retval := make([]interface{}, 0, arguments.LengthNonIndexed()) - virtualArgs := 0 - for index, arg := range arguments.NonIndexed() { - marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data) - if arg.Type.T == ArrayTy && !isDynamicType(arg.Type) { - // If we have a static array, like [3]uint256, these are coded as - // just like uint256,uint256,uint256. - // This means that we need to add two 'virtual' arguments when - // we count the index from now on. - // - // Array values nested multiple levels deep are also encoded inline: - // [2][3]uint256: uint256,uint256,uint256,uint256,uint256,uint256 - // - // Calculate the full array size to get the correct offset for the next argument. - // Decrement it by 1, as the normal index increment is still applied. - virtualArgs += getTypeSize(arg.Type)/32 - 1 - } else if arg.Type.T == TupleTy && !isDynamicType(arg.Type) { - // If we have a static tuple, like (uint256, bool, uint256), these are - // coded as just like uint256,bool,uint256 - virtualArgs += getTypeSize(arg.Type)/32 - 1 - } - if err != nil { - return nil, err - } - retval = append(retval, marshalledValue) - } - return retval, nil -} - -// PackValues performs the operation Go format -> Hexdata -// It is the semantic opposite of UnpackValues -func (arguments Arguments) PackValues(args []interface{}) ([]byte, error) { - return arguments.Pack(args...) -} - -// Pack performs the operation Go format -> Hexdata -func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { - // Make sure arguments match up and pack them - abiArgs := arguments - if len(args) != len(abiArgs) { - return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(abiArgs)) - } - // variable input is the output appended at the end of packed - // output. This is used for strings and bytes types input. - var variableInput []byte - - // input offset is the bytes offset for packed output - inputOffset := 0 - for _, abiArg := range abiArgs { - inputOffset += getTypeSize(abiArg.Type) - } - var ret []byte - for i, a := range args { - input := abiArgs[i] - // pack the input - packed, err := input.Type.pack(reflect.ValueOf(a)) - if err != nil { - return nil, err - } - // check for dynamic types - if isDynamicType(input.Type) { - // set the offset - ret = append(ret, packNum(reflect.ValueOf(inputOffset))...) - // calculate next offset - inputOffset += len(packed) - // append to variable input - variableInput = append(variableInput, packed...) - } else { - // append the packed value to the input - ret = append(ret, packed...) - } - } - // append the variable input at the end of the packed input - ret = append(ret, variableInput...) - - return ret, nil -} - -// ToCamelCase converts an under-score string to a camel-case string -func ToCamelCase(input string) string { - parts := strings.Split(input, "_") - for i, s := range parts { - if len(s) > 0 { - parts[i] = strings.ToUpper(s[:1]) + s[1:] - } - } - return strings.Join(parts, "") -} diff --git a/accounts/abi/bind/auth.go b/accounts/abi/bind/auth.go deleted file mode 100644 index c916cc4..0000000 --- a/accounts/abi/bind/auth.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package bind - -import ( - "crypto/ecdsa" - "errors" - "io" - "io/ioutil" - - "github.com/ava-labs/coreth/accounts" - "github.com/ava-labs/coreth/accounts/external" - "github.com/ava-labs/coreth/accounts/keystore" - "github.com/ava-labs/coreth/core/types" - "github.com/ava-labs/go-ethereum/common" - "github.com/ava-labs/go-ethereum/crypto" -) - -// NewTransactor is a utility method to easily create a transaction signer from -// an encrypted json key stream and the associated passphrase. -func NewTransactor(keyin io.Reader, passphrase string) (*TransactOpts, error) { - json, err := ioutil.ReadAll(keyin) - if err != nil { - return nil, err - } - key, err := keystore.DecryptKey(json, passphrase) - if err != nil { - return nil, err - } - return NewKeyedTransactor(key.PrivateKey), nil -} - -// NewKeyStoreTransactor is a utility method to easily create a transaction signer from -// an decrypted key from a keystore -func NewKeyStoreTransactor(keystore *keystore.KeyStore, account accounts.Account) (*TransactOpts, error) { - return &TransactOpts{ - From: account.Address, - Signer: func(signer types.Signer, address common.Address, tx *types.Transaction) (*types.Transaction, error) { - if address != account.Address { - return nil, errors.New("not authorized to sign this account") - } - signature, err := keystore.SignHash(account, signer.Hash(tx).Bytes()) - if err != nil { - return nil, err - } - return tx.WithSignature(signer, signature) - }, - }, nil -} - -// NewKeyedTransactor is a utility method to easily create a transaction signer -// from a single private key. -func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts { - keyAddr := crypto.PubkeyToAddress(key.PublicKey) - return &TransactOpts{ - From: keyAddr, - Signer: func(signer types.Signer, address common.Address, tx *types.Transaction) (*types.Transaction, error) { - if address != keyAddr { - return nil, errors.New("not authorized to sign this account") - } - signature, err := crypto.Sign(signer.Hash(tx).Bytes(), key) - if err != nil { - return nil, err - } - return tx.WithSignature(signer, signature) - }, - } -} - -// NewClefTransactor is a utility method to easily create a transaction signer -// with a clef backend. -func NewClefTransactor(clef *external.ExternalSigner, account accounts.Account) *TransactOpts { - return &TransactOpts{ - From: account.Address, - Signer: func(signer types.Signer, address common.Address, transaction *types.Transaction) (*types.Transaction, error) { - if address != account.Address { - return nil, errors.New("not authorized to sign this account") - } - return clef.SignTx(account, transaction, nil) // Clef enforces its own chain id - }, - } -} diff --git a/accounts/abi/bind/backend.go b/accounts/abi/bind/backend.go deleted file mode 100644 index 556394f..0000000 --- a/accounts/abi/bind/backend.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package bind - -import ( - "context" - "errors" - "math/big" - - "github.com/ava-labs/coreth/core/types" - "github.com/ava-labs/go-ethereum" - "github.com/ava-labs/go-ethereum/common" -) - -var ( - // ErrNoCode is returned by call and transact operations for which the requested - // recipient contract to operate on does not exist in the state db or does not - // have any code associated with it (i.e. suicided). - ErrNoCode = errors.New("no contract code at given address") - - // This error is raised when attempting to perform a pending state action - // on a backend that doesn't implement PendingContractCaller. - ErrNoPendingState = errors.New("backend does not support pending state") - - // This error is returned by WaitDeployed if contract creation leaves an - // empty contract behind. - ErrNoCodeAfterDeploy = errors.New("no contract code after deployment") -) - -// ContractCaller defines the methods needed to allow operating with contract on a read -// only basis. -type ContractCaller interface { - // CodeAt returns the code of the given account. This is needed to differentiate - // between contract internal errors and the local chain being out of sync. - CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) - // ContractCall executes an Ethereum contract call with the specified data as the - // input. - CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) -} - -// PendingContractCaller defines methods to perform contract calls on the pending state. -// Call will try to discover this interface when access to the pending state is requested. -// If the backend does not support the pending state, Call returns ErrNoPendingState. -type PendingContractCaller interface { - // PendingCodeAt returns the code of the given account in the pending state. - PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) - // PendingCallContract executes an Ethereum contract call against the pending state. - PendingCallContract(ctx context.Context, call ethereum.CallMsg) ([]byte, error) -} - -// ContractTransactor defines the methods needed to allow operating with contract -// on a write only basis. Beside the transacting method, the remainder are helpers -// used when the user does not provide some needed values, but rather leaves it up -// to the transactor to decide. -type ContractTransactor interface { - // PendingCodeAt returns the code of the given account in the pending state. - PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) - // PendingNonceAt retrieves the current pending nonce associated with an account. - PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) - // SuggestGasPrice retrieves the currently suggested gas price to allow a timely - // execution of a transaction. - SuggestGasPrice(ctx context.Context) (*big.Int, error) - // EstimateGas tries to estimate the gas needed to execute a specific - // transaction based on the current pending state of the backend blockchain. - // There is no guarantee that this is the true gas limit requirement as other - // transactions may be added or removed by miners, but it should provide a basis - // for setting a reasonable default. - EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error) - // SendTransaction injects the transaction into the pending pool for execution. - SendTransaction(ctx context.Context, tx *types.Transaction) error -} - -// ContractFilterer defines the methods needed to access log events using one-off -// queries or continuous event subscriptions. -type ContractFilterer interface { - // FilterLogs executes a log filter operation, blocking during execution and - // returning all the results in one batch. - // - // TODO(karalabe): Deprecate when the subscription one can return past data too. - FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) - - // SubscribeFilterLogs creates a background log filtering operation, returning - // a subscription immediately, which can be used to stream the found events. - SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) -} - -// DeployBackend wraps the operations needed by WaitMined and WaitDeployed. -type DeployBackend interface { - TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) - CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) -} - -// ContractBackend defines the methods needed to work with contracts on a read-write basis. -type ContractBackend interface { - ContractCaller - ContractTransactor - ContractFilterer -} diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go deleted file mode 100644 index 88610a4..0000000 --- a/accounts/abi/bind/backends/simulated.go +++ /dev/null @@ -1,523 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package backends - -import ( - "context" - "errors" - "fmt" - "math/big" - "sync" - "time" - - "github.com/ava-labs/coreth/accounts/abi/bind" - "github.com/ava-labs/coreth/consensus/ethash" - "github.com/ava-labs/coreth/core" - "github.com/ava-labs/coreth/core/bloombits" - "github.com/ava-labs/coreth/core/rawdb" - "github.com/ava-labs/coreth/core/state" - "github.com/ava-labs/coreth/core/types" - "github.com/ava-labs/coreth/core/vm" - "github.com/ava-labs/coreth/params" - "github.com/ava-labs/coreth/rpc" - "github.com/ava-labs/go-ethereum" - "github.com/ava-labs/go-ethereum/common" - "github.com/ava-labs/go-ethereum/common/math" - "github.com/ava-labs/go-ethereum/eth/filters" - "github.com/ava-labs/go-ethereum/ethdb" - "github.com/ava-labs/go-ethereum/event" -) - -// This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend. -var _ bind.ContractBackend = (*SimulatedBackend)(nil) - -var ( - errBlockNumberUnsupported = errors.New("simulatedBackend cannot access blocks other than the latest block") - errGasEstimationFailed = errors.New("gas required exceeds allowance or always failing transaction") -) - -// SimulatedBackend implements bind.ContractBackend, simulating a blockchain in -// the background. Its main purpose is to allow easily testing contract bindings. -type SimulatedBackend struct { - database ethdb.Database // In memory database to store our testing data - blockchain *core.BlockChain // Ethereum blockchain to handle the consensus - - mu sync.Mutex - pendingBlock *types.Block // Currently pending block that will be imported on request - pendingState *state.StateDB // Currently pending state that will be the active on on request - - events *filters.EventSystem // Event system for filtering log events live - - config *params.ChainConfig -} - -// NewSimulatedBackendWithDatabase creates a new binding backend based on the given database -// and uses a simulated blockchain for testing purposes. -func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend { - genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc} - genesis.MustCommit(database) - blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}, nil) - - backend := &SimulatedBackend{ - database: database, - blockchain: blockchain, - config: genesis.Config, - events: filters.NewEventSystem(new(event.TypeMux), &filterBackend{database, blockchain}, false), - } - backend.rollback() - return backend -} - -// NewSimulatedBackend creates a new binding backend using a simulated blockchain -// for testing purposes. -func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend { - return NewSimulatedBackendWithDatabase(rawdb.NewMemoryDatabase(), alloc, gasLimit) -} - -// Close terminates the underlying blockchain's update loop. -func (b *SimulatedBackend) Close() error { - b.blockchain.Stop() - return nil -} - -// Commit imports all the pending transactions as a single block and starts a -// fresh new state. -func (b *SimulatedBackend) Commit() { - b.mu.Lock() - defer b.mu.Unlock() - - if _, err := b.blockchain.InsertChain([]*types.Block{b.pendingBlock}); err != nil { - panic(err) // This cannot happen unless the simulator is wrong, fail in that case - } - b.rollback() -} - -// Rollback aborts all pending transactions, reverting to the last committed state. -func (b *SimulatedBackend) Rollback() { - b.mu.Lock() - defer b.mu.Unlock() - - b.rollback() -} - -func (b *SimulatedBackend) rollback() { - blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {}) - statedb, _ := b.blockchain.State() - - b.pendingBlock = blocks[0] - b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database()) -} - -// CodeAt returns the code associated with a certain account in the blockchain. -func (b *SimulatedBackend) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) { - b.mu.Lock() - defer b.mu.Unlock() - - if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { - return nil, errBlockNumberUnsupported - } - statedb, _ := b.blockchain.State() - return statedb.GetCode(contract), nil -} - -// BalanceAt returns the wei balance of a certain account in the blockchain. -func (b *SimulatedBackend) BalanceAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (*big.Int, error) { - b.mu.Lock() - defer b.mu.Unlock() - - if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { - return nil, errBlockNumberUnsupported - } - statedb, _ := b.blockchain.State() - return statedb.GetBalance(contract), nil -} - -// NonceAt returns the nonce of a certain account in the blockchain. -func (b *SimulatedBackend) NonceAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (uint64, error) { - b.mu.Lock() - defer b.mu.Unlock() - - if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { - return 0, errBlockNumberUnsupported - } - statedb, _ := b.blockchain.State() - return statedb.GetNonce(contract), nil -} - -// StorageAt returns the value of key in the storage of an account in the blockchain. -func (b *SimulatedBackend) StorageAt(ctx context.Context, contract common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) { - b.mu.Lock() - defer b.mu.Unlock() - - if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { - return nil, errBlockNumberUnsupported - } - statedb, _ := b.blockchain.State() - val := statedb.GetState(contract, key) - return val[:], nil -} - -// TransactionReceipt returns the receipt of a transaction. -func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { - receipt, _, _, _ := rawdb.ReadReceipt(b.database, txHash, b.config) - return receipt, nil -} - -// TransactionByHash checks the pool of pending transactions in addition to the -// blockchain. The isPending return value indicates whether the transaction has been -// mined yet. Note that the transaction may not be part of the canonical chain even if -// it's not pending. -func (b *SimulatedBackend) TransactionByHash(ctx context.Context, txHash common.Hash) (*types.Transaction, bool, error) { - b.mu.Lock() - defer b.mu.Unlock() - - tx := b.pendingBlock.Transaction(txHash) - if tx != nil { - return tx, true, nil - } - tx, _, _, _ = rawdb.ReadTransaction(b.database, txHash) - if tx != nil { - return tx, false, nil - } - return nil, false, ethereum.NotFound -} - -// PendingCodeAt returns the code associated with an account in the pending state. -func (b *SimulatedBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) { - b.mu.Lock() - defer b.mu.Unlock() - - return b.pendingState.GetCode(contract), nil -} - -// CallContract executes a contract call. -func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { - b.mu.Lock() - defer b.mu.Unlock() - - if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { - return nil, errBlockNumberUnsupported - } - state, err := b.blockchain.State() - if err != nil { - return nil, err - } - rval, _, _, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state) - return rval, err -} - -// PendingCallContract executes a contract call on the pending state. -func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call ethereum.CallMsg) ([]byte, error) { - b.mu.Lock() - defer b.mu.Unlock() - defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot()) - - rval, _, _, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState) - return rval, err -} - -// PendingNonceAt implements PendingStateReader.PendingNonceAt, retrieving -// the nonce currently pending for the account. -func (b *SimulatedBackend) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { - b.mu.Lock() - defer b.mu.Unlock() - - return b.pendingState.GetOrNewStateObject(account).Nonce(), nil -} - -// SuggestGasPrice implements ContractTransactor.SuggestGasPrice. Since the simulated -// chain doesn't have miners, we just return a gas price of 1 for any call. -func (b *SimulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) { - return big.NewInt(1), nil -} - -// EstimateGas executes the requested code against the currently pending block/state and -// returns the used amount of gas. -func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) { - b.mu.Lock() - defer b.mu.Unlock() - - // Determine the lowest and highest possible gas limits to binary search in between - var ( - lo uint64 = params.TxGas - 1 - hi uint64 - cap uint64 - ) - if call.Gas >= params.TxGas { - hi = call.Gas - } else { - hi = b.pendingBlock.GasLimit() - } - cap = hi - - // Create a helper to check if a gas allowance results in an executable transaction - executable := func(gas uint64) bool { - call.Gas = gas - - snapshot := b.pendingState.Snapshot() - _, _, failed, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState) - b.pendingState.RevertToSnapshot(snapshot) - - if err != nil || failed { - return false - } - return true - } - // Execute the binary search and hone in on an executable gas limit - for lo+1 < hi { - mid := (hi + lo) / 2 - if !executable(mid) { - lo = mid - } else { - hi = mid - } - } - // Reject the transaction as invalid if it still fails at the highest allowance - if hi == cap { - if !executable(hi) { - return 0, errGasEstimationFailed - } - } - return hi, nil -} - -// callContract implements common code between normal and pending contract calls. -// state is modified during execution, make sure to copy it if necessary. -func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, statedb *state.StateDB) ([]byte, uint64, bool, error) { - // Ensure message is initialized properly. - if call.GasPrice == nil { - call.GasPrice = big.NewInt(1) - } - if call.Gas == 0 { - call.Gas = 50000000 - } - if call.Value == nil { - call.Value = new(big.Int) - } - // Set infinite balance to the fake caller account. - from := statedb.GetOrNewStateObject(call.From) - from.SetBalance(math.MaxBig256) - // Execute the call. - msg := callmsg{call} - - evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain, nil) - // Create a new environment which holds all relevant information - // about the transaction and calling mechanisms. - vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{}) - gaspool := new(core.GasPool).AddGas(math.MaxUint64) - - return core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() -} - -// SendTransaction updates the pending block to include the given transaction. -// It panics if the transaction is invalid. -func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error { - b.mu.Lock() - defer b.mu.Unlock() - - sender, err := types.Sender(types.NewEIP155Signer(b.config.ChainID), tx) - if err != nil { - panic(fmt.Errorf("invalid transaction: %v", err)) - } - nonce := b.pendingState.GetNonce(sender) - if tx.Nonce() != nonce { - panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce)) - } - - blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { - for _, tx := range b.pendingBlock.Transactions() { - block.AddTxWithChain(b.blockchain, tx) - } - block.AddTxWithChain(b.blockchain, tx) - }) - statedb, _ := b.blockchain.State() - - b.pendingBlock = blocks[0] - b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database()) - return nil -} - -// FilterLogs executes a log filter operation, blocking during execution and -// returning all the results in one batch. -// -// TODO(karalabe): Deprecate when the subscription one can return past data too. -func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) { - var filter *filters.Filter - if query.BlockHash != nil { - // Block filter requested, construct a single-shot filter - filter = filters.NewBlockFilter(&filterBackend{b.database, b.blockchain}, *query.BlockHash, query.Addresses, query.Topics) - } else { - // Initialize unset filter boundaried to run from genesis to chain head - from := int64(0) - if query.FromBlock != nil { - from = query.FromBlock.Int64() - } - to := int64(-1) - if query.ToBlock != nil { - to = query.ToBlock.Int64() - } - // Construct the range filter - filter = filters.NewRangeFilter(&filterBackend{b.database, b.blockchain}, from, to, query.Addresses, query.Topics) - } - // Run the filter and return all the logs - logs, err := filter.Logs(ctx) - if err != nil { - return nil, err - } - res := make([]types.Log, len(logs)) - for i, log := range logs { - res[i] = *log - } - return res, nil -} - -// SubscribeFilterLogs creates a background log filtering operation, returning a -// subscription immediately, which can be used to stream the found events. -func (b *SimulatedBackend) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { - // Subscribe to contract events - sink := make(chan []*types.Log) - - sub, err := b.events.SubscribeLogs(query, sink) - if err != nil { - return nil, err - } - // Since we're getting logs in batches, we need to flatten them into a plain stream - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case logs := <-sink: - for _, log := range logs { - select { - case ch <- *log: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// AdjustTime adds a time shift to the simulated clock. -func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error { - b.mu.Lock() - defer b.mu.Unlock() - blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { - for _, tx := range b.pendingBlock.Transactions() { - block.AddTx(tx) - } - block.OffsetTime(int64(adjustment.Seconds())) - }) - statedb, _ := b.blockchain.State() - - b.pendingBlock = blocks[0] - b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database()) - - return nil -} - -// Blockchain returns the underlying blockchain. -func (b *SimulatedBackend) Blockchain() *core.BlockChain { - return b.blockchain -} - -// callmsg implements core.Message to allow passing it as a transaction simulator. -type callmsg struct { - ethereum.CallMsg -} - -func (m callmsg) From() common.Address { return m.CallMsg.From } -func (m callmsg) Nonce() uint64 { return 0 } -func (m callmsg) CheckNonce() bool { return false } -func (m callmsg) To() *common.Address { return m.CallMsg.To } -func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } -func (m callmsg) Gas() uint64 { return m.CallMsg.Gas } -func (m callmsg) Value() *big.Int { return m.CallMsg.Value } -func (m callmsg) Data() []byte { return m.CallMsg.Data } - -// filterBackend implements filters.Backend to support filtering for logs without -// taking bloom-bits acceleration structures into account. -type filterBackend struct { - db ethdb.Database - bc *core.BlockChain -} - -func (fb *filterBackend) ChainDb() ethdb.Database { return fb.db } -func (fb *filterBackend) EventMux() *event.TypeMux { panic("not supported") } - -func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumber) (*types.Header, error) { - if block == rpc.LatestBlockNumber { - return fb.bc.CurrentHeader(), nil - } - return fb.bc.GetHeaderByNumber(uint64(block.Int64())), nil -} - -func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { - return fb.bc.GetHeaderByHash(hash), nil -} - -func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { - number := rawdb.ReadHeaderNumber(fb.db, hash) - if number == nil { - return nil, nil - } - return rawdb.ReadReceipts(fb.db, hash, *number, fb.bc.Config()), nil -} - -func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { - number := rawdb.ReadHeaderNumber(fb.db, hash) - if number == nil { - return nil, nil - } - receipts := rawdb.ReadReceipts(fb.db, hash, *number, fb.bc.Config()) - if receipts == nil { - return nil, nil - } - logs := make([][]*types.Log, len(receipts)) - for i, receipt := range receipts { - logs[i] = receipt.Logs - } - return logs, nil -} - -func (fb *filterBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { - return event.NewSubscription(func(quit <-chan struct{}) error { - <-quit - return nil - }) -} -func (fb *filterBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { - return fb.bc.SubscribeChainEvent(ch) -} -func (fb *filterBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { - return fb.bc.SubscribeRemovedLogsEvent(ch) -} -func (fb *filterBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { - return fb.bc.SubscribeLogsEvent(ch) -} - -func (fb *filterBackend) BloomStatus() (uint64, uint64) { return 4096, 0 } -func (fb *filterBackend) ServiceFilter(ctx context.Context, ms *bloombits.MatcherSession) { - panic("not supported") -} diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go deleted file mode 100644 index 3d64f85..0000000 --- a/accounts/abi/bind/base.go +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package bind - -import ( - "context" - "errors" - "fmt" - "math/big" - - "github.com/ava-labs/coreth/accounts/abi" - "github.com/ava-labs/coreth/core/types" - "github.com/ava-labs/go-ethereum" - "github.com/ava-labs/go-ethereum/common" - "github.com/ava-labs/go-ethereum/crypto" - "github.com/ava-labs/go-ethereum/event" -) - -// SignerFn is a signer function callback when a contract requires a method to -// sign the transaction before submission. -type SignerFn func(types.Signer, common.Address, *types.Transaction) (*types.Transaction, error) - -// CallOpts is the collection of options to fine tune a contract call request. -type CallOpts struct { - Pending bool // Whether to operate on the pending state or the last known one - From common.Address // Optional the sender address, otherwise the first account is used - BlockNumber *big.Int // Optional the block number on which the call should be performed - Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) -} - -// TransactOpts is the collection of authorization data required to create a -// valid Ethereum transaction. -type TransactOpts struct { - From common.Address // Ethereum account to send the transaction from - Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state) - Signer SignerFn // Method to use for signing the transaction (mandatory) - - Value *big.Int // Funds to transfer along along the transaction (nil = 0 = no funds) - GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle) - GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate) - - Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) -} - -// FilterOpts is the collection of options to fine tune filtering for events -// within a bound contract. -type FilterOpts struct { - Start uint64 // Start of the queried range - End *uint64 // End of the range (nil = latest) - - Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) -} - -// WatchOpts is the collection of options to fine tune subscribing for events -// within a bound contract. -type WatchOpts struct { - Start *uint64 // Start of the queried range (nil = latest) - Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) -} - -// BoundContract is the base wrapper object that reflects a contract on the -// Ethereum network. It contains a collection of methods that are used by the -// higher level contract bindings to operate. -type BoundContract struct { - address common.Address // Deployment address of the contract on the Ethereum blockchain - abi abi.ABI // Reflect based ABI to access the correct Ethereum methods - caller ContractCaller // Read interface to interact with the blockchain - transactor ContractTransactor // Write interface to interact with the blockchain - filterer ContractFilterer // Event filtering to interact with the blockchain -} - -// NewBoundContract creates a low level contract interface through which calls -// and transactions may be made through. -func NewBoundContract(address common.Address, abi abi.ABI, caller ContractCaller, transactor ContractTransactor, filterer ContractFilterer) *BoundContract { - return &BoundContract{ - address: address, - abi: abi, - caller: caller, - transactor: transactor, - filterer: filterer, - } -} - -// DeployContract deploys a contract onto the Ethereum blockchain and binds the -// deployment address with a Go wrapper. -func DeployContract(opts *TransactOpts, abi abi.ABI, bytecode []byte, backend ContractBackend, params ...interface{}) (common.Address, *types.Transaction, *BoundContract, error) { - // Otherwise try to deploy the contract - c := NewBoundContract(common.Address{}, abi, backend, backend, backend) - - input, err := c.abi.Pack("", params...) - if err != nil { - return common.Address{}, nil, nil, err - } - tx, err := c.transact(opts, nil, append(bytecode, input...)) - if err != nil { - return common.Address{}, nil, nil, err - } - c.address = crypto.CreateAddress(opts.From, tx.Nonce()) - return c.address, tx, c, nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string, params ...interface{}) error { - // Don't crash on a lazy user - if opts == nil { - opts = new(CallOpts) - } - // Pack the input, call and unpack the results - input, err := c.abi.Pack(method, params...) - if err != nil { - return err - } - var ( - msg = ethereum.CallMsg{From: opts.From, To: &c.address, Data: input} - ctx = ensureContext(opts.Context) - code []byte - output []byte - ) - if opts.Pending { - pb, ok := c.caller.(PendingContractCaller) - if !ok { - return ErrNoPendingState - } - output, err = pb.PendingCallContract(ctx, msg) - if err == nil && len(output) == 0 { - // Make sure we have a contract to operate on, and bail out otherwise. - if code, err = pb.PendingCodeAt(ctx, c.address); err != nil { - return err - } else if len(code) == 0 { - return ErrNoCode - } - } - } else { - output, err = c.caller.CallContract(ctx, msg, opts.BlockNumber) - if err == nil && len(output) == 0 { - // Make sure we have a contract to operate on, and bail out otherwise. - if code, err = c.caller.CodeAt(ctx, c.address, opts.BlockNumber); err != nil { - return err - } else if len(code) == 0 { - return ErrNoCode - } - } - } - if err != nil { - return err - } - return c.abi.Unpack(result, method, output) -} - -// Transact invokes the (paid) contract method with params as input values. -func (c *BoundContract) Transact(opts *TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - // Otherwise pack up the parameters and invoke the contract - input, err := c.abi.Pack(method, params...) - if err != nil { - return nil, err - } - return c.transact(opts, &c.address, input) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (c *BoundContract) Transfer(opts *TransactOpts) (*types.Transaction, error) { - return c.transact(opts, &c.address, nil) -} - -// transact executes an actual transaction invocation, first deriving any missing -// authorization fields, and then scheduling the transaction for execution. -func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) { - var err error - - // Ensure a valid value field and resolve the account nonce - value := opts.Value - if value == nil { - value = new(big.Int) - } - var nonce uint64 - if opts.Nonce == nil { - nonce, err = c.transactor.PendingNonceAt(ensureContext(opts.Context), opts.From) - if err != nil { - return nil, fmt.Errorf("failed to retrieve account nonce: %v", err) - } - } else { - nonce = opts.Nonce.Uint64() - } - // Figure out the gas allowance and gas price values - gasPrice := opts.GasPrice - if gasPrice == nil { - gasPrice, err = c.transactor.SuggestGasPrice(ensureContext(opts.Context)) - if err != nil { - return nil, fmt.Errorf("failed to suggest gas price: %v", err) - } - } - gasLimit := opts.GasLimit - if gasLimit == 0 { - // Gas estimation cannot succeed without code for method invocations - if contract != nil { - if code, err := c.transactor.PendingCodeAt(ensureContext(opts.Context), c.address); err != nil { - return nil, err - } else if len(code) == 0 { - return nil, ErrNoCode - } - } - // If the contract surely has code (or code is not needed), estimate the transaction - msg := ethereum.CallMsg{From: opts.From, To: contract, Value: value, Data: input} - gasLimit, err = c.transactor.EstimateGas(ensureContext(opts.Context), msg) - if err != nil { - return nil, fmt.Errorf("failed to estimate gas needed: %v", err) - } - } - // Create the transaction, sign it and schedule it for execution - var rawTx *types.Transaction - if contract == nil { - rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, input) - } else { - rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, input) - } - if opts.Signer == nil { - return nil, errors.New("no signer to authorize the transaction with") - } - signedTx, err := opts.Signer(types.HomesteadSigner{}, opts.From, rawTx) - if err != nil { - return nil, err - } - if err := c.transactor.SendTransaction(ensureContext(opts.Context), signedTx); err != nil { - return nil, err - } - return signedTx, nil -} - -// FilterLogs filters contract logs for past blocks, returning the necessary -// channels to construct a strongly typed bound iterator on top of them. -func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]interface{}) (chan types.Log, event.Subscription, error) { - // Don't crash on a lazy user - if opts == nil { - opts = new(FilterOpts) - } - // Append the event selector to the query parameters and construct the topic set - query = append([][]interface{}{{c.abi.Events[name].ID()}}, query...) - - topics, err := makeTopics(query...) - if err != nil { - return nil, nil, err - } - // Start the background filtering - logs := make(chan types.Log, 128) - - config := ethereum.FilterQuery{ - Addresses: []common.Address{c.address}, - Topics: topics, - FromBlock: new(big.Int).SetUint64(opts.Start), - } - if opts.End != nil { - config.ToBlock = new(big.Int).SetUint64(*opts.End) - } - /* TODO(karalabe): Replace the rest of the method below with this when supported - sub, err := c.filterer.SubscribeFilterLogs(ensureContext(opts.Context), config, logs) - */ - buff, err := c.filterer.FilterLogs(ensureContext(opts.Context), config) - if err != nil { - return nil, nil, err - } - sub, err := event.NewSubscription(func(quit <-chan struct{}) error { - for _, log := range buff { - select { - case logs <- log: - case <-quit: - return nil - } - } - return nil - }), nil - - if err != nil { - return nil, nil, err - } - return logs, sub, nil -} - -// WatchLogs filters subscribes to contract logs for future blocks, returning a -// subscription object that can be used to tear down the watcher. -func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]interface{}) (chan types.Log, event.Subscription, error) { - // Don't crash on a lazy user - if opts == nil { - opts = new(WatchOpts) - } - // Append the event selector to the query parameters and construct the topic set - query = append([][]interface{}{{c.abi.Events[name].ID()}}, query...) - - topics, err := makeTopics(query...) - if err != nil { - return nil, nil, err - } - // Start the background filtering - logs := make(chan types.Log, 128) - - config := ethereum.FilterQuery{ - Addresses: []common.Address{c.address}, - Topics: topics, - } - if opts.Start != nil { - config.FromBlock = new(big.Int).SetUint64(*opts.Start) - } - sub, err := c.filterer.SubscribeFilterLogs(ensureContext(opts.Context), config, logs) - if err != nil { - return nil, nil, err - } - return logs, sub, nil -} - -// UnpackLog unpacks a retrieved log into the provided output structure. -func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error { - if len(log.Data) > 0 { - if err := c.abi.Unpack(out, event, log.Data); err != nil { - return err - } - } - var indexed abi.Arguments - for _, arg := range c.abi.Events[event].Inputs { - if arg.Indexed { - indexed = append(indexed, arg) - } - } - return parseTopics(out, indexed, log.Topics[1:]) -} - -// UnpackLogIntoMap unpacks a retrieved log into the provided map. -func (c *BoundContract) UnpackLogIntoMap(out map[string]interface{}, event string, log types.Log) error { - if len(log.Data) > 0 { - if err := c.abi.UnpackIntoMap(out, event, log.Data); err != nil { - return err - } - } - var indexed abi.Arguments - for _, arg := range c.abi.Events[event].Inputs { - if arg.Indexed { - indexed = append(indexed, arg) - } - } - return parseTopicsIntoMap(out, indexed, log.Topics[1:]) -} - -// ensureContext is a helper method to ensure a context is not nil, even if the -// user specified it as such. -func ensureContext(ctx context.Context) context.Context { - if ctx == nil { - return context.TODO() - } - return ctx -} diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go deleted file mode 100644 index e869eef..0000000 --- a/accounts/abi/bind/bind.go +++ /dev/null @@ -1,558 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -// Package bind generates Ethereum contract Go bindings. -// -// Detailed usage document and tutorial available on the go-ethereum Wiki page: -// https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts -package bind - -import ( - "bytes" - "errors" - "fmt" - "go/format" - "regexp" - "strings" - "text/template" - "unicode" - - "github.com/ava-labs/coreth/accounts/abi" - "github.com/ava-labs/go-ethereum/log" -) - -// Lang is a target programming language selector to generate bindings for. -type Lang int - -const ( - LangGo Lang = iota - LangJava - LangObjC -) - -// Bind generates a Go wrapper around a contract ABI. This wrapper isn't meant -// 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) (string, error) { - // Process each individual contract requested binding - contracts := make(map[string]*tmplContract) - - // Map used to flag each encountered library as such - isLib := make(map[string]struct{}) - - for i := 0; i < len(types); i++ { - // Parse the actual ABI to generate the binding for - evmABI, err := abi.JSON(strings.NewReader(abis[i])) - if err != nil { - return "", err - } - // Strip any whitespace from the JSON ABI - strippedABI := strings.Map(func(r rune) rune { - if unicode.IsSpace(r) { - return -1 - } - return r - }, abis[i]) - - // Extract the call and transact methods; events, struct definitions; and sort them alphabetically - var ( - calls = make(map[string]*tmplMethod) - transacts = make(map[string]*tmplMethod) - events = make(map[string]*tmplEvent) - structs = make(map[string]*tmplStruct) - ) - for _, original := range evmABI.Methods { - // Normalize the method for capital cases and non-anonymous inputs/outputs - normalized := original - normalized.Name = methodNormalizer[lang](original.Name) - - normalized.Inputs = make([]abi.Argument, len(original.Inputs)) - copy(normalized.Inputs, original.Inputs) - for j, input := range normalized.Inputs { - if input.Name == "" { - normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j) - } - if _, exist := structs[input.Type.String()]; input.Type.T == abi.TupleTy && !exist { - bindStructType[lang](input.Type, structs) - } - } - normalized.Outputs = make([]abi.Argument, len(original.Outputs)) - copy(normalized.Outputs, original.Outputs) - for j, output := range normalized.Outputs { - if output.Name != "" { - normalized.Outputs[j].Name = capitalise(output.Name) - } - if _, exist := structs[output.Type.String()]; output.Type.T == abi.TupleTy && !exist { - bindStructType[lang](output.Type, structs) - } - } - // Append the methods to the call or transact lists - if original.Const { - 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)} - } - } - for _, original := range evmABI.Events { - // Skip anonymous events as they don't support explicit filtering - if original.Anonymous { - continue - } - // Normalize the event for capital cases and non-anonymous outputs - normalized := original - normalized.Name = methodNormalizer[lang](original.Name) - - normalized.Inputs = make([]abi.Argument, len(original.Inputs)) - copy(normalized.Inputs, original.Inputs) - for j, input := range normalized.Inputs { - // Indexed fields are input, non-indexed ones are outputs - if input.Indexed { - if input.Name == "" { - normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j) - } - if _, exist := structs[input.Type.String()]; input.Type.T == abi.TupleTy && !exist { - bindStructType[lang](input.Type, structs) - } - } - } - // Append the event to the accumulator list - events[original.Name] = &tmplEvent{Original: original, Normalized: normalized} - } - - // 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{ - Type: capitalise(types[i]), - InputABI: strings.Replace(strippedABI, "\"", "\\\"", -1), - InputBin: strings.TrimPrefix(strings.TrimSpace(bytecodes[i]), "0x"), - Constructor: evmABI.Constructor, - Calls: calls, - Transacts: transacts, - Events: events, - Libraries: make(map[string]string), - Structs: structs, - } - // Function 4-byte signatures are stored in the same sequence - // as types, if available. - if len(fsigs) > i { - contracts[types[i]].FuncSigs = fsigs[i] - } - // Parse library references. - for pattern, name := range libs { - matched, err := regexp.Match("__\\$"+pattern+"\\$__", []byte(contracts[types[i]].InputBin)) - if err != nil { - log.Error("Could not search for pattern", "pattern", pattern, "contract", contracts[types[i]], "err", err) - } - if matched { - contracts[types[i]].Libraries[pattern] = name - // keep track that this type is a library - if _, ok := isLib[name]; !ok { - isLib[name] = struct{}{} - } - } - } - } - // Check if that type has already been identified as a library - for i := 0; i < len(types); i++ { - _, ok := isLib[types[i]] - contracts[types[i]].Library = ok - } - // Generate the contract template data content and render it - data := &tmplData{ - Package: pkg, - Contracts: contracts, - Libraries: libs, - } - buffer := new(bytes.Buffer) - - funcs := map[string]interface{}{ - "bindtype": bindType[lang], - "bindtopictype": bindTopicType[lang], - "namedtype": namedType[lang], - "formatmethod": formatMethod, - "formatevent": formatEvent, - "capitalise": capitalise, - "decapitalise": decapitalise, - } - tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplSource[lang])) - if err := tmpl.Execute(buffer, data); err != nil { - return "", err - } - // For Go bindings pass the code through gofmt to clean it up - if lang == LangGo { - code, err := format.Source(buffer.Bytes()) - if err != nil { - return "", fmt.Errorf("%v\n%s", err, buffer) - } - return string(code), nil - } - // For all others just return as is for now - return buffer.String(), nil -} - -// 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{ - LangGo: bindTypeGo, - LangJava: bindTypeJava, -} - -// bindBasicTypeGo converts basic solidity types(except array, slice and tuple) to Go one. -func bindBasicTypeGo(kind abi.Type) string { - switch kind.T { - case abi.AddressTy: - return "common.Address" - case abi.IntTy, abi.UintTy: - parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(kind.String()) - switch parts[2] { - case "8", "16", "32", "64": - return fmt.Sprintf("%sint%s", parts[1], parts[2]) - } - return "*big.Int" - case abi.FixedBytesTy: - return fmt.Sprintf("[%d]byte", kind.Size) - case abi.BytesTy: - return "[]byte" - case abi.FunctionTy: - return "[24]byte" - default: - // string, bool types - return kind.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 { - switch kind.T { - case abi.TupleTy: - return structs[kind.String()].Name - case abi.ArrayTy: - return fmt.Sprintf("[%d]", kind.Size) + bindTypeGo(*kind.Elem, structs) - case abi.SliceTy: - return "[]" + bindTypeGo(*kind.Elem, structs) - default: - return bindBasicTypeGo(kind) - } -} - -// bindBasicTypeJava converts basic solidity types(except array, slice and tuple) to Java one. -func bindBasicTypeJava(kind abi.Type) string { - switch kind.T { - case abi.AddressTy: - return "Address" - case abi.IntTy, abi.UintTy: - // Note that uint and int (without digits) are also matched, - // these are size 256, and will translate to BigInt (the default). - parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(kind.String()) - if len(parts) != 3 { - return kind.String() - } - // All unsigned integers should be translated to BigInt since gomobile doesn't - // support them. - if parts[1] == "u" { - return "BigInt" - } - - namedSize := map[string]string{ - "8": "byte", - "16": "short", - "32": "int", - "64": "long", - }[parts[2]] - - // default to BigInt - if namedSize == "" { - namedSize = "BigInt" - } - return namedSize - case abi.FixedBytesTy, abi.BytesTy: - return "byte[]" - case abi.BoolTy: - return "boolean" - case abi.StringTy: - return "String" - case abi.FunctionTy: - return "byte[24]" - default: - return kind.String() - } -} - -// pluralizeJavaType explicitly converts multidimensional types to predefined -// type in go side. -func pluralizeJavaType(typ string) string { - switch typ { - case "boolean": - return "Bools" - case "String": - return "Strings" - case "Address": - return "Addresses" - case "byte[]": - return "Binaries" - case "BigInt": - return "BigInts" - } - return typ + "[]" -} - -// 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 { - switch kind.T { - case abi.TupleTy: - return structs[kind.String()].Name - case abi.ArrayTy, abi.SliceTy: - return pluralizeJavaType(bindTypeJava(*kind.Elem, structs)) - default: - return bindBasicTypeJava(kind) - } -} - -// 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{ - LangGo: bindTopicTypeGo, - LangJava: bindTopicTypeJava, -} - -// bindTopicTypeGo converts a Solidity topic type to a Go one. It is almost the same -// funcionality as for simple types, but dynamic types get converted to hashes. -func bindTopicTypeGo(kind abi.Type, structs map[string]*tmplStruct) string { - bound := bindTypeGo(kind, structs) - if bound == "string" || bound == "[]byte" { - bound = "common.Hash" - } - return bound -} - -// bindTopicTypeJava converts a Solidity topic type to a Java one. It is almost the same -// funcionality as for simple types, but dynamic types get converted to hashes. -func bindTopicTypeJava(kind abi.Type, structs map[string]*tmplStruct) string { - bound := bindTypeJava(kind, structs) - if bound == "String" || bound == "byte[]" { - bound = "Hash" - } - return bound -} - -// 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{ - 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 { - switch kind.T { - case abi.TupleTy: - if s, exist := structs[kind.String()]; exist { - return s.Name - } - var fields []*tmplField - for i, elem := range kind.TupleElems { - field := bindStructTypeGo(*elem, structs) - fields = append(fields, &tmplField{Type: field, Name: capitalise(kind.TupleRawNames[i]), SolKind: *elem}) - } - name := fmt.Sprintf("Struct%d", len(structs)) - structs[kind.String()] = &tmplStruct{ - Name: name, - Fields: fields, - } - return name - case abi.ArrayTy: - return fmt.Sprintf("[%d]", kind.Size) + bindStructTypeGo(*kind.Elem, structs) - case abi.SliceTy: - return "[]" + bindStructTypeGo(*kind.Elem, structs) - default: - return bindBasicTypeGo(kind) - } -} - -// 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 { - switch kind.T { - case abi.TupleTy: - if s, exist := structs[kind.String()]; exist { - return s.Name - } - var fields []*tmplField - for i, elem := range kind.TupleElems { - field := bindStructTypeJava(*elem, structs) - fields = append(fields, &tmplField{Type: field, Name: decapitalise(kind.TupleRawNames[i]), SolKind: *elem}) - } - name := fmt.Sprintf("Class%d", len(structs)) - structs[kind.String()] = &tmplStruct{ - Name: name, - Fields: fields, - } - return name - case abi.ArrayTy, abi.SliceTy: - return pluralizeJavaType(bindStructTypeJava(*kind.Elem, structs)) - default: - return bindBasicTypeJava(kind) - } -} - -// namedType is a set of functions that transform language specific types to -// named versions that my be used inside method names. -var namedType = map[Lang]func(string, abi.Type) string{ - LangGo: func(string, abi.Type) string { panic("this shouldn't be needed") }, - LangJava: namedTypeJava, -} - -// namedTypeJava converts some primitive data types to named variants that can -// be used as parts of method names. -func namedTypeJava(javaKind string, solKind abi.Type) string { - switch javaKind { - case "byte[]": - return "Binary" - case "boolean": - return "Bool" - default: - parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(solKind.String()) - if len(parts) != 4 { - return javaKind - } - switch parts[2] { - case "8", "16", "32", "64": - if parts[3] == "" { - return capitalise(fmt.Sprintf("%sint%s", parts[1], parts[2])) - } - return capitalise(fmt.Sprintf("%sint%ss", parts[1], parts[2])) - - default: - return javaKind - } - } -} - -// methodNormalizer is a name transformer that modifies Solidity method names to -// conform to target language naming concentions. -var methodNormalizer = map[Lang]func(string) string{ - LangGo: abi.ToCamelCase, - LangJava: decapitalise, -} - -// capitalise makes a camel-case string which starts with an upper case character. -func capitalise(input string) string { - return abi.ToCamelCase(input) -} - -// decapitalise makes a camel-case string which starts with a lower case character. -func decapitalise(input string) string { - if len(input) == 0 { - return input - } - - goForm := abi.ToCamelCase(input) - return strings.ToLower(goForm[:1]) + goForm[1:] -} - -// structured checks whether a list of ABI data types has enough information to -// operate through a proper Go struct or if flat returns are needed. -func structured(args abi.Arguments) bool { - if len(args) < 2 { - return false - } - exists := make(map[string]bool) - for _, out := range args { - // If the name is anonymous, we can't organize into a struct - if out.Name == "" { - return false - } - // If the field name is empty when normalized or collides (var, Var, _var, _Var), - // we can't organize into a struct - field := capitalise(out.Name) - if field == "" || exists[field] { - return false - } - exists[field] = true - } - return true -} - -// resolveArgName converts a raw argument representation into a user friendly format. -func resolveArgName(arg abi.Argument, structs map[string]*tmplStruct) string { - var ( - prefix string - embedded string - typ = &arg.Type - ) -loop: - for { - switch typ.T { - case abi.SliceTy: - prefix += "[]" - case abi.ArrayTy: - prefix += fmt.Sprintf("[%d]", typ.Size) - default: - embedded = typ.String() - break loop - } - typ = typ.Elem - } - if s, exist := structs[embedded]; exist { - return prefix + s.Name - } else { - return arg.Type.String() - } -} - -// formatMethod transforms raw method representation into a user friendly one. -func formatMethod(method abi.Method, structs map[string]*tmplStruct) string { - inputs := make([]string, len(method.Inputs)) - for i, input := range method.Inputs { - inputs[i] = fmt.Sprintf("%v %v", resolveArgName(input, structs), input.Name) - } - outputs := make([]string, len(method.Outputs)) - for i, output := range method.Outputs { - outputs[i] = resolveArgName(output, structs) - if len(output.Name) > 0 { - outputs[i] += fmt.Sprintf(" %v", output.Name) - } - } - constant := "" - if method.Const { - constant = "constant " - } - return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.RawName, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", ")) -} - -// formatEvent transforms raw event representation into a user friendly one. -func formatEvent(event abi.Event, structs map[string]*tmplStruct) string { - inputs := make([]string, len(event.Inputs)) - for i, input := range event.Inputs { - if input.Indexed { - inputs[i] = fmt.Sprintf("%v indexed %v", resolveArgName(input, structs), input.Name) - } else { - inputs[i] = fmt.Sprintf("%v %v", resolveArgName(input, structs), input.Name) - } - } - return fmt.Sprintf("event %v(%v)", event.RawName, strings.Join(inputs, ", ")) -} diff --git a/accounts/abi/bind/template.go b/accounts/abi/bind/template.go deleted file mode 100644 index e90d02e..0000000 --- a/accounts/abi/bind/template.go +++ /dev/null @@ -1,616 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package bind - -import "github.com/ava-labs/coreth/accounts/abi" - -// tmplData is the data structure required to fill the binding template. -type tmplData struct { - Package string // Name of the package to place the generated file in - Contracts map[string]*tmplContract // List of contracts to generate into this file - Libraries map[string]string // Map the bytecode's link pattern to the library name -} - -// tmplContract contains the data needed to generate an individual contract binding. -type tmplContract struct { - Type string // Type name of the main contract binding - InputABI string // JSON ABI used as the input to generate the binding from - InputBin string // Optional EVM bytecode used to denetare deploy code from - FuncSigs map[string]string // Optional map: string signature -> 4-byte signature - Constructor abi.Method // Contract constructor for deploy parametrization - Calls map[string]*tmplMethod // Contract calls that only read state data - Transacts map[string]*tmplMethod // Contract calls that write state data - Events map[string]*tmplEvent // Contract events accessors - Libraries map[string]string // Same as tmplData, but filtered to only keep what the contract needs - Structs map[string]*tmplStruct // Contract struct type definitions - Library bool -} - -// tmplMethod is a wrapper around an abi.Method that contains a few preprocessed -// and cached data fields. -type tmplMethod struct { - Original abi.Method // Original method as parsed by the abi package - Normalized abi.Method // Normalized version of the parsed method (capitalized names, non-anonymous args/returns) - Structured bool // Whether the returns should be accumulated into a struct -} - -// tmplEvent is a wrapper around an a -type tmplEvent struct { - Original abi.Event // Original event as parsed by the abi package - Normalized abi.Event // Normalized version of the parsed fields -} - -// tmplField is a wrapper around a struct field with binding language -// struct type definition and relative filed name. -type tmplField struct { - Type string // Field type representation depends on target binding language - Name string // Field name converted from the raw user-defined field name - SolKind abi.Type // Raw abi type information -} - -// tmplStruct is a wrapper around an abi.tuple contains a auto-generated -// struct name. -type tmplStruct struct { - Name string // Auto-generated struct name(We can't obtain the raw struct name through abi) - Fields []*tmplField // Struct fields definition depends on the binding language. -} - -// tmplSource is language to template mapping containing all the supported -// programming languages the package can generate to. -var tmplSource = map[Lang]string{ - LangGo: tmplSourceGo, - LangJava: tmplSourceJava, -} - -// tmplSourceGo is the Go source template use to generate the contract binding -// based on. -const tmplSourceGo = ` -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package {{.Package}} - -import ( - "math/big" - "strings" - - ethereum "github.com/ava-labs/go-ethereum" - "github.com/ava-labs/coreth/accounts/abi" - "github.com/ava-labs/coreth/accounts/abi/bind" - "github.com/ava-labs/go-ethereum/common" - "github.com/ava-labs/coreth/core/types" - "github.com/ava-labs/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = abi.U256 - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription -) - -{{range $contract := .Contracts}} - {{$structs := $contract.Structs}} - // {{.Type}}ABI is the input ABI used to generate the binding from. - const {{.Type}}ABI = "{{.InputABI}}" - - {{if $contract.FuncSigs}} - // {{.Type}}FuncSigs maps the 4-byte function signature to its string representation. - var {{.Type}}FuncSigs = map[string]string{ - {{range $strsig, $binsig := .FuncSigs}}"{{$binsig}}": "{{$strsig}}", - {{end}} - } - {{end}} - - {{if .InputBin}} - // {{.Type}}Bin is the compiled bytecode used for deploying new contracts. - var {{.Type}}Bin = "0x{{.InputBin}}" - - // Deploy{{.Type}} deploys a new Ethereum contract, binding an instance of {{.Type}} to it. - func Deploy{{.Type}}(auth *bind.TransactOpts, backend bind.ContractBackend {{range .Constructor.Inputs}}, {{.Name}} {{bindtype .Type $structs}}{{end}}) (common.Address, *types.Transaction, *{{.Type}}, error) { - parsed, err := abi.JSON(strings.NewReader({{.Type}}ABI)) - if err != nil { - return common.Address{}, nil, nil, err - } - {{range $pattern, $name := .Libraries}} - {{decapitalise $name}}Addr, _, _, _ := Deploy{{capitalise $name}}(auth, backend) - {{$contract.Type}}Bin = strings.Replace({{$contract.Type}}Bin, "__${{$pattern}}$__", {{decapitalise $name}}Addr.String()[2:], -1) - {{end}} - address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex({{.Type}}Bin), backend {{range .Constructor.Inputs}}, {{.Name}}{{end}}) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil - } - {{end}} - - // {{.Type}} is an auto generated Go binding around an Ethereum contract. - type {{.Type}} struct { - {{.Type}}Caller // Read-only binding to the contract - {{.Type}}Transactor // Write-only binding to the contract - {{.Type}}Filterer // Log filterer for contract events - } - - // {{.Type}}Caller is an auto generated read-only Go binding around an Ethereum contract. - type {{.Type}}Caller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls - } - - // {{.Type}}Transactor is an auto generated write-only Go binding around an Ethereum contract. - type {{.Type}}Transactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls - } - - // {{.Type}}Filterer is an auto generated log filtering Go binding around an Ethereum contract events. - type {{.Type}}Filterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls - } - - // {{.Type}}Session is an auto generated Go binding around an Ethereum contract, - // with pre-set call and transact options. - type {{.Type}}Session struct { - Contract *{{.Type}} // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session - } - - // {{.Type}}CallerSession is an auto generated read-only Go binding around an Ethereum contract, - // with pre-set call options. - type {{.Type}}CallerSession struct { - Contract *{{.Type}}Caller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - } - - // {{.Type}}TransactorSession is an auto generated write-only Go binding around an Ethereum contract, - // with pre-set transact options. - type {{.Type}}TransactorSession struct { - Contract *{{.Type}}Transactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session - } - - // {{.Type}}Raw is an auto generated low-level Go binding around an Ethereum contract. - type {{.Type}}Raw struct { - Contract *{{.Type}} // Generic contract binding to access the raw methods on - } - - // {{.Type}}CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. - type {{.Type}}CallerRaw struct { - Contract *{{.Type}}Caller // Generic read-only contract binding to access the raw methods on - } - - // {{.Type}}TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. - type {{.Type}}TransactorRaw struct { - Contract *{{.Type}}Transactor // Generic write-only contract binding to access the raw methods on - } - - // New{{.Type}} creates a new instance of {{.Type}}, bound to a specific deployed contract. - func New{{.Type}}(address common.Address, backend bind.ContractBackend) (*{{.Type}}, error) { - contract, err := bind{{.Type}}(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil - } - - // New{{.Type}}Caller creates a new read-only instance of {{.Type}}, bound to a specific deployed contract. - func New{{.Type}}Caller(address common.Address, caller bind.ContractCaller) (*{{.Type}}Caller, error) { - contract, err := bind{{.Type}}(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &{{.Type}}Caller{contract: contract}, nil - } - - // New{{.Type}}Transactor creates a new write-only instance of {{.Type}}, bound to a specific deployed contract. - func New{{.Type}}Transactor(address common.Address, transactor bind.ContractTransactor) (*{{.Type}}Transactor, error) { - contract, err := bind{{.Type}}(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &{{.Type}}Transactor{contract: contract}, nil - } - - // New{{.Type}}Filterer creates a new log filterer instance of {{.Type}}, bound to a specific deployed contract. - func New{{.Type}}Filterer(address common.Address, filterer bind.ContractFilterer) (*{{.Type}}Filterer, error) { - contract, err := bind{{.Type}}(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &{{.Type}}Filterer{contract: contract}, nil - } - - // bind{{.Type}} binds a generic wrapper to an already deployed contract. - func bind{{.Type}}(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader({{.Type}}ABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil - } - - // Call invokes the (constant) contract method with params as input values and - // sets the output to result. The result type might be a single field for simple - // returns, a slice of interfaces for anonymous returns and a struct for named - // returns. - func (_{{$contract.Type}} *{{$contract.Type}}Raw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _{{$contract.Type}}.Contract.{{$contract.Type}}Caller.contract.Call(opts, result, method, params...) - } - - // Transfer initiates a plain transaction to move funds to the contract, calling - // its default method if one is available. - func (_{{$contract.Type}} *{{$contract.Type}}Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.contract.Transfer(opts) - } - - // Transact invokes the (paid) contract method with params as input values. - func (_{{$contract.Type}} *{{$contract.Type}}Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.contract.Transact(opts, method, params...) - } - - // Call invokes the (constant) contract method with params as input values and - // sets the output to result. The result type might be a single field for simple - // returns, a slice of interfaces for anonymous returns and a struct for named - // returns. - func (_{{$contract.Type}} *{{$contract.Type}}CallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _{{$contract.Type}}.Contract.contract.Call(opts, result, method, params...) - } - - // Transfer initiates a plain transaction to move funds to the contract, calling - // its default method if one is available. - func (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.contract.Transfer(opts) - } - - // Transact invokes the (paid) contract method with params as input values. - func (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.contract.Transact(opts, method, params...) - } - - {{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 .Calls}} - // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{formatmethod .Original $structs}} - func (_{{$contract.Type}} *{{$contract.Type}}Caller) {{.Normalized.Name}}(opts *bind.CallOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} },{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}}{{end}} error) { - {{if .Structured}}ret := new(struct{ - {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}} - {{end}} - }){{else}}var ( - {{range $i, $_ := .Normalized.Outputs}}ret{{$i}} = new({{bindtype .Type $structs}}) - {{end}} - ){{end}} - out := {{if .Structured}}ret{{else}}{{if eq (len .Normalized.Outputs) 1}}ret0{{else}}&[]interface{}{ - {{range $i, $_ := .Normalized.Outputs}}ret{{$i}}, - {{end}} - }{{end}}{{end}} - err := _{{$contract.Type}}.contract.Call(opts, out, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}}) - return {{if .Structured}}*ret,{{else}}{{range $i, $_ := .Normalized.Outputs}}*ret{{$i}},{{end}}{{end}} err - } - - // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{formatmethod .Original $structs}} - func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) { - return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}}) - } - - // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{formatmethod .Original $structs}} - func (_{{$contract.Type}} *{{$contract.Type}}CallerSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) { - return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}}) - } - {{end}} - - {{range .Transacts}} - // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{formatmethod .Original $structs}} - func (_{{$contract.Type}} *{{$contract.Type}}Transactor) {{.Normalized.Name}}(opts *bind.TransactOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) { - return _{{$contract.Type}}.contract.Transact(opts, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}}) - } - - // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{formatmethod .Original $structs}} - func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}}) - } - - // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{formatmethod .Original $structs}} - func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}}) - } - {{end}} - - {{range .Events}} - // {{$contract.Type}}{{.Normalized.Name}}Iterator is returned from Filter{{.Normalized.Name}} and is used to iterate over the raw logs and unpacked data for {{.Normalized.Name}} events raised by the {{$contract.Type}} contract. - type {{$contract.Type}}{{.Normalized.Name}}Iterator struct { - Event *{{$contract.Type}}{{.Normalized.Name}} // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration - } - // Next advances the iterator to the subsequent event, returning whether there - // are any more events found. In case of a retrieval or parsing error, false is - // returned and Error() can be queried for the exact failure. - func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Next() bool { - // If the iterator failed, stop iterating - if (it.fail != nil) { - return false - } - // If the iterator completed, deliver directly whatever's available - if (it.done) { - select { - case log := <-it.logs: - it.Event = new({{$contract.Type}}{{.Normalized.Name}}) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new({{$contract.Type}}{{.Normalized.Name}}) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } - } - // Error returns any retrieval or parsing error occurred during filtering. - func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Error() error { - return it.fail - } - // Close terminates the iteration process, releasing any pending underlying - // resources. - func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Close() error { - it.sub.Unsubscribe() - return nil - } - - // {{$contract.Type}}{{.Normalized.Name}} represents a {{.Normalized.Name}} event 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}} - Raw types.Log // Blockchain specific contextual infos - } - - // Filter{{.Normalized.Name}} is a free log retrieval operation binding the contract event 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{formatevent .Original $structs}} - func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Filter{{.Normalized.Name}}(opts *bind.FilterOpts{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (*{{$contract.Type}}{{.Normalized.Name}}Iterator, error) { - {{range .Normalized.Inputs}} - {{if .Indexed}}var {{.Name}}Rule []interface{} - for _, {{.Name}}Item := range {{.Name}} { - {{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item) - }{{end}}{{end}} - - logs, sub, err := _{{$contract.Type}}.contract.FilterLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}}) - if err != nil { - return nil, err - } - return &{{$contract.Type}}{{.Normalized.Name}}Iterator{contract: _{{$contract.Type}}.contract, event: "{{.Original.Name}}", logs: logs, sub: sub}, nil - } - - // Watch{{.Normalized.Name}} is a free log subscription operation binding the contract event 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{formatevent .Original $structs}} - func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Watch{{.Normalized.Name}}(opts *bind.WatchOpts, sink chan<- *{{$contract.Type}}{{.Normalized.Name}}{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (event.Subscription, error) { - {{range .Normalized.Inputs}} - {{if .Indexed}}var {{.Name}}Rule []interface{} - for _, {{.Name}}Item := range {{.Name}} { - {{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item) - }{{end}}{{end}} - - logs, sub, err := _{{$contract.Type}}.contract.WatchLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}}) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new({{$contract.Type}}{{.Normalized.Name}}) - if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil - } - - // Parse{{.Normalized.Name}} is a log parse operation binding the contract event 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Parse{{.Normalized.Name}}(log types.Log) (*{{$contract.Type}}{{.Normalized.Name}}, error) { - event := new({{$contract.Type}}{{.Normalized.Name}}) - if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", log); err != nil { - return nil, err - } - return event, nil - } - - {{end}} -{{end}} -` - -// tmplSourceJava is the Java source template use to generate the contract binding -// based on. -const tmplSourceJava = ` -// This file is an automatically generated Java binding. Do not modify as any -// change will likely be lost upon the next re-generation! - -package {{.Package}}; - -import org.ethereum.geth.*; -import java.util.*; - -{{range $contract := .Contracts}} -{{$structs := $contract.Structs}} -{{if not .Library}}public {{end}}class {{.Type}} { - // ABI is the input ABI used to generate the binding from. - public final static String ABI = "{{.InputABI}}"; - {{if $contract.FuncSigs}} - // {{.Type}}FuncSigs maps the 4-byte function signature to its string representation. - public final static Map<String, String> {{.Type}}FuncSigs; - static { - Hashtable<String, String> temp = new Hashtable<String, String>(); - {{range $strsig, $binsig := .FuncSigs}}temp.put("{{$binsig}}", "{{$strsig}}"); - {{end}} - {{.Type}}FuncSigs = Collections.unmodifiableMap(temp); - } - {{end}} - {{if .InputBin}} - // BYTECODE is the compiled bytecode used for deploying new contracts. - public final static String BYTECODE = "0x{{.InputBin}}"; - - // deploy deploys a new Ethereum contract, binding an instance of {{.Type}} to it. - public static {{.Type}} deploy(TransactOpts auth, EthereumClient client{{range .Constructor.Inputs}}, {{bindtype .Type $structs}} {{.Name}}{{end}}) throws Exception { - Interfaces args = Geth.newInterfaces({{(len .Constructor.Inputs)}}); - String bytecode = BYTECODE; - {{if .Libraries}} - - // "link" contract to dependent libraries by deploying them first. - {{range $pattern, $name := .Libraries}} - {{capitalise $name}} {{decapitalise $name}}Inst = {{capitalise $name}}.deploy(auth, client); - bytecode = bytecode.replace("__${{$pattern}}$__", {{decapitalise $name}}Inst.Address.getHex().substring(2)); - {{end}} - {{end}} - {{range $index, $element := .Constructor.Inputs}}Interface arg{{$index}} = Geth.newInterface();arg{{$index}}.set{{namedtype (bindtype .Type $structs) .Type}}({{.Name}});args.set({{$index}},arg{{$index}}); - {{end}} - return new {{.Type}}(Geth.deployContract(auth, ABI, Geth.decodeFromHex(bytecode), client, args)); - } - - // Internal constructor used by contract deployment. - private {{.Type}}(BoundContract deployment) { - this.Address = deployment.getAddress(); - this.Deployer = deployment.getDeployer(); - this.Contract = deployment; - } - {{end}} - - // Ethereum address where this contract is located at. - public final Address Address; - - // Ethereum transaction in which this contract was deployed (if known!). - public final Transaction Deployer; - - // Contract instance bound to a blockchain address. - private final BoundContract Contract; - - // Creates a new instance of {{.Type}}, bound to a specific deployed contract. - public {{.Type}}(Address address, EthereumClient client) throws Exception { - this(Geth.bindContract(address, ABI, client)); - } - - {{range .Calls}} - {{if gt (len .Normalized.Outputs) 1}} - // {{capitalise .Normalized.Name}}Results is the output of a call to {{.Normalized.Name}}. - public class {{capitalise .Normalized.Name}}Results { - {{range $index, $item := .Normalized.Outputs}}public {{bindtype .Type $structs}} {{if ne .Name ""}}{{.Name}}{{else}}Return{{$index}}{{end}}; - {{end}} - } - {{end}} - - // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - public {{if gt (len .Normalized.Outputs) 1}}{{capitalise .Normalized.Name}}Results{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}}{{end}}{{end}} {{.Normalized.Name}}(CallOpts opts{{range .Normalized.Inputs}}, {{bindtype .Type $structs}} {{.Name}}{{end}}) throws Exception { - Interfaces args = Geth.newInterfaces({{(len .Normalized.Inputs)}}); - {{range $index, $item := .Normalized.Inputs}}Interface arg{{$index}} = Geth.newInterface();arg{{$index}}.set{{namedtype (bindtype .Type $structs) .Type}}({{.Name}});args.set({{$index}},arg{{$index}}); - {{end}} - - Interfaces results = Geth.newInterfaces({{(len .Normalized.Outputs)}}); - {{range $index, $item := .Normalized.Outputs}}Interface result{{$index}} = Geth.newInterface(); result{{$index}}.setDefault{{namedtype (bindtype .Type $structs) .Type}}(); results.set({{$index}}, result{{$index}}); - {{end}} - - if (opts == null) { - opts = Geth.newCallOpts(); - } - this.Contract.call(opts, results, "{{.Original.Name}}", args); - {{if gt (len .Normalized.Outputs) 1}} - {{capitalise .Normalized.Name}}Results result = new {{capitalise .Normalized.Name}}Results(); - {{range $index, $item := .Normalized.Outputs}}result.{{if ne .Name ""}}{{.Name}}{{else}}Return{{$index}}{{end}} = results.get({{$index}}).get{{namedtype (bindtype .Type $structs) .Type}}(); - {{end}} - return result; - {{else}}{{range .Normalized.Outputs}}return results.get(0).get{{namedtype (bindtype .Type $structs) .Type}}();{{end}} - {{end}} - } - {{end}} - - {{range .Transacts}} - // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - public Transaction {{.Normalized.Name}}(TransactOpts opts{{range .Normalized.Inputs}}, {{bindtype .Type $structs}} {{.Name}}{{end}}) throws Exception { - Interfaces args = Geth.newInterfaces({{(len .Normalized.Inputs)}}); - {{range $index, $item := .Normalized.Inputs}}Interface arg{{$index}} = Geth.newInterface();arg{{$index}}.set{{namedtype (bindtype .Type $structs) .Type}}({{.Name}});args.set({{$index}},arg{{$index}}); - {{end}} - return this.Contract.transact(opts, "{{.Original.Name}}" , args); - } - {{end}} -} -{{end}} -` diff --git a/accounts/abi/bind/topics.go b/accounts/abi/bind/topics.go deleted file mode 100644 index 58e4ff3..0000000 --- a/accounts/abi/bind/topics.go +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package bind - -import ( - "encoding/binary" - "errors" - "fmt" - "math/big" - "reflect" - - "github.com/ava-labs/coreth/accounts/abi" - "github.com/ava-labs/go-ethereum/common" - "github.com/ava-labs/go-ethereum/crypto" -) - -// makeTopics converts a filter query argument list into a filter topic set. -func makeTopics(query ...[]interface{}) ([][]common.Hash, error) { - topics := make([][]common.Hash, len(query)) - for i, filter := range query { - for _, rule := range filter { - var topic common.Hash - - // Try to generate the topic based on simple types - switch rule := rule.(type) { - case common.Hash: - copy(topic[:], rule[:]) - case common.Address: - copy(topic[common.HashLength-common.AddressLength:], rule[:]) - case *big.Int: - blob := rule.Bytes() - copy(topic[common.HashLength-len(blob):], blob) - case bool: - if rule { - topic[common.HashLength-1] = 1 - } - case int8: - blob := big.NewInt(int64(rule)).Bytes() - copy(topic[common.HashLength-len(blob):], blob) - case int16: - blob := big.NewInt(int64(rule)).Bytes() - copy(topic[common.HashLength-len(blob):], blob) - case int32: - blob := big.NewInt(int64(rule)).Bytes() - copy(topic[common.HashLength-len(blob):], blob) - case int64: - blob := big.NewInt(rule).Bytes() - copy(topic[common.HashLength-len(blob):], blob) - case uint8: - blob := new(big.Int).SetUint64(uint64(rule)).Bytes() - copy(topic[common.HashLength-len(blob):], blob) - case uint16: - blob := new(big.Int).SetUint64(uint64(rule)).Bytes() - copy(topic[common.HashLength-len(blob):], blob) - case uint32: - blob := new(big.Int).SetUint64(uint64(rule)).Bytes() - copy(topic[common.HashLength-len(blob):], blob) - case uint64: - blob := new(big.Int).SetUint64(rule).Bytes() - copy(topic[common.HashLength-len(blob):], blob) - case string: - hash := crypto.Keccak256Hash([]byte(rule)) - copy(topic[:], hash[:]) - case []byte: - hash := crypto.Keccak256Hash(rule) - copy(topic[:], hash[:]) - - default: - // Attempt to generate the topic from funky types - val := reflect.ValueOf(rule) - - switch { - - // static byte array - case val.Kind() == reflect.Array && reflect.TypeOf(rule).Elem().Kind() == reflect.Uint8: - reflect.Copy(reflect.ValueOf(topic[:val.Len()]), val) - - default: - return nil, fmt.Errorf("unsupported indexed type: %T", rule) - } - } - topics[i] = append(topics[i], topic) - } - } - return topics, nil -} - -// Big batch of reflect types for topic reconstruction. -var ( - reflectHash = reflect.TypeOf(common.Hash{}) - reflectAddress = reflect.TypeOf(common.Address{}) - reflectBigInt = reflect.TypeOf(new(big.Int)) -) - -// parseTopics converts the indexed topic fields into actual log field values. -// -// Note, dynamic types cannot be reconstructed since they get mapped to Keccak256 -// hashes as the topic value! -func parseTopics(out interface{}, fields abi.Arguments, topics []common.Hash) error { - // Sanity check that the fields and topics match up - if len(fields) != len(topics) { - return errors.New("topic/field count mismatch") - } - // Iterate over all the fields and reconstruct them from topics - for _, arg := range fields { - if !arg.Indexed { - return errors.New("non-indexed field in topic reconstruction") - } - field := reflect.ValueOf(out).Elem().FieldByName(capitalise(arg.Name)) - - // Try to parse the topic back into the fields based on primitive types - switch field.Kind() { - case reflect.Bool: - if topics[0][common.HashLength-1] == 1 { - field.Set(reflect.ValueOf(true)) - } - case reflect.Int8: - num := new(big.Int).SetBytes(topics[0][:]) - field.Set(reflect.ValueOf(int8(num.Int64()))) - - case reflect.Int16: - num := new(big.Int).SetBytes(topics[0][:]) - field.Set(reflect.ValueOf(int16(num.Int64()))) - - case reflect.Int32: - num := new(big.Int).SetBytes(topics[0][:]) - field.Set(reflect.ValueOf(int32(num.Int64()))) - - case reflect.Int64: - num := new(big.Int).SetBytes(topics[0][:]) - field.Set(reflect.ValueOf(num.Int64())) - - case reflect.Uint8: - num := new(big.Int).SetBytes(topics[0][:]) - field.Set(reflect.ValueOf(uint8(num.Uint64()))) - - case reflect.Uint16: - num := new(big.Int).SetBytes(topics[0][:]) - field.Set(reflect.ValueOf(uint16(num.Uint64()))) - - case reflect.Uint32: - num := new(big.Int).SetBytes(topics[0][:]) - field.Set(reflect.ValueOf(uint32(num.Uint64()))) - - case reflect.Uint64: - num := new(big.Int).SetBytes(topics[0][:]) - field.Set(reflect.ValueOf(num.Uint64())) - - default: - // Ran out of plain primitive types, try custom types - switch field.Type() { - case reflectHash: // Also covers all dynamic types - field.Set(reflect.ValueOf(topics[0])) - - case reflectAddress: - var addr common.Address - copy(addr[:], topics[0][common.HashLength-common.AddressLength:]) - field.Set(reflect.ValueOf(addr)) - - case reflectBigInt: - num := new(big.Int).SetBytes(topics[0][:]) - field.Set(reflect.ValueOf(num)) - - default: - // Ran out of custom types, try the crazies - switch { - - // static byte array - case arg.Type.T == abi.FixedBytesTy: - reflect.Copy(field, reflect.ValueOf(topics[0][:arg.Type.Size])) - - default: - return fmt.Errorf("unsupported indexed type: %v", arg.Type) - } - } - } - topics = topics[1:] - } - return nil -} - -// parseTopicsIntoMap converts the indexed topic field-value pairs into map key-value pairs -func parseTopicsIntoMap(out map[string]interface{}, fields abi.Arguments, topics []common.Hash) error { - // Sanity check that the fields and topics match up - if len(fields) != len(topics) { - return errors.New("topic/field count mismatch") - } - // Iterate over all the fields and reconstruct them from topics - for _, arg := range fields { - if !arg.Indexed { - return errors.New("non-indexed field in topic reconstruction") - } - - switch arg.Type.T { - case abi.BoolTy: - out[arg.Name] = topics[0][common.HashLength-1] == 1 - case abi.IntTy, abi.UintTy: - num := new(big.Int).SetBytes(topics[0][:]) - out[arg.Name] = num - case abi.AddressTy: - var addr common.Address - copy(addr[:], topics[0][common.HashLength-common.AddressLength:]) - out[arg.Name] = addr - case abi.HashTy: - out[arg.Name] = topics[0] - case abi.FixedBytesTy: - out[arg.Name] = topics[0][:] - case abi.StringTy, abi.BytesTy, abi.SliceTy, abi.ArrayTy: - // Array types (including strings and bytes) have their keccak256 hashes stored in the topic- not a hash - // whose bytes can be decoded to the actual value- so the best we can do is retrieve that hash - out[arg.Name] = topics[0] - case abi.FunctionTy: - if garbage := binary.BigEndian.Uint64(topics[0][0:8]); garbage != 0 { - return fmt.Errorf("bind: got improperly encoded function type, got %v", topics[0].Bytes()) - } - var tmp [24]byte - copy(tmp[:], topics[0][8:32]) - out[arg.Name] = tmp - default: // Not handling tuples - return fmt.Errorf("unsupported indexed type: %v", arg.Type) - } - - topics = topics[1:] - } - - return nil -} diff --git a/accounts/abi/bind/util.go b/accounts/abi/bind/util.go deleted file mode 100644 index b3ec22c..0000000 --- a/accounts/abi/bind/util.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package bind - -import ( - "context" - "fmt" - "time" - - "github.com/ava-labs/coreth/core/types" - "github.com/ava-labs/go-ethereum/common" - "github.com/ava-labs/go-ethereum/log" -) - -// WaitMined waits for tx to be mined on the blockchain. -// It stops waiting when the context is canceled. -func WaitMined(ctx context.Context, b DeployBackend, tx *types.Transaction) (*types.Receipt, error) { - queryTicker := time.NewTicker(time.Second) - defer queryTicker.Stop() - - logger := log.New("hash", tx.Hash()) - for { - receipt, err := b.TransactionReceipt(ctx, tx.Hash()) - if receipt != nil { - return receipt, nil - } - if err != nil { - logger.Trace("Receipt retrieval failed", "err", err) - } else { - logger.Trace("Transaction not yet mined") - } - // Wait for the next round. - select { - case <-ctx.Done(): - return nil, ctx.Err() - case <-queryTicker.C: - } - } -} - -// WaitDeployed waits for a contract deployment transaction and returns the on-chain -// contract address when it is mined. It stops waiting when ctx is canceled. -func WaitDeployed(ctx context.Context, b DeployBackend, tx *types.Transaction) (common.Address, error) { - if tx.To() != nil { - return common.Address{}, fmt.Errorf("tx is not contract creation") - } - receipt, err := WaitMined(ctx, b, tx) - if err != nil { - return common.Address{}, err - } - if receipt.ContractAddress == (common.Address{}) { - return common.Address{}, fmt.Errorf("zero address") - } - // Check that code has indeed been deployed at the address. - // This matters on pre-Homestead chains: OOG in the constructor - // could leave an empty account behind. - code, err := b.CodeAt(ctx, receipt.ContractAddress, nil) - if err == nil && len(code) == 0 { - err = ErrNoCodeAfterDeploy - } - return receipt.ContractAddress, err -} diff --git a/accounts/abi/doc.go b/accounts/abi/doc.go deleted file mode 100644 index 8242068..0000000 --- a/accounts/abi/doc.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -// Package abi implements the Ethereum ABI (Application Binary -// Interface). -// -// The Ethereum ABI is strongly typed, known at compile time -// and static. This ABI will handle basic type casting; unsigned -// to signed and visa versa. It does not handle slice casting such -// as unsigned slice to signed slice. Bit size type casting is also -// handled. ints with a bit size of 32 will be properly cast to int256, -// etc. -package abi diff --git a/accounts/abi/error.go b/accounts/abi/error.go deleted file mode 100644 index 9d8674a..0000000 --- a/accounts/abi/error.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package abi - -import ( - "errors" - "fmt" - "reflect" -) - -var ( - errBadBool = errors.New("abi: improperly encoded boolean value") -) - -// formatSliceString formats the reflection kind with the given slice size -// and returns a formatted string representation. -func formatSliceString(kind reflect.Kind, sliceSize int) string { - if sliceSize == -1 { - return fmt.Sprintf("[]%v", kind) - } - return fmt.Sprintf("[%d]%v", sliceSize, kind) -} - -// sliceTypeCheck checks that the given slice can by assigned to the reflection -// type in t. -func sliceTypeCheck(t Type, val reflect.Value) error { - if val.Kind() != reflect.Slice && val.Kind() != reflect.Array { - return typeErr(formatSliceString(t.Kind, t.Size), val.Type()) - } - - if t.T == ArrayTy && val.Len() != t.Size { - return typeErr(formatSliceString(t.Elem.Kind, t.Size), formatSliceString(val.Type().Elem().Kind(), val.Len())) - } - - if t.Elem.T == SliceTy { - if val.Len() > 0 { - return sliceTypeCheck(*t.Elem, val.Index(0)) - } - } else if t.Elem.T == ArrayTy { - return sliceTypeCheck(*t.Elem, val.Index(0)) - } - - if elemKind := val.Type().Elem().Kind(); elemKind != t.Elem.Kind { - return typeErr(formatSliceString(t.Elem.Kind, t.Size), val.Type()) - } - return nil -} - -// typeCheck checks that the given reflection value can be assigned to the reflection -// type in t. -func typeCheck(t Type, value reflect.Value) error { - if t.T == SliceTy || t.T == ArrayTy { - return sliceTypeCheck(t, value) - } - - // Check base type validity. Element types will be checked later on. - if t.Kind != value.Kind() { - return typeErr(t.Kind, value.Kind()) - } else if t.T == FixedBytesTy && t.Size != value.Len() { - return typeErr(t.Type, value.Type()) - } else { - return nil - } - -} - -// typeErr returns a formatted type casting error. -func typeErr(expected, got interface{}) error { - return fmt.Errorf("abi: cannot use %v as type %v as argument", got, expected) -} diff --git a/accounts/abi/event.go b/accounts/abi/event.go deleted file mode 100644 index 7a41baa..0000000 --- a/accounts/abi/event.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package abi - -import ( - "fmt" - "strings" - - "github.com/ava-labs/go-ethereum/common" - "github.com/ava-labs/go-ethereum/crypto" -) - -// Event is an event potentially triggered by the EVM's LOG mechanism. The Event -// holds type information (inputs) about the yielded output. Anonymous events -// don't get the signature canonical representation as the first LOG topic. -type Event struct { - // Name is the event name used for internal representation. It's derived from - // the raw name and a suffix will be added in the case of a event overload. - // - // e.g. - // There are two events have same name: - // * foo(int,int) - // * foo(uint,uint) - // The event name of the first one wll be resolved as foo while the second one - // will be resolved as foo0. - Name string - // RawName is the raw event name parsed from ABI. - RawName string - Anonymous bool - Inputs Arguments -} - -func (e Event) String() string { - inputs := make([]string, len(e.Inputs)) - for i, input := range e.Inputs { - inputs[i] = fmt.Sprintf("%v %v", input.Type, input.Name) - if input.Indexed { - inputs[i] = fmt.Sprintf("%v indexed %v", input.Type, input.Name) - } - } - return fmt.Sprintf("event %v(%v)", e.RawName, strings.Join(inputs, ", ")) -} - -// Sig returns the event string signature according to the ABI spec. -// -// Example -// -// event foo(uint32 a, int b) = "foo(uint32,int256)" -// -// Please note that "int" is substitute for its canonical representation "int256" -func (e Event) Sig() string { - types := make([]string, len(e.Inputs)) - for i, input := range e.Inputs { - types[i] = input.Type.String() - } - return fmt.Sprintf("%v(%v)", e.RawName, strings.Join(types, ",")) -} - -// ID returns the canonical representation of the event's signature used by the -// abi definition to identify event names and types. -func (e Event) ID() common.Hash { - return common.BytesToHash(crypto.Keccak256([]byte(e.Sig()))) -} diff --git a/accounts/abi/method.go b/accounts/abi/method.go deleted file mode 100644 index 9cceaba..0000000 --- a/accounts/abi/method.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package abi - -import ( - "fmt" - "strings" - - "github.com/ava-labs/go-ethereum/crypto" -) - -// Method represents a callable given a `Name` and whether the method is a constant. -// If the method is `Const` no transaction needs to be created for this -// particular Method call. It can easily be simulated using a local VM. -// For example a `Balance()` method only needs to retrieve something -// from the storage and therefore requires no Tx to be send to the -// network. A method such as `Transact` does require a Tx and thus will -// be flagged `false`. -// Input specifies the required input parameters for this gives method. -type Method struct { - // Name is the method name used for internal representation. It's derived from - // the raw name and a suffix will be added in the case of a function overload. - // - // e.g. - // There are two functions have same name: - // * foo(int,int) - // * foo(uint,uint) - // The method name of the first one will be resolved as foo while the second one - // will be resolved as foo0. - Name string - // RawName is the raw method name parsed from ABI. - RawName string - Const bool - Inputs Arguments - Outputs Arguments -} - -// Sig returns the methods string signature according to the ABI spec. -// -// Example -// -// function foo(uint32 a, int b) = "foo(uint32,int256)" -// -// Please note that "int" is substitute for its canonical representation "int256" -func (method Method) Sig() string { - types := make([]string, len(method.Inputs)) - for i, input := range method.Inputs { - types[i] = input.Type.String() - } - return fmt.Sprintf("%v(%v)", method.RawName, strings.Join(types, ",")) -} - -func (method Method) String() string { - inputs := make([]string, len(method.Inputs)) - for i, input := range method.Inputs { - inputs[i] = fmt.Sprintf("%v %v", input.Type, input.Name) - } - outputs := make([]string, len(method.Outputs)) - for i, output := range method.Outputs { - outputs[i] = output.Type.String() - if len(output.Name) > 0 { - outputs[i] += fmt.Sprintf(" %v", output.Name) - } - } - constant := "" - if method.Const { - constant = "constant " - } - return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.RawName, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", ")) -} - -// ID returns the canonical representation of the method's signature used by the -// abi definition to identify method names and types. -func (method Method) ID() []byte { - return crypto.Keccak256([]byte(method.Sig()))[:4] -} diff --git a/accounts/abi/numbers.go b/accounts/abi/numbers.go deleted file mode 100644 index c2e844c..0000000 --- a/accounts/abi/numbers.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package abi - -import ( - "math/big" - "reflect" - - "github.com/ava-labs/go-ethereum/common" - "github.com/ava-labs/go-ethereum/common/math" -) - -var ( - bigT = reflect.TypeOf(&big.Int{}) - derefbigT = reflect.TypeOf(big.Int{}) - uint8T = reflect.TypeOf(uint8(0)) - uint16T = reflect.TypeOf(uint16(0)) - uint32T = reflect.TypeOf(uint32(0)) - uint64T = reflect.TypeOf(uint64(0)) - int8T = reflect.TypeOf(int8(0)) - int16T = reflect.TypeOf(int16(0)) - int32T = reflect.TypeOf(int32(0)) - int64T = reflect.TypeOf(int64(0)) - addressT = reflect.TypeOf(common.Address{}) -) - -// U256 converts a big Int into a 256bit EVM number. -func U256(n *big.Int) []byte { - return math.PaddedBigBytes(math.U256(n), 32) -} diff --git a/accounts/abi/pack.go b/accounts/abi/pack.go deleted file mode 100644 index d88dde8..0000000 --- a/accounts/abi/pack.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package abi - -import ( - "math/big" - "reflect" - - "github.com/ava-labs/go-ethereum/common" - "github.com/ava-labs/go-ethereum/common/math" -) - -// packBytesSlice packs the given bytes as [L, V] as the canonical representation -// bytes slice -func packBytesSlice(bytes []byte, l int) []byte { - len := packNum(reflect.ValueOf(l)) - return append(len, common.RightPadBytes(bytes, (l+31)/32*32)...) -} - -// packElement packs the given reflect value according to the abi specification in -// t. -func packElement(t Type, reflectValue reflect.Value) []byte { - switch t.T { - case IntTy, UintTy: - return packNum(reflectValue) - case StringTy: - return packBytesSlice([]byte(reflectValue.String()), reflectValue.Len()) - case AddressTy: - if reflectValue.Kind() == reflect.Array { - reflectValue = mustArrayToByteSlice(reflectValue) - } - - return common.LeftPadBytes(reflectValue.Bytes(), 32) - case BoolTy: - if reflectValue.Bool() { - return math.PaddedBigBytes(common.Big1, 32) - } - return math.PaddedBigBytes(common.Big0, 32) - case BytesTy: - if reflectValue.Kind() == reflect.Array { - reflectValue = mustArrayToByteSlice(reflectValue) - } - return packBytesSlice(reflectValue.Bytes(), reflectValue.Len()) - case FixedBytesTy, FunctionTy: - if reflectValue.Kind() == reflect.Array { - reflectValue = mustArrayToByteSlice(reflectValue) - } - return common.RightPadBytes(reflectValue.Bytes(), 32) - default: - panic("abi: fatal error") - } -} - -// packNum packs the given number (using the reflect value) and will cast it to appropriate number representation -func packNum(value reflect.Value) []byte { - switch kind := value.Kind(); kind { - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return U256(new(big.Int).SetUint64(value.Uint())) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return U256(big.NewInt(value.Int())) - case reflect.Ptr: - return U256(value.Interface().(*big.Int)) - default: - panic("abi: fatal error") - } - -} diff --git a/accounts/abi/reflect.go b/accounts/abi/reflect.go deleted file mode 100644 index 73ca8fa..0000000 --- a/accounts/abi/reflect.go +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package abi - -import ( - "fmt" - "reflect" - "strings" -) - -// indirect recursively dereferences the value until it either gets the value -// or finds a big.Int -func indirect(v reflect.Value) reflect.Value { - if v.Kind() == reflect.Ptr && v.Elem().Type() != derefbigT { - return indirect(v.Elem()) - } - return v -} - -// indirectInterfaceOrPtr recursively dereferences the value until value is not interface. -func indirectInterfaceOrPtr(v reflect.Value) reflect.Value { - if (v.Kind() == reflect.Interface || v.Kind() == reflect.Ptr) && v.Elem().IsValid() { - return indirect(v.Elem()) - } - return v -} - -// reflectIntKind returns the reflect using the given size and -// unsignedness. -func reflectIntKindAndType(unsigned bool, size int) (reflect.Kind, reflect.Type) { - switch size { - case 8: - if unsigned { - return reflect.Uint8, uint8T - } - return reflect.Int8, int8T - case 16: - if unsigned { - return reflect.Uint16, uint16T - } - return reflect.Int16, int16T - case 32: - if unsigned { - return reflect.Uint32, uint32T - } - return reflect.Int32, int32T - case 64: - if unsigned { - return reflect.Uint64, uint64T - } - return reflect.Int64, int64T - } - return reflect.Ptr, bigT -} - -// mustArrayToBytesSlice creates a new byte slice with the exact same size as value -// and copies the bytes in value to the new slice. -func mustArrayToByteSlice(value reflect.Value) reflect.Value { - slice := reflect.MakeSlice(reflect.TypeOf([]byte{}), value.Len(), value.Len()) - reflect.Copy(slice, value) - return slice -} - -// set attempts to assign src to dst by either setting, copying or otherwise. -// -// set is a bit more lenient when it comes to assignment and doesn't force an as -// strict ruleset as bare `reflect` does. -func set(dst, src reflect.Value) error { - dstType, srcType := dst.Type(), src.Type() - switch { - case dstType.Kind() == reflect.Interface && dst.Elem().IsValid(): - return set(dst.Elem(), src) - case dstType.Kind() == reflect.Ptr && dstType.Elem() != derefbigT: - return set(dst.Elem(), src) - case srcType.AssignableTo(dstType) && dst.CanSet(): - dst.Set(src) - case dstType.Kind() == reflect.Slice && srcType.Kind() == reflect.Slice: - return setSlice(dst, src) - default: - return fmt.Errorf("abi: cannot unmarshal %v in to %v", src.Type(), dst.Type()) - } - return nil -} - -// setSlice attempts to assign src to dst when slices are not assignable by default -// e.g. src: [][]byte -> dst: [][15]byte -func setSlice(dst, src reflect.Value) error { - slice := reflect.MakeSlice(dst.Type(), src.Len(), src.Len()) - for i := 0; i < src.Len(); i++ { - v := src.Index(i) - reflect.Copy(slice.Index(i), v) - } - - dst.Set(slice) - return nil -} - -// requireAssignable assures that `dest` is a pointer and it's not an interface. -func requireAssignable(dst, src reflect.Value) error { - if dst.Kind() != reflect.Ptr && dst.Kind() != reflect.Interface { - return fmt.Errorf("abi: cannot unmarshal %v into %v", src.Type(), dst.Type()) - } - return nil -} - -// requireUnpackKind verifies preconditions for unpacking `args` into `kind` -func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind, - args Arguments) error { - - switch k { - case reflect.Struct: - case reflect.Slice, reflect.Array: - if minLen := args.LengthNonIndexed(); v.Len() < minLen { - return fmt.Errorf("abi: insufficient number of elements in the list/array for unpack, want %d, got %d", - minLen, v.Len()) - } - default: - return fmt.Errorf("abi: cannot unmarshal tuple into %v", t) - } - return nil -} - -// mapArgNamesToStructFields maps a slice of argument names to struct fields. -// first round: for each Exportable field that contains a `abi:""` tag -// and this field name exists in the given argument name list, pair them together. -// second round: for each argument name that has not been already linked, -// find what variable is expected to be mapped into, if it exists and has not been -// used, pair them. -// Note this function assumes the given value is a struct value. -func mapArgNamesToStructFields(argNames []string, value reflect.Value) (map[string]string, error) { - typ := value.Type() - - abi2struct := make(map[string]string) - struct2abi := make(map[string]string) - - // first round ~~~ - for i := 0; i < typ.NumField(); i++ { - structFieldName := typ.Field(i).Name - - // skip private struct fields. - if structFieldName[:1] != strings.ToUpper(structFieldName[:1]) { - continue - } - // skip fields that have no abi:"" tag. - var ok bool - var tagName string - if tagName, ok = typ.Field(i).Tag.Lookup("abi"); !ok { - continue - } - // check if tag is empty. - if tagName == "" { - return nil, fmt.Errorf("struct: abi tag in '%s' is empty", structFieldName) - } - // check which argument field matches with the abi tag. - found := false - for _, arg := range argNames { - if arg == tagName { - if abi2struct[arg] != "" { - return nil, fmt.Errorf("struct: abi tag in '%s' already mapped", structFieldName) - } - // pair them - abi2struct[arg] = structFieldName - struct2abi[structFieldName] = arg - found = true - } - } - // check if this tag has been mapped. - if !found { - return nil, fmt.Errorf("struct: abi tag '%s' defined but not found in abi", tagName) - } - } - - // second round ~~~ - for _, argName := range argNames { - - structFieldName := ToCamelCase(argName) - - if structFieldName == "" { - return nil, fmt.Errorf("abi: purely underscored output cannot unpack to struct") - } - - // this abi has already been paired, skip it... unless there exists another, yet unassigned - // struct field with the same field name. If so, raise an error: - // abi: [ { "name": "value" } ] - // struct { Value *big.Int , Value1 *big.Int `abi:"value"`} - if abi2struct[argName] != "" { - if abi2struct[argName] != structFieldName && - struct2abi[structFieldName] == "" && - value.FieldByName(structFieldName).IsValid() { - return nil, fmt.Errorf("abi: multiple variables maps to the same abi field '%s'", argName) - } - continue - } - - // return an error if this struct field has already been paired. - if struct2abi[structFieldName] != "" { - return nil, fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", structFieldName) - } - - if value.FieldByName(structFieldName).IsValid() { - // pair them - abi2struct[argName] = structFieldName - struct2abi[structFieldName] = argName - } else { - // not paired, but annotate as used, to detect cases like - // abi : [ { "name": "value" }, { "name": "_value" } ] - // struct { Value *big.Int } - struct2abi[structFieldName] = argName - } - } - return abi2struct, nil -} diff --git a/accounts/abi/type.go b/accounts/abi/type.go deleted file mode 100644 index 597d314..0000000 --- a/accounts/abi/type.go +++ /dev/null @@ -1,348 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package abi - -import ( - "errors" - "fmt" - "reflect" - "regexp" - "strconv" - "strings" -) - -// Type enumerator -const ( - IntTy byte = iota - UintTy - BoolTy - StringTy - SliceTy - ArrayTy - TupleTy - AddressTy - FixedBytesTy - BytesTy - HashTy - FixedPointTy - FunctionTy -) - -// Type is the reflection of the supported argument type -type Type struct { - Elem *Type - Kind reflect.Kind - Type reflect.Type - Size int - T byte // Our own type checking - - stringKind string // holds the unparsed string for deriving signatures - - // Tuple relative fields - TupleElems []*Type // Type information of all tuple fields - TupleRawNames []string // Raw field name of all tuple fields -} - -var ( - // typeRegex parses the abi sub types - typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?") -) - -// NewType creates a new reflection type of abi type given in t. -func NewType(t string, components []ArgumentMarshaling) (typ Type, err error) { - // check that array brackets are equal if they exist - if strings.Count(t, "[") != strings.Count(t, "]") { - return Type{}, fmt.Errorf("invalid arg type in abi") - } - typ.stringKind = t - - // if there are brackets, get ready to go into slice/array mode and - // recursively create the type - if strings.Count(t, "[") != 0 { - i := strings.LastIndex(t, "[") - // recursively embed the type - embeddedType, err := NewType(t[:i], components) - if err != nil { - return Type{}, err - } - // grab the last cell and create a type from there - sliced := t[i:] - // grab the slice size with regexp - re := regexp.MustCompile("[0-9]+") - intz := re.FindAllString(sliced, -1) - - if len(intz) == 0 { - // is a slice - typ.T = SliceTy - typ.Kind = reflect.Slice - typ.Elem = &embeddedType - typ.Type = reflect.SliceOf(embeddedType.Type) - typ.stringKind = embeddedType.stringKind + sliced - } else if len(intz) == 1 { - // is a array - typ.T = ArrayTy - typ.Kind = reflect.Array - typ.Elem = &embeddedType - typ.Size, err = strconv.Atoi(intz[0]) - if err != nil { - return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) - } - typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type) - typ.stringKind = embeddedType.stringKind + sliced - } else { - return Type{}, fmt.Errorf("invalid formatting of array type") - } - return typ, err - } - // parse the type and size of the abi-type. - matches := typeRegex.FindAllStringSubmatch(t, -1) - if len(matches) == 0 { - return Type{}, fmt.Errorf("invalid type '%v'", t) - } - parsedType := matches[0] - - // varSize is the size of the variable - var varSize int - if len(parsedType[3]) > 0 { - var err error - varSize, err = strconv.Atoi(parsedType[2]) - if err != nil { - return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) - } - } else { - if parsedType[0] == "uint" || parsedType[0] == "int" { - // this should fail because it means that there's something wrong with - // the abi type (the compiler should always format it to the size...always) - return Type{}, fmt.Errorf("unsupported arg type: %s", t) - } - } - // varType is the parsed abi type - switch varType := parsedType[1]; varType { - case "int": - typ.Kind, typ.Type = reflectIntKindAndType(false, varSize) - typ.Size = varSize - typ.T = IntTy - case "uint": - typ.Kind, typ.Type = reflectIntKindAndType(true, varSize) - typ.Size = varSize - typ.T = UintTy - case "bool": - typ.Kind = reflect.Bool - typ.T = BoolTy - typ.Type = reflect.TypeOf(bool(false)) - case "address": - typ.Kind = reflect.Array - typ.Type = addressT - typ.Size = 20 - typ.T = AddressTy - case "string": - typ.Kind = reflect.String - typ.Type = reflect.TypeOf("") - typ.T = StringTy - case "bytes": - if varSize == 0 { - typ.T = BytesTy - typ.Kind = reflect.Slice - typ.Type = reflect.SliceOf(reflect.TypeOf(byte(0))) - } else { - typ.T = FixedBytesTy - typ.Kind = reflect.Array - typ.Size = varSize - typ.Type = reflect.ArrayOf(varSize, reflect.TypeOf(byte(0))) - } - case "tuple": - var ( - fields []reflect.StructField - elems []*Type - names []string - expression string // canonical parameter expression - ) - expression += "(" - for idx, c := range components { - cType, err := NewType(c.Type, c.Components) - if err != nil { - return Type{}, err - } - if ToCamelCase(c.Name) == "" { - return Type{}, errors.New("abi: purely anonymous or underscored field is not supported") - } - fields = append(fields, reflect.StructField{ - Name: ToCamelCase(c.Name), // reflect.StructOf will panic for any exported field. - Type: cType.Type, - Tag: reflect.StructTag("json:\"" + c.Name + "\""), - }) - elems = append(elems, &cType) - names = append(names, c.Name) - expression += cType.stringKind - if idx != len(components)-1 { - expression += "," - } - } - expression += ")" - typ.Kind = reflect.Struct - typ.Type = reflect.StructOf(fields) - typ.TupleElems = elems - typ.TupleRawNames = names - typ.T = TupleTy - typ.stringKind = expression - case "function": - typ.Kind = reflect.Array - typ.T = FunctionTy - typ.Size = 24 - typ.Type = reflect.ArrayOf(24, reflect.TypeOf(byte(0))) - default: - return Type{}, fmt.Errorf("unsupported arg type: %s", t) - } - - return -} - -// String implements Stringer -func (t Type) String() (out string) { - return t.stringKind -} - -func (t Type) pack(v reflect.Value) ([]byte, error) { - // dereference pointer first if it's a pointer - v = indirect(v) - if err := typeCheck(t, v); err != nil { - return nil, err - } - - switch t.T { - case SliceTy, ArrayTy: - var ret []byte - - if t.requiresLengthPrefix() { - // append length - ret = append(ret, packNum(reflect.ValueOf(v.Len()))...) - } - - // calculate offset if any - offset := 0 - offsetReq := isDynamicType(*t.Elem) - if offsetReq { - offset = getTypeSize(*t.Elem) * v.Len() - } - var tail []byte - for i := 0; i < v.Len(); i++ { - val, err := t.Elem.pack(v.Index(i)) - if err != nil { - return nil, err - } - if !offsetReq { - ret = append(ret, val...) - continue - } - ret = append(ret, packNum(reflect.ValueOf(offset))...) - offset += len(val) - tail = append(tail, val...) - } - return append(ret, tail...), nil - case TupleTy: - // (T1,...,Tk) for k >= 0 and any types T1, …, Tk - // enc(X) = head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(k)) - // where X = (X(1), ..., X(k)) and head and tail are defined for Ti being a static - // type as - // head(X(i)) = enc(X(i)) and tail(X(i)) = "" (the empty string) - // and as - // head(X(i)) = enc(len(head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(i-1)))) - // tail(X(i)) = enc(X(i)) - // otherwise, i.e. if Ti is a dynamic type. - fieldmap, err := mapArgNamesToStructFields(t.TupleRawNames, v) - if err != nil { - return nil, err - } - // Calculate prefix occupied size. - offset := 0 - for _, elem := range t.TupleElems { - offset += getTypeSize(*elem) - } - var ret, tail []byte - for i, elem := range t.TupleElems { - field := v.FieldByName(fieldmap[t.TupleRawNames[i]]) - if !field.IsValid() { - return nil, fmt.Errorf("field %s for tuple not found in the given struct", t.TupleRawNames[i]) - } - val, err := elem.pack(field) - if err != nil { - return nil, err - } - if isDynamicType(*elem) { - ret = append(ret, packNum(reflect.ValueOf(offset))...) - tail = append(tail, val...) - offset += len(val) - } else { - ret = append(ret, val...) - } - } - return append(ret, tail...), nil - - default: - return packElement(t, v), nil - } -} - -// requireLengthPrefix returns whether the type requires any sort of length -// prefixing. -func (t Type) requiresLengthPrefix() bool { - return t.T == StringTy || t.T == BytesTy || t.T == SliceTy -} - -// isDynamicType returns true if the type is dynamic. -// The following types are called “dynamic”: -// * bytes -// * string -// * T[] for any T -// * T[k] for any dynamic T and any k >= 0 -// * (T1,...,Tk) if Ti is dynamic for some 1 <= i <= k -func isDynamicType(t Type) bool { - if t.T == TupleTy { - for _, elem := range t.TupleElems { - if isDynamicType(*elem) { - return true - } - } - return false - } - return t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && isDynamicType(*t.Elem)) -} - -// getTypeSize returns the size that this type needs to occupy. -// We distinguish static and dynamic types. Static types are encoded in-place -// and dynamic types are encoded at a separately allocated location after the -// current block. -// So for a static variable, the size returned represents the size that the -// variable actually occupies. -// For a dynamic variable, the returned size is fixed 32 bytes, which is used -// to store the location reference for actual value storage. -func getTypeSize(t Type) int { - if t.T == ArrayTy && !isDynamicType(*t.Elem) { - // Recursively calculate type size if it is a nested array - if t.Elem.T == ArrayTy { - return t.Size * getTypeSize(*t.Elem) - } - return t.Size * 32 - } else if t.T == TupleTy && !isDynamicType(t) { - total := 0 - for _, elem := range t.TupleElems { - total += getTypeSize(*elem) - } - return total - } - return 32 -} diff --git a/accounts/abi/unpack.go b/accounts/abi/unpack.go deleted file mode 100644 index d3cd310..0000000 --- a/accounts/abi/unpack.go +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package abi - -import ( - "encoding/binary" - "fmt" - "math/big" - "reflect" - - "github.com/ava-labs/go-ethereum/common" -) - -var ( - maxUint256 = big.NewInt(0).Add( - big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil), - big.NewInt(-1)) - maxInt256 = big.NewInt(0).Add( - big.NewInt(0).Exp(big.NewInt(2), big.NewInt(255), nil), - big.NewInt(-1)) -) - -// reads the integer based on its kind -func readInteger(typ byte, kind reflect.Kind, b []byte) interface{} { - switch kind { - case reflect.Uint8: - return b[len(b)-1] - case reflect.Uint16: - return binary.BigEndian.Uint16(b[len(b)-2:]) - case reflect.Uint32: - return binary.BigEndian.Uint32(b[len(b)-4:]) - case reflect.Uint64: - return binary.BigEndian.Uint64(b[len(b)-8:]) - case reflect.Int8: - return int8(b[len(b)-1]) - case reflect.Int16: - return int16(binary.BigEndian.Uint16(b[len(b)-2:])) - case reflect.Int32: - return int32(binary.BigEndian.Uint32(b[len(b)-4:])) - case reflect.Int64: - return int64(binary.BigEndian.Uint64(b[len(b)-8:])) - default: - // the only case lefts for integer is int256/uint256. - // big.SetBytes can't tell if a number is negative, positive on itself. - // On EVM, if the returned number > max int256, it is negative. - ret := new(big.Int).SetBytes(b) - if typ == UintTy { - return ret - } - - if ret.Cmp(maxInt256) > 0 { - ret.Add(maxUint256, big.NewInt(0).Neg(ret)) - ret.Add(ret, big.NewInt(1)) - ret.Neg(ret) - } - return ret - } -} - -// reads a bool -func readBool(word []byte) (bool, error) { - for _, b := range word[:31] { - if b != 0 { - return false, errBadBool - } - } - switch word[31] { - case 0: - return false, nil - case 1: - return true, nil - default: - return false, errBadBool - } -} - -// A function type is simply the address with the function selection signature at the end. -// This enforces that standard by always presenting it as a 24-array (address + sig = 24 bytes) -func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) { - if t.T != FunctionTy { - return [24]byte{}, fmt.Errorf("abi: invalid type in call to make function type byte array") - } - if garbage := binary.BigEndian.Uint64(word[24:32]); garbage != 0 { - err = fmt.Errorf("abi: got improperly encoded function type, got %v", word) - } else { - copy(funcTy[:], word[0:24]) - } - return -} - -// through reflection, creates a fixed array to be read from -func readFixedBytes(t Type, word []byte) (interface{}, error) { - if t.T != FixedBytesTy { - return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array") - } - // convert - array := reflect.New(t.Type).Elem() - - reflect.Copy(array, reflect.ValueOf(word[0:t.Size])) - return array.Interface(), nil - -} - -// iteratively unpack elements -func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) { - if size < 0 { - return nil, fmt.Errorf("cannot marshal input to array, size is negative (%d)", size) - } - if start+32*size > len(output) { - return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), start+32*size) - } - - // this value will become our slice or our array, depending on the type - var refSlice reflect.Value - - if t.T == SliceTy { - // declare our slice - refSlice = reflect.MakeSlice(t.Type, size, size) - } else if t.T == ArrayTy { - // declare our array - refSlice = reflect.New(t.Type).Elem() - } else { - return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage") - } - - // Arrays have packed elements, resulting in longer unpack steps. - // Slices have just 32 bytes per element (pointing to the contents). - elemSize := getTypeSize(*t.Elem) - - for i, j := start, 0; j < size; i, j = i+elemSize, j+1 { - inter, err := toGoType(i, *t.Elem, output) - if err != nil { - return nil, err - } - - // append the item to our reflect slice - refSlice.Index(j).Set(reflect.ValueOf(inter)) - } - - // return the interface - return refSlice.Interface(), nil -} - -func forTupleUnpack(t Type, output []byte) (interface{}, error) { - retval := reflect.New(t.Type).Elem() - virtualArgs := 0 - for index, elem := range t.TupleElems { - marshalledValue, err := toGoType((index+virtualArgs)*32, *elem, output) - if elem.T == ArrayTy && !isDynamicType(*elem) { - // If we have a static array, like [3]uint256, these are coded as - // just like uint256,uint256,uint256. - // This means that we need to add two 'virtual' arguments when - // we count the index from now on. - // - // Array values nested multiple levels deep are also encoded inline: - // [2][3]uint256: uint256,uint256,uint256,uint256,uint256,uint256 - // - // Calculate the full array size to get the correct offset for the next argument. - // Decrement it by 1, as the normal index increment is still applied. - virtualArgs += getTypeSize(*elem)/32 - 1 - } else if elem.T == TupleTy && !isDynamicType(*elem) { - // If we have a static tuple, like (uint256, bool, uint256), these are - // coded as just like uint256,bool,uint256 - virtualArgs += getTypeSize(*elem)/32 - 1 - } - if err != nil { - return nil, err - } - retval.Field(index).Set(reflect.ValueOf(marshalledValue)) - } - return retval.Interface(), nil -} - -// toGoType parses the output bytes and recursively assigns the value of these bytes -// into a go type with accordance with the ABI spec. -func toGoType(index int, t Type, output []byte) (interface{}, error) { - if index+32 > len(output) { - return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), index+32) - } - - var ( - returnOutput []byte - begin, length int - err error - ) - - // if we require a length prefix, find the beginning word and size returned. - if t.requiresLengthPrefix() { - begin, length, err = lengthPrefixPointsTo(index, output) - if err != nil { - return nil, err - } - } else { - returnOutput = output[index : index+32] - } - - switch t.T { - case TupleTy: - if isDynamicType(t) { - begin, err := tuplePointsTo(index, output) - if err != nil { - return nil, err - } - return forTupleUnpack(t, output[begin:]) - } else { - return forTupleUnpack(t, output[index:]) - } - case SliceTy: - return forEachUnpack(t, output[begin:], 0, length) - case ArrayTy: - if isDynamicType(*t.Elem) { - offset := int64(binary.BigEndian.Uint64(returnOutput[len(returnOutput)-8:])) - return forEachUnpack(t, output[offset:], 0, t.Size) - } - return forEachUnpack(t, output[index:], 0, t.Size) - case StringTy: // variable arrays are written at the end of the return bytes - return string(output[begin : begin+length]), nil - case IntTy, UintTy: - return readInteger(t.T, t.Kind, returnOutput), nil - case BoolTy: - return readBool(returnOutput) - case AddressTy: - return common.BytesToAddress(returnOutput), nil - case HashTy: - return common.BytesToHash(returnOutput), nil - case BytesTy: - return output[begin : begin+length], nil - case FixedBytesTy: - return readFixedBytes(t, returnOutput) - case FunctionTy: - return readFunctionType(t, returnOutput) - default: - return nil, fmt.Errorf("abi: unknown type %v", t.T) - } -} - -// interprets a 32 byte slice as an offset and then determines which indice to look to decode the type. -func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) { - bigOffsetEnd := big.NewInt(0).SetBytes(output[index : index+32]) - bigOffsetEnd.Add(bigOffsetEnd, common.Big32) - outputLength := big.NewInt(int64(len(output))) - - if bigOffsetEnd.Cmp(outputLength) > 0 { - return 0, 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %v would go over slice boundary (len=%v)", bigOffsetEnd, outputLength) - } - - if bigOffsetEnd.BitLen() > 63 { - return 0, 0, fmt.Errorf("abi offset larger than int64: %v", bigOffsetEnd) - } - - offsetEnd := int(bigOffsetEnd.Uint64()) - lengthBig := big.NewInt(0).SetBytes(output[offsetEnd-32 : offsetEnd]) - - totalSize := big.NewInt(0) - totalSize.Add(totalSize, bigOffsetEnd) - totalSize.Add(totalSize, lengthBig) - if totalSize.BitLen() > 63 { - return 0, 0, fmt.Errorf("abi: length larger than int64: %v", totalSize) - } - - if totalSize.Cmp(outputLength) > 0 { - return 0, 0, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %v require %v", outputLength, totalSize) - } - start = int(bigOffsetEnd.Uint64()) - length = int(lengthBig.Uint64()) - return -} - -// tuplePointsTo resolves the location reference for dynamic tuple. -func tuplePointsTo(index int, output []byte) (start int, err error) { - offset := big.NewInt(0).SetBytes(output[index : index+32]) - outputLen := big.NewInt(int64(len(output))) - - if offset.Cmp(big.NewInt(int64(len(output)))) > 0 { - return 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %v would go over slice boundary (len=%v)", offset, outputLen) - } - if offset.BitLen() > 63 { - return 0, fmt.Errorf("abi offset larger than int64: %v", offset) - } - return int(offset.Uint64()), nil -} diff --git a/accounts/accounts.go b/accounts/accounts.go index bca3223..2f39684 100644 --- a/accounts/accounts.go +++ b/accounts/accounts.go @@ -23,6 +23,7 @@ import ( "github.com/ava-labs/coreth/core/types" ethereum "github.com/ava-labs/go-ethereum" + gethaccounts "github.com/ava-labs/go-ethereum/accounts" "github.com/ava-labs/go-ethereum/common" "github.com/ava-labs/go-ethereum/event" "golang.org/x/crypto/sha3" @@ -129,6 +130,8 @@ type Wallet interface { // about which fields or actions are needed. The user may retry by providing // the needed details via SignHashWithPassphrase, or by other means (e.g. unlock // the account in a keystore). + // + // This method should return the signature in 'canonical' format, with v 0 or 1 SignText(account Account, text []byte) ([]byte, error) // SignTextWithPassphrase is identical to Signtext, but also takes a password @@ -199,7 +202,7 @@ func TextAndHash(data []byte) ([]byte, string) { // WalletEventType represents the different event types that can be fired by // the wallet subscription subsystem. -type WalletEventType int +type WalletEventType = gethaccounts.WalletEventType const ( // WalletArrived is fired when a new wallet is detected either via USB or via diff --git a/accounts/external/backend.go b/accounts/external/backend.go index 16e201d..41329d3 100644 --- a/accounts/external/backend.go +++ b/accounts/external/backend.go @@ -23,13 +23,12 @@ import ( "github.com/ava-labs/coreth/accounts" "github.com/ava-labs/coreth/core/types" - "github.com/ava-labs/coreth/internal/ethapi" - "github.com/ava-labs/coreth/rpc" "github.com/ava-labs/go-ethereum" "github.com/ava-labs/go-ethereum/common" "github.com/ava-labs/go-ethereum/common/hexutil" "github.com/ava-labs/go-ethereum/event" "github.com/ava-labs/go-ethereum/log" + "github.com/ava-labs/go-ethereum/rpc" "github.com/ava-labs/go-ethereum/signer/core" ) @@ -131,6 +130,12 @@ func (api *ExternalSigner) Accounts() []accounts.Account { func (api *ExternalSigner) Contains(account accounts.Account) bool { api.cacheMu.RLock() defer api.cacheMu.RUnlock() + if api.cache == nil { + // If we haven't already fetched the accounts, it's time to do so now + api.cacheMu.RUnlock() + api.Accounts() + api.cacheMu.RLock() + } for _, a := range api.cache { if a.Address == account.Address && (account.URL == (accounts.URL{}) || account.URL == api.URL()) { return true @@ -161,7 +166,7 @@ func (api *ExternalSigner) SignData(account accounts.Account, mimeType string, d hexutil.Encode(data)); err != nil { return nil, err } - // If V is on 27/28-form, convert to to 0/1 for Clique + // If V is on 27/28-form, convert to 0/1 for Clique if mimeType == accounts.MimetypeClique && (res[64] == 27 || res[64] == 28) { res[64] -= 27 // Transform V from 27/28 to 0/1 for Clique use } @@ -169,19 +174,29 @@ func (api *ExternalSigner) SignData(account accounts.Account, mimeType string, d } func (api *ExternalSigner) SignText(account accounts.Account, text []byte) ([]byte, error) { - var res hexutil.Bytes + var signature hexutil.Bytes var signAddress = common.NewMixedcaseAddress(account.Address) - if err := api.client.Call(&res, "account_signData", + if err := api.client.Call(&signature, "account_signData", accounts.MimetypeTextPlain, &signAddress, // Need to use the pointer here, because of how MarshalJSON is defined hexutil.Encode(text)); err != nil { return nil, err } - return res, nil + if signature[64] == 27 || signature[64] == 28 { + // If clef is used as a backend, it may already have transformed + // the signature to ethereum-type signature. + signature[64] -= 27 // Transform V from Ethereum-legacy to 0/1 + } + return signature, nil +} + +// signTransactionResult represents the signinig result returned by clef. +type signTransactionResult struct { + Raw hexutil.Bytes `json:"raw"` + Tx *types.Transaction `json:"tx"` } func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { - res := ethapi.SignTransactionResult{} data := hexutil.Bytes(tx.Data()) var to *common.MixedcaseAddress if tx.To() != nil { @@ -197,6 +212,7 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio To: to, From: common.NewMixedcaseAddress(account.Address), } + var res signTransactionResult if err := api.client.Call(&res, "account_signTransaction", args); err != nil { return nil, err } diff --git a/accounts/keystore/keystore.go b/accounts/keystore/keystore.go index a3ce33f..1bcaf13 100644 --- a/accounts/keystore/keystore.go +++ b/accounts/keystore/keystore.go @@ -24,7 +24,6 @@ import ( "crypto/ecdsa" crand "crypto/rand" "errors" - "fmt" "math/big" "os" "path/filepath" @@ -44,6 +43,10 @@ var ( ErrLocked = accounts.NewAuthNeededError("password or unlock") ErrNoMatch = errors.New("no key for given address or file") ErrDecrypt = errors.New("could not decrypt key with given password") + + // ErrAccountAlreadyExists is returned if an account attempted to import is + // already present in the keystore. + ErrAccountAlreadyExists = errors.New("account already exists") ) // KeyStoreType is the reflect type of a keystore backend. @@ -67,7 +70,8 @@ type KeyStore struct { updateScope event.SubscriptionScope // Subscription scope tracking current live listeners updating bool // Whether the event notification loop is running - mu sync.RWMutex + mu sync.RWMutex + importMu sync.Mutex // Import Mutex locks the import to prevent two insertions from racing } type unlocked struct { @@ -443,14 +447,27 @@ func (ks *KeyStore) Import(keyJSON []byte, passphrase, newPassphrase string) (ac if err != nil { return accounts.Account{}, err } + ks.importMu.Lock() + defer ks.importMu.Unlock() + + if ks.cache.hasAddress(key.Address) { + return accounts.Account{ + Address: key.Address, + }, ErrAccountAlreadyExists + } return ks.importKey(key, newPassphrase) } // ImportECDSA stores the given key into the key directory, encrypting it with the passphrase. func (ks *KeyStore) ImportECDSA(priv *ecdsa.PrivateKey, passphrase string) (accounts.Account, error) { + ks.importMu.Lock() + defer ks.importMu.Unlock() + key := newKeyFromECDSA(priv) if ks.cache.hasAddress(key.Address) { - return accounts.Account{}, fmt.Errorf("account already exists") + return accounts.Account{ + Address: key.Address, + }, ErrAccountAlreadyExists } return ks.importKey(key, passphrase) } diff --git a/accounts/keystore/passphrase.go b/accounts/keystore/passphrase.go index fa5a09d..04f31ff 100644 --- a/accounts/keystore/passphrase.go +++ b/accounts/keystore/passphrase.go @@ -121,8 +121,9 @@ func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) er "This indicates that the keystore is corrupted. \n" + "The corrupted file is stored at \n%v\n" + "Please file a ticket at:\n\n" + - "https://github.com/ethereum/go-ethereum/issues." + + "https://github.com/ava-labs/go-ethereum/issues." + "The error was : %s" + //lint:ignore ST1005 This is a message for the user return fmt.Errorf(msg, tmpName, err) } } @@ -237,7 +238,7 @@ func DecryptKey(keyjson []byte, auth string) (*Key, error) { func DecryptDataV3(cryptoJson CryptoJSON, auth string) ([]byte, error) { if cryptoJson.Cipher != "aes-128-ctr" { - return nil, fmt.Errorf("Cipher not supported: %v", cryptoJson.Cipher) + return nil, fmt.Errorf("cipher not supported: %v", cryptoJson.Cipher) } mac, err := hex.DecodeString(cryptoJson.MAC) if err != nil { @@ -273,7 +274,7 @@ func DecryptDataV3(cryptoJson CryptoJSON, auth string) ([]byte, error) { func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) { if keyProtected.Version != version { - return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version) + return nil, nil, fmt.Errorf("version not supported: %v", keyProtected.Version) } keyId = uuid.Parse(keyProtected.Id) plainText, err := DecryptDataV3(keyProtected.Crypto, auth) @@ -335,13 +336,13 @@ func getKDFKey(cryptoJSON CryptoJSON, auth string) ([]byte, error) { c := ensureInt(cryptoJSON.KDFParams["c"]) prf := cryptoJSON.KDFParams["prf"].(string) if prf != "hmac-sha256" { - return nil, fmt.Errorf("Unsupported PBKDF2 PRF: %s", prf) + return nil, fmt.Errorf("unsupported PBKDF2 PRF: %s", prf) } key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New) return key, nil } - return nil, fmt.Errorf("Unsupported KDF: %s", cryptoJSON.KDF) + return nil, fmt.Errorf("unsupported KDF: %s", cryptoJSON.KDF) } // TODO: can we do without this when unmarshalling dynamic JSON? diff --git a/accounts/manager.go b/accounts/manager.go index 39211da..87d3df8 100644 --- a/accounts/manager.go +++ b/accounts/manager.go @@ -141,6 +141,11 @@ func (am *Manager) Wallets() []Wallet { am.lock.RLock() defer am.lock.RUnlock() + return am.walletsNoLock() +} + +// walletsNoLock returns all registered wallets. Callers must hold am.lock. +func (am *Manager) walletsNoLock() []Wallet { cpy := make([]Wallet, len(am.wallets)) copy(cpy, am.wallets) return cpy @@ -155,7 +160,7 @@ func (am *Manager) Wallet(url string) (Wallet, error) { if err != nil { return nil, err } - for _, wallet := range am.Wallets() { + for _, wallet := range am.walletsNoLock() { if wallet.URL() == parsed { return wallet, nil } diff --git a/accounts/scwallet/hub.go b/accounts/scwallet/hub.go index ceb422c..67483b8 100644 --- a/accounts/scwallet/hub.go +++ b/accounts/scwallet/hub.go @@ -220,7 +220,7 @@ func (hub *Hub) refreshWallets() { // Mark the reader as present seen[reader] = struct{}{} - // If we alreay know about this card, skip to the next reader, otherwise clean up + // If we already know about this card, skip to the next reader, otherwise clean up if wallet, ok := hub.wallets[reader]; ok { if err := wallet.ping(); err == nil { continue diff --git a/accounts/scwallet/securechannel.go b/accounts/scwallet/securechannel.go index c1b7cff..a5666c9 100644 --- a/accounts/scwallet/securechannel.go +++ b/accounts/scwallet/securechannel.go @@ -71,7 +71,7 @@ func NewSecureChannelSession(card *pcsc.Card, keyData []byte) (*SecureChannelSes cardPublic, ok := gen.Unmarshal(keyData) if !ok { - return nil, fmt.Errorf("Could not unmarshal public key from card") + return nil, fmt.Errorf("could not unmarshal public key from card") } secret, err := gen.GenerateSharedSecret(private, cardPublic) @@ -109,7 +109,7 @@ func (s *SecureChannelSession) Pair(pairingPassword []byte) error { cardChallenge := response.Data[32:64] if !bytes.Equal(expectedCryptogram, cardCryptogram) { - return fmt.Errorf("Invalid card cryptogram %v != %v", expectedCryptogram, cardCryptogram) + return fmt.Errorf("invalid card cryptogram %v != %v", expectedCryptogram, cardCryptogram) } md.Reset() @@ -132,7 +132,7 @@ func (s *SecureChannelSession) Pair(pairingPassword []byte) error { // Unpair disestablishes an existing pairing. func (s *SecureChannelSession) Unpair() error { if s.PairingKey == nil { - return fmt.Errorf("Cannot unpair: not paired") + return fmt.Errorf("cannot unpair: not paired") } _, err := s.transmitEncrypted(claSCWallet, insUnpair, s.PairingIndex, 0, []byte{}) @@ -148,7 +148,7 @@ func (s *SecureChannelSession) Unpair() error { // Open initializes the secure channel. func (s *SecureChannelSession) Open() error { if s.iv != nil { - return fmt.Errorf("Session already opened") + return fmt.Errorf("session already opened") } response, err := s.open() @@ -185,11 +185,11 @@ func (s *SecureChannelSession) mutuallyAuthenticate() error { return err } if response.Sw1 != 0x90 || response.Sw2 != 0x00 { - return fmt.Errorf("Got unexpected response from MUTUALLY_AUTHENTICATE: 0x%x%x", response.Sw1, response.Sw2) + return fmt.Errorf("got unexpected response from MUTUALLY_AUTHENTICATE: 0x%x%x", response.Sw1, response.Sw2) } if len(response.Data) != scSecretLength { - return fmt.Errorf("Response from MUTUALLY_AUTHENTICATE was %d bytes, expected %d", len(response.Data), scSecretLength) + return fmt.Errorf("response from MUTUALLY_AUTHENTICATE was %d bytes, expected %d", len(response.Data), scSecretLength) } return nil @@ -222,7 +222,7 @@ func (s *SecureChannelSession) pair(p1 uint8, data []byte) (*responseAPDU, error // transmitEncrypted sends an encrypted message, and decrypts and returns the response. func (s *SecureChannelSession) transmitEncrypted(cla, ins, p1, p2 byte, data []byte) (*responseAPDU, error) { if s.iv == nil { - return nil, fmt.Errorf("Channel not open") + return nil, fmt.Errorf("channel not open") } data, err := s.encryptAPDU(data) @@ -261,14 +261,14 @@ func (s *SecureChannelSession) transmitEncrypted(cla, ins, p1, p2 byte, data []b return nil, err } if !bytes.Equal(s.iv, rmac) { - return nil, fmt.Errorf("Invalid MAC in response") + return nil, fmt.Errorf("invalid MAC in response") } rapdu := &responseAPDU{} rapdu.deserialize(plainData) if rapdu.Sw1 != sw1Ok { - return nil, fmt.Errorf("Unexpected response status Cla=0x%x, Ins=0x%x, Sw=0x%x%x", cla, ins, rapdu.Sw1, rapdu.Sw2) + return nil, fmt.Errorf("unexpected response status Cla=0x%x, Ins=0x%x, Sw=0x%x%x", cla, ins, rapdu.Sw1, rapdu.Sw2) } return rapdu, nil @@ -277,7 +277,7 @@ func (s *SecureChannelSession) transmitEncrypted(cla, ins, p1, p2 byte, data []b // encryptAPDU is an internal method that serializes and encrypts an APDU. func (s *SecureChannelSession) encryptAPDU(data []byte) ([]byte, error) { if len(data) > maxPayloadSize { - return nil, fmt.Errorf("Payload of %d bytes exceeds maximum of %d", len(data), maxPayloadSize) + return nil, fmt.Errorf("payload of %d bytes exceeds maximum of %d", len(data), maxPayloadSize) } data = pad(data, 0x80) @@ -323,10 +323,10 @@ func unpad(data []byte, terminator byte) ([]byte, error) { case terminator: return data[:len(data)-i], nil default: - return nil, fmt.Errorf("Expected end of padding, got %d", data[len(data)-i]) + return nil, fmt.Errorf("expected end of padding, got %d", data[len(data)-i]) } } - return nil, fmt.Errorf("Expected end of padding, got 0") + return nil, fmt.Errorf("expected end of padding, got 0") } // updateIV is an internal method that updates the initialization vector after diff --git a/accounts/scwallet/wallet.go b/accounts/scwallet/wallet.go index f72e685..5d2aff8 100644 --- a/accounts/scwallet/wallet.go +++ b/accounts/scwallet/wallet.go @@ -167,7 +167,7 @@ func transmit(card *pcsc.Card, command *commandAPDU) (*responseAPDU, error) { } if response.Sw1 != sw1Ok { - return nil, fmt.Errorf("Unexpected insecure response status Cla=0x%x, Ins=0x%x, Sw=0x%x%x", command.Cla, command.Ins, response.Sw1, response.Sw2) + return nil, fmt.Errorf("unexpected insecure response status Cla=0x%x, Ins=0x%x, Sw=0x%x%x", command.Cla, command.Ins, response.Sw1, response.Sw2) } return response, nil @@ -252,7 +252,7 @@ func (w *Wallet) release() error { // with the wallet. func (w *Wallet) pair(puk []byte) error { if w.session.paired() { - return fmt.Errorf("Wallet already paired") + return fmt.Errorf("wallet already paired") } pairing, err := w.session.pair(puk) if err != nil { @@ -312,15 +312,15 @@ func (w *Wallet) Status() (string, error) { } switch { case !w.session.verified && status.PinRetryCount == 0 && status.PukRetryCount == 0: - return fmt.Sprintf("Bricked, waiting for full wipe"), nil + return "Bricked, waiting for full wipe", nil case !w.session.verified && status.PinRetryCount == 0: return fmt.Sprintf("Blocked, waiting for PUK (%d attempts left) and new PIN", status.PukRetryCount), nil case !w.session.verified: return fmt.Sprintf("Locked, waiting for PIN (%d attempts left)", status.PinRetryCount), nil case !status.Initialized: - return fmt.Sprintf("Empty, waiting for initialization"), nil + return "Empty, waiting for initialization", nil default: - return fmt.Sprintf("Online"), nil + return "Online", nil } } @@ -362,7 +362,7 @@ func (w *Wallet) Open(passphrase string) error { return err } // Pairing succeeded, fall through to PIN checks. This will of course fail, - // but we can't return ErrPINNeeded directly here becase we don't know whether + // but we can't return ErrPINNeeded directly here because we don't know whether // a PIN check or a PIN reset is needed. passphrase = "" } @@ -773,12 +773,12 @@ func (w *Wallet) findAccountPath(account accounts.Account) (accounts.DerivationP // Look for the path in the URL if account.URL.Scheme != w.Hub.scheme { - return nil, fmt.Errorf("Scheme %s does not match wallet scheme %s", account.URL.Scheme, w.Hub.scheme) + return nil, fmt.Errorf("scheme %s does not match wallet scheme %s", account.URL.Scheme, w.Hub.scheme) } parts := strings.SplitN(account.URL.Path, "/", 2) if len(parts) != 2 { - return nil, fmt.Errorf("Invalid URL format: %s", account.URL) + return nil, fmt.Errorf("invalid URL format: %s", account.URL) } if parts[0] != fmt.Sprintf("%x", w.PublicKey[1:3]) { @@ -813,7 +813,7 @@ func (s *Session) pair(secret []byte) (smartcardPairing, error) { // unpair deletes an existing pairing. func (s *Session) unpair() error { if !s.verified { - return fmt.Errorf("Unpair requires that the PIN be verified") + return fmt.Errorf("unpair requires that the PIN be verified") } return s.Channel.Unpair() } @@ -850,7 +850,7 @@ func (s *Session) paired() bool { // authenticate uses an existing pairing to establish a secure channel. func (s *Session) authenticate(pairing smartcardPairing) error { if !bytes.Equal(s.Wallet.PublicKey, pairing.PublicKey) { - return fmt.Errorf("Cannot pair using another wallet's pairing; %x != %x", s.Wallet.PublicKey, pairing.PublicKey) + return fmt.Errorf("cannot pair using another wallet's pairing; %x != %x", s.Wallet.PublicKey, pairing.PublicKey) } s.Channel.PairingKey = pairing.PairingKey s.Channel.PairingIndex = pairing.PairingIndex @@ -879,6 +879,7 @@ func (s *Session) walletStatus() (*walletStatus, error) { } // derivationPath fetches the wallet's current derivation path from the card. +//lint:ignore U1000 needs to be added to the console interface func (s *Session) derivationPath() (accounts.DerivationPath, error) { response, err := s.Channel.transmitEncrypted(claSCWallet, insStatus, statusP1Path, 0, nil) if err != nil { @@ -993,12 +994,14 @@ func (s *Session) derive(path accounts.DerivationPath) (accounts.Account, error) } // keyExport contains information on an exported keypair. +//lint:ignore U1000 needs to be added to the console interface type keyExport struct { PublicKey []byte `asn1:"tag:0"` PrivateKey []byte `asn1:"tag:1,optional"` } // publicKey returns the public key for the current derivation path. +//lint:ignore U1000 needs to be added to the console interface func (s *Session) publicKey() ([]byte, error) { response, err := s.Channel.transmitEncrypted(claSCWallet, insExportKey, exportP1Any, exportP2Pubkey, nil) if err != nil { |