Skip to content

Commit 311f5a0

Browse files
committed
Merge branch 'release/1.4'
2 parents 8ea3c88 + 68ae6b5 commit 311f5a0

File tree

15 files changed

+559
-174
lines changed

15 files changed

+559
-174
lines changed

accounts/abi/abi_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,10 +305,10 @@ func TestUnpackSetInterfaceSlice(t *testing.T) {
305305
t.Fatal(err)
306306
}
307307
if *var1 != 1 {
308-
t.Errorf("expected var1 to be 1, got", *var1)
308+
t.Error("expected var1 to be 1, got", *var1)
309309
}
310310
if *var2 != 2 {
311-
t.Errorf("expected var2 to be 2, got", *var2)
311+
t.Error("expected var2 to be 2, got", *var2)
312312
}
313313

314314
out = []interface{}{var1}

accounts/abi/bind/backend.go

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,16 @@ import (
2727
// ErrNoCode is returned by call and transact operations for which the requested
2828
// recipient contract to operate on does not exist in the state db or does not
2929
// have any code associated with it (i.e. suicided).
30-
//
31-
// Please note, this error string is part of the RPC API and is expected by the
32-
// native contract bindings to signal this particular error. Do not change this
33-
// as it will break all dependent code!
3430
var ErrNoCode = errors.New("no contract code at given address")
3531

3632
// ContractCaller defines the methods needed to allow operating with contract on a read
3733
// only basis.
3834
type ContractCaller interface {
35+
// HasCode checks if the contract at the given address has any code associated
36+
// with it or not. This is needed to differentiate between contract internal
37+
// errors and the local chain being out of sync.
38+
HasCode(contract common.Address, pending bool) (bool, error)
39+
3940
// ContractCall executes an Ethereum contract call with the specified data as
4041
// the input. The pending flag requests execution against the pending block, not
4142
// the stable head of the chain.
@@ -55,6 +56,11 @@ type ContractTransactor interface {
5556
// execution of a transaction.
5657
SuggestGasPrice() (*big.Int, error)
5758

59+
// HasCode checks if the contract at the given address has any code associated
60+
// with it or not. This is needed to differentiate between contract internal
61+
// errors and the local chain being out of sync.
62+
HasCode(contract common.Address, pending bool) (bool, error)
63+
5864
// EstimateGasLimit tries to estimate the gas needed to execute a specific
5965
// transaction based on the current pending state of the backend blockchain.
6066
// There is no guarantee that this is the true gas limit requirement as other
@@ -68,7 +74,38 @@ type ContractTransactor interface {
6874

6975
// ContractBackend defines the methods needed to allow operating with contract
7076
// on a read-write basis.
77+
//
78+
// This interface is essentially the union of ContractCaller and ContractTransactor
79+
// but due to a bug in the Go compiler (https://github.com/golang/go/issues/6977),
80+
// we cannot simply list it as the two interfaces. The other solution is to add a
81+
// third interface containing the common methods, but that convolutes the user API
82+
// as it introduces yet another parameter to require for initialization.
7183
type ContractBackend interface {
72-
ContractCaller
73-
ContractTransactor
84+
// HasCode checks if the contract at the given address has any code associated
85+
// with it or not. This is needed to differentiate between contract internal
86+
// errors and the local chain being out of sync.
87+
HasCode(contract common.Address, pending bool) (bool, error)
88+
89+
// ContractCall executes an Ethereum contract call with the specified data as
90+
// the input. The pending flag requests execution against the pending block, not
91+
// the stable head of the chain.
92+
ContractCall(contract common.Address, data []byte, pending bool) ([]byte, error)
93+
94+
// PendingAccountNonce retrieves the current pending nonce associated with an
95+
// account.
96+
PendingAccountNonce(account common.Address) (uint64, error)
97+
98+
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely
99+
// execution of a transaction.
100+
SuggestGasPrice() (*big.Int, error)
101+
102+
// EstimateGasLimit tries to estimate the gas needed to execute a specific
103+
// transaction based on the current pending state of the backend blockchain.
104+
// There is no guarantee that this is the true gas limit requirement as other
105+
// transactions may be added or removed by miners, but it should provide a basis
106+
// for setting a reasonable default.
107+
EstimateGasLimit(sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error)
108+
109+
// SendTransaction injects the transaction into the pending pool for execution.
110+
SendTransaction(tx *types.Transaction) error
74111
}

accounts/abi/bind/backends/nil.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ func (*nilBackend) ContractCall(common.Address, []byte, bool) ([]byte, error) {
3838
func (*nilBackend) EstimateGasLimit(common.Address, *common.Address, *big.Int, []byte) (*big.Int, error) {
3939
panic("not implemented")
4040
}
41+
func (*nilBackend) HasCode(common.Address, bool) (bool, error) { panic("not implemented") }
4142
func (*nilBackend) SuggestGasPrice() (*big.Int, error) { panic("not implemented") }
4243
func (*nilBackend) PendingAccountNonce(common.Address) (uint64, error) { panic("not implemented") }
4344
func (*nilBackend) SendTransaction(*types.Transaction) error { panic("not implemented") }

accounts/abi/bind/backends/remote.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,26 @@ func (b *rpcBackend) request(method string, params []interface{}) (json.RawMessa
111111
return res.Result, nil
112112
}
113113

114+
// HasCode implements ContractVerifier.HasCode by retrieving any code associated
115+
// with the contract from the remote node, and checking its size.
116+
func (b *rpcBackend) HasCode(contract common.Address, pending bool) (bool, error) {
117+
// Execute the RPC code retrieval
118+
block := "latest"
119+
if pending {
120+
block = "pending"
121+
}
122+
res, err := b.request("eth_getCode", []interface{}{contract.Hex(), block})
123+
if err != nil {
124+
return false, err
125+
}
126+
var hex string
127+
if err := json.Unmarshal(res, &hex); err != nil {
128+
return false, err
129+
}
130+
// Convert the response back to a Go byte slice and return
131+
return len(common.FromHex(hex)) > 0, nil
132+
}
133+
114134
// ContractCall implements ContractCaller.ContractCall, delegating the execution of
115135
// a contract call to the remote node, returning the reply to for local processing.
116136
func (b *rpcBackend) ContractCall(contract common.Address, data []byte, pending bool) ([]byte, error) {

accounts/abi/bind/backends/simulated.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,16 @@ func (b *SimulatedBackend) Rollback() {
7878
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database)
7979
}
8080

81+
// HasCode implements ContractVerifier.HasCode, checking whether there is any
82+
// code associated with a certain account in the blockchain.
83+
func (b *SimulatedBackend) HasCode(contract common.Address, pending bool) (bool, error) {
84+
if pending {
85+
return len(b.pendingState.GetCode(contract)) > 0, nil
86+
}
87+
statedb, _ := b.blockchain.State()
88+
return len(statedb.GetCode(contract)) > 0, nil
89+
}
90+
8191
// ContractCall implements ContractCaller.ContractCall, executing the specified
8292
// contract with the given input data.
8393
func (b *SimulatedBackend) ContractCall(contract common.Address, data []byte, pending bool) ([]byte, error) {

accounts/abi/bind/base.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"errors"
2121
"fmt"
2222
"math/big"
23+
"sync/atomic"
2324

2425
"github.com/ethereum/go-ethereum/accounts/abi"
2526
"github.com/ethereum/go-ethereum/common"
@@ -56,6 +57,9 @@ type BoundContract struct {
5657
abi abi.ABI // Reflect based ABI to access the correct Ethereum methods
5758
caller ContractCaller // Read interface to interact with the blockchain
5859
transactor ContractTransactor // Write interface to interact with the blockchain
60+
61+
latestHasCode uint32 // Cached verification that the latest state contains code for this contract
62+
pendingHasCode uint32 // Cached verification that the pending state contains code for this contract
5963
}
6064

6165
// NewBoundContract creates a low level contract interface through which calls
@@ -96,6 +100,19 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
96100
if opts == nil {
97101
opts = new(CallOpts)
98102
}
103+
// Make sure we have a contract to operate on, and bail out otherwise
104+
if (opts.Pending && atomic.LoadUint32(&c.pendingHasCode) == 0) || (!opts.Pending && atomic.LoadUint32(&c.latestHasCode) == 0) {
105+
if code, err := c.caller.HasCode(c.address, opts.Pending); err != nil {
106+
return err
107+
} else if !code {
108+
return ErrNoCode
109+
}
110+
if opts.Pending {
111+
atomic.StoreUint32(&c.pendingHasCode, 1)
112+
} else {
113+
atomic.StoreUint32(&c.latestHasCode, 1)
114+
}
115+
}
99116
// Pack the input, call and unpack the results
100117
input, err := c.abi.Pack(method, params...)
101118
if err != nil {
@@ -153,6 +170,16 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
153170
}
154171
gasLimit := opts.GasLimit
155172
if gasLimit == nil {
173+
// Gas estimation cannot succeed without code for method invocations
174+
if contract != nil && atomic.LoadUint32(&c.pendingHasCode) == 0 {
175+
if code, err := c.transactor.HasCode(c.address, true); err != nil {
176+
return nil, err
177+
} else if !code {
178+
return nil, ErrNoCode
179+
}
180+
atomic.StoreUint32(&c.pendingHasCode, 1)
181+
}
182+
// If the contract surely has code (or code is not needed), estimate the transaction
156183
gasLimit, err = c.transactor.EstimateGasLimit(opts.From, contract, value, input)
157184
if err != nil {
158185
return nil, fmt.Errorf("failed to exstimate gas needed: %v", err)

accounts/account_manager.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,21 @@ func (am *Manager) Sign(addr common.Address, hash []byte) (signature []byte, err
147147
return crypto.Sign(hash, unlockedKey.PrivateKey)
148148
}
149149

150+
// SignWithPassphrase signs hash if the private key matching the given address can be
151+
// decrypted with the given passphrase.
152+
func (am *Manager) SignWithPassphrase(addr common.Address, passphrase string, hash []byte) (signature []byte, err error) {
153+
_, key, err := am.getDecryptedKey(Account{Address: addr}, passphrase)
154+
if err != nil {
155+
return nil, err
156+
}
157+
158+
defer zeroKey(key.PrivateKey)
159+
return crypto.Sign(hash, key.PrivateKey)
160+
}
161+
150162
// Unlock unlocks the given account indefinitely.
151-
func (am *Manager) Unlock(a Account, keyAuth string) error {
152-
return am.TimedUnlock(a, keyAuth, 0)
163+
func (am *Manager) Unlock(a Account, passphrase string) error {
164+
return am.TimedUnlock(a, passphrase, 0)
153165
}
154166

155167
// Lock removes the private key with the given address from memory.

accounts/accounts_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,34 @@ func TestSign(t *testing.T) {
8181
}
8282
}
8383

84+
func TestSignWithPassphrase(t *testing.T) {
85+
dir, am := tmpManager(t, true)
86+
defer os.RemoveAll(dir)
87+
88+
pass := "passwd"
89+
acc, err := am.NewAccount(pass)
90+
if err != nil {
91+
t.Fatal(err)
92+
}
93+
94+
if _, unlocked := am.unlocked[acc.Address]; unlocked {
95+
t.Fatal("expected account to be locked")
96+
}
97+
98+
_, err = am.SignWithPassphrase(acc.Address, pass, testSigData)
99+
if err != nil {
100+
t.Fatal(err)
101+
}
102+
103+
if _, unlocked := am.unlocked[acc.Address]; unlocked {
104+
t.Fatal("expected account to be locked")
105+
}
106+
107+
if _, err = am.SignWithPassphrase(acc.Address, "invalid passwd", testSigData); err == nil {
108+
t.Fatal("expected SignHash to fail with invalid password")
109+
}
110+
}
111+
84112
func TestTimedUnlock(t *testing.T) {
85113
dir, am := tmpManager(t, true)
86114
defer os.RemoveAll(dir)

cmd/geth/js.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ import (
4141
)
4242

4343
var (
44-
passwordRegexp = regexp.MustCompile("personal.[nu]")
45-
leadingSpace = regexp.MustCompile("^ ")
44+
passwordRegexp = regexp.MustCompile("personal.[nus]")
4645
onlyws = regexp.MustCompile("^\\s*$")
4746
exit = regexp.MustCompile("^\\s*exit\\s*;*\\s*$")
4847
)
@@ -361,7 +360,7 @@ func (self *jsre) interactive() {
361360
str += input + "\n"
362361
self.setIndent()
363362
if indentCount <= 0 {
364-
if mustLogInHistory(str) {
363+
if !excludeFromHistory(str) {
365364
utils.Stdin.AppendHistory(str[:len(str)-1])
366365
}
367366
self.parseInput(str)
@@ -371,10 +370,8 @@ func (self *jsre) interactive() {
371370
}
372371
}
373372

374-
func mustLogInHistory(input string) bool {
375-
return len(input) == 0 ||
376-
passwordRegexp.MatchString(input) ||
377-
!leadingSpace.MatchString(input)
373+
func excludeFromHistory(input string) bool {
374+
return len(input) == 0 || input[0] == ' ' || passwordRegexp.MatchString(input)
378375
}
379376

380377
func (self *jsre) withHistory(datadir string, op func(*os.File)) {

0 commit comments

Comments
 (0)