aboutsummaryrefslogtreecommitdiffstats
path: root/accounts/abi
diff options
context:
space:
mode:
Diffstat (limited to 'accounts/abi')
-rw-r--r--accounts/abi/argument.go17
-rw-r--r--accounts/abi/bind/base.go12
-rw-r--r--accounts/abi/bind/base_test.go64
-rw-r--r--accounts/abi/bind/bind.go41
-rw-r--r--accounts/abi/reflect.go2
-rw-r--r--accounts/abi/unpack_test.go47
6 files changed, 131 insertions, 52 deletions
diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go
index 90fd9d05f..fdc6ff164 100644
--- a/accounts/abi/argument.go
+++ b/accounts/abi/argument.go
@@ -272,14 +272,13 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
return ret, nil
}
-// capitalise makes the first character of a string upper case, also removing any
-// prefixing underscores from the variable names.
-func capitalise(input string) string {
- for len(input) > 0 && input[0] == '_' {
- input = input[1:]
- }
- if len(input) == 0 {
- return ""
+// 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.ToUpper(input[:1]) + input[1:]
+ return strings.Join(parts, "")
}
diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go
index 83ad1c8ae..c37bdf11d 100644
--- a/accounts/abi/bind/base.go
+++ b/accounts/abi/bind/base.go
@@ -36,10 +36,10 @@ type SignerFn func(types.Signer, common.Address, *types.Transaction) (*types.Tra
// 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
-
- Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
+ 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
@@ -148,10 +148,10 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
}
}
} else {
- output, err = c.caller.CallContract(ctx, msg, nil)
+ 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, nil); err != nil {
+ if code, err = c.caller.CodeAt(ctx, c.address, opts.BlockNumber); err != nil {
return err
} else if len(code) == 0 {
return ErrNoCode
diff --git a/accounts/abi/bind/base_test.go b/accounts/abi/bind/base_test.go
new file mode 100644
index 000000000..8adff8b59
--- /dev/null
+++ b/accounts/abi/bind/base_test.go
@@ -0,0 +1,64 @@
+package bind_test
+
+import (
+ "context"
+ "math/big"
+ "testing"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "github.com/ethereum/go-ethereum/accounts/abi"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+)
+
+type mockCaller struct {
+ codeAtBlockNumber *big.Int
+ callContractBlockNumber *big.Int
+}
+
+func (mc *mockCaller) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) {
+ mc.codeAtBlockNumber = blockNumber
+ return []byte{1, 2, 3}, nil
+}
+
+func (mc *mockCaller) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
+ mc.callContractBlockNumber = blockNumber
+ return nil, nil
+}
+
+func TestPassingBlockNumber(t *testing.T) {
+
+ mc := &mockCaller{}
+
+ bc := bind.NewBoundContract(common.HexToAddress("0x0"), abi.ABI{
+ Methods: map[string]abi.Method{
+ "something": {
+ Name: "something",
+ Outputs: abi.Arguments{},
+ },
+ },
+ }, mc, nil, nil)
+ var ret string
+
+ blockNumber := big.NewInt(42)
+
+ bc.Call(&bind.CallOpts{BlockNumber: blockNumber}, &ret, "something")
+
+ if mc.callContractBlockNumber != blockNumber {
+ t.Fatalf("CallContract() was not passed the block number")
+ }
+
+ if mc.codeAtBlockNumber != blockNumber {
+ t.Fatalf("CodeAt() was not passed the block number")
+ }
+
+ bc.Call(&bind.CallOpts{}, &ret, "something")
+
+ if mc.callContractBlockNumber != nil {
+ t.Fatalf("CallContract() was passed a block number when it should not have been")
+ }
+
+ if mc.codeAtBlockNumber != nil {
+ t.Fatalf("CodeAt() was passed a block number when it should not have been")
+ }
+}
diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go
index 4dca4b4ea..5ee30d024 100644
--- a/accounts/abi/bind/bind.go
+++ b/accounts/abi/bind/bind.go
@@ -381,54 +381,23 @@ func namedTypeJava(javaKind string, solKind abi.Type) string {
// 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: capitalise,
+ LangGo: abi.ToCamelCase,
LangJava: decapitalise,
}
// capitalise makes a camel-case string which starts with an upper case character.
func capitalise(input string) string {
- for len(input) > 0 && input[0] == '_' {
- input = input[1:]
- }
- if len(input) == 0 {
- return ""
- }
- return toCamelCase(strings.ToUpper(input[:1]) + input[1:])
+ return abi.ToCamelCase(input)
}
// decapitalise makes a camel-case string which starts with a lower case character.
func decapitalise(input string) string {
- for len(input) > 0 && input[0] == '_' {
- input = input[1:]
- }
if len(input) == 0 {
- return ""
+ return input
}
- return toCamelCase(strings.ToLower(input[:1]) + input[1:])
-}
-
-// toCamelCase converts an under-score string to a camel-case string
-func toCamelCase(input string) string {
- toupper := false
- result := ""
- for k, v := range input {
- switch {
- case k == 0:
- result = strings.ToUpper(string(input[0]))
-
- case toupper:
- result += strings.ToUpper(string(v))
- toupper = false
-
- case v == '_':
- toupper = true
-
- default:
- result += string(v)
- }
- }
- return result
+ goForm := abi.ToCamelCase(input)
+ return strings.ToLower(goForm[:1]) + goForm[1:]
}
// structured checks whether a list of ABI data types has enough information to
diff --git a/accounts/abi/reflect.go b/accounts/abi/reflect.go
index 6ec79a12f..f541cf3bf 100644
--- a/accounts/abi/reflect.go
+++ b/accounts/abi/reflect.go
@@ -186,7 +186,7 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin
for _, arg := range args {
abiFieldName := arg.Name
- structFieldName := capitalise(abiFieldName)
+ structFieldName := ToCamelCase(abiFieldName)
if structFieldName == "" {
return nil, fmt.Errorf("abi: purely underscored output cannot unpack to struct")
diff --git a/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go
index 22aa1a857..3873414c9 100644
--- a/accounts/abi/unpack_test.go
+++ b/accounts/abi/unpack_test.go
@@ -311,6 +311,53 @@ var unpackTests = []unpackTest{
}{big.NewInt(1), big.NewInt(2)},
},
{
+ def: `[{"name":"int_one","type":"int256"}]`,
+ enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
+ want: struct {
+ IntOne *big.Int
+ }{big.NewInt(1)},
+ },
+ {
+ def: `[{"name":"int__one","type":"int256"}]`,
+ enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
+ want: struct {
+ IntOne *big.Int
+ }{big.NewInt(1)},
+ },
+ {
+ def: `[{"name":"int_one_","type":"int256"}]`,
+ enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
+ want: struct {
+ IntOne *big.Int
+ }{big.NewInt(1)},
+ },
+ {
+ def: `[{"name":"int_one","type":"int256"}, {"name":"intone","type":"int256"}]`,
+ enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
+ want: struct {
+ IntOne *big.Int
+ Intone *big.Int
+ }{big.NewInt(1), big.NewInt(2)},
+ },
+ {
+ def: `[{"name":"___","type":"int256"}]`,
+ enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
+ want: struct {
+ IntOne *big.Int
+ Intone *big.Int
+ }{},
+ err: "abi: purely underscored output cannot unpack to struct",
+ },
+ {
+ def: `[{"name":"int_one","type":"int256"},{"name":"IntOne","type":"int256"}]`,
+ enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
+ want: struct {
+ Int1 *big.Int
+ Int2 *big.Int
+ }{},
+ err: "abi: multiple outputs mapping to the same struct field 'IntOne'",
+ },
+ {
def: `[{"name":"int","type":"int256"},{"name":"Int","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {