mirror of https://github.com/status-im/op-geth.git
Merge pull request #2159 from zsfelfoldi/light-backend
eth: separate common and full node-specific API and backend service
This commit is contained in:
commit
1e50f5dd28
|
@ -22,6 +22,7 @@ import (
|
||||||
|
|
||||||
"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"
|
||||||
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrNoCode is returned by call and transact operations for which the requested
|
// ErrNoCode is returned by call and transact operations for which the requested
|
||||||
|
@ -35,12 +36,12 @@ type ContractCaller interface {
|
||||||
// HasCode checks if the contract at the given address has any code associated
|
// 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
|
// with it or not. This is needed to differentiate between contract internal
|
||||||
// errors and the local chain being out of sync.
|
// errors and the local chain being out of sync.
|
||||||
HasCode(contract common.Address, pending bool) (bool, error)
|
HasCode(ctx context.Context, 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.
|
||||||
ContractCall(contract common.Address, data []byte, pending bool) ([]byte, error)
|
ContractCall(ctx context.Context, contract common.Address, data []byte, pending bool) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContractTransactor defines the methods needed to allow operating with contract
|
// ContractTransactor defines the methods needed to allow operating with contract
|
||||||
|
@ -50,26 +51,26 @@ type ContractCaller interface {
|
||||||
type ContractTransactor interface {
|
type ContractTransactor interface {
|
||||||
// PendingAccountNonce retrieves the current pending nonce associated with an
|
// PendingAccountNonce retrieves the current pending nonce associated with an
|
||||||
// account.
|
// account.
|
||||||
PendingAccountNonce(account common.Address) (uint64, error)
|
PendingAccountNonce(ctx context.Context, account common.Address) (uint64, error)
|
||||||
|
|
||||||
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely
|
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely
|
||||||
// execution of a transaction.
|
// execution of a transaction.
|
||||||
SuggestGasPrice() (*big.Int, error)
|
SuggestGasPrice(ctx context.Context) (*big.Int, error)
|
||||||
|
|
||||||
// HasCode checks if the contract at the given address has any code associated
|
// 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
|
// with it or not. This is needed to differentiate between contract internal
|
||||||
// errors and the local chain being out of sync.
|
// errors and the local chain being out of sync.
|
||||||
HasCode(contract common.Address, pending bool) (bool, error)
|
HasCode(ctx context.Context, 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
|
||||||
// transactions may be added or removed by miners, but it should provide a basis
|
// transactions may be added or removed by miners, but it should provide a basis
|
||||||
// for setting a reasonable default.
|
// for setting a reasonable default.
|
||||||
EstimateGasLimit(sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error)
|
EstimateGasLimit(ctx context.Context, 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 injects the transaction into the pending pool for execution.
|
||||||
SendTransaction(tx *types.Transaction) error
|
SendTransaction(ctx context.Context, tx *types.Transaction) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContractBackend defines the methods needed to allow operating with contract
|
// ContractBackend defines the methods needed to allow operating with contract
|
||||||
|
@ -84,28 +85,28 @@ type ContractBackend interface {
|
||||||
// HasCode checks if the contract at the given address has any code associated
|
// 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
|
// with it or not. This is needed to differentiate between contract internal
|
||||||
// errors and the local chain being out of sync.
|
// errors and the local chain being out of sync.
|
||||||
HasCode(contract common.Address, pending bool) (bool, error)
|
HasCode(ctx context.Context, 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.
|
||||||
ContractCall(contract common.Address, data []byte, pending bool) ([]byte, error)
|
ContractCall(ctx context.Context, contract common.Address, data []byte, pending bool) ([]byte, error)
|
||||||
|
|
||||||
// PendingAccountNonce retrieves the current pending nonce associated with an
|
// PendingAccountNonce retrieves the current pending nonce associated with an
|
||||||
// account.
|
// account.
|
||||||
PendingAccountNonce(account common.Address) (uint64, error)
|
PendingAccountNonce(ctx context.Context, account common.Address) (uint64, error)
|
||||||
|
|
||||||
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely
|
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely
|
||||||
// execution of a transaction.
|
// execution of a transaction.
|
||||||
SuggestGasPrice() (*big.Int, error)
|
SuggestGasPrice(ctx context.Context) (*big.Int, 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
|
||||||
// transactions may be added or removed by miners, but it should provide a basis
|
// transactions may be added or removed by miners, but it should provide a basis
|
||||||
// for setting a reasonable default.
|
// for setting a reasonable default.
|
||||||
EstimateGasLimit(sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error)
|
EstimateGasLimit(ctx context.Context, 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 injects the transaction into the pending pool for execution.
|
||||||
SendTransaction(tx *types.Transaction) error
|
SendTransaction(ctx context.Context, tx *types.Transaction) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"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"
|
||||||
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This nil assignment ensures compile time that nilBackend implements bind.ContractBackend.
|
// This nil assignment ensures compile time that nilBackend implements bind.ContractBackend.
|
||||||
|
@ -32,16 +33,22 @@ var _ bind.ContractBackend = (*nilBackend)(nil)
|
||||||
// wrappers without calling any methods on them.
|
// wrappers without calling any methods on them.
|
||||||
type nilBackend struct{}
|
type nilBackend struct{}
|
||||||
|
|
||||||
func (*nilBackend) ContractCall(common.Address, []byte, bool) ([]byte, error) {
|
func (*nilBackend) ContractCall(context.Context, common.Address, []byte, bool) ([]byte, error) {
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
func (*nilBackend) EstimateGasLimit(common.Address, *common.Address, *big.Int, []byte) (*big.Int, error) {
|
func (*nilBackend) EstimateGasLimit(context.Context, common.Address, *common.Address, *big.Int, []byte) (*big.Int, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
func (*nilBackend) HasCode(context.Context, common.Address, bool) (bool, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
func (*nilBackend) SuggestGasPrice(context.Context) (*big.Int, error) { panic("not implemented") }
|
||||||
|
func (*nilBackend) PendingAccountNonce(context.Context, common.Address) (uint64, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
func (*nilBackend) SendTransaction(context.Context, *types.Transaction) 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) PendingAccountNonce(common.Address) (uint64, error) { panic("not implemented") }
|
|
||||||
func (*nilBackend) SendTransaction(*types.Transaction) error { panic("not implemented") }
|
|
||||||
|
|
||||||
// NewNilBackend creates a new binding backend that can be used for instantiation
|
// NewNilBackend creates a new binding backend that can be used for instantiation
|
||||||
// but will panic on any invocation. Its sole purpose is to help testing.
|
// but will panic on any invocation. Its sole purpose is to help testing.
|
||||||
|
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"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"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This nil assignment ensures compile time that rpcBackend implements bind.ContractBackend.
|
// This nil assignment ensures compile time that rpcBackend implements bind.ContractBackend.
|
||||||
|
@ -80,18 +81,23 @@ type failure struct {
|
||||||
//
|
//
|
||||||
// This is currently painfully non-concurrent, but it will have to do until we
|
// This is currently painfully non-concurrent, but it will have to do until we
|
||||||
// find the time for niceties like this :P
|
// find the time for niceties like this :P
|
||||||
func (b *rpcBackend) request(method string, params []interface{}) (json.RawMessage, error) {
|
func (b *rpcBackend) request(ctx context.Context, method string, params []interface{}) (json.RawMessage, error) {
|
||||||
b.lock.Lock()
|
b.lock.Lock()
|
||||||
defer b.lock.Unlock()
|
defer b.lock.Unlock()
|
||||||
|
|
||||||
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
|
|
||||||
// Ugly hack to serialize an empty list properly
|
// Ugly hack to serialize an empty list properly
|
||||||
if params == nil {
|
if params == nil {
|
||||||
params = []interface{}{}
|
params = []interface{}{}
|
||||||
}
|
}
|
||||||
// Assemble the request object
|
// Assemble the request object
|
||||||
|
reqID := int(atomic.AddUint32(&b.autoid, 1))
|
||||||
req := &request{
|
req := &request{
|
||||||
JSONRPC: "2.0",
|
JSONRPC: "2.0",
|
||||||
ID: int(atomic.AddUint32(&b.autoid, 1)),
|
ID: reqID,
|
||||||
Method: method,
|
Method: method,
|
||||||
Params: params,
|
Params: params,
|
||||||
}
|
}
|
||||||
|
@ -99,9 +105,18 @@ func (b *rpcBackend) request(method string, params []interface{}) (json.RawMessa
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
res := new(response)
|
res := new(response)
|
||||||
if err := b.client.Recv(res); err != nil {
|
errc := make(chan error, 1)
|
||||||
|
go func() {
|
||||||
|
errc <- b.client.Recv(res)
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case err := <-errc:
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, ctx.Err()
|
||||||
|
}
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
if res.Error.Message == bind.ErrNoCode.Error() {
|
if res.Error.Message == bind.ErrNoCode.Error() {
|
||||||
return nil, bind.ErrNoCode
|
return nil, bind.ErrNoCode
|
||||||
|
@ -113,13 +128,13 @@ func (b *rpcBackend) request(method string, params []interface{}) (json.RawMessa
|
||||||
|
|
||||||
// HasCode implements ContractVerifier.HasCode by retrieving any code associated
|
// HasCode implements ContractVerifier.HasCode by retrieving any code associated
|
||||||
// with the contract from the remote node, and checking its size.
|
// with the contract from the remote node, and checking its size.
|
||||||
func (b *rpcBackend) HasCode(contract common.Address, pending bool) (bool, error) {
|
func (b *rpcBackend) HasCode(ctx context.Context, contract common.Address, pending bool) (bool, error) {
|
||||||
// Execute the RPC code retrieval
|
// Execute the RPC code retrieval
|
||||||
block := "latest"
|
block := "latest"
|
||||||
if pending {
|
if pending {
|
||||||
block = "pending"
|
block = "pending"
|
||||||
}
|
}
|
||||||
res, err := b.request("eth_getCode", []interface{}{contract.Hex(), block})
|
res, err := b.request(ctx, "eth_getCode", []interface{}{contract.Hex(), block})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -133,7 +148,7 @@ func (b *rpcBackend) HasCode(contract common.Address, pending bool) (bool, error
|
||||||
|
|
||||||
// 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(ctx context.Context, contract common.Address, data []byte, pending bool) ([]byte, error) {
|
||||||
// Pack up the request into an RPC argument
|
// Pack up the request into an RPC argument
|
||||||
args := struct {
|
args := struct {
|
||||||
To common.Address `json:"to"`
|
To common.Address `json:"to"`
|
||||||
|
@ -147,7 +162,7 @@ func (b *rpcBackend) ContractCall(contract common.Address, data []byte, pending
|
||||||
if pending {
|
if pending {
|
||||||
block = "pending"
|
block = "pending"
|
||||||
}
|
}
|
||||||
res, err := b.request("eth_call", []interface{}{args, block})
|
res, err := b.request(ctx, "eth_call", []interface{}{args, block})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -161,8 +176,8 @@ func (b *rpcBackend) ContractCall(contract common.Address, data []byte, pending
|
||||||
|
|
||||||
// PendingAccountNonce implements ContractTransactor.PendingAccountNonce, delegating
|
// PendingAccountNonce implements ContractTransactor.PendingAccountNonce, delegating
|
||||||
// the current account nonce retrieval to the remote node.
|
// the current account nonce retrieval to the remote node.
|
||||||
func (b *rpcBackend) PendingAccountNonce(account common.Address) (uint64, error) {
|
func (b *rpcBackend) PendingAccountNonce(ctx context.Context, account common.Address) (uint64, error) {
|
||||||
res, err := b.request("eth_getTransactionCount", []interface{}{account.Hex(), "pending"})
|
res, err := b.request(ctx, "eth_getTransactionCount", []interface{}{account.Hex(), "pending"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
@ -179,8 +194,8 @@ func (b *rpcBackend) PendingAccountNonce(account common.Address) (uint64, error)
|
||||||
|
|
||||||
// SuggestGasPrice implements ContractTransactor.SuggestGasPrice, delegating the
|
// SuggestGasPrice implements ContractTransactor.SuggestGasPrice, delegating the
|
||||||
// gas price oracle request to the remote node.
|
// gas price oracle request to the remote node.
|
||||||
func (b *rpcBackend) SuggestGasPrice() (*big.Int, error) {
|
func (b *rpcBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
|
||||||
res, err := b.request("eth_gasPrice", nil)
|
res, err := b.request(ctx, "eth_gasPrice", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -197,7 +212,7 @@ func (b *rpcBackend) SuggestGasPrice() (*big.Int, error) {
|
||||||
|
|
||||||
// EstimateGasLimit implements ContractTransactor.EstimateGasLimit, delegating
|
// EstimateGasLimit implements ContractTransactor.EstimateGasLimit, delegating
|
||||||
// the gas estimation to the remote node.
|
// the gas estimation to the remote node.
|
||||||
func (b *rpcBackend) EstimateGasLimit(sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error) {
|
func (b *rpcBackend) EstimateGasLimit(ctx context.Context, sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error) {
|
||||||
// Pack up the request into an RPC argument
|
// Pack up the request into an RPC argument
|
||||||
args := struct {
|
args := struct {
|
||||||
From common.Address `json:"from"`
|
From common.Address `json:"from"`
|
||||||
|
@ -211,7 +226,7 @@ func (b *rpcBackend) EstimateGasLimit(sender common.Address, contract *common.Ad
|
||||||
Value: rpc.NewHexNumber(value),
|
Value: rpc.NewHexNumber(value),
|
||||||
}
|
}
|
||||||
// Execute the RPC call and retrieve the response
|
// Execute the RPC call and retrieve the response
|
||||||
res, err := b.request("eth_estimateGas", []interface{}{args})
|
res, err := b.request(ctx, "eth_estimateGas", []interface{}{args})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -228,12 +243,12 @@ func (b *rpcBackend) EstimateGasLimit(sender common.Address, contract *common.Ad
|
||||||
|
|
||||||
// SendTransaction implements ContractTransactor.SendTransaction, delegating the
|
// SendTransaction implements ContractTransactor.SendTransaction, delegating the
|
||||||
// raw transaction injection to the remote node.
|
// raw transaction injection to the remote node.
|
||||||
func (b *rpcBackend) SendTransaction(tx *types.Transaction) error {
|
func (b *rpcBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error {
|
||||||
data, err := rlp.EncodeToBytes(tx)
|
data, err := rlp.EncodeToBytes(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
res, err := b.request("eth_sendRawTransaction", []interface{}{common.ToHex(data)})
|
res, err := b.request(ctx, "eth_sendRawTransaction", []interface{}{common.ToHex(data)})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default chain configuration which sets homestead phase at block 0 (i.e. no frontier)
|
// Default chain configuration which sets homestead phase at block 0 (i.e. no frontier)
|
||||||
|
@ -80,7 +81,7 @@ func (b *SimulatedBackend) Rollback() {
|
||||||
|
|
||||||
// HasCode implements ContractVerifier.HasCode, checking whether there is any
|
// HasCode implements ContractVerifier.HasCode, checking whether there is any
|
||||||
// code associated with a certain account in the blockchain.
|
// code associated with a certain account in the blockchain.
|
||||||
func (b *SimulatedBackend) HasCode(contract common.Address, pending bool) (bool, error) {
|
func (b *SimulatedBackend) HasCode(ctx context.Context, contract common.Address, pending bool) (bool, error) {
|
||||||
if pending {
|
if pending {
|
||||||
return len(b.pendingState.GetCode(contract)) > 0, nil
|
return len(b.pendingState.GetCode(contract)) > 0, nil
|
||||||
}
|
}
|
||||||
|
@ -90,7 +91,7 @@ func (b *SimulatedBackend) HasCode(contract common.Address, pending bool) (bool,
|
||||||
|
|
||||||
// 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(ctx context.Context, contract common.Address, data []byte, pending bool) ([]byte, error) {
|
||||||
// Create a copy of the current state db to screw around with
|
// Create a copy of the current state db to screw around with
|
||||||
var (
|
var (
|
||||||
block *types.Block
|
block *types.Block
|
||||||
|
@ -129,20 +130,20 @@ func (b *SimulatedBackend) ContractCall(contract common.Address, data []byte, pe
|
||||||
|
|
||||||
// PendingAccountNonce implements ContractTransactor.PendingAccountNonce, retrieving
|
// PendingAccountNonce implements ContractTransactor.PendingAccountNonce, retrieving
|
||||||
// the nonce currently pending for the account.
|
// the nonce currently pending for the account.
|
||||||
func (b *SimulatedBackend) PendingAccountNonce(account common.Address) (uint64, error) {
|
func (b *SimulatedBackend) PendingAccountNonce(ctx context.Context, account common.Address) (uint64, error) {
|
||||||
return b.pendingState.GetOrNewStateObject(account).Nonce(), nil
|
return b.pendingState.GetOrNewStateObject(account).Nonce(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SuggestGasPrice implements ContractTransactor.SuggestGasPrice. Since the simulated
|
// SuggestGasPrice implements ContractTransactor.SuggestGasPrice. Since the simulated
|
||||||
// chain doens't have miners, we just return a gas price of 1 for any call.
|
// chain doens't have miners, we just return a gas price of 1 for any call.
|
||||||
func (b *SimulatedBackend) SuggestGasPrice() (*big.Int, error) {
|
func (b *SimulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
|
||||||
return big.NewInt(1), nil
|
return big.NewInt(1), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EstimateGasLimit implements ContractTransactor.EstimateGasLimit, executing the
|
// EstimateGasLimit implements ContractTransactor.EstimateGasLimit, executing the
|
||||||
// requested code against the currently pending block/state and returning the used
|
// requested code against the currently pending block/state and returning the used
|
||||||
// gas.
|
// gas.
|
||||||
func (b *SimulatedBackend) EstimateGasLimit(sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error) {
|
func (b *SimulatedBackend) EstimateGasLimit(ctx context.Context, sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error) {
|
||||||
// Create a copy of the currently pending state db to screw around with
|
// Create a copy of the currently pending state db to screw around with
|
||||||
var (
|
var (
|
||||||
block = b.pendingBlock
|
block = b.pendingBlock
|
||||||
|
@ -177,7 +178,7 @@ func (b *SimulatedBackend) EstimateGasLimit(sender common.Address, contract *com
|
||||||
|
|
||||||
// SendTransaction implements ContractTransactor.SendTransaction, delegating the raw
|
// SendTransaction implements ContractTransactor.SendTransaction, delegating the raw
|
||||||
// transaction injection to the remote node.
|
// transaction injection to the remote node.
|
||||||
func (b *SimulatedBackend) SendTransaction(tx *types.Transaction) error {
|
func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error {
|
||||||
blocks, _ := core.GenerateChain(b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) {
|
blocks, _ := core.GenerateChain(b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) {
|
||||||
for _, tx := range b.pendingBlock.Transactions() {
|
for _, tx := range b.pendingBlock.Transactions() {
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"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/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SignerFn is a signer function callback when a contract requires a method to
|
// SignerFn is a signer function callback when a contract requires a method to
|
||||||
|
@ -35,6 +36,8 @@ type SignerFn func(common.Address, *types.Transaction) (*types.Transaction, erro
|
||||||
// CallOpts is the collection of options to fine tune a contract call request.
|
// CallOpts is the collection of options to fine tune a contract call request.
|
||||||
type CallOpts struct {
|
type CallOpts struct {
|
||||||
Pending bool // Whether to operate on the pending state or the last known one
|
Pending bool // Whether to operate on the pending state or the last known one
|
||||||
|
|
||||||
|
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransactOpts is the collection of authorization data required to create a
|
// TransactOpts is the collection of authorization data required to create a
|
||||||
|
@ -47,6 +50,8 @@ type TransactOpts struct {
|
||||||
Value *big.Int // Funds to transfer along along the transaction (nil = 0 = no funds)
|
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)
|
GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle)
|
||||||
GasLimit *big.Int // Gas limit to set for the transaction execution (nil = estimate + 10%)
|
GasLimit *big.Int // Gas limit to set for the transaction execution (nil = estimate + 10%)
|
||||||
|
|
||||||
|
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
|
// BoundContract is the base wrapper object that reflects a contract on the
|
||||||
|
@ -102,7 +107,7 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
|
||||||
}
|
}
|
||||||
// Make sure we have a contract to operate on, and bail out otherwise
|
// 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 (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 {
|
if code, err := c.caller.HasCode(opts.Context, c.address, opts.Pending); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if !code {
|
} else if !code {
|
||||||
return ErrNoCode
|
return ErrNoCode
|
||||||
|
@ -118,7 +123,7 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
output, err := c.caller.ContractCall(c.address, input, opts.Pending)
|
output, err := c.caller.ContractCall(opts.Context, c.address, input, opts.Pending)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -153,7 +158,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
|
||||||
}
|
}
|
||||||
nonce := uint64(0)
|
nonce := uint64(0)
|
||||||
if opts.Nonce == nil {
|
if opts.Nonce == nil {
|
||||||
nonce, err = c.transactor.PendingAccountNonce(opts.From)
|
nonce, err = c.transactor.PendingAccountNonce(opts.Context, opts.From)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to retrieve account nonce: %v", err)
|
return nil, fmt.Errorf("failed to retrieve account nonce: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -163,7 +168,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
|
||||||
// Figure out the gas allowance and gas price values
|
// Figure out the gas allowance and gas price values
|
||||||
gasPrice := opts.GasPrice
|
gasPrice := opts.GasPrice
|
||||||
if gasPrice == nil {
|
if gasPrice == nil {
|
||||||
gasPrice, err = c.transactor.SuggestGasPrice()
|
gasPrice, err = c.transactor.SuggestGasPrice(opts.Context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to suggest gas price: %v", err)
|
return nil, fmt.Errorf("failed to suggest gas price: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -172,7 +177,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
|
||||||
if gasLimit == nil {
|
if gasLimit == nil {
|
||||||
// Gas estimation cannot succeed without code for method invocations
|
// Gas estimation cannot succeed without code for method invocations
|
||||||
if contract != nil && atomic.LoadUint32(&c.pendingHasCode) == 0 {
|
if contract != nil && atomic.LoadUint32(&c.pendingHasCode) == 0 {
|
||||||
if code, err := c.transactor.HasCode(c.address, true); err != nil {
|
if code, err := c.transactor.HasCode(opts.Context, c.address, true); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !code {
|
} else if !code {
|
||||||
return nil, ErrNoCode
|
return nil, ErrNoCode
|
||||||
|
@ -180,7 +185,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
|
||||||
atomic.StoreUint32(&c.pendingHasCode, 1)
|
atomic.StoreUint32(&c.pendingHasCode, 1)
|
||||||
}
|
}
|
||||||
// If the contract surely has code (or code is not needed), estimate the transaction
|
// 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.Context, 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)
|
||||||
}
|
}
|
||||||
|
@ -199,7 +204,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := c.transactor.SendTransaction(signedTx); err != nil {
|
if err := c.transactor.SendTransaction(opts.Context, signedTx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return signedTx, nil
|
return signedTx, nil
|
||||||
|
|
|
@ -34,6 +34,8 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -340,3 +342,23 @@ func zeroKey(k *ecdsa.PrivateKey) {
|
||||||
b[i] = 0
|
b[i] = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// APIs implements node.Service
|
||||||
|
func (am *Manager) APIs() []rpc.API {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protocols implements node.Service
|
||||||
|
func (am *Manager) Protocols() []p2p.Protocol {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start implements node.Service
|
||||||
|
func (am *Manager) Start(srvr *p2p.Server) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop implements node.Service
|
||||||
|
func (am *Manager) Stop() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/ethash"
|
"github.com/ethereum/ethash"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/console"
|
"github.com/ethereum/go-ethereum/console"
|
||||||
|
@ -313,11 +314,10 @@ func startNode(ctx *cli.Context, stack *node.Node) {
|
||||||
utils.StartNode(stack)
|
utils.StartNode(stack)
|
||||||
|
|
||||||
// Unlock any account specifically requested
|
// Unlock any account specifically requested
|
||||||
var ethereum *eth.Ethereum
|
var accman *accounts.Manager
|
||||||
if err := stack.Service(ðereum); err != nil {
|
if err := stack.Service(&accman); err != nil {
|
||||||
utils.Fatalf("ethereum service not running: %v", err)
|
utils.Fatalf("ethereum service not running: %v", err)
|
||||||
}
|
}
|
||||||
accman := ethereum.AccountManager()
|
|
||||||
passwords := utils.MakePasswordList(ctx)
|
passwords := utils.MakePasswordList(ctx)
|
||||||
|
|
||||||
accounts := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",")
|
accounts := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",")
|
||||||
|
@ -328,6 +328,10 @@ func startNode(ctx *cli.Context, stack *node.Node) {
|
||||||
}
|
}
|
||||||
// Start auxiliary services if enabled
|
// Start auxiliary services if enabled
|
||||||
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) {
|
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) {
|
||||||
|
var ethereum *eth.FullNodeService
|
||||||
|
if err := stack.Service(ðereum); err != nil {
|
||||||
|
utils.Fatalf("ethereum service not running: %v", err)
|
||||||
|
}
|
||||||
if err := ethereum.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name), ctx.GlobalString(utils.MiningGPUFlag.Name)); err != nil {
|
if err := ethereum.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name), ctx.GlobalString(utils.MiningGPUFlag.Name)); err != nil {
|
||||||
utils.Fatalf("Failed to start mining: %v", err)
|
utils.Fatalf("Failed to start mining: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,7 +146,7 @@ func MakeSystemNode(keydir string, privkey string, test *tests.BlockTest) (*node
|
||||||
// RunTest executes the specified test against an already pre-configured protocol
|
// RunTest executes the specified test against an already pre-configured protocol
|
||||||
// stack to ensure basic checks pass before running RPC tests.
|
// stack to ensure basic checks pass before running RPC tests.
|
||||||
func RunTest(stack *node.Node, test *tests.BlockTest) error {
|
func RunTest(stack *node.Node, test *tests.BlockTest) error {
|
||||||
var ethereum *eth.Ethereum
|
var ethereum *eth.FullNodeService
|
||||||
stack.Service(ðereum)
|
stack.Service(ðereum)
|
||||||
blockchain := ethereum.BlockChain()
|
blockchain := ethereum.BlockChain()
|
||||||
|
|
||||||
|
|
|
@ -763,6 +763,13 @@ func MakeSystemNode(name, version string, relconf release.Config, extra []byte,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("Failed to create the protocol stack: %v", err)
|
Fatalf("Failed to create the protocol stack: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
||||||
|
return accman, nil
|
||||||
|
}); err != nil {
|
||||||
|
Fatalf("Failed to register the account manager service: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
||||||
return eth.New(ctx, ethConf)
|
return eth.New(ctx, ethConf)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
|
@ -99,7 +99,7 @@ const (
|
||||||
|
|
||||||
type testFrontend struct {
|
type testFrontend struct {
|
||||||
t *testing.T
|
t *testing.T
|
||||||
ethereum *eth.Ethereum
|
ethereum *eth.FullNodeService
|
||||||
xeth *xe.XEth
|
xeth *xe.XEth
|
||||||
wait chan *big.Int
|
wait chan *big.Int
|
||||||
lastConfirm string
|
lastConfirm string
|
||||||
|
@ -123,7 +123,7 @@ func (self *testFrontend) ConfirmTransaction(tx string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) {
|
func testEth(t *testing.T) (ethereum *eth.FullNodeService, err error) {
|
||||||
|
|
||||||
tmp, err := ioutil.TempDir("", "natspec-test")
|
tmp, err := ioutil.TempDir("", "natspec-test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -76,7 +76,7 @@ func (p *hookedPrompter) SetWordCompleter(completer WordCompleter) {}
|
||||||
type tester struct {
|
type tester struct {
|
||||||
workspace string
|
workspace string
|
||||||
stack *node.Node
|
stack *node.Node
|
||||||
ethereum *eth.Ethereum
|
ethereum *eth.FullNodeService
|
||||||
console *Console
|
console *Console
|
||||||
input *hookedPrompter
|
input *hookedPrompter
|
||||||
output *bytes.Buffer
|
output *bytes.Buffer
|
||||||
|
@ -134,7 +134,7 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
|
||||||
t.Fatalf("failed to create JavaScript console: %v", err)
|
t.Fatalf("failed to create JavaScript console: %v", err)
|
||||||
}
|
}
|
||||||
// Create the final tester and return
|
// Create the final tester and return
|
||||||
var ethereum *eth.Ethereum
|
var ethereum *eth.FullNodeService
|
||||||
stack.Service(ðereum)
|
stack.Service(ðereum)
|
||||||
|
|
||||||
return &tester{
|
return &tester{
|
||||||
|
|
|
@ -73,6 +73,8 @@ type Environment interface {
|
||||||
DelegateCall(me ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error)
|
DelegateCall(me ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error)
|
||||||
// Create a new contract
|
// Create a new contract
|
||||||
Create(me ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error)
|
Create(me ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error)
|
||||||
|
|
||||||
|
StructLogs() []StructLog
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vm is the basic interface for an implementation of the EVM.
|
// Vm is the basic interface for an implementation of the EVM.
|
||||||
|
|
1603
eth/api.go
1603
eth/api.go
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,201 @@
|
||||||
|
// Copyright 2015 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package eth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
|
rpc "github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EthApiBackend implements ethapi.Backend for full nodes
|
||||||
|
type EthApiBackend struct {
|
||||||
|
eth *FullNodeService
|
||||||
|
gpo *gasprice.GasPriceOracle
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) SetHead(number uint64) {
|
||||||
|
b.eth.blockchain.SetHead(number)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) HeaderByNumber(blockNr rpc.BlockNumber) *types.Header {
|
||||||
|
// Pending block is only known by the miner
|
||||||
|
if blockNr == rpc.PendingBlockNumber {
|
||||||
|
block, _ := b.eth.miner.Pending()
|
||||||
|
return block.Header()
|
||||||
|
}
|
||||||
|
// Otherwise resolve and return the block
|
||||||
|
if blockNr == rpc.LatestBlockNumber {
|
||||||
|
return b.eth.blockchain.CurrentBlock().Header()
|
||||||
|
}
|
||||||
|
return b.eth.blockchain.GetHeaderByNumber(uint64(blockNr))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error) {
|
||||||
|
// Pending block is only known by the miner
|
||||||
|
if blockNr == rpc.PendingBlockNumber {
|
||||||
|
block, _ := b.eth.miner.Pending()
|
||||||
|
return block, nil
|
||||||
|
}
|
||||||
|
// Otherwise resolve and return the block
|
||||||
|
if blockNr == rpc.LatestBlockNumber {
|
||||||
|
return b.eth.blockchain.CurrentBlock(), nil
|
||||||
|
}
|
||||||
|
return b.eth.blockchain.GetBlockByNumber(uint64(blockNr)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) StateAndHeaderByNumber(blockNr rpc.BlockNumber) (ethapi.State, *types.Header, error) {
|
||||||
|
// Pending state is only known by the miner
|
||||||
|
if blockNr == rpc.PendingBlockNumber {
|
||||||
|
block, state := b.eth.miner.Pending()
|
||||||
|
return EthApiState{state}, block.Header(), nil
|
||||||
|
}
|
||||||
|
// Otherwise resolve the block number and return its state
|
||||||
|
header := b.HeaderByNumber(blockNr)
|
||||||
|
if header == nil {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
stateDb, err := state.New(header.Root, b.eth.chainDb)
|
||||||
|
return EthApiState{stateDb}, header, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) {
|
||||||
|
return b.eth.blockchain.GetBlockByHash(blockHash), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) {
|
||||||
|
return core.GetBlockReceipts(b.eth.chainDb, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int {
|
||||||
|
return b.eth.blockchain.GetTdByHash(blockHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) {
|
||||||
|
stateDb := state.(EthApiState).state.Copy()
|
||||||
|
addr, _ := msg.From()
|
||||||
|
from := stateDb.GetOrNewStateObject(addr)
|
||||||
|
from.SetBalance(common.MaxBig)
|
||||||
|
vmError := func() error { return nil }
|
||||||
|
return core.NewEnv(stateDb, b.eth.chainConfig, b.eth.blockchain, msg, header, b.eth.chainConfig.VmConfig), vmError, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
|
||||||
|
b.eth.txMu.Lock()
|
||||||
|
defer b.eth.txMu.Unlock()
|
||||||
|
|
||||||
|
b.eth.txPool.SetLocal(signedTx)
|
||||||
|
return b.eth.txPool.Add(signedTx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) RemoveTx(txHash common.Hash) {
|
||||||
|
b.eth.txMu.Lock()
|
||||||
|
defer b.eth.txMu.Unlock()
|
||||||
|
|
||||||
|
b.eth.txPool.RemoveTx(txHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) GetPoolTransactions() types.Transactions {
|
||||||
|
b.eth.txMu.Lock()
|
||||||
|
defer b.eth.txMu.Unlock()
|
||||||
|
|
||||||
|
return b.eth.txPool.GetTransactions()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction {
|
||||||
|
b.eth.txMu.Lock()
|
||||||
|
defer b.eth.txMu.Unlock()
|
||||||
|
|
||||||
|
return b.eth.txPool.GetTransaction(txHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
|
||||||
|
b.eth.txMu.Lock()
|
||||||
|
defer b.eth.txMu.Unlock()
|
||||||
|
|
||||||
|
return b.eth.txPool.State().GetNonce(addr), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) Stats() (pending int, queued int) {
|
||||||
|
b.eth.txMu.Lock()
|
||||||
|
defer b.eth.txMu.Unlock()
|
||||||
|
|
||||||
|
return b.eth.txPool.Stats()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) TxPoolContent() (map[common.Address]map[uint64][]*types.Transaction, map[common.Address]map[uint64][]*types.Transaction) {
|
||||||
|
b.eth.txMu.Lock()
|
||||||
|
defer b.eth.txMu.Unlock()
|
||||||
|
|
||||||
|
return b.eth.TxPool().Content()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) Downloader() *downloader.Downloader {
|
||||||
|
return b.eth.Downloader()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) ProtocolVersion() int {
|
||||||
|
return b.eth.EthVersion()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
|
||||||
|
return b.gpo.SuggestPrice(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) ChainDb() ethdb.Database {
|
||||||
|
return b.eth.ChainDb()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) EventMux() *event.TypeMux {
|
||||||
|
return b.eth.EventMux()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) AccountManager() *accounts.Manager {
|
||||||
|
return b.eth.AccountManager()
|
||||||
|
}
|
||||||
|
|
||||||
|
type EthApiState struct {
|
||||||
|
state *state.StateDB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s EthApiState) GetBalance(ctx context.Context, addr common.Address) (*big.Int, error) {
|
||||||
|
return s.state.GetBalance(addr), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s EthApiState) GetCode(ctx context.Context, addr common.Address) ([]byte, error) {
|
||||||
|
return s.state.GetCode(addr), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s EthApiState) GetState(ctx context.Context, a common.Address, b common.Hash) (common.Hash, error) {
|
||||||
|
return s.state.GetState(a, b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s EthApiState) GetNonce(ctx context.Context, addr common.Address) (uint64, error) {
|
||||||
|
return s.state.GetNonce(addr), nil
|
||||||
|
}
|
322
eth/backend.go
322
eth/backend.go
|
@ -39,8 +39,10 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
"github.com/ethereum/go-ethereum/eth/filters"
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/miner"
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
|
@ -101,95 +103,86 @@ type Config struct {
|
||||||
TestGenesisState ethdb.Database // Genesis state to seed the database with (testing only!)
|
TestGenesisState ethdb.Database // Genesis state to seed the database with (testing only!)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Ethereum struct {
|
// FullNodeService implements the Ethereum full node service.
|
||||||
|
type FullNodeService struct {
|
||||||
chainConfig *core.ChainConfig
|
chainConfig *core.ChainConfig
|
||||||
|
// Channel for shutting down the service
|
||||||
shutdownChan chan bool // Channel for shutting down the ethereum
|
shutdownChan chan bool // Channel for shutting down the ethereum
|
||||||
stopDbUpgrade func() // stop chain db sequential key upgrade
|
stopDbUpgrade func() // stop chain db sequential key upgrade
|
||||||
|
|
||||||
// DB interfaces
|
|
||||||
chainDb ethdb.Database // Block chain database
|
|
||||||
dappDb ethdb.Database // Dapp database
|
|
||||||
|
|
||||||
// Handlers
|
// Handlers
|
||||||
txPool *core.TxPool
|
txPool *core.TxPool
|
||||||
txMu sync.Mutex
|
txMu sync.Mutex
|
||||||
blockchain *core.BlockChain
|
blockchain *core.BlockChain
|
||||||
accountManager *accounts.Manager
|
|
||||||
pow *ethash.Ethash
|
|
||||||
protocolManager *ProtocolManager
|
protocolManager *ProtocolManager
|
||||||
SolcPath string
|
// DB interfaces
|
||||||
solc *compiler.Solidity
|
chainDb ethdb.Database // Block chain database
|
||||||
gpo *GasPriceOracle
|
dappDb ethdb.Database // Dapp database
|
||||||
|
|
||||||
GpoMinGasPrice *big.Int
|
|
||||||
GpoMaxGasPrice *big.Int
|
|
||||||
GpoFullBlockRatio int
|
|
||||||
GpobaseStepDown int
|
|
||||||
GpobaseStepUp int
|
|
||||||
GpobaseCorrectionFactor int
|
|
||||||
|
|
||||||
httpclient *httpclient.HTTPClient
|
|
||||||
|
|
||||||
eventMux *event.TypeMux
|
eventMux *event.TypeMux
|
||||||
miner *miner.Miner
|
pow *ethash.Ethash
|
||||||
|
httpclient *httpclient.HTTPClient
|
||||||
|
accountManager *accounts.Manager
|
||||||
|
|
||||||
|
apiBackend *EthApiBackend
|
||||||
|
|
||||||
|
miner *miner.Miner
|
||||||
Mining bool
|
Mining bool
|
||||||
MinerThreads int
|
MinerThreads int
|
||||||
NatSpec bool
|
|
||||||
AutoDAG bool
|
AutoDAG bool
|
||||||
PowTest bool
|
|
||||||
autodagquit chan bool
|
autodagquit chan bool
|
||||||
etherbase common.Address
|
etherbase common.Address
|
||||||
|
solcPath string
|
||||||
|
solc *compiler.Solidity
|
||||||
|
|
||||||
|
NatSpec bool
|
||||||
|
PowTest bool
|
||||||
netVersionId int
|
netVersionId int
|
||||||
netRPCService *PublicNetAPI
|
netRPCService *ethapi.PublicNetAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
// New creates a new FullNodeService object (including the
|
||||||
// Open the chain database and perform any upgrades needed
|
// initialisation of the common Ethereum object)
|
||||||
chainDb, err := ctx.OpenDatabase("chaindata", config.DatabaseCache, config.DatabaseHandles)
|
func New(ctx *node.ServiceContext, config *Config) (*FullNodeService, error) {
|
||||||
|
chainDb, dappDb, err := CreateDBs(ctx, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if db, ok := chainDb.(*ethdb.LDBDatabase); ok {
|
stopDbUpgrade := upgradeSequentialKeys(chainDb)
|
||||||
db.Meter("eth/db/chaindata/")
|
if err := SetupGenesisBlock(&chainDb, config); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
pow, err := CreatePoW(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
eth := &FullNodeService{
|
||||||
|
chainDb: chainDb,
|
||||||
|
dappDb: dappDb,
|
||||||
|
eventMux: ctx.EventMux,
|
||||||
|
accountManager: config.AccountManager,
|
||||||
|
pow: pow,
|
||||||
|
shutdownChan: make(chan bool),
|
||||||
|
stopDbUpgrade: stopDbUpgrade,
|
||||||
|
httpclient: httpclient.New(config.DocRoot),
|
||||||
|
netVersionId: config.NetworkId,
|
||||||
|
NatSpec: config.NatSpec,
|
||||||
|
PowTest: config.PowTest,
|
||||||
|
etherbase: config.Etherbase,
|
||||||
|
MinerThreads: config.MinerThreads,
|
||||||
|
AutoDAG: config.AutoDAG,
|
||||||
|
solcPath: config.SolcPath,
|
||||||
|
}
|
||||||
|
|
||||||
if err := upgradeChainDatabase(chainDb); err != nil {
|
if err := upgradeChainDatabase(chainDb); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := addMipmapBloomBins(chainDb); err != nil {
|
if err := addMipmapBloomBins(chainDb); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
stopDbUpgrade := upgradeSequentialKeys(chainDb)
|
|
||||||
|
|
||||||
dappDb, err := ctx.OpenDatabase("dapp", config.DatabaseCache, config.DatabaseHandles)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if db, ok := dappDb.(*ethdb.LDBDatabase); ok {
|
|
||||||
db.Meter("eth/db/dapp/")
|
|
||||||
}
|
|
||||||
glog.V(logger.Info).Infof("Protocol Versions: %v, Network Id: %v", ProtocolVersions, config.NetworkId)
|
glog.V(logger.Info).Infof("Protocol Versions: %v, Network Id: %v", ProtocolVersions, config.NetworkId)
|
||||||
|
|
||||||
// Load up any custom genesis block if requested
|
|
||||||
if len(config.Genesis) > 0 {
|
|
||||||
block, err := core.WriteGenesisBlock(chainDb, strings.NewReader(config.Genesis))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
glog.V(logger.Info).Infof("Successfully wrote custom genesis block: %x", block.Hash())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load up a test setup if directly injected
|
|
||||||
if config.TestGenesisState != nil {
|
|
||||||
chainDb = config.TestGenesisState
|
|
||||||
}
|
|
||||||
if config.TestGenesisBlock != nil {
|
|
||||||
core.WriteTd(chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.NumberU64(), config.TestGenesisBlock.Difficulty())
|
|
||||||
core.WriteBlock(chainDb, config.TestGenesisBlock)
|
|
||||||
core.WriteCanonicalHash(chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.NumberU64())
|
|
||||||
core.WriteHeadBlockHash(chainDb, config.TestGenesisBlock.Hash())
|
|
||||||
}
|
|
||||||
|
|
||||||
if !config.SkipBcVersionCheck {
|
if !config.SkipBcVersionCheck {
|
||||||
bcVersion := core.GetBlockChainVersion(chainDb)
|
bcVersion := core.GetBlockChainVersion(chainDb)
|
||||||
if bcVersion != config.BlockChainVersion && bcVersion != 0 {
|
if bcVersion != config.BlockChainVersion && bcVersion != 0 {
|
||||||
|
@ -197,44 +190,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||||
}
|
}
|
||||||
core.WriteBlockChainVersion(chainDb, config.BlockChainVersion)
|
core.WriteBlockChainVersion(chainDb, config.BlockChainVersion)
|
||||||
}
|
}
|
||||||
glog.V(logger.Info).Infof("Blockchain DB Version: %d", config.BlockChainVersion)
|
|
||||||
|
|
||||||
eth := &Ethereum{
|
|
||||||
shutdownChan: make(chan bool),
|
|
||||||
stopDbUpgrade: stopDbUpgrade,
|
|
||||||
chainDb: chainDb,
|
|
||||||
dappDb: dappDb,
|
|
||||||
eventMux: ctx.EventMux,
|
|
||||||
accountManager: config.AccountManager,
|
|
||||||
etherbase: config.Etherbase,
|
|
||||||
netVersionId: config.NetworkId,
|
|
||||||
NatSpec: config.NatSpec,
|
|
||||||
MinerThreads: config.MinerThreads,
|
|
||||||
SolcPath: config.SolcPath,
|
|
||||||
AutoDAG: config.AutoDAG,
|
|
||||||
PowTest: config.PowTest,
|
|
||||||
GpoMinGasPrice: config.GpoMinGasPrice,
|
|
||||||
GpoMaxGasPrice: config.GpoMaxGasPrice,
|
|
||||||
GpoFullBlockRatio: config.GpoFullBlockRatio,
|
|
||||||
GpobaseStepDown: config.GpobaseStepDown,
|
|
||||||
GpobaseStepUp: config.GpobaseStepUp,
|
|
||||||
GpobaseCorrectionFactor: config.GpobaseCorrectionFactor,
|
|
||||||
httpclient: httpclient.New(config.DocRoot),
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case config.PowTest:
|
|
||||||
glog.V(logger.Info).Infof("ethash used in test mode")
|
|
||||||
eth.pow, err = ethash.NewForTesting()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case config.PowShared:
|
|
||||||
glog.V(logger.Info).Infof("ethash used in shared mode")
|
|
||||||
eth.pow = ethash.NewShared()
|
|
||||||
|
|
||||||
default:
|
|
||||||
eth.pow = ethash.New()
|
|
||||||
}
|
|
||||||
|
|
||||||
// load the genesis block or write a new one if no genesis
|
// load the genesis block or write a new one if no genesis
|
||||||
// block is prenent in the database.
|
// block is prenent in the database.
|
||||||
|
@ -263,8 +218,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
eth.gpo = NewGasPriceOracle(eth)
|
|
||||||
|
|
||||||
newPool := core.NewTxPool(eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit)
|
newPool := core.NewTxPool(eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit)
|
||||||
eth.txPool = newPool
|
eth.txPool = newPool
|
||||||
|
|
||||||
|
@ -275,37 +228,87 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||||
eth.miner.SetGasPrice(config.GasPrice)
|
eth.miner.SetGasPrice(config.GasPrice)
|
||||||
eth.miner.SetExtra(config.ExtraData)
|
eth.miner.SetExtra(config.ExtraData)
|
||||||
|
|
||||||
|
gpoParams := &gasprice.GpoParams{
|
||||||
|
GpoMinGasPrice: config.GpoMinGasPrice,
|
||||||
|
GpoMaxGasPrice: config.GpoMaxGasPrice,
|
||||||
|
GpoFullBlockRatio: config.GpoFullBlockRatio,
|
||||||
|
GpobaseStepDown: config.GpobaseStepDown,
|
||||||
|
GpobaseStepUp: config.GpobaseStepUp,
|
||||||
|
GpobaseCorrectionFactor: config.GpobaseCorrectionFactor,
|
||||||
|
}
|
||||||
|
gpo := gasprice.NewGasPriceOracle(eth.blockchain, chainDb, eth.eventMux, gpoParams)
|
||||||
|
eth.apiBackend = &EthApiBackend{eth, gpo}
|
||||||
|
|
||||||
return eth, nil
|
return eth, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateDBs creates the chain and dapp databases for an Ethereum service
|
||||||
|
func CreateDBs(ctx *node.ServiceContext, config *Config) (chainDb, dappDb ethdb.Database, err error) {
|
||||||
|
// Open the chain database and perform any upgrades needed
|
||||||
|
chainDb, err = ctx.OpenDatabase("chaindata", config.DatabaseCache, config.DatabaseHandles)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if db, ok := chainDb.(*ethdb.LDBDatabase); ok {
|
||||||
|
db.Meter("eth/db/chaindata/")
|
||||||
|
}
|
||||||
|
|
||||||
|
dappDb, err = ctx.OpenDatabase("dapp", config.DatabaseCache, config.DatabaseHandles)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if db, ok := dappDb.(*ethdb.LDBDatabase); ok {
|
||||||
|
db.Meter("eth/db/dapp/")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupGenesisBlock initializes the genesis block for an Ethereum service
|
||||||
|
func SetupGenesisBlock(chainDb *ethdb.Database, config *Config) error {
|
||||||
|
// Load up any custom genesis block if requested
|
||||||
|
if len(config.Genesis) > 0 {
|
||||||
|
block, err := core.WriteGenesisBlock(*chainDb, strings.NewReader(config.Genesis))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
glog.V(logger.Info).Infof("Successfully wrote custom genesis block: %x", block.Hash())
|
||||||
|
}
|
||||||
|
// Load up a test setup if directly injected
|
||||||
|
if config.TestGenesisState != nil {
|
||||||
|
*chainDb = config.TestGenesisState
|
||||||
|
}
|
||||||
|
if config.TestGenesisBlock != nil {
|
||||||
|
core.WriteTd(*chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.NumberU64(), config.TestGenesisBlock.Difficulty())
|
||||||
|
core.WriteBlock(*chainDb, config.TestGenesisBlock)
|
||||||
|
core.WriteCanonicalHash(*chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.NumberU64())
|
||||||
|
core.WriteHeadBlockHash(*chainDb, config.TestGenesisBlock.Hash())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreatePoW creates the required type of PoW instance for an Ethereum service
|
||||||
|
func CreatePoW(config *Config) (*ethash.Ethash, error) {
|
||||||
|
switch {
|
||||||
|
case config.PowTest:
|
||||||
|
glog.V(logger.Info).Infof("ethash used in test mode")
|
||||||
|
return ethash.NewForTesting()
|
||||||
|
case config.PowShared:
|
||||||
|
glog.V(logger.Info).Infof("ethash used in shared mode")
|
||||||
|
return ethash.NewShared(), nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ethash.New(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// APIs returns the collection of RPC services the ethereum package offers.
|
// APIs returns the collection of RPC services the ethereum package offers.
|
||||||
// NOTE, some of these services probably need to be moved to somewhere else.
|
// NOTE, some of these services probably need to be moved to somewhere else.
|
||||||
func (s *Ethereum) APIs() []rpc.API {
|
func (s *FullNodeService) APIs() []rpc.API {
|
||||||
return []rpc.API{
|
return append(ethapi.GetAPIs(s.apiBackend, &s.solcPath, &s.solc), []rpc.API{
|
||||||
{
|
{
|
||||||
Namespace: "eth",
|
Namespace: "eth",
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
Service: NewPublicEthereumAPI(s),
|
Service: NewPublicFullEthereumAPI(s),
|
||||||
Public: true,
|
|
||||||
}, {
|
|
||||||
Namespace: "eth",
|
|
||||||
Version: "1.0",
|
|
||||||
Service: NewPublicAccountAPI(s.accountManager),
|
|
||||||
Public: true,
|
|
||||||
}, {
|
|
||||||
Namespace: "personal",
|
|
||||||
Version: "1.0",
|
|
||||||
Service: NewPrivateAccountAPI(s),
|
|
||||||
Public: false,
|
|
||||||
}, {
|
|
||||||
Namespace: "eth",
|
|
||||||
Version: "1.0",
|
|
||||||
Service: NewPublicBlockChainAPI(s.chainConfig, s.blockchain, s.miner, s.chainDb, s.gpo, s.eventMux, s.accountManager),
|
|
||||||
Public: true,
|
|
||||||
}, {
|
|
||||||
Namespace: "eth",
|
|
||||||
Version: "1.0",
|
|
||||||
Service: NewPublicTransactionPoolAPI(s),
|
|
||||||
Public: true,
|
Public: true,
|
||||||
}, {
|
}, {
|
||||||
Namespace: "eth",
|
Namespace: "eth",
|
||||||
|
@ -322,11 +325,6 @@ func (s *Ethereum) APIs() []rpc.API {
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
Service: NewPrivateMinerAPI(s),
|
Service: NewPrivateMinerAPI(s),
|
||||||
Public: false,
|
Public: false,
|
||||||
}, {
|
|
||||||
Namespace: "txpool",
|
|
||||||
Version: "1.0",
|
|
||||||
Service: NewPublicTxPoolAPI(s),
|
|
||||||
Public: true,
|
|
||||||
}, {
|
}, {
|
||||||
Namespace: "eth",
|
Namespace: "eth",
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
|
@ -335,16 +333,16 @@ func (s *Ethereum) APIs() []rpc.API {
|
||||||
}, {
|
}, {
|
||||||
Namespace: "admin",
|
Namespace: "admin",
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
Service: NewPrivateAdminAPI(s),
|
Service: NewPrivateFullAdminAPI(s),
|
||||||
}, {
|
}, {
|
||||||
Namespace: "debug",
|
Namespace: "debug",
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
Service: NewPublicDebugAPI(s),
|
Service: NewPublicFullDebugAPI(s),
|
||||||
Public: true,
|
Public: true,
|
||||||
}, {
|
}, {
|
||||||
Namespace: "debug",
|
Namespace: "debug",
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
Service: NewPrivateDebugAPI(s.chainConfig, s),
|
Service: NewPrivateFullDebugAPI(s.chainConfig, s),
|
||||||
}, {
|
}, {
|
||||||
Namespace: "net",
|
Namespace: "net",
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
|
@ -355,14 +353,14 @@ func (s *Ethereum) APIs() []rpc.API {
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
Service: ethreg.NewPrivateRegistarAPI(s.chainConfig, s.blockchain, s.chainDb, s.txPool, s.accountManager),
|
Service: ethreg.NewPrivateRegistarAPI(s.chainConfig, s.blockchain, s.chainDb, s.txPool, s.accountManager),
|
||||||
},
|
},
|
||||||
}
|
}...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) {
|
func (s *FullNodeService) ResetWithGenesisBlock(gb *types.Block) {
|
||||||
s.blockchain.ResetWithGenesisBlock(gb)
|
s.blockchain.ResetWithGenesisBlock(gb)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Ethereum) Etherbase() (eb common.Address, err error) {
|
func (s *FullNodeService) Etherbase() (eb common.Address, err error) {
|
||||||
eb = s.etherbase
|
eb = s.etherbase
|
||||||
if (eb == common.Address{}) {
|
if (eb == common.Address{}) {
|
||||||
firstAccount, err := s.AccountManager().AccountByIndex(0)
|
firstAccount, err := s.AccountManager().AccountByIndex(0)
|
||||||
|
@ -375,46 +373,47 @@ func (s *Ethereum) Etherbase() (eb common.Address, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// set in js console via admin interface or wrapper from cli flags
|
// set in js console via admin interface or wrapper from cli flags
|
||||||
func (self *Ethereum) SetEtherbase(etherbase common.Address) {
|
func (self *FullNodeService) SetEtherbase(etherbase common.Address) {
|
||||||
self.etherbase = etherbase
|
self.etherbase = etherbase
|
||||||
self.miner.SetEtherbase(etherbase)
|
self.miner.SetEtherbase(etherbase)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Ethereum) StopMining() { s.miner.Stop() }
|
func (s *FullNodeService) StopMining() { s.miner.Stop() }
|
||||||
func (s *Ethereum) IsMining() bool { return s.miner.Mining() }
|
func (s *FullNodeService) IsMining() bool { return s.miner.Mining() }
|
||||||
func (s *Ethereum) Miner() *miner.Miner { return s.miner }
|
func (s *FullNodeService) Miner() *miner.Miner { return s.miner }
|
||||||
|
|
||||||
func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager }
|
func (s *FullNodeService) AccountManager() *accounts.Manager { return s.accountManager }
|
||||||
func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain }
|
func (s *FullNodeService) BlockChain() *core.BlockChain { return s.blockchain }
|
||||||
func (s *Ethereum) TxPool() *core.TxPool { return s.txPool }
|
func (s *FullNodeService) TxPool() *core.TxPool { return s.txPool }
|
||||||
func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux }
|
func (s *FullNodeService) EventMux() *event.TypeMux { return s.eventMux }
|
||||||
func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb }
|
func (s *FullNodeService) Pow() *ethash.Ethash { return s.pow }
|
||||||
func (s *Ethereum) DappDb() ethdb.Database { return s.dappDb }
|
func (s *FullNodeService) ChainDb() ethdb.Database { return s.chainDb }
|
||||||
func (s *Ethereum) IsListening() bool { return true } // Always listening
|
func (s *FullNodeService) DappDb() ethdb.Database { return s.dappDb }
|
||||||
func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) }
|
func (s *FullNodeService) IsListening() bool { return true } // Always listening
|
||||||
func (s *Ethereum) NetVersion() int { return s.netVersionId }
|
func (s *FullNodeService) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) }
|
||||||
func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
|
func (s *FullNodeService) NetVersion() int { return s.netVersionId }
|
||||||
|
func (s *FullNodeService) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
|
||||||
|
|
||||||
// Protocols implements node.Service, returning all the currently configured
|
// Protocols implements node.Service, returning all the currently configured
|
||||||
// network protocols to start.
|
// network protocols to start.
|
||||||
func (s *Ethereum) Protocols() []p2p.Protocol {
|
func (s *FullNodeService) Protocols() []p2p.Protocol {
|
||||||
return s.protocolManager.SubProtocols
|
return s.protocolManager.SubProtocols
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start implements node.Service, starting all internal goroutines needed by the
|
// Start implements node.Service, starting all internal goroutines needed by the
|
||||||
// Ethereum protocol implementation.
|
// FullNodeService protocol implementation.
|
||||||
func (s *Ethereum) Start(srvr *p2p.Server) error {
|
func (s *FullNodeService) Start(srvr *p2p.Server) error {
|
||||||
|
s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.NetVersion())
|
||||||
if s.AutoDAG {
|
if s.AutoDAG {
|
||||||
s.StartAutoDAG()
|
s.StartAutoDAG()
|
||||||
}
|
}
|
||||||
s.protocolManager.Start()
|
s.protocolManager.Start()
|
||||||
s.netRPCService = NewPublicNetAPI(srvr, s.NetVersion())
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop implements node.Service, terminating all internal goroutines used by the
|
// Stop implements node.Service, terminating all internal goroutines used by the
|
||||||
// Ethereum protocol.
|
// Ethereum protocol.
|
||||||
func (s *Ethereum) Stop() error {
|
func (s *FullNodeService) Stop() error {
|
||||||
if s.stopDbUpgrade != nil {
|
if s.stopDbUpgrade != nil {
|
||||||
s.stopDbUpgrade()
|
s.stopDbUpgrade()
|
||||||
}
|
}
|
||||||
|
@ -434,7 +433,7 @@ func (s *Ethereum) Stop() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function will wait for a shutdown and resumes main thread execution
|
// This function will wait for a shutdown and resumes main thread execution
|
||||||
func (s *Ethereum) WaitForShutdown() {
|
func (s *FullNodeService) WaitForShutdown() {
|
||||||
<-s.shutdownChan
|
<-s.shutdownChan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,7 +446,7 @@ func (s *Ethereum) WaitForShutdown() {
|
||||||
// stop any number of times.
|
// stop any number of times.
|
||||||
// For any more sophisticated pattern of DAG generation, use CLI subcommand
|
// For any more sophisticated pattern of DAG generation, use CLI subcommand
|
||||||
// makedag
|
// makedag
|
||||||
func (self *Ethereum) StartAutoDAG() {
|
func (self *FullNodeService) StartAutoDAG() {
|
||||||
if self.autodagquit != nil {
|
if self.autodagquit != nil {
|
||||||
return // already started
|
return // already started
|
||||||
}
|
}
|
||||||
|
@ -493,7 +492,7 @@ func (self *Ethereum) StartAutoDAG() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// stopAutoDAG stops automatic DAG pregeneration by quitting the loop
|
// stopAutoDAG stops automatic DAG pregeneration by quitting the loop
|
||||||
func (self *Ethereum) StopAutoDAG() {
|
func (self *FullNodeService) StopAutoDAG() {
|
||||||
if self.autodagquit != nil {
|
if self.autodagquit != nil {
|
||||||
close(self.autodagquit)
|
close(self.autodagquit)
|
||||||
self.autodagquit = nil
|
self.autodagquit = nil
|
||||||
|
@ -503,25 +502,10 @@ func (self *Ethereum) StopAutoDAG() {
|
||||||
|
|
||||||
// HTTPClient returns the light http client used for fetching offchain docs
|
// HTTPClient returns the light http client used for fetching offchain docs
|
||||||
// (natspec, source for verification)
|
// (natspec, source for verification)
|
||||||
func (self *Ethereum) HTTPClient() *httpclient.HTTPClient {
|
func (self *FullNodeService) HTTPClient() *httpclient.HTTPClient {
|
||||||
return self.httpclient
|
return self.httpclient
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Ethereum) Solc() (*compiler.Solidity, error) {
|
|
||||||
var err error
|
|
||||||
if self.solc == nil {
|
|
||||||
self.solc, err = compiler.New(self.SolcPath)
|
|
||||||
}
|
|
||||||
return self.solc, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// set in js console via admin interface or wrapper from cli flags
|
|
||||||
func (self *Ethereum) SetSolc(solcPath string) (*compiler.Solidity, error) {
|
|
||||||
self.SolcPath = solcPath
|
|
||||||
self.solc = nil
|
|
||||||
return self.Solc()
|
|
||||||
}
|
|
||||||
|
|
||||||
// dagFiles(epoch) returns the two alternative DAG filenames (not a path)
|
// dagFiles(epoch) returns the two alternative DAG filenames (not a path)
|
||||||
// 1) <revision>-<hex(seedhash[8])> 2) full-R<revision>-<hex(seedhash[8])>
|
// 1) <revision>-<hex(seedhash[8])> 2) full-R<revision>-<hex(seedhash[8])>
|
||||||
func dagFiles(epoch uint64) (string, string) {
|
func dagFiles(epoch uint64) (string, string) {
|
||||||
|
|
60
eth/bind.go
60
eth/bind.go
|
@ -21,8 +21,10 @@ import (
|
||||||
|
|
||||||
"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/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContractBackend implements bind.ContractBackend with direct calls to Ethereum
|
// ContractBackend implements bind.ContractBackend with direct calls to Ethereum
|
||||||
|
@ -33,38 +35,44 @@ import (
|
||||||
// object. These should be rewritten to internal Go method calls when the Go API
|
// object. These should be rewritten to internal Go method calls when the Go API
|
||||||
// is refactored to support a clean library use.
|
// is refactored to support a clean library use.
|
||||||
type ContractBackend struct {
|
type ContractBackend struct {
|
||||||
eapi *PublicEthereumAPI // Wrapper around the Ethereum object to access metadata
|
eapi *ethapi.PublicEthereumAPI // Wrapper around the Ethereum object to access metadata
|
||||||
bcapi *PublicBlockChainAPI // Wrapper around the blockchain to access chain data
|
bcapi *ethapi.PublicBlockChainAPI // Wrapper around the blockchain to access chain data
|
||||||
txapi *PublicTransactionPoolAPI // Wrapper around the transaction pool to access transaction data
|
txapi *ethapi.PublicTransactionPoolAPI // Wrapper around the transaction pool to access transaction data
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContractBackend creates a new native contract backend using an existing
|
// NewContractBackend creates a new native contract backend using an existing
|
||||||
// Etheruem object.
|
// Etheruem object.
|
||||||
func NewContractBackend(eth *Ethereum) *ContractBackend {
|
func NewContractBackend(eth *FullNodeService) *ContractBackend {
|
||||||
return &ContractBackend{
|
return &ContractBackend{
|
||||||
eapi: NewPublicEthereumAPI(eth),
|
eapi: ethapi.NewPublicEthereumAPI(eth.apiBackend, nil, nil),
|
||||||
bcapi: NewPublicBlockChainAPI(eth.chainConfig, eth.blockchain, eth.miner, eth.chainDb, eth.gpo, eth.eventMux, eth.accountManager),
|
bcapi: ethapi.NewPublicBlockChainAPI(eth.apiBackend),
|
||||||
txapi: NewPublicTransactionPoolAPI(eth),
|
txapi: ethapi.NewPublicTransactionPoolAPI(eth.apiBackend),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasCode implements bind.ContractVerifier.HasCode by retrieving any code associated
|
// HasCode implements bind.ContractVerifier.HasCode by retrieving any code associated
|
||||||
// with the contract from the local API, and checking its size.
|
// with the contract from the local API, and checking its size.
|
||||||
func (b *ContractBackend) HasCode(contract common.Address, pending bool) (bool, error) {
|
func (b *ContractBackend) HasCode(ctx context.Context, contract common.Address, pending bool) (bool, error) {
|
||||||
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
block := rpc.LatestBlockNumber
|
block := rpc.LatestBlockNumber
|
||||||
if pending {
|
if pending {
|
||||||
block = rpc.PendingBlockNumber
|
block = rpc.PendingBlockNumber
|
||||||
}
|
}
|
||||||
out, err := b.bcapi.GetCode(contract, block)
|
out, err := b.bcapi.GetCode(ctx, contract, block)
|
||||||
return len(common.FromHex(out)) > 0, err
|
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.
|
||||||
func (b *ContractBackend) ContractCall(contract common.Address, data []byte, pending bool) ([]byte, error) {
|
func (b *ContractBackend) ContractCall(ctx context.Context, contract common.Address, data []byte, pending bool) ([]byte, error) {
|
||||||
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
// Convert the input args to the API spec
|
// Convert the input args to the API spec
|
||||||
args := CallArgs{
|
args := ethapi.CallArgs{
|
||||||
To: &contract,
|
To: &contract,
|
||||||
Data: common.ToHex(data),
|
Data: common.ToHex(data),
|
||||||
}
|
}
|
||||||
|
@ -73,21 +81,27 @@ func (b *ContractBackend) ContractCall(contract common.Address, data []byte, pen
|
||||||
block = rpc.PendingBlockNumber
|
block = rpc.PendingBlockNumber
|
||||||
}
|
}
|
||||||
// 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(ctx, args, block)
|
||||||
return common.FromHex(out), err
|
return common.FromHex(out), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// PendingAccountNonce implements bind.ContractTransactor retrieving the current
|
// PendingAccountNonce implements bind.ContractTransactor retrieving the current
|
||||||
// pending nonce associated with an account.
|
// pending nonce associated with an account.
|
||||||
func (b *ContractBackend) PendingAccountNonce(account common.Address) (uint64, error) {
|
func (b *ContractBackend) PendingAccountNonce(ctx context.Context, account common.Address) (uint64, error) {
|
||||||
out, err := b.txapi.GetTransactionCount(account, rpc.PendingBlockNumber)
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
|
out, err := b.txapi.GetTransactionCount(ctx, account, rpc.PendingBlockNumber)
|
||||||
return out.Uint64(), err
|
return out.Uint64(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SuggestGasPrice implements bind.ContractTransactor retrieving the currently
|
// SuggestGasPrice implements bind.ContractTransactor retrieving the currently
|
||||||
// suggested gas price to allow a timely execution of a transaction.
|
// suggested gas price to allow a timely execution of a transaction.
|
||||||
func (b *ContractBackend) SuggestGasPrice() (*big.Int, error) {
|
func (b *ContractBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
|
||||||
return b.eapi.GasPrice(), nil
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
|
return b.eapi.GasPrice(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EstimateGasLimit implements bind.ContractTransactor triing to estimate the gas
|
// EstimateGasLimit implements bind.ContractTransactor triing to estimate the gas
|
||||||
|
@ -95,8 +109,11 @@ func (b *ContractBackend) SuggestGasPrice() (*big.Int, error) {
|
||||||
// the backend blockchain. There is no guarantee that this is the true gas limit
|
// 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
|
// requirement as other transactions may be added or removed by miners, but it
|
||||||
// should provide a basis for setting a reasonable default.
|
// should provide a basis for setting a reasonable default.
|
||||||
func (b *ContractBackend) EstimateGasLimit(sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error) {
|
func (b *ContractBackend) EstimateGasLimit(ctx context.Context, sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error) {
|
||||||
out, err := b.bcapi.EstimateGas(CallArgs{
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
|
out, err := b.bcapi.EstimateGas(ctx, ethapi.CallArgs{
|
||||||
From: sender,
|
From: sender,
|
||||||
To: contract,
|
To: contract,
|
||||||
Value: *rpc.NewHexNumber(value),
|
Value: *rpc.NewHexNumber(value),
|
||||||
|
@ -107,8 +124,11 @@ func (b *ContractBackend) EstimateGasLimit(sender common.Address, contract *comm
|
||||||
|
|
||||||
// SendTransaction implements bind.ContractTransactor injects the transaction
|
// SendTransaction implements bind.ContractTransactor injects the transaction
|
||||||
// into the pending pool for execution.
|
// into the pending pool for execution.
|
||||||
func (b *ContractBackend) SendTransaction(tx *types.Transaction) error {
|
func (b *ContractBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error {
|
||||||
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
raw, _ := rlp.EncodeToBytes(tx)
|
raw, _ := rlp.EncodeToBytes(tx)
|
||||||
_, err := b.txapi.SendRawTransaction(common.ToHex(raw))
|
_, err := b.txapi.SendRawTransaction(ctx, common.ToHex(raw))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ import (
|
||||||
|
|
||||||
const disabledInfo = "Set GO_OPENCL and re-build to enable."
|
const disabledInfo = "Set GO_OPENCL and re-build to enable."
|
||||||
|
|
||||||
func (s *Ethereum) StartMining(threads int, gpus string) error {
|
func (s *FullNodeService) StartMining(threads int, gpus string) error {
|
||||||
eb, err := s.Etherbase()
|
eb, err := s.Etherbase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("Cannot start mining without etherbase address: %v", err)
|
err = fmt.Errorf("Cannot start mining without etherbase address: %v", err)
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
// 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/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package eth
|
package gasprice
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
@ -23,6 +23,8 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
)
|
)
|
||||||
|
@ -39,10 +41,22 @@ type blockPriceInfo struct {
|
||||||
baseGasPrice *big.Int
|
baseGasPrice *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GpoParams struct {
|
||||||
|
GpoMinGasPrice *big.Int
|
||||||
|
GpoMaxGasPrice *big.Int
|
||||||
|
GpoFullBlockRatio int
|
||||||
|
GpobaseStepDown int
|
||||||
|
GpobaseStepUp int
|
||||||
|
GpobaseCorrectionFactor int
|
||||||
|
}
|
||||||
|
|
||||||
// GasPriceOracle recommends gas prices based on the content of recent
|
// GasPriceOracle recommends gas prices based on the content of recent
|
||||||
// blocks.
|
// blocks.
|
||||||
type GasPriceOracle struct {
|
type GasPriceOracle struct {
|
||||||
eth *Ethereum
|
chain *core.BlockChain
|
||||||
|
db ethdb.Database
|
||||||
|
evmux *event.TypeMux
|
||||||
|
params *GpoParams
|
||||||
initOnce sync.Once
|
initOnce sync.Once
|
||||||
minPrice *big.Int
|
minPrice *big.Int
|
||||||
lastBaseMutex sync.Mutex
|
lastBaseMutex sync.Mutex
|
||||||
|
@ -55,17 +69,20 @@ type GasPriceOracle struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGasPriceOracle returns a new oracle.
|
// NewGasPriceOracle returns a new oracle.
|
||||||
func NewGasPriceOracle(eth *Ethereum) *GasPriceOracle {
|
func NewGasPriceOracle(chain *core.BlockChain, db ethdb.Database, evmux *event.TypeMux, params *GpoParams) *GasPriceOracle {
|
||||||
minprice := eth.GpoMinGasPrice
|
minprice := params.GpoMinGasPrice
|
||||||
if minprice == nil {
|
if minprice == nil {
|
||||||
minprice = big.NewInt(gpoDefaultMinGasPrice)
|
minprice = big.NewInt(gpoDefaultMinGasPrice)
|
||||||
}
|
}
|
||||||
minbase := new(big.Int).Mul(minprice, big.NewInt(100))
|
minbase := new(big.Int).Mul(minprice, big.NewInt(100))
|
||||||
if eth.GpobaseCorrectionFactor > 0 {
|
if params.GpobaseCorrectionFactor > 0 {
|
||||||
minbase = minbase.Div(minbase, big.NewInt(int64(eth.GpobaseCorrectionFactor)))
|
minbase = minbase.Div(minbase, big.NewInt(int64(params.GpobaseCorrectionFactor)))
|
||||||
}
|
}
|
||||||
return &GasPriceOracle{
|
return &GasPriceOracle{
|
||||||
eth: eth,
|
chain: chain,
|
||||||
|
db: db,
|
||||||
|
evmux: evmux,
|
||||||
|
params: params,
|
||||||
blocks: make(map[uint64]*blockPriceInfo),
|
blocks: make(map[uint64]*blockPriceInfo),
|
||||||
minBase: minbase,
|
minBase: minbase,
|
||||||
minPrice: minprice,
|
minPrice: minprice,
|
||||||
|
@ -75,14 +92,14 @@ func NewGasPriceOracle(eth *Ethereum) *GasPriceOracle {
|
||||||
|
|
||||||
func (gpo *GasPriceOracle) init() {
|
func (gpo *GasPriceOracle) init() {
|
||||||
gpo.initOnce.Do(func() {
|
gpo.initOnce.Do(func() {
|
||||||
gpo.processPastBlocks(gpo.eth.BlockChain())
|
gpo.processPastBlocks()
|
||||||
go gpo.listenLoop()
|
go gpo.listenLoop()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *GasPriceOracle) processPastBlocks(chain *core.BlockChain) {
|
func (self *GasPriceOracle) processPastBlocks() {
|
||||||
last := int64(-1)
|
last := int64(-1)
|
||||||
cblock := chain.CurrentBlock()
|
cblock := self.chain.CurrentBlock()
|
||||||
if cblock != nil {
|
if cblock != nil {
|
||||||
last = int64(cblock.NumberU64())
|
last = int64(cblock.NumberU64())
|
||||||
}
|
}
|
||||||
|
@ -92,7 +109,7 @@ func (self *GasPriceOracle) processPastBlocks(chain *core.BlockChain) {
|
||||||
}
|
}
|
||||||
self.firstProcessed = uint64(first)
|
self.firstProcessed = uint64(first)
|
||||||
for i := first; i <= last; i++ {
|
for i := first; i <= last; i++ {
|
||||||
block := chain.GetBlockByNumber(uint64(i))
|
block := self.chain.GetBlockByNumber(uint64(i))
|
||||||
if block != nil {
|
if block != nil {
|
||||||
self.processBlock(block)
|
self.processBlock(block)
|
||||||
}
|
}
|
||||||
|
@ -101,7 +118,7 @@ func (self *GasPriceOracle) processPastBlocks(chain *core.BlockChain) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *GasPriceOracle) listenLoop() {
|
func (self *GasPriceOracle) listenLoop() {
|
||||||
events := self.eth.EventMux().Subscribe(core.ChainEvent{}, core.ChainSplitEvent{})
|
events := self.evmux.Subscribe(core.ChainEvent{}, core.ChainSplitEvent{})
|
||||||
defer events.Unsubscribe()
|
defer events.Unsubscribe()
|
||||||
|
|
||||||
for event := range events.Chan() {
|
for event := range events.Chan() {
|
||||||
|
@ -136,9 +153,9 @@ func (self *GasPriceOracle) processBlock(block *types.Block) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if lastBase.Cmp(lp) < 0 {
|
if lastBase.Cmp(lp) < 0 {
|
||||||
corr = self.eth.GpobaseStepUp
|
corr = self.params.GpobaseStepUp
|
||||||
} else {
|
} else {
|
||||||
corr = -self.eth.GpobaseStepDown
|
corr = -self.params.GpobaseStepDown
|
||||||
}
|
}
|
||||||
|
|
||||||
crand := int64(corr * (900 + rand.Intn(201)))
|
crand := int64(corr * (900 + rand.Intn(201)))
|
||||||
|
@ -159,14 +176,14 @@ func (self *GasPriceOracle) processBlock(block *types.Block) {
|
||||||
self.lastBase = newBase
|
self.lastBase = newBase
|
||||||
self.lastBaseMutex.Unlock()
|
self.lastBaseMutex.Unlock()
|
||||||
|
|
||||||
glog.V(logger.Detail).Infof("Processed block #%v, base price is %v\n", block.NumberU64(), newBase.Int64())
|
glog.V(logger.Detail).Infof("Processed block #%v, base price is %v\n", i, newBase.Int64())
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the lowers possible price with which a tx was or could have been included
|
// returns the lowers possible price with which a tx was or could have been included
|
||||||
func (self *GasPriceOracle) lowestPrice(block *types.Block) *big.Int {
|
func (self *GasPriceOracle) lowestPrice(block *types.Block) *big.Int {
|
||||||
gasUsed := big.NewInt(0)
|
gasUsed := big.NewInt(0)
|
||||||
|
|
||||||
receipts := core.GetBlockReceipts(self.eth.ChainDb(), block.Hash(), block.NumberU64())
|
receipts := core.GetBlockReceipts(self.db, block.Hash(), block.NumberU64())
|
||||||
if len(receipts) > 0 {
|
if len(receipts) > 0 {
|
||||||
if cgu := receipts[len(receipts)-1].CumulativeGasUsed; cgu != nil {
|
if cgu := receipts[len(receipts)-1].CumulativeGasUsed; cgu != nil {
|
||||||
gasUsed = receipts[len(receipts)-1].CumulativeGasUsed
|
gasUsed = receipts[len(receipts)-1].CumulativeGasUsed
|
||||||
|
@ -174,7 +191,7 @@ func (self *GasPriceOracle) lowestPrice(block *types.Block) *big.Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
if new(big.Int).Mul(gasUsed, big.NewInt(100)).Cmp(new(big.Int).Mul(block.GasLimit(),
|
if new(big.Int).Mul(gasUsed, big.NewInt(100)).Cmp(new(big.Int).Mul(block.GasLimit(),
|
||||||
big.NewInt(int64(self.eth.GpoFullBlockRatio)))) < 0 {
|
big.NewInt(int64(self.params.GpoFullBlockRatio)))) < 0 {
|
||||||
// block is not full, could have posted a tx with MinGasPrice
|
// block is not full, could have posted a tx with MinGasPrice
|
||||||
return big.NewInt(0)
|
return big.NewInt(0)
|
||||||
}
|
}
|
||||||
|
@ -201,12 +218,12 @@ func (self *GasPriceOracle) SuggestPrice() *big.Int {
|
||||||
price := new(big.Int).Set(self.lastBase)
|
price := new(big.Int).Set(self.lastBase)
|
||||||
self.lastBaseMutex.Unlock()
|
self.lastBaseMutex.Unlock()
|
||||||
|
|
||||||
price.Mul(price, big.NewInt(int64(self.eth.GpobaseCorrectionFactor)))
|
price.Mul(price, big.NewInt(int64(self.params.GpobaseCorrectionFactor)))
|
||||||
price.Div(price, big.NewInt(100))
|
price.Div(price, big.NewInt(100))
|
||||||
if price.Cmp(self.minPrice) < 0 {
|
if price.Cmp(self.minPrice) < 0 {
|
||||||
price.Set(self.minPrice)
|
price.Set(self.minPrice)
|
||||||
} else if self.eth.GpoMaxGasPrice != nil && price.Cmp(self.eth.GpoMaxGasPrice) > 0 {
|
} else if self.params.GpoMaxGasPrice != nil && price.Cmp(self.params.GpoMaxGasPrice) > 0 {
|
||||||
price.Set(self.eth.GpoMaxGasPrice)
|
price.Set(self.params.GpoMaxGasPrice)
|
||||||
}
|
}
|
||||||
return price
|
return price
|
||||||
}
|
}
|
|
@ -33,7 +33,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/miner"
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Ethereum) StartMining(threads int, gpus string) error {
|
func (s *FullNodeService) StartMining(threads int, gpus string) error {
|
||||||
eb, err := s.Etherbase()
|
eb, err := s.Etherbase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("Cannot start mining without etherbase address: %v", err)
|
err = fmt.Errorf("Cannot start mining without etherbase address: %v", err)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,119 @@
|
||||||
|
// 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 ethapi implements the general Ethereum API functions.
|
||||||
|
package ethapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/compiler"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Backend interface provides the common API services (that are provided by
|
||||||
|
// both full and light clients) with access to necessary functions.
|
||||||
|
type Backend interface {
|
||||||
|
// general Ethereum API
|
||||||
|
Downloader() *downloader.Downloader
|
||||||
|
ProtocolVersion() int
|
||||||
|
SuggestPrice(ctx context.Context) (*big.Int, error)
|
||||||
|
ChainDb() ethdb.Database
|
||||||
|
EventMux() *event.TypeMux
|
||||||
|
AccountManager() *accounts.Manager
|
||||||
|
// BlockChain API
|
||||||
|
SetHead(number uint64)
|
||||||
|
HeaderByNumber(blockNr rpc.BlockNumber) *types.Header
|
||||||
|
BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error)
|
||||||
|
StateAndHeaderByNumber(blockNr rpc.BlockNumber) (State, *types.Header, error)
|
||||||
|
GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error)
|
||||||
|
GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
|
||||||
|
GetTd(blockHash common.Hash) *big.Int
|
||||||
|
GetVMEnv(ctx context.Context, msg core.Message, state State, header *types.Header) (vm.Environment, func() error, error)
|
||||||
|
// TxPool API
|
||||||
|
SendTx(ctx context.Context, signedTx *types.Transaction) error
|
||||||
|
RemoveTx(txHash common.Hash)
|
||||||
|
GetPoolTransactions() types.Transactions
|
||||||
|
GetPoolTransaction(txHash common.Hash) *types.Transaction
|
||||||
|
GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error)
|
||||||
|
Stats() (pending int, queued int)
|
||||||
|
TxPoolContent() (map[common.Address]map[uint64][]*types.Transaction, map[common.Address]map[uint64][]*types.Transaction)
|
||||||
|
}
|
||||||
|
|
||||||
|
type State interface {
|
||||||
|
GetBalance(ctx context.Context, addr common.Address) (*big.Int, error)
|
||||||
|
GetCode(ctx context.Context, addr common.Address) ([]byte, error)
|
||||||
|
GetState(ctx context.Context, a common.Address, b common.Hash) (common.Hash, error)
|
||||||
|
GetNonce(ctx context.Context, addr common.Address) (uint64, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAPIs(apiBackend Backend, solcPath *string, solc **compiler.Solidity) []rpc.API {
|
||||||
|
return []rpc.API{
|
||||||
|
{
|
||||||
|
Namespace: "eth",
|
||||||
|
Version: "1.0",
|
||||||
|
Service: NewPublicEthereumAPI(apiBackend, solcPath, solc),
|
||||||
|
Public: true,
|
||||||
|
}, {
|
||||||
|
Namespace: "eth",
|
||||||
|
Version: "1.0",
|
||||||
|
Service: NewPublicBlockChainAPI(apiBackend),
|
||||||
|
Public: true,
|
||||||
|
}, {
|
||||||
|
Namespace: "eth",
|
||||||
|
Version: "1.0",
|
||||||
|
Service: NewPublicTransactionPoolAPI(apiBackend),
|
||||||
|
Public: true,
|
||||||
|
}, {
|
||||||
|
Namespace: "txpool",
|
||||||
|
Version: "1.0",
|
||||||
|
Service: NewPublicTxPoolAPI(apiBackend),
|
||||||
|
Public: true,
|
||||||
|
}, {
|
||||||
|
Namespace: "admin",
|
||||||
|
Version: "1.0",
|
||||||
|
Service: NewPrivateAdminAPI(apiBackend, solcPath, solc),
|
||||||
|
}, {
|
||||||
|
Namespace: "debug",
|
||||||
|
Version: "1.0",
|
||||||
|
Service: NewPublicDebugAPI(apiBackend),
|
||||||
|
Public: true,
|
||||||
|
}, {
|
||||||
|
Namespace: "debug",
|
||||||
|
Version: "1.0",
|
||||||
|
Service: NewPrivateDebugAPI(apiBackend),
|
||||||
|
}, {
|
||||||
|
Namespace: "eth",
|
||||||
|
Version: "1.0",
|
||||||
|
Service: NewPublicAccountAPI(apiBackend.AccountManager()),
|
||||||
|
Public: true,
|
||||||
|
}, {
|
||||||
|
Namespace: "personal",
|
||||||
|
Version: "1.0",
|
||||||
|
Service: NewPrivateAccountAPI(apiBackend),
|
||||||
|
Public: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Interval to check for new releases
|
// Interval to check for new releases
|
||||||
|
@ -57,7 +58,7 @@ type ReleaseService struct {
|
||||||
// releases and notify the user of such.
|
// releases and notify the user of such.
|
||||||
func NewReleaseService(ctx *node.ServiceContext, config Config) (node.Service, error) {
|
func NewReleaseService(ctx *node.ServiceContext, config Config) (node.Service, error) {
|
||||||
// Retrieve the Ethereum service dependency to access the blockchain
|
// Retrieve the Ethereum service dependency to access the blockchain
|
||||||
var ethereum *eth.Ethereum
|
var ethereum *eth.FullNodeService
|
||||||
if err := ctx.Service(ðereum); err != nil {
|
if err := ctx.Service(ðereum); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -110,7 +111,9 @@ func (r *ReleaseService) checker() {
|
||||||
timer.Reset(releaseRecheckInterval)
|
timer.Reset(releaseRecheckInterval)
|
||||||
|
|
||||||
// Retrieve the current version, and handle missing contracts gracefully
|
// Retrieve the current version, and handle missing contracts gracefully
|
||||||
version, err := r.oracle.CurrentVersion(nil)
|
ctx, _ := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
|
opts := &bind.CallOpts{Context: ctx}
|
||||||
|
version, err := r.oracle.CurrentVersion(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == bind.ErrNoCode {
|
if err == bind.ErrNoCode {
|
||||||
glog.V(logger.Debug).Infof("Release oracle not found at %x", r.config.Oracle)
|
glog.V(logger.Debug).Infof("Release oracle not found at %x", r.config.Oracle)
|
||||||
|
|
Loading…
Reference in New Issue