Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
1580ec18
Commit
1580ec18
authored
May 20, 2016
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
accounts/abi/bind, eth: rely on getCode for sanity checks, not estimate and call
parent
e798e4fd
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
112 additions
and
28 deletions
+112
-28
backend.go
accounts/abi/bind/backend.go
+43
-6
nil.go
accounts/abi/bind/backends/nil.go
+1
-0
remote.go
accounts/abi/bind/backends/remote.go
+20
-0
simulated.go
accounts/abi/bind/backends/simulated.go
+10
-0
base.go
accounts/abi/bind/base.go
+27
-0
api.go
eth/api.go
+0
-15
bind.go
eth/bind.go
+11
-7
No files found.
accounts/abi/bind/backend.go
View file @
1580ec18
...
@@ -27,15 +27,16 @@ import (
...
@@ -27,15 +27,16 @@ import (
// ErrNoCode is returned by call and transact operations for which the requested
// 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
// recipient contract to operate on does not exist in the state db or does not
// have any code associated with it (i.e. suicided).
// have any code associated with it (i.e. suicided).
//
// Please note, this error string is part of the RPC API and is expected by the
// native contract bindings to signal this particular error. Do not change this
// as it will break all dependent code!
var
ErrNoCode
=
errors
.
New
(
"no contract code at given address"
)
var
ErrNoCode
=
errors
.
New
(
"no contract code at given address"
)
// ContractCaller defines the methods needed to allow operating with contract on a read
// ContractCaller defines the methods needed to allow operating with contract on a read
// only basis.
// only basis.
type
ContractCaller
interface
{
type
ContractCaller
interface
{
// HasCode checks if the contract at the given address has any code associated
// with it or not. This is needed to differentiate between contract internal
// errors and the local chain being out of sync.
HasCode
(
contract
common
.
Address
,
pending
bool
)
(
bool
,
error
)
// ContractCall executes an Ethereum contract call with the specified data as
// ContractCall executes an Ethereum contract call with the specified data as
// the input. The pending flag requests execution against the pending block, not
// the input. The pending flag requests execution against the pending block, not
// the stable head of the chain.
// the stable head of the chain.
...
@@ -55,6 +56,11 @@ type ContractTransactor interface {
...
@@ -55,6 +56,11 @@ type ContractTransactor interface {
// execution of a transaction.
// execution of a transaction.
SuggestGasPrice
()
(
*
big
.
Int
,
error
)
SuggestGasPrice
()
(
*
big
.
Int
,
error
)
// HasCode checks if the contract at the given address has any code associated
// with it or not. This is needed to differentiate between contract internal
// errors and the local chain being out of sync.
HasCode
(
contract
common
.
Address
,
pending
bool
)
(
bool
,
error
)
// EstimateGasLimit tries to estimate the gas needed to execute a specific
// EstimateGasLimit tries to estimate the gas needed to execute a specific
// transaction based on the current pending state of the backend blockchain.
// 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
// There is no guarantee that this is the true gas limit requirement as other
...
@@ -68,7 +74,38 @@ type ContractTransactor interface {
...
@@ -68,7 +74,38 @@ type ContractTransactor interface {
// ContractBackend defines the methods needed to allow operating with contract
// ContractBackend defines the methods needed to allow operating with contract
// on a read-write basis.
// on a read-write basis.
//
// This interface is essentially the union of ContractCaller and ContractTransactor
// but due to a bug in the Go compiler (https://github.com/golang/go/issues/6977),
// we cannot simply list it as the two interfaces. The other solution is to add a
// third interface containing the common methods, but that convolutes the user API
// as it introduces yet another parameter to require for initialization.
type
ContractBackend
interface
{
type
ContractBackend
interface
{
ContractCaller
// HasCode checks if the contract at the given address has any code associated
ContractTransactor
// with it or not. This is needed to differentiate between contract internal
// errors and the local chain being out of sync.
HasCode
(
contract
common
.
Address
,
pending
bool
)
(
bool
,
error
)
// ContractCall executes an Ethereum contract call with the specified data as
// the input. The pending flag requests execution against the pending block, not
// the stable head of the chain.
ContractCall
(
contract
common
.
Address
,
data
[]
byte
,
pending
bool
)
([]
byte
,
error
)
// PendingAccountNonce retrieves the current pending nonce associated with an
// account.
PendingAccountNonce
(
account
common
.
Address
)
(
uint64
,
error
)
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely
// execution of a transaction.
SuggestGasPrice
()
(
*
big
.
Int
,
error
)
// EstimateGasLimit 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.
EstimateGasLimit
(
sender
common
.
Address
,
contract
*
common
.
Address
,
value
*
big
.
Int
,
data
[]
byte
)
(
*
big
.
Int
,
error
)
// SendTransaction injects the transaction into the pending pool for execution.
SendTransaction
(
tx
*
types
.
Transaction
)
error
}
}
accounts/abi/bind/backends/nil.go
View file @
1580ec18
...
@@ -38,6 +38,7 @@ func (*nilBackend) ContractCall(common.Address, []byte, bool) ([]byte, error) {
...
@@ -38,6 +38,7 @@ func (*nilBackend) ContractCall(common.Address, []byte, bool) ([]byte, error) {
func
(
*
nilBackend
)
EstimateGasLimit
(
common
.
Address
,
*
common
.
Address
,
*
big
.
Int
,
[]
byte
)
(
*
big
.
Int
,
error
)
{
func
(
*
nilBackend
)
EstimateGasLimit
(
common
.
Address
,
*
common
.
Address
,
*
big
.
Int
,
[]
byte
)
(
*
big
.
Int
,
error
)
{
panic
(
"not implemented"
)
panic
(
"not implemented"
)
}
}
func
(
*
nilBackend
)
HasCode
(
common
.
Address
,
bool
)
(
bool
,
error
)
{
panic
(
"not implemented"
)
}
func
(
*
nilBackend
)
SuggestGasPrice
()
(
*
big
.
Int
,
error
)
{
panic
(
"not implemented"
)
}
func
(
*
nilBackend
)
SuggestGasPrice
()
(
*
big
.
Int
,
error
)
{
panic
(
"not implemented"
)
}
func
(
*
nilBackend
)
PendingAccountNonce
(
common
.
Address
)
(
uint64
,
error
)
{
panic
(
"not implemented"
)
}
func
(
*
nilBackend
)
PendingAccountNonce
(
common
.
Address
)
(
uint64
,
error
)
{
panic
(
"not implemented"
)
}
func
(
*
nilBackend
)
SendTransaction
(
*
types
.
Transaction
)
error
{
panic
(
"not implemented"
)
}
func
(
*
nilBackend
)
SendTransaction
(
*
types
.
Transaction
)
error
{
panic
(
"not implemented"
)
}
...
...
accounts/abi/bind/backends/remote.go
View file @
1580ec18
...
@@ -111,6 +111,26 @@ func (b *rpcBackend) request(method string, params []interface{}) (json.RawMessa
...
@@ -111,6 +111,26 @@ func (b *rpcBackend) request(method string, params []interface{}) (json.RawMessa
return
res
.
Result
,
nil
return
res
.
Result
,
nil
}
}
// HasCode implements ContractVerifier.HasCode by retrieving any code associated
// with the contract from the remote node, and checking its size.
func
(
b
*
rpcBackend
)
HasCode
(
contract
common
.
Address
,
pending
bool
)
(
bool
,
error
)
{
// Execute the RPC code retrieval
block
:=
"latest"
if
pending
{
block
=
"pending"
}
res
,
err
:=
b
.
request
(
"eth_getCode"
,
[]
interface
{}{
contract
.
Hex
(),
block
})
if
err
!=
nil
{
return
false
,
err
}
var
hex
string
if
err
:=
json
.
Unmarshal
(
res
,
&
hex
);
err
!=
nil
{
return
false
,
err
}
// Convert the response back to a Go byte slice and return
return
len
(
common
.
FromHex
(
hex
))
>
0
,
nil
}
// ContractCall implements ContractCaller.ContractCall, delegating the execution of
// ContractCall implements ContractCaller.ContractCall, delegating the execution of
// a contract call to the remote node, returning the reply to for local processing.
// a contract call to the remote node, returning the reply to for local processing.
func
(
b
*
rpcBackend
)
ContractCall
(
contract
common
.
Address
,
data
[]
byte
,
pending
bool
)
([]
byte
,
error
)
{
func
(
b
*
rpcBackend
)
ContractCall
(
contract
common
.
Address
,
data
[]
byte
,
pending
bool
)
([]
byte
,
error
)
{
...
...
accounts/abi/bind/backends/simulated.go
View file @
1580ec18
...
@@ -78,6 +78,16 @@ func (b *SimulatedBackend) Rollback() {
...
@@ -78,6 +78,16 @@ func (b *SimulatedBackend) Rollback() {
b
.
pendingState
,
_
=
state
.
New
(
b
.
pendingBlock
.
Root
(),
b
.
database
)
b
.
pendingState
,
_
=
state
.
New
(
b
.
pendingBlock
.
Root
(),
b
.
database
)
}
}
// HasCode implements ContractVerifier.HasCode, checking whether there is any
// code associated with a certain account in the blockchain.
func
(
b
*
SimulatedBackend
)
HasCode
(
contract
common
.
Address
,
pending
bool
)
(
bool
,
error
)
{
if
pending
{
return
len
(
b
.
pendingState
.
GetCode
(
contract
))
>
0
,
nil
}
statedb
,
_
:=
b
.
blockchain
.
State
()
return
len
(
statedb
.
GetCode
(
contract
))
>
0
,
nil
}
// ContractCall implements ContractCaller.ContractCall, executing the specified
// ContractCall implements ContractCaller.ContractCall, executing the specified
// contract with the given input data.
// contract with the given input data.
func
(
b
*
SimulatedBackend
)
ContractCall
(
contract
common
.
Address
,
data
[]
byte
,
pending
bool
)
([]
byte
,
error
)
{
func
(
b
*
SimulatedBackend
)
ContractCall
(
contract
common
.
Address
,
data
[]
byte
,
pending
bool
)
([]
byte
,
error
)
{
...
...
accounts/abi/bind/base.go
View file @
1580ec18
...
@@ -20,6 +20,7 @@ import (
...
@@ -20,6 +20,7 @@ import (
"errors"
"errors"
"fmt"
"fmt"
"math/big"
"math/big"
"sync/atomic"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
...
@@ -56,6 +57,9 @@ type BoundContract struct {
...
@@ -56,6 +57,9 @@ type BoundContract struct {
abi
abi
.
ABI
// Reflect based ABI to access the correct Ethereum methods
abi
abi
.
ABI
// Reflect based ABI to access the correct Ethereum methods
caller
ContractCaller
// Read interface to interact with the blockchain
caller
ContractCaller
// Read interface to interact with the blockchain
transactor
ContractTransactor
// Write interface to interact with the blockchain
transactor
ContractTransactor
// Write interface to interact with the blockchain
latestHasCode
uint32
// Cached verification that the latest state contains code for this contract
pendingHasCode
uint32
// Cached verification that the pending state contains code for this contract
}
}
// NewBoundContract creates a low level contract interface through which calls
// NewBoundContract creates a low level contract interface through which calls
...
@@ -96,6 +100,19 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
...
@@ -96,6 +100,19 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
if
opts
==
nil
{
if
opts
==
nil
{
opts
=
new
(
CallOpts
)
opts
=
new
(
CallOpts
)
}
}
// Make sure we have a contract to operate on, and bail out otherwise
if
(
opts
.
Pending
&&
atomic
.
LoadUint32
(
&
c
.
pendingHasCode
)
==
0
)
||
(
!
opts
.
Pending
&&
atomic
.
LoadUint32
(
&
c
.
latestHasCode
)
==
0
)
{
if
code
,
err
:=
c
.
caller
.
HasCode
(
c
.
address
,
opts
.
Pending
);
err
!=
nil
{
return
err
}
else
if
!
code
{
return
ErrNoCode
}
if
opts
.
Pending
{
atomic
.
StoreUint32
(
&
c
.
pendingHasCode
,
1
)
}
else
{
atomic
.
StoreUint32
(
&
c
.
latestHasCode
,
1
)
}
}
// Pack the input, call and unpack the results
// Pack the input, call and unpack the results
input
,
err
:=
c
.
abi
.
Pack
(
method
,
params
...
)
input
,
err
:=
c
.
abi
.
Pack
(
method
,
params
...
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -153,6 +170,16 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
...
@@ -153,6 +170,16 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
}
}
gasLimit
:=
opts
.
GasLimit
gasLimit
:=
opts
.
GasLimit
if
gasLimit
==
nil
{
if
gasLimit
==
nil
{
// Gas estimation cannot succeed without code for method invocations
if
contract
!=
nil
&&
atomic
.
LoadUint32
(
&
c
.
pendingHasCode
)
==
0
{
if
code
,
err
:=
c
.
transactor
.
HasCode
(
c
.
address
,
true
);
err
!=
nil
{
return
nil
,
err
}
else
if
!
code
{
return
nil
,
ErrNoCode
}
atomic
.
StoreUint32
(
&
c
.
pendingHasCode
,
1
)
}
// If the contract surely has code (or code is not needed), estimate the transaction
gasLimit
,
err
=
c
.
transactor
.
EstimateGasLimit
(
opts
.
From
,
contract
,
value
,
input
)
gasLimit
,
err
=
c
.
transactor
.
EstimateGasLimit
(
opts
.
From
,
contract
,
value
,
input
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"failed to exstimate gas needed: %v"
,
err
)
return
nil
,
fmt
.
Errorf
(
"failed to exstimate gas needed: %v"
,
err
)
...
...
eth/api.go
View file @
1580ec18
...
@@ -52,15 +52,6 @@ import (
...
@@ -52,15 +52,6 @@ import (
"golang.org/x/net/context"
"golang.org/x/net/context"
)
)
// 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).
//
// Please note, this error string is part of the RPC API and is expected by the
// native contract bindings to signal this particular error. Do not change this
// as it will break all dependent code!
var
errNoCode
=
errors
.
New
(
"no contract code at given address"
)
const
defaultGas
=
uint64
(
90000
)
const
defaultGas
=
uint64
(
90000
)
// blockByNumber is a commonly used helper function which retrieves and returns
// blockByNumber is a commonly used helper function which retrieves and returns
...
@@ -717,12 +708,6 @@ func (s *PublicBlockChainAPI) doCall(args CallArgs, blockNr rpc.BlockNumber) (st
...
@@ -717,12 +708,6 @@ func (s *PublicBlockChainAPI) doCall(args CallArgs, blockNr rpc.BlockNumber) (st
}
}
stateDb
=
stateDb
.
Copy
()
stateDb
=
stateDb
.
Copy
()
// If there's no code to interact with, respond with an appropriate error
if
args
.
To
!=
nil
{
if
code
:=
stateDb
.
GetCode
(
*
args
.
To
);
len
(
code
)
==
0
{
return
"0x"
,
nil
,
errNoCode
}
}
// Retrieve the account state object to interact with
// Retrieve the account state object to interact with
var
from
*
state
.
StateObject
var
from
*
state
.
StateObject
if
args
.
From
==
(
common
.
Address
{})
{
if
args
.
From
==
(
common
.
Address
{})
{
...
...
eth/bind.go
View file @
1580ec18
...
@@ -19,7 +19,6 @@ package eth
...
@@ -19,7 +19,6 @@ package eth
import
(
import
(
"math/big"
"math/big"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rlp"
...
@@ -49,6 +48,17 @@ func NewContractBackend(eth *Ethereum) *ContractBackend {
...
@@ -49,6 +48,17 @@ func NewContractBackend(eth *Ethereum) *ContractBackend {
}
}
}
}
// HasCode implements bind.ContractVerifier.HasCode by retrieving any code associated
// with the contract from the local API, and checking its size.
func
(
b
*
ContractBackend
)
HasCode
(
contract
common
.
Address
,
pending
bool
)
(
bool
,
error
)
{
block
:=
rpc
.
LatestBlockNumber
if
pending
{
block
=
rpc
.
PendingBlockNumber
}
out
,
err
:=
b
.
bcapi
.
GetCode
(
contract
,
block
)
return
len
(
common
.
FromHex
(
out
))
>
0
,
err
}
// ContractCall implements bind.ContractCaller executing an Ethereum contract
// ContractCall implements bind.ContractCaller executing an Ethereum contract
// call with the specified data as the input. The pending flag requests execution
// call with the specified data as the input. The pending flag requests execution
// against the pending block, not the stable head of the chain.
// against the pending block, not the stable head of the chain.
...
@@ -64,9 +74,6 @@ func (b *ContractBackend) ContractCall(contract common.Address, data []byte, pen
...
@@ -64,9 +74,6 @@ func (b *ContractBackend) ContractCall(contract common.Address, data []byte, pen
}
}
// Execute the call and convert the output back to Go types
// Execute the call and convert the output back to Go types
out
,
err
:=
b
.
bcapi
.
Call
(
args
,
block
)
out
,
err
:=
b
.
bcapi
.
Call
(
args
,
block
)
if
err
==
errNoCode
{
err
=
bind
.
ErrNoCode
}
return
common
.
FromHex
(
out
),
err
return
common
.
FromHex
(
out
),
err
}
}
...
@@ -95,9 +102,6 @@ func (b *ContractBackend) EstimateGasLimit(sender common.Address, contract *comm
...
@@ -95,9 +102,6 @@ func (b *ContractBackend) EstimateGasLimit(sender common.Address, contract *comm
Value
:
*
rpc
.
NewHexNumber
(
value
),
Value
:
*
rpc
.
NewHexNumber
(
value
),
Data
:
common
.
ToHex
(
data
),
Data
:
common
.
ToHex
(
data
),
})
})
if
err
==
errNoCode
{
err
=
bind
.
ErrNoCode
}
return
out
.
BigInt
(),
err
return
out
.
BigInt
(),
err
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment