mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 06:36:43 +00:00
Merge 6353cddea2 into 21701190ac
This commit is contained in:
commit
27ca56101e
34 changed files with 938 additions and 2059 deletions
|
|
@ -164,7 +164,7 @@ func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallM
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rval, _, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state)
|
||||
rval, _, err := b.callContract(call, b.blockchain.CurrentBlock(), state)
|
||||
return rval, err
|
||||
}
|
||||
|
||||
|
|
@ -174,7 +174,7 @@ func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call ethereu
|
|||
defer b.mu.Unlock()
|
||||
defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot())
|
||||
|
||||
rval, _, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
|
||||
rval, _, err := b.callContract(call, b.pendingBlock, b.pendingState)
|
||||
return rval, err
|
||||
}
|
||||
|
||||
|
|
@ -200,32 +200,16 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
|
|||
defer b.mu.Unlock()
|
||||
defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot())
|
||||
|
||||
_, gas, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
|
||||
_, gas, err := b.callContract(call, b.pendingBlock, b.pendingState)
|
||||
return gas, err
|
||||
}
|
||||
|
||||
// callContract implemens common code between normal and pending contract calls.
|
||||
// state is modified during execution, make sure to copy it if necessary.
|
||||
func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, statedb *state.StateDB) ([]byte, *big.Int, error) {
|
||||
// Ensure message is initialized properly.
|
||||
if call.GasPrice == nil {
|
||||
call.GasPrice = big.NewInt(1)
|
||||
}
|
||||
if call.Gas == nil || call.Gas.BitLen() == 0 {
|
||||
call.Gas = big.NewInt(50000000)
|
||||
}
|
||||
if call.Value == nil {
|
||||
call.Value = new(big.Int)
|
||||
}
|
||||
// Set infinite balance to the fake caller account.
|
||||
from := statedb.GetOrNewStateObject(call.From)
|
||||
from.SetBalance(common.MaxBig)
|
||||
// Execute the call.
|
||||
msg := callmsg{call}
|
||||
vmenv := core.NewEnv(statedb, chainConfig, b.blockchain, msg, block.Header(), vm.Config{})
|
||||
gaspool := new(core.GasPool).AddGas(common.MaxBig)
|
||||
ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
|
||||
return ret, gasUsed, err
|
||||
func (b *SimulatedBackend) callContract(call ethereum.CallMsg, block *types.Block, state *state.StateDB) ([]byte, *big.Int, error) {
|
||||
return core.ApplyCallMessage(call, func(msg core.Message) vm.Environment {
|
||||
return core.NewEnv(state, chainConfig, b.blockchain, msg, block.Header(), vm.Config{})
|
||||
})
|
||||
}
|
||||
|
||||
// SendTransaction updates the pending block to include the given transaction.
|
||||
|
|
@ -253,18 +237,3 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
|
|||
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database)
|
||||
return nil
|
||||
}
|
||||
|
||||
// callmsg implements core.Message to allow passing it as a transaction simulator.
|
||||
type callmsg struct {
|
||||
ethereum.CallMsg
|
||||
}
|
||||
|
||||
func (m callmsg) From() (common.Address, error) { return m.CallMsg.From, nil }
|
||||
func (m callmsg) FromFrontier() (common.Address, error) { return m.CallMsg.From, nil }
|
||||
func (m callmsg) Nonce() uint64 { return 0 }
|
||||
func (m callmsg) CheckNonce() bool { return false }
|
||||
func (m callmsg) To() *common.Address { return m.CallMsg.To }
|
||||
func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
|
||||
func (m callmsg) Gas() *big.Int { return m.CallMsg.Gas }
|
||||
func (m callmsg) Value() *big.Int { return m.CallMsg.Value }
|
||||
func (m callmsg) Data() []byte { return m.CallMsg.Data }
|
||||
|
|
|
|||
|
|
@ -768,7 +768,7 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
|
|||
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
||||
fullNode, err := eth.New(ctx, ethConf)
|
||||
if fullNode != nil && ethConf.LightServ > 0 {
|
||||
ls, _ := les.NewLesServer(fullNode, ethConf)
|
||||
ls, _ := les.NewLesServer(fullNode, stack.EventMux(), ethConf)
|
||||
fullNode.AddLesServer(ls)
|
||||
}
|
||||
return fullNode, err
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,282 +0,0 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package ethreg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"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/common/registrar"
|
||||
"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/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
)
|
||||
|
||||
// registryAPIBackend is a backend for an Ethereum Registry.
|
||||
type registryAPIBackend struct {
|
||||
config *core.ChainConfig
|
||||
bc *core.BlockChain
|
||||
chainDb ethdb.Database
|
||||
txPool *core.TxPool
|
||||
am *accounts.Manager
|
||||
}
|
||||
|
||||
// PrivateRegistarAPI offers various functions to access the Ethereum registry.
|
||||
type PrivateRegistarAPI struct {
|
||||
config *core.ChainConfig
|
||||
be *registryAPIBackend
|
||||
}
|
||||
|
||||
// NewPrivateRegistarAPI creates a new PrivateRegistarAPI instance.
|
||||
func NewPrivateRegistarAPI(config *core.ChainConfig, bc *core.BlockChain, chainDb ethdb.Database, txPool *core.TxPool, am *accounts.Manager) *PrivateRegistarAPI {
|
||||
return &PrivateRegistarAPI{
|
||||
config: config,
|
||||
be: ®istryAPIBackend{
|
||||
config: config,
|
||||
bc: bc,
|
||||
chainDb: chainDb,
|
||||
txPool: txPool,
|
||||
am: am,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// SetGlobalRegistrar allows clients to set the global registry for the node.
|
||||
// This method can be used to deploy a new registry. First zero out the current
|
||||
// address by calling the method with namereg = '0x0' and then call this method
|
||||
// again with '' as namereg. This will submit a transaction to the network which
|
||||
// will deploy a new registry on execution. The TX hash is returned. When called
|
||||
// with namereg '' and the current address is not zero the current global is
|
||||
// address is returned..
|
||||
func (api *PrivateRegistarAPI) SetGlobalRegistrar(namereg string, from common.Address) (string, error) {
|
||||
return registrar.New(api.be).SetGlobalRegistrar(namereg, from)
|
||||
}
|
||||
|
||||
// SetHashReg queries the registry for a hash.
|
||||
func (api *PrivateRegistarAPI) SetHashReg(hashreg string, from common.Address) (string, error) {
|
||||
return registrar.New(api.be).SetHashReg(hashreg, from)
|
||||
}
|
||||
|
||||
// SetUrlHint queries the registry for an url.
|
||||
func (api *PrivateRegistarAPI) SetUrlHint(hashreg string, from common.Address) (string, error) {
|
||||
return registrar.New(api.be).SetUrlHint(hashreg, from)
|
||||
}
|
||||
|
||||
// SaveInfo stores contract information on the local file system.
|
||||
func (api *PrivateRegistarAPI) SaveInfo(info *compiler.ContractInfo, filename string) (contenthash common.Hash, err error) {
|
||||
return compiler.SaveInfo(info, filename)
|
||||
}
|
||||
|
||||
// Register registers a new content hash in the registry.
|
||||
func (api *PrivateRegistarAPI) Register(sender common.Address, addr common.Address, contentHashHex string) (bool, error) {
|
||||
block := api.be.bc.CurrentBlock()
|
||||
state, err := state.New(block.Root(), api.be.chainDb)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
codeb := state.GetCode(addr)
|
||||
codeHash := common.BytesToHash(crypto.Keccak256(codeb))
|
||||
contentHash := common.HexToHash(contentHashHex)
|
||||
|
||||
_, err = registrar.New(api.be).SetHashToHash(sender, codeHash, contentHash)
|
||||
return err == nil, err
|
||||
}
|
||||
|
||||
// RegisterUrl registers a new url in the registry.
|
||||
func (api *PrivateRegistarAPI) RegisterUrl(sender common.Address, contentHashHex string, url string) (bool, error) {
|
||||
_, err := registrar.New(api.be).SetUrlToHash(sender, common.HexToHash(contentHashHex), url)
|
||||
return err == nil, err
|
||||
}
|
||||
|
||||
// callmsg is the message type used for call transations.
|
||||
type callmsg struct {
|
||||
from *state.StateObject
|
||||
to *common.Address
|
||||
gas, gasPrice *big.Int
|
||||
value *big.Int
|
||||
data []byte
|
||||
}
|
||||
|
||||
// accessor boilerplate to implement core.Message
|
||||
func (m callmsg) From() (common.Address, error) {
|
||||
return m.from.Address(), nil
|
||||
}
|
||||
func (m callmsg) FromFrontier() (common.Address, error) {
|
||||
return m.from.Address(), nil
|
||||
}
|
||||
func (m callmsg) Nonce() uint64 {
|
||||
return 0
|
||||
}
|
||||
func (m callmsg) CheckNonce() bool {
|
||||
return false
|
||||
}
|
||||
func (m callmsg) To() *common.Address {
|
||||
return m.to
|
||||
}
|
||||
func (m callmsg) GasPrice() *big.Int {
|
||||
return m.gasPrice
|
||||
}
|
||||
func (m callmsg) Gas() *big.Int {
|
||||
return m.gas
|
||||
}
|
||||
func (m callmsg) Value() *big.Int {
|
||||
return m.value
|
||||
}
|
||||
func (m callmsg) Data() []byte {
|
||||
return m.data
|
||||
}
|
||||
|
||||
// Call forms a transaction from the given arguments and tries to execute it on
|
||||
// a private VM with a copy of the state. Any changes are therefore only temporary
|
||||
// and not part of the actual state. This allows for local execution/queries.
|
||||
func (be *registryAPIBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, string, error) {
|
||||
block := be.bc.CurrentBlock()
|
||||
statedb, err := state.New(block.Root(), be.chainDb)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
var from *state.StateObject
|
||||
if len(fromStr) == 0 {
|
||||
accounts := be.am.Accounts()
|
||||
if len(accounts) == 0 {
|
||||
from = statedb.GetOrNewStateObject(common.Address{})
|
||||
} else {
|
||||
from = statedb.GetOrNewStateObject(accounts[0].Address)
|
||||
}
|
||||
} else {
|
||||
from = statedb.GetOrNewStateObject(common.HexToAddress(fromStr))
|
||||
}
|
||||
|
||||
from.SetBalance(common.MaxBig)
|
||||
|
||||
msg := callmsg{
|
||||
from: from,
|
||||
gas: common.Big(gasStr),
|
||||
gasPrice: common.Big(gasPriceStr),
|
||||
value: common.Big(valueStr),
|
||||
data: common.FromHex(dataStr),
|
||||
}
|
||||
if len(toStr) > 0 {
|
||||
addr := common.HexToAddress(toStr)
|
||||
msg.to = &addr
|
||||
}
|
||||
|
||||
if msg.gas.Cmp(big.NewInt(0)) == 0 {
|
||||
msg.gas = big.NewInt(50000000)
|
||||
}
|
||||
|
||||
if msg.gasPrice.Cmp(big.NewInt(0)) == 0 {
|
||||
msg.gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
|
||||
}
|
||||
|
||||
header := be.bc.CurrentBlock().Header()
|
||||
vmenv := core.NewEnv(statedb, be.config, be.bc, msg, header, vm.Config{})
|
||||
gp := new(core.GasPool).AddGas(common.MaxBig)
|
||||
res, gas, err := core.ApplyMessage(vmenv, msg, gp)
|
||||
|
||||
return common.ToHex(res), gas.String(), err
|
||||
}
|
||||
|
||||
// StorageAt returns the data stores in the state for the given address and location.
|
||||
func (be *registryAPIBackend) StorageAt(addr string, storageAddr string) string {
|
||||
block := be.bc.CurrentBlock()
|
||||
state, err := state.New(block.Root(), be.chainDb)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return state.GetState(common.HexToAddress(addr), common.HexToHash(storageAddr)).Hex()
|
||||
}
|
||||
|
||||
// Transact forms a transaction from the given arguments and submits it to the
|
||||
// transactio pool for execution.
|
||||
func (be *registryAPIBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
|
||||
if len(toStr) > 0 && toStr != "0x" && !common.IsHexAddress(toStr) {
|
||||
return "", errors.New("invalid address")
|
||||
}
|
||||
|
||||
var (
|
||||
from = common.HexToAddress(fromStr)
|
||||
to = common.HexToAddress(toStr)
|
||||
value = common.Big(valueStr)
|
||||
gas *big.Int
|
||||
price *big.Int
|
||||
data []byte
|
||||
contractCreation bool
|
||||
)
|
||||
|
||||
if len(gasStr) == 0 {
|
||||
gas = big.NewInt(90000)
|
||||
} else {
|
||||
gas = common.Big(gasStr)
|
||||
}
|
||||
|
||||
if len(gasPriceStr) == 0 {
|
||||
price = big.NewInt(10000000000000)
|
||||
} else {
|
||||
price = common.Big(gasPriceStr)
|
||||
}
|
||||
|
||||
data = common.FromHex(codeStr)
|
||||
if len(toStr) == 0 {
|
||||
contractCreation = true
|
||||
}
|
||||
|
||||
nonce := be.txPool.State().GetNonce(from)
|
||||
if len(nonceStr) != 0 {
|
||||
nonce = common.Big(nonceStr).Uint64()
|
||||
}
|
||||
|
||||
var tx *types.Transaction
|
||||
if contractCreation {
|
||||
tx = types.NewContractCreation(nonce, value, gas, price, data)
|
||||
} else {
|
||||
tx = types.NewTransaction(nonce, to, value, gas, price, data)
|
||||
}
|
||||
|
||||
signature, err := be.am.SignEthereum(from, tx.SigHash().Bytes())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
signedTx, err := tx.WithSignature(signature)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
be.txPool.SetLocal(signedTx)
|
||||
if err := be.txPool.Add(signedTx); err != nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
if contractCreation {
|
||||
addr := crypto.CreateAddress(from, nonce)
|
||||
glog.V(logger.Info).Infof("Tx(%s) created: %s\n", signedTx.Hash().Hex(), addr.Hex())
|
||||
} else {
|
||||
glog.V(logger.Info).Infof("Tx(%s) to: %s\n", signedTx.Hash().Hex(), tx.To().Hex())
|
||||
}
|
||||
|
||||
return signedTx.Hash().Hex(), nil
|
||||
}
|
||||
|
|
@ -1,436 +0,0 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package registrar
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"regexp"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
)
|
||||
|
||||
/*
|
||||
Registrar implements the Ethereum name registrar services mapping
|
||||
- arbitrary strings to ethereum addresses
|
||||
- hashes to hashes
|
||||
- hashes to arbitrary strings
|
||||
(likely will provide lookup service for all three)
|
||||
|
||||
The Registrar is used by
|
||||
* the roundtripper transport implementation of
|
||||
url schemes to resolve domain names and services that register these names
|
||||
* contract info retrieval (NatSpec).
|
||||
|
||||
The Registrar uses 3 contracts on the blockchain:
|
||||
* GlobalRegistrar: Name (string) -> Address (Owner)
|
||||
* HashReg : Key Hash (hash of domain name or contract code) -> Content Hash
|
||||
* UrlHint : Content Hash -> Url Hint
|
||||
|
||||
These contracts are (currently) not included in the genesis block.
|
||||
Each Set<X> needs to be called once on each blockchain/network once.
|
||||
|
||||
Contract addresses need to be set the first time any Registrar method is called
|
||||
in a client session.
|
||||
This is done for frontier by default, otherwise the caller needs to make sure
|
||||
the relevant environment initialised the desired contracts
|
||||
*/
|
||||
var (
|
||||
// GlobalRegistrarAddr = "0xc6d9d2cd449a754c494264e1809c50e34d64562b" // olympic
|
||||
GlobalRegistrarAddr = "0x33990122638b9132ca29c723bdf037f1a891a70c" // frontier
|
||||
HashRegAddr = "0x23bf622b5a65f6060d855fca401133ded3520620" // frontier
|
||||
UrlHintAddr = "0x73ed5ef6c010727dfd2671dbb70faac19ec18626" // frontier
|
||||
|
||||
zero = regexp.MustCompile("^(0x)?0*$")
|
||||
)
|
||||
|
||||
const (
|
||||
trueHex = "0000000000000000000000000000000000000000000000000000000000000001"
|
||||
falseHex = "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
)
|
||||
|
||||
func abiSignature(s string) string {
|
||||
return common.ToHex(crypto.Keccak256([]byte(s))[:4])
|
||||
}
|
||||
|
||||
var (
|
||||
HashRegName = "HashReg"
|
||||
UrlHintName = "UrlHint"
|
||||
|
||||
registerContentHashAbi = abiSignature("register(uint256,uint256)")
|
||||
registerUrlAbi = abiSignature("register(uint256,uint8,uint256)")
|
||||
setOwnerAbi = abiSignature("setowner()")
|
||||
reserveAbi = abiSignature("reserve(bytes32)")
|
||||
resolveAbi = abiSignature("addr(bytes32)")
|
||||
registerAbi = abiSignature("setAddress(bytes32,address,bool)")
|
||||
addressAbiPrefix = falseHex[:24]
|
||||
)
|
||||
|
||||
// Registrar's backend is defined as an interface (implemented by xeth, but could be remote)
|
||||
type Backend interface {
|
||||
StorageAt(string, string) string
|
||||
Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error)
|
||||
Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, string, error)
|
||||
}
|
||||
|
||||
// TODO Registrar should also just implement The Resolver and Registry interfaces
|
||||
// Simplify for now.
|
||||
type VersionedRegistrar interface {
|
||||
Resolver(*big.Int) *Registrar
|
||||
Registry() *Registrar
|
||||
}
|
||||
|
||||
type Registrar struct {
|
||||
backend Backend
|
||||
}
|
||||
|
||||
func New(b Backend) (res *Registrar) {
|
||||
res = &Registrar{b}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Registrar) SetGlobalRegistrar(namereg string, addr common.Address) (txhash string, err error) {
|
||||
if namereg != "" {
|
||||
GlobalRegistrarAddr = namereg
|
||||
return
|
||||
}
|
||||
if zero.MatchString(GlobalRegistrarAddr) {
|
||||
if (addr == common.Address{}) {
|
||||
err = fmt.Errorf("GlobalRegistrar address not found and sender for creation not given")
|
||||
return
|
||||
} else {
|
||||
txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "800000", "", GlobalRegistrarCode)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("GlobalRegistrar address not found and sender for creation failed: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Registrar) SetHashReg(hashreg string, addr common.Address) (txhash string, err error) {
|
||||
if hashreg != "" {
|
||||
HashRegAddr = hashreg
|
||||
} else {
|
||||
if !zero.MatchString(HashRegAddr) {
|
||||
return
|
||||
}
|
||||
nameHex, extra := encodeName(HashRegName, 2)
|
||||
hashRegAbi := resolveAbi + nameHex + extra
|
||||
glog.V(logger.Detail).Infof("\ncall HashRegAddr %v with %v\n", GlobalRegistrarAddr, hashRegAbi)
|
||||
var res string
|
||||
res, _, err = self.backend.Call("", GlobalRegistrarAddr, "", "", "", hashRegAbi)
|
||||
if len(res) >= 40 {
|
||||
HashRegAddr = "0x" + res[len(res)-40:len(res)]
|
||||
}
|
||||
if err != nil || zero.MatchString(HashRegAddr) {
|
||||
if (addr == common.Address{}) {
|
||||
err = fmt.Errorf("HashReg address not found and sender for creation not given")
|
||||
return
|
||||
}
|
||||
|
||||
txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "", "", HashRegCode)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("HashReg address not found and sender for creation failed: %v", err)
|
||||
}
|
||||
glog.V(logger.Detail).Infof("created HashRegAddr @ txhash %v\n", txhash)
|
||||
} else {
|
||||
glog.V(logger.Detail).Infof("HashRegAddr found at @ %v\n", HashRegAddr)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Registrar) SetUrlHint(urlhint string, addr common.Address) (txhash string, err error) {
|
||||
if urlhint != "" {
|
||||
UrlHintAddr = urlhint
|
||||
} else {
|
||||
if !zero.MatchString(UrlHintAddr) {
|
||||
return
|
||||
}
|
||||
nameHex, extra := encodeName(UrlHintName, 2)
|
||||
urlHintAbi := resolveAbi + nameHex + extra
|
||||
glog.V(logger.Detail).Infof("UrlHint address query data: %s to %s", urlHintAbi, GlobalRegistrarAddr)
|
||||
var res string
|
||||
res, _, err = self.backend.Call("", GlobalRegistrarAddr, "", "", "", urlHintAbi)
|
||||
if len(res) >= 40 {
|
||||
UrlHintAddr = "0x" + res[len(res)-40:len(res)]
|
||||
}
|
||||
if err != nil || zero.MatchString(UrlHintAddr) {
|
||||
if (addr == common.Address{}) {
|
||||
err = fmt.Errorf("UrlHint address not found and sender for creation not given")
|
||||
return
|
||||
}
|
||||
txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "210000", "", UrlHintCode)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("UrlHint address not found and sender for creation failed: %v", err)
|
||||
}
|
||||
glog.V(logger.Detail).Infof("created UrlHint @ txhash %v\n", txhash)
|
||||
} else {
|
||||
glog.V(logger.Detail).Infof("UrlHint found @ %v\n", HashRegAddr)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ReserveName(from, name) reserves name for the sender address in the globalRegistrar
|
||||
// the tx needs to be mined to take effect
|
||||
func (self *Registrar) ReserveName(address common.Address, name string) (txh string, err error) {
|
||||
if zero.MatchString(GlobalRegistrarAddr) {
|
||||
return "", fmt.Errorf("GlobalRegistrar address is not set")
|
||||
}
|
||||
nameHex, extra := encodeName(name, 2)
|
||||
abi := reserveAbi + nameHex + extra
|
||||
glog.V(logger.Detail).Infof("Reserve data: %s", abi)
|
||||
return self.backend.Transact(
|
||||
address.Hex(),
|
||||
GlobalRegistrarAddr,
|
||||
"", "", "", "",
|
||||
abi,
|
||||
)
|
||||
}
|
||||
|
||||
// SetAddressToName(from, name, addr) will set the Address to address for name
|
||||
// in the globalRegistrar using from as the sender of the transaction
|
||||
// the tx needs to be mined to take effect
|
||||
func (self *Registrar) SetAddressToName(from common.Address, name string, address common.Address) (txh string, err error) {
|
||||
if zero.MatchString(GlobalRegistrarAddr) {
|
||||
return "", fmt.Errorf("GlobalRegistrar address is not set")
|
||||
}
|
||||
|
||||
nameHex, extra := encodeName(name, 6)
|
||||
addrHex := encodeAddress(address)
|
||||
|
||||
abi := registerAbi + nameHex + addrHex + trueHex + extra
|
||||
glog.V(logger.Detail).Infof("SetAddressToName data: %s to %s ", abi, GlobalRegistrarAddr)
|
||||
|
||||
return self.backend.Transact(
|
||||
from.Hex(),
|
||||
GlobalRegistrarAddr,
|
||||
"", "", "", "",
|
||||
abi,
|
||||
)
|
||||
}
|
||||
|
||||
// NameToAddr(from, name) queries the registrar for the address on name
|
||||
func (self *Registrar) NameToAddr(from common.Address, name string) (address common.Address, err error) {
|
||||
if zero.MatchString(GlobalRegistrarAddr) {
|
||||
return address, fmt.Errorf("GlobalRegistrar address is not set")
|
||||
}
|
||||
|
||||
nameHex, extra := encodeName(name, 2)
|
||||
abi := resolveAbi + nameHex + extra
|
||||
glog.V(logger.Detail).Infof("NameToAddr data: %s", abi)
|
||||
res, _, err := self.backend.Call(
|
||||
from.Hex(),
|
||||
GlobalRegistrarAddr,
|
||||
"", "", "",
|
||||
abi,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
address = common.HexToAddress(res)
|
||||
return
|
||||
}
|
||||
|
||||
// called as first step in the registration process on HashReg
|
||||
func (self *Registrar) SetOwner(address common.Address) (txh string, err error) {
|
||||
if zero.MatchString(HashRegAddr) {
|
||||
return "", fmt.Errorf("HashReg address is not set")
|
||||
}
|
||||
return self.backend.Transact(
|
||||
address.Hex(),
|
||||
HashRegAddr,
|
||||
"", "", "", "",
|
||||
setOwnerAbi,
|
||||
)
|
||||
}
|
||||
|
||||
// registers some content hash to a key/code hash
|
||||
// e.g., the contract Info combined Json Doc's ContentHash
|
||||
// to CodeHash of a contract or hash of a domain
|
||||
func (self *Registrar) SetHashToHash(address common.Address, codehash, dochash common.Hash) (txh string, err error) {
|
||||
if zero.MatchString(HashRegAddr) {
|
||||
return "", fmt.Errorf("HashReg address is not set")
|
||||
}
|
||||
|
||||
_, err = self.SetOwner(address)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
codehex := common.Bytes2Hex(codehash[:])
|
||||
dochex := common.Bytes2Hex(dochash[:])
|
||||
|
||||
data := registerContentHashAbi + codehex + dochex
|
||||
glog.V(logger.Detail).Infof("SetHashToHash data: %s sent to %v\n", data, HashRegAddr)
|
||||
return self.backend.Transact(
|
||||
address.Hex(),
|
||||
HashRegAddr,
|
||||
"", "", "", "",
|
||||
data,
|
||||
)
|
||||
}
|
||||
|
||||
// SetUrlToHash(from, hash, url) registers a url to a content hash so that the content can be fetched
|
||||
// address is used as sender for the transaction and will be the owner of a new
|
||||
// registry entry on first time use
|
||||
// FIXME: silently doing nothing if sender is not the owner
|
||||
// note that with content addressed storage, this step is no longer necessary
|
||||
func (self *Registrar) SetUrlToHash(address common.Address, hash common.Hash, url string) (txh string, err error) {
|
||||
if zero.MatchString(UrlHintAddr) {
|
||||
return "", fmt.Errorf("UrlHint address is not set")
|
||||
}
|
||||
|
||||
hashHex := common.Bytes2Hex(hash[:])
|
||||
var urlHex string
|
||||
urlb := []byte(url)
|
||||
var cnt byte
|
||||
n := len(urlb)
|
||||
|
||||
for n > 0 {
|
||||
if n > 32 {
|
||||
n = 32
|
||||
}
|
||||
urlHex = common.Bytes2Hex(urlb[:n])
|
||||
urlb = urlb[n:]
|
||||
n = len(urlb)
|
||||
bcnt := make([]byte, 32)
|
||||
bcnt[31] = cnt
|
||||
data := registerUrlAbi +
|
||||
hashHex +
|
||||
common.Bytes2Hex(bcnt) +
|
||||
common.Bytes2Hex(common.Hex2BytesFixed(urlHex, 32))
|
||||
txh, err = self.backend.Transact(
|
||||
address.Hex(),
|
||||
UrlHintAddr,
|
||||
"", "", "", "",
|
||||
data,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cnt++
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// HashToHash(key) resolves contenthash for key (a hash) using HashReg
|
||||
// resolution is costless non-transactional
|
||||
// implemented as direct retrieval from db
|
||||
func (self *Registrar) HashToHash(khash common.Hash) (chash common.Hash, err error) {
|
||||
if zero.MatchString(HashRegAddr) {
|
||||
return common.Hash{}, fmt.Errorf("HashReg address is not set")
|
||||
}
|
||||
|
||||
// look up in hashReg
|
||||
at := HashRegAddr[2:]
|
||||
key := storageAddress(storageMapping(storageIdx2Addr(1), khash[:]))
|
||||
hash := self.backend.StorageAt(at, key)
|
||||
|
||||
if hash == "0x0" || len(hash) < 3 || (hash == common.Hash{}.Hex()) {
|
||||
err = fmt.Errorf("HashToHash: content hash not found for '%v'", khash.Hex())
|
||||
return
|
||||
}
|
||||
copy(chash[:], common.Hex2BytesFixed(hash[2:], 32))
|
||||
return
|
||||
}
|
||||
|
||||
// HashToUrl(contenthash) resolves the url for contenthash using UrlHint
|
||||
// resolution is costless non-transactional
|
||||
// implemented as direct retrieval from db
|
||||
// if we use content addressed storage, this step is no longer necessary
|
||||
func (self *Registrar) HashToUrl(chash common.Hash) (uri string, err error) {
|
||||
if zero.MatchString(UrlHintAddr) {
|
||||
return "", fmt.Errorf("UrlHint address is not set")
|
||||
}
|
||||
// look up in URL reg
|
||||
var str string = " "
|
||||
var idx uint32
|
||||
for len(str) > 0 {
|
||||
mapaddr := storageMapping(storageIdx2Addr(1), chash[:])
|
||||
key := storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(idx)))
|
||||
hex := self.backend.StorageAt(UrlHintAddr[2:], key)
|
||||
str = string(common.Hex2Bytes(hex[2:]))
|
||||
l := 0
|
||||
for (l < len(str)) && (str[l] == 0) {
|
||||
l++
|
||||
}
|
||||
|
||||
str = str[l:]
|
||||
uri = uri + str
|
||||
idx++
|
||||
}
|
||||
|
||||
if len(uri) == 0 {
|
||||
err = fmt.Errorf("HashToUrl: URL hint not found for '%v'", chash.Hex())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func storageIdx2Addr(varidx uint32) []byte {
|
||||
data := make([]byte, 32)
|
||||
binary.BigEndian.PutUint32(data[28:32], varidx)
|
||||
return data
|
||||
}
|
||||
|
||||
func storageMapping(addr, key []byte) []byte {
|
||||
data := make([]byte, 64)
|
||||
copy(data[0:32], key[0:32])
|
||||
copy(data[32:64], addr[0:32])
|
||||
sha := crypto.Keccak256(data)
|
||||
return sha
|
||||
}
|
||||
|
||||
func storageFixedArray(addr, idx []byte) []byte {
|
||||
var carry byte
|
||||
for i := 31; i >= 0; i-- {
|
||||
var b byte = addr[i] + idx[i] + carry
|
||||
if b < addr[i] {
|
||||
carry = 1
|
||||
} else {
|
||||
carry = 0
|
||||
}
|
||||
addr[i] = b
|
||||
}
|
||||
return addr
|
||||
}
|
||||
|
||||
func storageAddress(addr []byte) string {
|
||||
return common.ToHex(addr)
|
||||
}
|
||||
|
||||
func encodeAddress(address common.Address) string {
|
||||
return addressAbiPrefix + address.Hex()[2:]
|
||||
}
|
||||
|
||||
func encodeName(name string, index uint8) (string, string) {
|
||||
extra := common.Bytes2Hex([]byte(name))
|
||||
if len(name) > 32 {
|
||||
return fmt.Sprintf("%064x", index), extra
|
||||
}
|
||||
return extra + falseHex[len(extra):], ""
|
||||
}
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package registrar
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
type testBackend struct {
|
||||
// contracts mock
|
||||
contracts map[string](map[string]string)
|
||||
}
|
||||
|
||||
var (
|
||||
text = "test"
|
||||
codehash = common.StringToHash("1234")
|
||||
hash = common.BytesToHash(crypto.Keccak256([]byte(text)))
|
||||
url = "bzz://bzzhash/my/path/contr.act"
|
||||
)
|
||||
|
||||
func NewTestBackend() *testBackend {
|
||||
self := &testBackend{}
|
||||
self.contracts = make(map[string](map[string]string))
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *testBackend) initHashReg() {
|
||||
self.contracts[HashRegAddr[2:]] = make(map[string]string)
|
||||
key := storageAddress(storageMapping(storageIdx2Addr(1), codehash[:]))
|
||||
self.contracts[HashRegAddr[2:]][key] = hash.Hex()
|
||||
}
|
||||
|
||||
func (self *testBackend) initUrlHint() {
|
||||
self.contracts[UrlHintAddr[2:]] = make(map[string]string)
|
||||
mapaddr := storageMapping(storageIdx2Addr(1), hash[:])
|
||||
|
||||
key := storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(0)))
|
||||
self.contracts[UrlHintAddr[2:]][key] = common.ToHex([]byte(url))
|
||||
key = storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(1)))
|
||||
self.contracts[UrlHintAddr[2:]][key] = "0x0"
|
||||
}
|
||||
|
||||
func (self *testBackend) StorageAt(ca, sa string) (res string) {
|
||||
c := self.contracts[ca]
|
||||
if c == nil {
|
||||
return "0x0"
|
||||
}
|
||||
res = c[sa]
|
||||
return
|
||||
}
|
||||
|
||||
func (self *testBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (self *testBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, string, error) {
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
func TestSetGlobalRegistrar(t *testing.T) {
|
||||
b := NewTestBackend()
|
||||
res := New(b)
|
||||
_, err := res.SetGlobalRegistrar("addresshex", common.BigToAddress(common.Big1))
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v'", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHashToHash(t *testing.T) {
|
||||
b := NewTestBackend()
|
||||
res := New(b)
|
||||
|
||||
HashRegAddr = "0x0"
|
||||
got, err := res.HashToHash(codehash)
|
||||
if err == nil {
|
||||
t.Errorf("expected error")
|
||||
} else {
|
||||
exp := "HashReg address is not set"
|
||||
if err.Error() != exp {
|
||||
t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
HashRegAddr = common.BigToAddress(common.Big1).Hex() //[2:]
|
||||
got, err = res.HashToHash(codehash)
|
||||
if err == nil {
|
||||
t.Errorf("expected error")
|
||||
} else {
|
||||
exp := "HashToHash: content hash not found for '" + codehash.Hex() + "'"
|
||||
if err.Error() != exp {
|
||||
t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
b.initHashReg()
|
||||
got, err = res.HashToHash(codehash)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, got %v", err)
|
||||
} else {
|
||||
if got != hash {
|
||||
t.Errorf("incorrect result, expected '%v', got '%v'", hash.Hex(), got.Hex())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHashToUrl(t *testing.T) {
|
||||
b := NewTestBackend()
|
||||
res := New(b)
|
||||
|
||||
UrlHintAddr = "0x0"
|
||||
got, err := res.HashToUrl(hash)
|
||||
if err == nil {
|
||||
t.Errorf("expected error")
|
||||
} else {
|
||||
exp := "UrlHint address is not set"
|
||||
if err.Error() != exp {
|
||||
t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
UrlHintAddr = common.BigToAddress(common.Big2).Hex() //[2:]
|
||||
got, err = res.HashToUrl(hash)
|
||||
if err == nil {
|
||||
t.Errorf("expected error")
|
||||
} else {
|
||||
exp := "HashToUrl: URL hint not found for '" + hash.Hex() + "'"
|
||||
if err.Error() != exp {
|
||||
t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
b.initUrlHint()
|
||||
got, err = res.HashToUrl(hash)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, got %v", err)
|
||||
} else {
|
||||
if got != url {
|
||||
t.Errorf("incorrect result, expected '%v', got '%s'", url, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -27,7 +27,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/les"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
|
|
@ -62,20 +61,20 @@ type ReleaseService struct {
|
|||
// releases and notify the user of such.
|
||||
func NewReleaseService(ctx *node.ServiceContext, config Config) (node.Service, error) {
|
||||
// Retrieve the Ethereum service dependency to access the blockchain
|
||||
var apiBackend ethapi.Backend
|
||||
var apiBackend bind.ContractBackend
|
||||
var ethereum *eth.Ethereum
|
||||
if err := ctx.Service(ðereum); err == nil {
|
||||
apiBackend = ethereum.ApiBackend
|
||||
apiBackend = ethereum
|
||||
} else {
|
||||
var ethereum *les.LightEthereum
|
||||
if err := ctx.Service(ðereum); err == nil {
|
||||
apiBackend = ethereum.ApiBackend
|
||||
apiBackend = ethereum
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Construct the release service
|
||||
contract, err := NewReleaseOracle(config.Oracle, eth.NewContractBackend(apiBackend))
|
||||
contract, err := NewReleaseOracle(config.Oracle, apiBackend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ func GetCanonicalHash(db ethdb.Database, number uint64) common.Hash {
|
|||
|
||||
// missingNumber is returned by GetBlockNumber if no header with the
|
||||
// given block hash has been stored in the database
|
||||
const missingNumber = uint64(0xffffffffffffffff)
|
||||
const MissingNumber = uint64(0xffffffffffffffff)
|
||||
|
||||
// GetBlockNumber returns the block number assigned to a block hash
|
||||
// if the corresponding header is present in the database
|
||||
|
|
@ -91,7 +91,7 @@ func GetBlockNumber(db ethdb.Database, hash common.Hash) uint64 {
|
|||
if len(data) != 8 {
|
||||
data, _ := db.Get(append(append(oldBlockPrefix, hash.Bytes()...), oldHeaderSuffix...))
|
||||
if len(data) == 0 {
|
||||
return missingNumber
|
||||
return MissingNumber
|
||||
}
|
||||
header := new(types.Header)
|
||||
if err := rlp.Decode(bytes.NewReader(data), header); err != nil {
|
||||
|
|
@ -247,7 +247,7 @@ func GetBlockReceipts(db ethdb.Database, hash common.Hash, number uint64) types.
|
|||
|
||||
// GetTransaction retrieves a specific transaction from the database, along with
|
||||
// its added positional metadata.
|
||||
func GetTransaction(db ethdb.Database, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) {
|
||||
func GetTransaction(db ethdb.Database, hash common.Hash) (*types.Transaction, common.Hash, uint64, int) {
|
||||
// Retrieve the transaction itself from the database
|
||||
data, _ := db.Get(hash.Bytes())
|
||||
if len(data) == 0 {
|
||||
|
|
@ -270,7 +270,7 @@ func GetTransaction(db ethdb.Database, hash common.Hash) (*types.Transaction, co
|
|||
if err := rlp.DecodeBytes(data, &meta); err != nil {
|
||||
return nil, common.Hash{}, 0, 0
|
||||
}
|
||||
return &tx, meta.BlockHash, meta.BlockIndex, meta.Index
|
||||
return &tx, meta.BlockHash, meta.BlockIndex, int(meta.Index)
|
||||
}
|
||||
|
||||
// GetReceipt returns a receipt by hash
|
||||
|
|
|
|||
|
|
@ -368,7 +368,7 @@ func TestTransactionStorage(t *testing.T) {
|
|||
if txn, hash, number, index := GetTransaction(db, tx.Hash()); txn == nil {
|
||||
t.Fatalf("tx #%d [%x]: transaction not found", i, tx.Hash())
|
||||
} else {
|
||||
if hash != block.Hash() || number != block.NumberU64() || index != uint64(i) {
|
||||
if hash != block.Hash() || number != block.NumberU64() || index != i {
|
||||
t.Fatalf("tx #%d [%x]: positional metadata mismatch: have %x/%d/%d, want %x/%v/%v", i, tx.Hash(), hash, number, index, block.Hash(), block.NumberU64(), i)
|
||||
}
|
||||
if tx.String() != txn.String() {
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ func (hc *HeaderChain) GetBlockNumber(hash common.Hash) uint64 {
|
|||
return cached.(uint64)
|
||||
}
|
||||
number := GetBlockNumber(hc.chainDb, hash)
|
||||
if number != missingNumber {
|
||||
if number != MissingNumber {
|
||||
hc.numberCache.Add(hash, number)
|
||||
}
|
||||
return number
|
||||
|
|
|
|||
|
|
@ -1,96 +0,0 @@
|
|||
// Copyright 2014 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 core
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
// "github.com/ethereum/go-ethereum/crypto"
|
||||
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
)
|
||||
|
||||
// Implement our EthTest Manager
|
||||
type TestManager struct {
|
||||
// stateManager *StateManager
|
||||
eventMux *event.TypeMux
|
||||
|
||||
db ethdb.Database
|
||||
txPool *TxPool
|
||||
blockChain *BlockChain
|
||||
Blocks []*types.Block
|
||||
}
|
||||
|
||||
func (s *TestManager) IsListening() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *TestManager) IsMining() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *TestManager) PeerCount() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *TestManager) Peers() *list.List {
|
||||
return list.New()
|
||||
}
|
||||
|
||||
func (s *TestManager) BlockChain() *BlockChain {
|
||||
return s.blockChain
|
||||
}
|
||||
|
||||
func (tm *TestManager) TxPool() *TxPool {
|
||||
return tm.txPool
|
||||
}
|
||||
|
||||
// func (tm *TestManager) StateManager() *StateManager {
|
||||
// return tm.stateManager
|
||||
// }
|
||||
|
||||
func (tm *TestManager) EventMux() *event.TypeMux {
|
||||
return tm.eventMux
|
||||
}
|
||||
|
||||
// func (tm *TestManager) KeyManager() *crypto.KeyManager {
|
||||
// return nil
|
||||
// }
|
||||
|
||||
func (tm *TestManager) Db() ethdb.Database {
|
||||
return tm.db
|
||||
}
|
||||
|
||||
func NewTestManager() *TestManager {
|
||||
db, err := ethdb.NewMemDatabase()
|
||||
if err != nil {
|
||||
fmt.Println("Could not create mem-db, failing")
|
||||
return nil
|
||||
}
|
||||
|
||||
testManager := &TestManager{}
|
||||
testManager.eventMux = new(event.TypeMux)
|
||||
testManager.db = db
|
||||
// testManager.txPool = NewTxPool(testManager)
|
||||
// testManager.blockChain = NewBlockChain(testManager)
|
||||
// testManager.stateManager = NewStateManager(testManager)
|
||||
|
||||
return testManager
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"fmt"
|
||||
"math/big"
|
||||
|
||||
ethereum "github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
|
|
@ -134,6 +135,39 @@ func ApplyMessage(env vm.Environment, msg Message, gp *GasPool) ([]byte, *big.In
|
|||
return ret, gasUsed, err
|
||||
}
|
||||
|
||||
// ApplyCallMessage runs the given message as a read-only contract call.
|
||||
//
|
||||
// It modifies the environment to provide a near infinite amount of ether to the sender
|
||||
// account and runs the message with the amount of gas configured in the message. This
|
||||
// function is meant to be used outside of regular block processing.
|
||||
//
|
||||
// It returns the bytes returned by any EVM execution (if it took place), the gas used
|
||||
// (not including gas refunds) and an error if it failed. An error always indicates a core
|
||||
// error meaning that the message would always fail for that particular state and would
|
||||
// never be accepted within a block.
|
||||
func ApplyCallMessage(call ethereum.CallMsg, newEnv func(Message) vm.Environment) ([]byte, *big.Int, error) {
|
||||
// Ensure message is initialized properly.
|
||||
if call.GasPrice == nil {
|
||||
call.GasPrice = big.NewInt(1)
|
||||
}
|
||||
if call.Gas == nil || call.Gas.BitLen() == 0 {
|
||||
call.Gas = big.NewInt(50000000)
|
||||
}
|
||||
if call.Value == nil {
|
||||
call.Value = new(big.Int)
|
||||
}
|
||||
msg := callmsg{call}
|
||||
env := newEnv(msg)
|
||||
// Provide ether to the caller account.
|
||||
have := env.Db().GetBalance(call.From)
|
||||
need := new(big.Int).Sub(common.MaxBig, have)
|
||||
env.Db().AddBalance(call.From, need)
|
||||
// Execute the call.
|
||||
gaspool := new(GasPool).AddGas(call.Gas)
|
||||
ret, gasUsed, _, err := NewStateTransition(env, msg, gaspool).TransitionDb()
|
||||
return ret, gasUsed, err
|
||||
}
|
||||
|
||||
func (self *StateTransition) from() (vm.Account, error) {
|
||||
var (
|
||||
f common.Address
|
||||
|
|
@ -300,3 +334,18 @@ func (self *StateTransition) refundGas() {
|
|||
func (self *StateTransition) gasUsed() *big.Int {
|
||||
return new(big.Int).Sub(self.initialGas, self.gas)
|
||||
}
|
||||
|
||||
// callmsg wraps ethereum.CallMsg so it implements Message.
|
||||
type callmsg struct {
|
||||
ethereum.CallMsg
|
||||
}
|
||||
|
||||
func (m callmsg) From() (common.Address, error) { return m.CallMsg.From, nil }
|
||||
func (m callmsg) FromFrontier() (common.Address, error) { return m.CallMsg.From, nil }
|
||||
func (m callmsg) Nonce() uint64 { return 0 }
|
||||
func (m callmsg) CheckNonce() bool { return false }
|
||||
func (m callmsg) To() *common.Address { return m.CallMsg.To }
|
||||
func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
|
||||
func (m callmsg) Gas() *big.Int { return m.CallMsg.Gas }
|
||||
func (m callmsg) Value() *big.Int { return m.CallMsg.Value }
|
||||
func (m callmsg) Data() []byte { return m.CallMsg.Data }
|
||||
|
|
|
|||
|
|
@ -190,11 +190,12 @@ func (pool *TxPool) Stop() {
|
|||
glog.V(logger.Info).Infoln("Transaction pool stopped")
|
||||
}
|
||||
|
||||
func (pool *TxPool) State() *state.ManagedState {
|
||||
pool.mu.RLock()
|
||||
defer pool.mu.RUnlock()
|
||||
// NonceAt returns the next valid nonce for the given account.
|
||||
func (pool *TxPool) NonceAt(addr common.Address) uint64 {
|
||||
pool.mu.Lock()
|
||||
defer pool.mu.Unlock()
|
||||
|
||||
return pool.pendingState
|
||||
return pool.pendingState.GetNonce(addr)
|
||||
}
|
||||
|
||||
// Stats retrieves the current pool stats, namely the number of pending and the
|
||||
|
|
|
|||
|
|
@ -521,7 +521,7 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common.
|
|||
data: tx.Data(),
|
||||
}
|
||||
// Mutate the state if we haven't reached the tracing transaction yet
|
||||
if uint64(idx) < txIndex {
|
||||
if idx < txIndex {
|
||||
vmenv := core.NewEnv(stateDb, api.config, api.eth.BlockChain(), msg, block.Header(), vm.Config{})
|
||||
_, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -17,189 +17,299 @@
|
|||
package eth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
ethereum "github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"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 *Ethereum
|
||||
gpo *gasprice.GasPriceOracle
|
||||
}
|
||||
// Assert at compile time that this implementation has all optional API features.
|
||||
var (
|
||||
_ ethapi.TransactionInclusionBlock = (*Ethereum)(nil)
|
||||
_ ethapi.PendingState = (*Ethereum)(nil)
|
||||
_ bind.ContractBackend = (*Ethereum)(nil)
|
||||
_ bind.PendingContractCaller = (*Ethereum)(nil)
|
||||
)
|
||||
|
||||
func (b *EthApiBackend) SetHead(number uint64) {
|
||||
b.eth.blockchain.SetHead(number)
|
||||
}
|
||||
var (
|
||||
ErrBlockNotFound = errors.New("block not found")
|
||||
ErrTxNotFound = errors.New("transaction not found")
|
||||
)
|
||||
|
||||
func (b *EthApiBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) {
|
||||
// Pending block is only known by the miner
|
||||
if blockNr == rpc.PendingBlockNumber {
|
||||
block, _ := b.eth.miner.Pending()
|
||||
return block.Header(), nil
|
||||
// HeaderByNumber returns headers from the canonical chain.
|
||||
func (eth *Ethereum) HeaderByNumber(ctx context.Context, num *big.Int) (*types.Header, error) {
|
||||
if num == nil {
|
||||
return eth.blockchain.CurrentBlock().Header(), nil
|
||||
}
|
||||
// Otherwise resolve and return the block
|
||||
if blockNr == rpc.LatestBlockNumber {
|
||||
return b.eth.blockchain.CurrentBlock().Header(), nil
|
||||
if h := eth.blockchain.GetHeaderByNumber(num.Uint64()); h != nil {
|
||||
return h, nil
|
||||
}
|
||||
return b.eth.blockchain.GetHeaderByNumber(uint64(blockNr)), nil
|
||||
return nil, ErrBlockNotFound
|
||||
}
|
||||
|
||||
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
|
||||
// HeaderByHash returns the header with the given hash.
|
||||
func (eth *Ethereum) HeaderByHash(ctx context.Context, blockhash common.Hash) (*types.Header, error) {
|
||||
if h := eth.blockchain.GetHeaderByHash(blockhash); h != nil {
|
||||
return h, nil
|
||||
}
|
||||
// Otherwise resolve and return the block
|
||||
if blockNr == rpc.LatestBlockNumber {
|
||||
return b.eth.blockchain.CurrentBlock(), nil
|
||||
return nil, ErrBlockNotFound
|
||||
}
|
||||
|
||||
// BlockByNumber returns blocks from the canonical chain.
|
||||
func (eth *Ethereum) BlockByNumber(ctx context.Context, num *big.Int) (*types.Block, error) {
|
||||
if num == nil {
|
||||
return eth.blockchain.CurrentBlock(), nil
|
||||
}
|
||||
return b.eth.blockchain.GetBlockByNumber(uint64(blockNr)), nil
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) StateAndHeaderByNumber(ctx context.Context, 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
|
||||
if b := eth.blockchain.GetBlockByNumber(num.Uint64()); b != nil {
|
||||
return b, nil
|
||||
}
|
||||
// Otherwise resolve the block number and return its state
|
||||
header, err := b.HeaderByNumber(ctx, blockNr)
|
||||
if header == nil || err != nil {
|
||||
return nil, nil, err
|
||||
return nil, ErrBlockNotFound
|
||||
}
|
||||
|
||||
// BlockByHash returns the block with the given hash.
|
||||
func (eth *Ethereum) BlockByHash(ctx context.Context, blockhash common.Hash) (*types.Block, error) {
|
||||
if b := eth.blockchain.GetBlockByHash(blockhash); b != nil {
|
||||
return b, nil
|
||||
}
|
||||
stateDb, err := b.eth.BlockChain().StateAt(header.Root)
|
||||
return EthApiState{stateDb}, header, err
|
||||
return nil, ErrBlockNotFound
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) {
|
||||
return b.eth.blockchain.GetBlockByHash(blockHash), nil
|
||||
// BlockReceipts returns all receipts contained in the given block.
|
||||
func (eth *Ethereum) BlockReceipts(ctx context.Context, blockhash common.Hash, number uint64) ([]*types.Receipt, error) {
|
||||
r := core.GetBlockReceipts(eth.chainDb, blockhash, number)
|
||||
if r == nil {
|
||||
return nil, errors.New("database has no valid receipts for the given block")
|
||||
}
|
||||
return r, 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
|
||||
// TransactionCount returns the number of transactions in a block.
|
||||
func (eth *Ethereum) TransactionCount(ctx context.Context, blockhash common.Hash) (uint, error) {
|
||||
b := eth.blockchain.GetBlockByHash(blockhash)
|
||||
if b == nil {
|
||||
return 0, nil
|
||||
}
|
||||
return uint(len(b.Transactions())), nil
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int {
|
||||
return b.eth.blockchain.GetTdByHash(blockHash)
|
||||
// TransactionInBlock returns the i'th transaction in the given block.
|
||||
func (eth *Ethereum) TransactionInBlock(ctx context.Context, blockhash common.Hash, i uint) (*types.Transaction, error) {
|
||||
b := eth.blockchain.GetBlockByHash(blockhash)
|
||||
if b == nil {
|
||||
return nil, fmt.Errorf("transaction index %d out of range for non-existent block", i)
|
||||
}
|
||||
if i >= uint(len(b.Transactions())) {
|
||||
return nil, fmt.Errorf("transaction index %d out of range", i)
|
||||
}
|
||||
return b.Transactions()[i], nil
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
// TransactionByHash returns the transaction with the given hash.
|
||||
func (eth *Ethereum) TransactionByHash(ctx context.Context, txhash common.Hash) (tx *types.Transaction, isPending bool, err error) {
|
||||
if tx = eth.txPool.Get(txhash); tx != nil {
|
||||
return tx, true, nil
|
||||
}
|
||||
if tx, _, _, _ = core.GetTransaction(eth.chainDb, txhash); tx != nil {
|
||||
return tx, false, nil
|
||||
}
|
||||
return nil, false, ErrTxNotFound
|
||||
}
|
||||
|
||||
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)
|
||||
// TransactionInclusionBlock returns the block in which the given transaction was included.
|
||||
func (eth *Ethereum) TransactionInclusionBlock(txhash common.Hash) (bhash common.Hash, bnum uint64, index int, err error) {
|
||||
var tx *types.Transaction
|
||||
if tx, bhash, bnum, index = core.GetTransaction(eth.chainDb, txhash); tx == nil {
|
||||
err = ErrTxNotFound
|
||||
}
|
||||
return bhash, bnum, index, err
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) RemoveTx(txHash common.Hash) {
|
||||
b.eth.txMu.Lock()
|
||||
defer b.eth.txMu.Unlock()
|
||||
|
||||
b.eth.txPool.Remove(txHash)
|
||||
// TransactionReceipt returns the receipt of a transaction.
|
||||
func (eth *Ethereum) TransactionReceipt(ctx context.Context, txhash common.Hash) (*types.Receipt, error) {
|
||||
r := core.GetReceipt(eth.chainDb, txhash)
|
||||
if r == nil {
|
||||
return nil, ErrTxNotFound
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) GetPoolTransactions() types.Transactions {
|
||||
b.eth.txMu.Lock()
|
||||
defer b.eth.txMu.Unlock()
|
||||
// BlockTD returns the total difficulty of a certain block.
|
||||
func (eth *Ethereum) BlockTD(blockhash common.Hash) *big.Int {
|
||||
return eth.blockchain.GetTdByHash(blockhash)
|
||||
}
|
||||
|
||||
// BalanceAt returns the balance of the given account.
|
||||
func (eth *Ethereum) BalanceAt(ctx context.Context, addr common.Address, block *big.Int) (bal *big.Int, err error) {
|
||||
err = eth.withStateAt(ctx, block, false, func(st *state.StateDB) { bal = st.GetBalance(addr) })
|
||||
return bal, err
|
||||
}
|
||||
|
||||
// CodeAt returns the code of the given account.
|
||||
func (eth *Ethereum) CodeAt(ctx context.Context, addr common.Address, block *big.Int) (code []byte, err error) {
|
||||
err = eth.withStateAt(ctx, block, false, func(st *state.StateDB) { code = st.GetCode(addr) })
|
||||
return code, err
|
||||
}
|
||||
|
||||
// NonceAt returns the nonce of the given account.
|
||||
func (eth *Ethereum) NonceAt(ctx context.Context, addr common.Address, block *big.Int) (nonce uint64, err error) {
|
||||
err = eth.withStateAt(ctx, block, false, func(st *state.StateDB) { nonce = st.GetNonce(addr) })
|
||||
return nonce, err
|
||||
}
|
||||
|
||||
// StorageAt returns a storage value of the given account.
|
||||
func (eth *Ethereum) StorageAt(ctx context.Context, addr common.Address, key common.Hash, block *big.Int) (val []byte, err error) {
|
||||
err = eth.withStateAt(ctx, block, false, func(st *state.StateDB) { v := st.GetState(addr, key); val = v[:] })
|
||||
return val, err
|
||||
}
|
||||
|
||||
// PendingBalanceAt returns the balance of the given account in the pending state.
|
||||
func (eth *Ethereum) PendingBalanceAt(ctx context.Context, addr common.Address) (bal *big.Int, err error) {
|
||||
err = eth.withStateAt(ctx, nil, true, func(st *state.StateDB) { bal = st.GetBalance(addr) })
|
||||
return bal, err
|
||||
}
|
||||
|
||||
// PendingBalanceAt returns the code of the given account in the pending state.
|
||||
func (eth *Ethereum) PendingCodeAt(ctx context.Context, addr common.Address) (code []byte, err error) {
|
||||
err = eth.withStateAt(ctx, nil, true, func(st *state.StateDB) { code = st.GetCode(addr) })
|
||||
return code, err
|
||||
}
|
||||
|
||||
// PendingBalanceAt returns a storage value of the given account in the pending state.
|
||||
func (eth *Ethereum) PendingStorageAt(ctx context.Context, addr common.Address, key common.Hash) (val []byte, err error) {
|
||||
err = eth.withStateAt(ctx, nil, true, func(st *state.StateDB) { v := st.GetState(addr, key); val = v[:] })
|
||||
return val, err
|
||||
}
|
||||
|
||||
// PendingTransaction count returns the number of transactions in the pending block.
|
||||
func (eth *Ethereum) PendingTransactionCount(ctx context.Context) (uint, error) {
|
||||
b, _ := eth.miner.Pending()
|
||||
return uint(len(b.Transactions())), nil
|
||||
}
|
||||
|
||||
func (eth *Ethereum) withStateAt(ctx context.Context, block *big.Int, pending bool, fn func(st *state.StateDB)) error {
|
||||
var st *state.StateDB
|
||||
if pending {
|
||||
_, st = eth.miner.Pending()
|
||||
} else {
|
||||
header, err := eth.HeaderByNumber(ctx, block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
st, err = eth.BlockChain().StateAt(header.Root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
fn(st)
|
||||
return nil
|
||||
}
|
||||
|
||||
// PendingBlock returns the next block as envisioned by the pending state.
|
||||
func (eth *Ethereum) PendingBlock() (*types.Block, error) {
|
||||
b, _ := eth.miner.Pending()
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// PendingNonceAt returns the next valid nonce according to the local transaction pool.
|
||||
func (eth *Ethereum) PendingNonceAt(ctx context.Context, addr common.Address) (uint64, error) {
|
||||
return eth.txPool.NonceAt(addr), nil
|
||||
}
|
||||
|
||||
// PendingTransactions returns all known pending transactions.
|
||||
func (eth *Ethereum) PendingTransactions() []*types.Transaction {
|
||||
eth.txMu.Lock()
|
||||
defer eth.txMu.Unlock()
|
||||
|
||||
var txs types.Transactions
|
||||
for _, batch := range b.eth.txPool.Pending() {
|
||||
for _, batch := range eth.txPool.Pending() {
|
||||
txs = append(txs, batch...)
|
||||
}
|
||||
return txs
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) GetPoolTransaction(hash common.Hash) *types.Transaction {
|
||||
b.eth.txMu.Lock()
|
||||
defer b.eth.txMu.Unlock()
|
||||
// SendTransaction queues a transaction in the pool.
|
||||
func (eth *Ethereum) SendTransaction(ctx context.Context, signedTx *types.Transaction) error {
|
||||
eth.txMu.Lock()
|
||||
defer eth.txMu.Unlock()
|
||||
|
||||
return b.eth.txPool.Get(hash)
|
||||
eth.txPool.SetLocal(signedTx)
|
||||
return eth.txPool.Add(signedTx)
|
||||
}
|
||||
|
||||
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
|
||||
// SyncProgress returns sync status information.
|
||||
func (b *Ethereum) SyncProgress(ctx context.Context) (*ethereum.SyncProgress, error) {
|
||||
return b.protocolManager.downloader.Progress(), nil
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) Stats() (pending int, queued int) {
|
||||
b.eth.txMu.Lock()
|
||||
defer b.eth.txMu.Unlock()
|
||||
|
||||
return b.eth.txPool.Stats()
|
||||
// SuggestGasPrice returns a suitable gas price based on the content of recently seen blocks.
|
||||
func (eth *Ethereum) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
|
||||
return eth.gpo.SuggestPrice(), nil
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) {
|
||||
b.eth.txMu.Lock()
|
||||
defer b.eth.txMu.Unlock()
|
||||
// RemoveTransaction removes the given transaction from the local pool.
|
||||
func (eth *Ethereum) RemoveTransaction(txHash common.Hash) {
|
||||
eth.txMu.Lock()
|
||||
defer eth.txMu.Unlock()
|
||||
|
||||
return b.eth.TxPool().Content()
|
||||
eth.txPool.Remove(txHash)
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) Downloader() *downloader.Downloader {
|
||||
return b.eth.Downloader()
|
||||
// ProtocolVersion returns the active protocol version.
|
||||
func (eth *Ethereum) ProtocolVersion() int {
|
||||
return int(eth.protocolManager.SubProtocols[0].Version)
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) ProtocolVersion() int {
|
||||
return b.eth.EthVersion()
|
||||
// AccountManager returns the internal account manager that accesses the data directory.
|
||||
// Deprecated: get the account manager through node.Node instead.
|
||||
func (eth *Ethereum) AccountManager() *accounts.Manager {
|
||||
return eth.accountManager
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
|
||||
return b.gpo.SuggestPrice(), nil
|
||||
// ResetHeadBlock resets the blockchain to the given number.
|
||||
// Use this method if you know what you're doing.
|
||||
func (eth *Ethereum) ResetHeadBlock(blocknum uint64) {
|
||||
eth.blockchain.SetHead(blocknum)
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) ChainDb() ethdb.Database {
|
||||
return b.eth.ChainDb()
|
||||
func (eth *Ethereum) EstimateGas(ctx context.Context, call ethereum.CallMsg) (usedGas *big.Int, err error) {
|
||||
block, state := eth.miner.Pending()
|
||||
_, gas, err := eth.callContract(call, block.Header(), state)
|
||||
return gas, err
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) EventMux() *event.TypeMux {
|
||||
return b.eth.EventMux()
|
||||
func (eth *Ethereum) PendingCallContract(ctx context.Context, call ethereum.CallMsg) ([]byte, error) {
|
||||
block, state := eth.miner.Pending()
|
||||
val, _, err := eth.callContract(call, block.Header(), state)
|
||||
return val, err
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) AccountManager() *accounts.Manager {
|
||||
return b.eth.AccountManager()
|
||||
func (eth *Ethereum) CallContract(ctx context.Context, call ethereum.CallMsg, blocknum *big.Int) ([]byte, error) {
|
||||
var head *types.Header
|
||||
if blocknum == nil {
|
||||
head = eth.blockchain.CurrentHeader()
|
||||
} else if head = eth.blockchain.GetHeaderByNumber(blocknum.Uint64()); head == nil {
|
||||
return nil, ErrBlockNotFound
|
||||
}
|
||||
state, err := eth.blockchain.StateAt(head.Root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, _, err := eth.callContract(call, head, state)
|
||||
return val, err
|
||||
}
|
||||
|
||||
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
|
||||
func (eth *Ethereum) callContract(call ethereum.CallMsg, head *types.Header, state *state.StateDB) ([]byte, *big.Int, error) {
|
||||
return core.ApplyCallMessage(call, func(msg core.Message) vm.Environment {
|
||||
return core.NewEnv(state, eth.chainConfig, eth.blockchain, msg, head, vm.Config{})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,8 +31,6 @@ import (
|
|||
"github.com/ethereum/ethash"
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/httpclient"
|
||||
"github.com/ethereum/go-ethereum/common/registrar/ethreg"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
|
|
@ -127,17 +125,15 @@ type Ethereum struct {
|
|||
|
||||
eventMux *event.TypeMux
|
||||
pow *ethash.Ethash
|
||||
httpclient *httpclient.HTTPClient
|
||||
accountManager *accounts.Manager
|
||||
|
||||
ApiBackend *EthApiBackend
|
||||
|
||||
miner *miner.Miner
|
||||
Mining bool
|
||||
MinerThreads int
|
||||
AutoDAG bool
|
||||
autodagquit chan bool
|
||||
etherbase common.Address
|
||||
gpo *gasprice.GasPriceOracle
|
||||
solcPath string
|
||||
|
||||
NatSpec bool
|
||||
|
|
@ -173,7 +169,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
|||
pow: pow,
|
||||
shutdownChan: make(chan bool),
|
||||
stopDbUpgrade: stopDbUpgrade,
|
||||
httpclient: httpclient.New(config.DocRoot),
|
||||
netVersionId: config.NetworkId,
|
||||
NatSpec: config.NatSpec,
|
||||
PowTest: config.PowTest,
|
||||
|
|
@ -222,14 +217,14 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
|||
ForceJit: config.ForceJit,
|
||||
}
|
||||
|
||||
eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.EventMux())
|
||||
eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.eventMux)
|
||||
if err != nil {
|
||||
if err == core.ErrNoGenesis {
|
||||
return nil, fmt.Errorf(`No chain found. Please initialise a new chain using the "init" subcommand.`)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
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
|
||||
|
||||
maxPeers := config.MaxPeers
|
||||
|
|
@ -246,10 +241,13 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
|||
if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.FastSync, config.NetworkId, maxPeers, eth.eventMux, eth.txPool, eth.pow, eth.blockchain, chainDb); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.pow)
|
||||
|
||||
// Set up the miner.
|
||||
eth.miner = miner.New(eth, eth.chainConfig, eth.eventMux, eth.pow)
|
||||
eth.miner.SetGasPrice(config.GasPrice)
|
||||
eth.miner.SetExtra(config.ExtraData)
|
||||
|
||||
// Set up the gas price oracle.
|
||||
gpoParams := &gasprice.GpoParams{
|
||||
GpoMinGasPrice: config.GpoMinGasPrice,
|
||||
GpoMaxGasPrice: config.GpoMaxGasPrice,
|
||||
|
|
@ -258,8 +256,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
|||
GpobaseStepUp: config.GpobaseStepUp,
|
||||
GpobaseCorrectionFactor: config.GpobaseCorrectionFactor,
|
||||
}
|
||||
gpo := gasprice.NewGasPriceOracle(eth.blockchain, chainDb, eth.eventMux, gpoParams)
|
||||
eth.ApiBackend = &EthApiBackend{eth, gpo}
|
||||
eth.gpo = gasprice.NewGasPriceOracle(eth.blockchain, chainDb, eth.eventMux, gpoParams)
|
||||
|
||||
return eth, nil
|
||||
}
|
||||
|
|
@ -313,55 +310,59 @@ func CreatePoW(config *Config) (*ethash.Ethash, error) {
|
|||
|
||||
// APIs returns the collection of RPC services the ethereum package offers.
|
||||
// NOTE, some of these services probably need to be moved to somewhere else.
|
||||
func (s *Ethereum) APIs() []rpc.API {
|
||||
return append(ethapi.GetAPIs(s.ApiBackend, s.solcPath), []rpc.API{
|
||||
func (eth *Ethereum) APIs() []rpc.API {
|
||||
return append(ethapi.GetAPIs(eth, eth.solcPath), []rpc.API{
|
||||
{
|
||||
Namespace: "eth",
|
||||
Version: "1.0",
|
||||
Service: NewPublicEthereumAPI(s),
|
||||
Service: NewPublicEthereumAPI(eth),
|
||||
Public: true,
|
||||
}, {
|
||||
Namespace: "eth",
|
||||
Version: "1.0",
|
||||
Service: NewPublicMinerAPI(s),
|
||||
Service: NewPublicMinerAPI(eth),
|
||||
Public: true,
|
||||
}, {
|
||||
Namespace: "eth",
|
||||
Version: "1.0",
|
||||
Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux),
|
||||
Service: downloader.NewPublicDownloaderAPI(eth.protocolManager.downloader, eth.eventMux),
|
||||
Public: true,
|
||||
}, {
|
||||
Namespace: "miner",
|
||||
Version: "1.0",
|
||||
Service: NewPrivateMinerAPI(s),
|
||||
Service: NewPrivateMinerAPI(eth),
|
||||
Public: false,
|
||||
}, {
|
||||
Namespace: "eth",
|
||||
Version: "1.0",
|
||||
Service: filters.NewPublicFilterAPI(s.ApiBackend, false),
|
||||
Service: filters.NewPublicFilterAPI(eth, eth.eventMux, eth.chainDb, false),
|
||||
Public: true,
|
||||
}, {
|
||||
Namespace: "admin",
|
||||
Version: "1.0",
|
||||
Service: NewPrivateAdminAPI(s),
|
||||
Service: NewPrivateAdminAPI(eth),
|
||||
}, {
|
||||
Namespace: "debug",
|
||||
Version: "1.0",
|
||||
Service: NewPublicDebugAPI(s),
|
||||
Service: NewPublicDebugAPI(eth),
|
||||
Public: true,
|
||||
}, {
|
||||
Namespace: "debug",
|
||||
Version: "1.0",
|
||||
Service: NewPrivateDebugAPI(s.chainConfig, s),
|
||||
Service: ethapi.NewPrivateDebugAPI(eth, eth.chainDb),
|
||||
}, {
|
||||
Namespace: "debug",
|
||||
Version: "1.0",
|
||||
Service: NewPrivateDebugAPI(eth.chainConfig, eth),
|
||||
}, {
|
||||
Namespace: "txpool",
|
||||
Version: "1.0",
|
||||
Service: ethapi.TxPoolDebugAPI{Pool: eth.txPool},
|
||||
}, {
|
||||
Namespace: "net",
|
||||
Version: "1.0",
|
||||
Service: s.netRPCService,
|
||||
Service: eth.netRPCService,
|
||||
Public: true,
|
||||
}, {
|
||||
Namespace: "admin",
|
||||
Version: "1.0",
|
||||
Service: ethreg.NewPrivateRegistarAPI(s.chainConfig, s.blockchain, s.chainDb, s.txPool, s.accountManager),
|
||||
},
|
||||
}...)
|
||||
}
|
||||
|
|
@ -399,20 +400,16 @@ func (s *Ethereum) StartMining(threads int) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Ethereum) StopMining() { s.miner.Stop() }
|
||||
func (s *Ethereum) IsMining() bool { return s.miner.Mining() }
|
||||
func (s *Ethereum) Miner() *miner.Miner { return s.miner }
|
||||
func (s *Ethereum) StopMining() { s.miner.Stop() }
|
||||
func (s *Ethereum) IsMining() bool { return s.miner.Mining() }
|
||||
|
||||
func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager }
|
||||
func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain }
|
||||
func (s *Ethereum) TxPool() *core.TxPool { return s.txPool }
|
||||
func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux }
|
||||
func (s *Ethereum) Pow() *ethash.Ethash { return s.pow }
|
||||
func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb }
|
||||
func (s *Ethereum) IsListening() bool { return true } // Always listening
|
||||
func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) }
|
||||
func (s *Ethereum) NetVersion() int { return s.netVersionId }
|
||||
func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
|
||||
// Deprecated Accessors
|
||||
|
||||
func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain }
|
||||
func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb }
|
||||
func (s *Ethereum) TxPool() *core.TxPool { return s.txPool }
|
||||
func (s *Ethereum) Pow() *ethash.Ethash { return s.pow }
|
||||
func (s *Ethereum) Miner() *miner.Miner { return s.miner }
|
||||
|
||||
// Protocols implements node.Service, returning all the currently configured
|
||||
// network protocols to start.
|
||||
|
|
@ -427,7 +424,7 @@ func (s *Ethereum) Protocols() []p2p.Protocol {
|
|||
// Start implements node.Service, starting all internal goroutines needed by the
|
||||
// Ethereum protocol implementation.
|
||||
func (s *Ethereum) Start(srvr *p2p.Server) error {
|
||||
s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.NetVersion())
|
||||
s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.netVersionId)
|
||||
if s.AutoDAG {
|
||||
s.StartAutoDAG()
|
||||
}
|
||||
|
|
@ -529,12 +526,6 @@ func (self *Ethereum) StopAutoDAG() {
|
|||
glog.V(logger.Info).Infof("Automatic pregeneration of ethash DAG OFF (ethash dir: %s)", ethash.DefaultDir)
|
||||
}
|
||||
|
||||
// HTTPClient returns the light http client used for fetching offchain docs
|
||||
// (natspec, source for verification)
|
||||
func (self *Ethereum) HTTPClient() *httpclient.HTTPClient {
|
||||
return self.httpclient
|
||||
}
|
||||
|
||||
// dagFiles(epoch) returns the two alternative DAG filenames (not a path)
|
||||
// 1) <revision>-<hex(seedhash[8])> 2) full-R<revision>-<hex(seedhash[8])>
|
||||
func dagFiles(epoch uint64) (string, string) {
|
||||
|
|
|
|||
136
eth/bind.go
136
eth/bind.go
|
|
@ -1,136 +0,0 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package eth
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"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/rpc"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// ContractBackend implements bind.ContractBackend with direct calls to Ethereum
|
||||
// internals to support operating on contracts within subprotocols like eth and
|
||||
// swarm.
|
||||
//
|
||||
// Internally this backend uses the already exposed API endpoints of the Ethereum
|
||||
// object. These should be rewritten to internal Go method calls when the Go API
|
||||
// is refactored to support a clean library use.
|
||||
type ContractBackend struct {
|
||||
eapi *ethapi.PublicEthereumAPI // Wrapper around the Ethereum object to access metadata
|
||||
bcapi *ethapi.PublicBlockChainAPI // Wrapper around the blockchain to access chain data
|
||||
txapi *ethapi.PublicTransactionPoolAPI // Wrapper around the transaction pool to access transaction data
|
||||
}
|
||||
|
||||
// NewContractBackend creates a new native contract backend using an existing
|
||||
// Etheruem object.
|
||||
func NewContractBackend(apiBackend ethapi.Backend) *ContractBackend {
|
||||
return &ContractBackend{
|
||||
eapi: ethapi.NewPublicEthereumAPI(apiBackend),
|
||||
bcapi: ethapi.NewPublicBlockChainAPI(apiBackend),
|
||||
txapi: ethapi.NewPublicTransactionPoolAPI(apiBackend),
|
||||
}
|
||||
}
|
||||
|
||||
// CodeAt retrieves any code associated with the contract from the local API.
|
||||
func (b *ContractBackend) CodeAt(ctx context.Context, contract common.Address, blockNum *big.Int) ([]byte, error) {
|
||||
out, err := b.bcapi.GetCode(ctx, contract, toBlockNumber(blockNum))
|
||||
return common.FromHex(out), err
|
||||
}
|
||||
|
||||
// CodeAt retrieves any code associated with the contract from the local API.
|
||||
func (b *ContractBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) {
|
||||
out, err := b.bcapi.GetCode(ctx, contract, rpc.PendingBlockNumber)
|
||||
return common.FromHex(out), err
|
||||
}
|
||||
|
||||
// ContractCall implements bind.ContractCaller executing an Ethereum contract
|
||||
// call with the specified data as the input. The pending flag requests execution
|
||||
// against the pending block, not the stable head of the chain.
|
||||
func (b *ContractBackend) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNum *big.Int) ([]byte, error) {
|
||||
out, err := b.bcapi.Call(ctx, toCallArgs(msg), toBlockNumber(blockNum))
|
||||
return common.FromHex(out), err
|
||||
}
|
||||
|
||||
// ContractCall implements bind.ContractCaller executing an Ethereum contract
|
||||
// call with the specified data as the input. The pending flag requests execution
|
||||
// against the pending block, not the stable head of the chain.
|
||||
func (b *ContractBackend) PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) {
|
||||
out, err := b.bcapi.Call(ctx, toCallArgs(msg), rpc.PendingBlockNumber)
|
||||
return common.FromHex(out), err
|
||||
}
|
||||
|
||||
func toCallArgs(msg ethereum.CallMsg) ethapi.CallArgs {
|
||||
args := ethapi.CallArgs{
|
||||
To: msg.To,
|
||||
From: msg.From,
|
||||
Data: common.ToHex(msg.Data),
|
||||
}
|
||||
if msg.Gas != nil {
|
||||
args.Gas = *rpc.NewHexNumber(msg.Gas)
|
||||
}
|
||||
if msg.GasPrice != nil {
|
||||
args.GasPrice = *rpc.NewHexNumber(msg.GasPrice)
|
||||
}
|
||||
if msg.Value != nil {
|
||||
args.Value = *rpc.NewHexNumber(msg.Value)
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func toBlockNumber(num *big.Int) rpc.BlockNumber {
|
||||
if num == nil {
|
||||
return rpc.LatestBlockNumber
|
||||
}
|
||||
return rpc.BlockNumber(num.Int64())
|
||||
}
|
||||
|
||||
// PendingAccountNonce implements bind.ContractTransactor retrieving the current
|
||||
// pending nonce associated with an account.
|
||||
func (b *ContractBackend) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) {
|
||||
out, err := b.txapi.GetTransactionCount(ctx, account, rpc.PendingBlockNumber)
|
||||
return out.Uint64(), err
|
||||
}
|
||||
|
||||
// SuggestGasPrice implements bind.ContractTransactor retrieving the currently
|
||||
// suggested gas price to allow a timely execution of a transaction.
|
||||
func (b *ContractBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
|
||||
return b.eapi.GasPrice(ctx)
|
||||
}
|
||||
|
||||
// EstimateGasLimit implements bind.ContractTransactor triing to estimate the gas
|
||||
// needed to execute a specific transaction based on the current pending state of
|
||||
// the backend blockchain. There is no guarantee that this is the true gas limit
|
||||
// requirement as other transactions may be added or removed by miners, but it
|
||||
// should provide a basis for setting a reasonable default.
|
||||
func (b *ContractBackend) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (*big.Int, error) {
|
||||
out, err := b.bcapi.EstimateGas(ctx, toCallArgs(msg))
|
||||
return out.BigInt(), err
|
||||
}
|
||||
|
||||
// SendTransaction implements bind.ContractTransactor injects the transaction
|
||||
// into the pending pool for execution.
|
||||
func (b *ContractBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error {
|
||||
raw, _ := rlp.EncodeToBytes(tx)
|
||||
_, err := b.txapi.SendRawTransaction(ctx, common.ToHex(raw))
|
||||
return err
|
||||
}
|
||||
|
|
@ -76,7 +76,7 @@ func (api *PublicDownloaderAPI) eventLoop() {
|
|||
case StartEvent:
|
||||
notification = &SyncingResult{
|
||||
Syncing: true,
|
||||
Status: api.d.Progress(),
|
||||
Status: *api.d.Progress(),
|
||||
}
|
||||
case DoneEvent, FailedEvent:
|
||||
notification = false
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ func New(mode SyncMode, stateDb ethdb.Database, mux *event.TypeMux, hasHeader he
|
|||
// In addition, during the state download phase of fast synchronisation the number
|
||||
// of processed and the total number of known states are also returned. Otherwise
|
||||
// these are zero.
|
||||
func (d *Downloader) Progress() ethereum.SyncProgress {
|
||||
func (d *Downloader) Progress() *ethereum.SyncProgress {
|
||||
// Fetch the pending state count outside of the lock to prevent unforeseen deadlocks
|
||||
pendingStates := uint64(d.queue.PendingNodeData())
|
||||
|
||||
|
|
@ -229,7 +229,7 @@ func (d *Downloader) Progress() ethereum.SyncProgress {
|
|||
case LightSync:
|
||||
current = d.headHeader().Number.Uint64()
|
||||
}
|
||||
return ethereum.SyncProgress{
|
||||
return ðereum.SyncProgress{
|
||||
StartingBlock: d.syncStatsChainOrigin,
|
||||
CurrentBlock: current,
|
||||
HighestBlock: d.syncStatsChainHeight,
|
||||
|
|
|
|||
|
|
@ -56,20 +56,20 @@ type PublicFilterAPI struct {
|
|||
useMipMap bool
|
||||
mux *event.TypeMux
|
||||
quit chan struct{}
|
||||
chainDb ethdb.Database
|
||||
chaindb ethdb.Database
|
||||
events *EventSystem
|
||||
filtersMu sync.Mutex
|
||||
filters map[rpc.ID]*filter
|
||||
}
|
||||
|
||||
// NewPublicFilterAPI returns a new PublicFilterAPI instance.
|
||||
func NewPublicFilterAPI(backend Backend, lightMode bool) *PublicFilterAPI {
|
||||
func NewPublicFilterAPI(backend Backend, mux *event.TypeMux, chaindb ethdb.Database, lightMode bool) *PublicFilterAPI {
|
||||
api := &PublicFilterAPI{
|
||||
backend: backend,
|
||||
useMipMap: !lightMode,
|
||||
mux: backend.EventMux(),
|
||||
chainDb: backend.ChainDb(),
|
||||
events: NewEventSystem(backend.EventMux(), backend, lightMode),
|
||||
mux: mux,
|
||||
chaindb: chaindb,
|
||||
events: NewEventSystem(mux, backend, lightMode),
|
||||
filters: make(map[rpc.ID]*filter),
|
||||
}
|
||||
|
||||
|
|
@ -326,7 +326,7 @@ func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([
|
|||
crit.ToBlock = big.NewInt(rpc.LatestBlockNumber.Int64())
|
||||
}
|
||||
|
||||
filter := New(api.backend, api.useMipMap)
|
||||
filter := New(api.backend, api.chaindb, api.useMipMap)
|
||||
filter.SetBeginBlock(crit.FromBlock.Int64())
|
||||
filter.SetEndBlock(crit.ToBlock.Int64())
|
||||
filter.SetAddresses(crit.Addresses)
|
||||
|
|
@ -366,7 +366,7 @@ func (api *PublicFilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]Log
|
|||
return []Log{}, nil
|
||||
}
|
||||
|
||||
filter := New(api.backend, api.useMipMap)
|
||||
filter := New(api.backend, api.chaindb, api.useMipMap)
|
||||
filter.SetBeginBlock(f.crit.FromBlock.Int64())
|
||||
filter.SetEndBlock(f.crit.ToBlock.Int64())
|
||||
filter.SetAddresses(f.crit.Addresses)
|
||||
|
|
|
|||
|
|
@ -18,22 +18,20 @@ package filters
|
|||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type Backend interface {
|
||||
ChainDb() ethdb.Database
|
||||
EventMux() *event.TypeMux
|
||||
HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error)
|
||||
GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
|
||||
HeaderByHash(context.Context, common.Hash) (*types.Header, error)
|
||||
HeaderByNumber(context.Context, *big.Int) (*types.Header, error)
|
||||
BlockReceipts(ctx context.Context, blockhash common.Hash, blocknum uint64) ([]*types.Receipt, error)
|
||||
}
|
||||
|
||||
// Filter can be used to retrieve and filter logs
|
||||
|
|
@ -51,11 +49,11 @@ type Filter struct {
|
|||
|
||||
// New creates a new filter which uses a bloom filter on blocks to figure out whether
|
||||
// a particular block is interesting or not.
|
||||
func New(backend Backend, useMipMap bool) *Filter {
|
||||
func New(backend Backend, chaindb ethdb.Database, useMipMap bool) *Filter {
|
||||
return &Filter{
|
||||
backend: backend,
|
||||
useMipMap: useMipMap,
|
||||
db: backend.ChainDb(),
|
||||
db: chaindb,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -84,7 +82,7 @@ func (f *Filter) SetTopics(topics [][]common.Hash) {
|
|||
|
||||
// Run filters logs with the current parameters set
|
||||
func (f *Filter) Find(ctx context.Context) ([]Log, error) {
|
||||
head, _ := f.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber)
|
||||
head, _ := f.backend.HeaderByNumber(ctx, nil)
|
||||
if head == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
|
@ -141,7 +139,7 @@ func (f *Filter) mipFind(start, end uint64, depth int) (logs []Log) {
|
|||
|
||||
func (f *Filter) getLogs(ctx context.Context, start, end uint64) (logs []Log, err error) {
|
||||
for i := start; i <= end; i++ {
|
||||
header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(i))
|
||||
header, err := f.backend.HeaderByNumber(ctx, new(big.Int).SetUint64(i))
|
||||
if header == nil || err != nil {
|
||||
return logs, err
|
||||
}
|
||||
|
|
@ -150,7 +148,7 @@ func (f *Filter) getLogs(ctx context.Context, start, end uint64) (logs []Log, er
|
|||
// current parameters
|
||||
if f.bloomFilter(header.Bloom) {
|
||||
// Get the logs of the block
|
||||
receipts, err := f.backend.GetReceipts(ctx, header.Hash())
|
||||
receipts, err := f.backend.BlockReceipts(ctx, header.Hash(), i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
|
@ -301,27 +303,44 @@ func (es *EventSystem) broadcast(filters filterIndex, ev *event.Event) {
|
|||
|
||||
func (es *EventSystem) lightFilterNewHead(newHeader *types.Header, callBack func(*types.Header, bool)) {
|
||||
oldh := es.lastHead
|
||||
es.lastHead = newHeader
|
||||
if oldh == nil {
|
||||
return
|
||||
}
|
||||
newh := newHeader
|
||||
ctx, _ := context.WithTimeout(context.Background(), time.Second*5)
|
||||
|
||||
// find common ancestor, create list of rolled back and new block hashes
|
||||
var oldHeaders, newHeaders []*types.Header
|
||||
var (
|
||||
oldHeaders, newHeaders []*types.Header
|
||||
newh = newHeader
|
||||
err error
|
||||
)
|
||||
for oldh.Hash() != newh.Hash() {
|
||||
if oldh.Number.Uint64() >= newh.Number.Uint64() {
|
||||
oldHeaders = append(oldHeaders, oldh)
|
||||
oldh = core.GetHeader(es.backend.ChainDb(), oldh.ParentHash, oldh.Number.Uint64()-1)
|
||||
oldh, err = es.backend.HeaderByHash(ctx, oldh.ParentHash)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if oldh.Number.Uint64() < newh.Number.Uint64() {
|
||||
newHeaders = append(newHeaders, newh)
|
||||
newh = core.GetHeader(es.backend.ChainDb(), newh.ParentHash, newh.Number.Uint64()-1)
|
||||
newh, err = es.backend.HeaderByHash(ctx, newh.ParentHash)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if newh == nil {
|
||||
// happens when CHT syncing, nothing to do
|
||||
newh = oldh
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if glog.V(logger.Error) {
|
||||
glog.Errorf("aborted rollback, can't fetch header: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// roll back old blocks
|
||||
for _, h := range oldHeaders {
|
||||
callBack(h, true)
|
||||
|
|
@ -330,6 +349,7 @@ func (es *EventSystem) lightFilterNewHead(newHeader *types.Header, callBack func
|
|||
for i := len(newHeaders) - 1; i >= 0; i-- {
|
||||
callBack(newHeaders[i], false)
|
||||
}
|
||||
es.lastHead = newh
|
||||
}
|
||||
|
||||
// filter logs of a single header in light client mode
|
||||
|
|
@ -339,7 +359,7 @@ func (es *EventSystem) lightFilterLogs(header *types.Header, addresses []common.
|
|||
//fmt.Println("bloom match")
|
||||
// Get the logs of the block
|
||||
ctx, _ := context.WithTimeout(context.Background(), time.Second*5)
|
||||
receipts, err := es.backend.GetReceipts(ctx, header.Hash())
|
||||
receipts, err := es.backend.BlockReceipts(ctx, header.Hash(), header.Number.Uint64())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ var (
|
|||
mux = new(event.TypeMux)
|
||||
db, _ = ethdb.NewMemDatabase()
|
||||
backend = &testBackend{mux, db}
|
||||
api = NewPublicFilterAPI(backend, false)
|
||||
api = NewPublicFilterAPI(backend, mux, db, false)
|
||||
)
|
||||
|
||||
type testBackend struct {
|
||||
|
|
@ -45,30 +45,26 @@ type testBackend struct {
|
|||
db ethdb.Database
|
||||
}
|
||||
|
||||
func (b *testBackend) ChainDb() ethdb.Database {
|
||||
return b.db
|
||||
}
|
||||
|
||||
func (b *testBackend) EventMux() *event.TypeMux {
|
||||
return b.mux
|
||||
}
|
||||
|
||||
func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) {
|
||||
func (b *testBackend) HeaderByNumber(ctx context.Context, blockNum *big.Int) (*types.Header, error) {
|
||||
var hash common.Hash
|
||||
var num uint64
|
||||
if blockNr == rpc.LatestBlockNumber {
|
||||
if blockNum == nil {
|
||||
hash = core.GetHeadBlockHash(b.db)
|
||||
num = core.GetBlockNumber(b.db, hash)
|
||||
} else {
|
||||
num = uint64(blockNr)
|
||||
num = blockNum.Uint64()
|
||||
hash = core.GetCanonicalHash(b.db, num)
|
||||
}
|
||||
return core.GetHeader(b.db, hash, num), nil
|
||||
}
|
||||
|
||||
func (b *testBackend) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) {
|
||||
func (b *testBackend) HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error) {
|
||||
num := core.GetBlockNumber(b.db, blockHash)
|
||||
return core.GetBlockReceipts(b.db, blockHash, num), nil
|
||||
return core.GetHeader(b.db, blockHash, num), nil
|
||||
}
|
||||
|
||||
func (b *testBackend) BlockReceipts(ctx context.Context, blockHash common.Hash, blockNum uint64) ([]*types.Receipt, error) {
|
||||
return core.GetBlockReceipts(b.db, blockHash, blockNum), nil
|
||||
}
|
||||
|
||||
// TestBlockSubscription tests if a block subscription returns block hashes for posted chain events.
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ func BenchmarkMipmaps(b *testing.B) {
|
|||
}
|
||||
b.ResetTimer()
|
||||
|
||||
filter := New(backend, true)
|
||||
filter := New(backend, db, true)
|
||||
filter.SetAddresses([]common.Address{addr1, addr2, addr3, addr4})
|
||||
filter.SetBeginBlock(0)
|
||||
filter.SetEndBlock(-1)
|
||||
|
|
@ -205,7 +205,7 @@ func TestFilters(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
filter := New(backend, true)
|
||||
filter := New(backend, db, true)
|
||||
filter.SetAddresses([]common.Address{addr})
|
||||
filter.SetTopics([][]common.Hash{[]common.Hash{hash1, hash2, hash3, hash4}})
|
||||
filter.SetBeginBlock(0)
|
||||
|
|
@ -216,7 +216,7 @@ func TestFilters(t *testing.T) {
|
|||
t.Error("expected 4 log, got", len(logs))
|
||||
}
|
||||
|
||||
filter = New(backend, true)
|
||||
filter = New(backend, db, true)
|
||||
filter.SetAddresses([]common.Address{addr})
|
||||
filter.SetTopics([][]common.Hash{[]common.Hash{hash3}})
|
||||
filter.SetBeginBlock(900)
|
||||
|
|
@ -229,7 +229,7 @@ func TestFilters(t *testing.T) {
|
|||
t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0])
|
||||
}
|
||||
|
||||
filter = New(backend, true)
|
||||
filter = New(backend, db, true)
|
||||
filter.SetAddresses([]common.Address{addr})
|
||||
filter.SetTopics([][]common.Hash{[]common.Hash{hash3}})
|
||||
filter.SetBeginBlock(990)
|
||||
|
|
@ -242,7 +242,7 @@ func TestFilters(t *testing.T) {
|
|||
t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0])
|
||||
}
|
||||
|
||||
filter = New(backend, true)
|
||||
filter = New(backend, db, true)
|
||||
filter.SetTopics([][]common.Hash{[]common.Hash{hash1, hash2}})
|
||||
filter.SetBeginBlock(1)
|
||||
filter.SetEndBlock(10)
|
||||
|
|
@ -253,7 +253,7 @@ func TestFilters(t *testing.T) {
|
|||
}
|
||||
|
||||
failHash := common.BytesToHash([]byte("fail"))
|
||||
filter = New(backend, true)
|
||||
filter = New(backend, db, true)
|
||||
filter.SetTopics([][]common.Hash{[]common.Hash{failHash}})
|
||||
filter.SetBeginBlock(0)
|
||||
filter.SetEndBlock(-1)
|
||||
|
|
@ -264,7 +264,7 @@ func TestFilters(t *testing.T) {
|
|||
}
|
||||
|
||||
failAddr := common.BytesToAddress([]byte("failmenow"))
|
||||
filter = New(backend, true)
|
||||
filter = New(backend, db, true)
|
||||
filter.SetAddresses([]common.Address{failAddr})
|
||||
filter.SetBeginBlock(0)
|
||||
filter.SetEndBlock(-1)
|
||||
|
|
@ -274,7 +274,7 @@ func TestFilters(t *testing.T) {
|
|||
t.Error("expected 0 log, got", len(logs))
|
||||
}
|
||||
|
||||
filter = New(backend, true)
|
||||
filter = New(backend, db, true)
|
||||
filter.SetTopics([][]common.Hash{[]common.Hash{failHash}, []common.Hash{hash1}})
|
||||
filter.SetBeginBlock(0)
|
||||
filter.SetEndBlock(-1)
|
||||
|
|
|
|||
|
|
@ -21,9 +21,8 @@ import (
|
|||
"sort"
|
||||
"sync"
|
||||
|
||||
ethereum "github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
|
@ -38,7 +37,7 @@ const (
|
|||
// LightPriceOracle recommends gas prices based on the content of recent
|
||||
// blocks. Suitable for both light and full clients.
|
||||
type LightPriceOracle struct {
|
||||
backend ethapi.Backend
|
||||
backend ethereum.ChainReader
|
||||
lastHead common.Hash
|
||||
lastPrice *big.Int
|
||||
cacheLock sync.RWMutex
|
||||
|
|
@ -46,7 +45,7 @@ type LightPriceOracle struct {
|
|||
}
|
||||
|
||||
// NewLightPriceOracle returns a new oracle.
|
||||
func NewLightPriceOracle(backend ethapi.Backend) *LightPriceOracle {
|
||||
func NewLightPriceOracle(backend ethereum.ChainReader) *LightPriceOracle {
|
||||
return &LightPriceOracle{
|
||||
backend: backend,
|
||||
lastPrice: big.NewInt(LpoDefaultPrice),
|
||||
|
|
@ -60,7 +59,7 @@ func (self *LightPriceOracle) SuggestPrice(ctx context.Context) (*big.Int, error
|
|||
lastPrice := self.lastPrice
|
||||
self.cacheLock.RUnlock()
|
||||
|
||||
head, _ := self.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber)
|
||||
head, _ := self.backend.HeaderByNumber(ctx, nil)
|
||||
headHash := head.Hash()
|
||||
if headHash == lastHead {
|
||||
return lastPrice, nil
|
||||
|
|
@ -132,7 +131,7 @@ type lpResult struct {
|
|||
// getLowestPrice calculates the lowest transaction gas price in a given block
|
||||
// and sends it to the result channel. If the block is empty, price is nil.
|
||||
func (self *LightPriceOracle) getLowestPrice(ctx context.Context, blockNum uint64, chn chan lpResult) {
|
||||
block, err := self.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNum))
|
||||
block, err := self.backend.BlockByNumber(ctx, new(big.Int).SetUint64(blockNum))
|
||||
if block == nil {
|
||||
chn <- lpResult{nil, err}
|
||||
return
|
||||
|
|
|
|||
|
|
@ -143,15 +143,18 @@ func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.H
|
|||
}
|
||||
|
||||
// TransactionByHash returns the transaction with the given hash.
|
||||
func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (*types.Transaction, error) {
|
||||
var tx *types.Transaction
|
||||
err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByHash", hash)
|
||||
func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) {
|
||||
var rtx struct {
|
||||
*types.Transaction
|
||||
BlockHash *common.Hash
|
||||
}
|
||||
err = ec.c.CallContext(ctx, &rtx, "eth_getTransactionByHash", hash)
|
||||
if err == nil {
|
||||
if _, r, _ := tx.SignatureValues(); r == nil {
|
||||
return nil, fmt.Errorf("server returned transaction without signature")
|
||||
if _, r, _ := rtx.SignatureValues(); r == nil {
|
||||
return nil, false, fmt.Errorf("server returned transaction without signature")
|
||||
}
|
||||
}
|
||||
return tx, err
|
||||
return rtx.Transaction, rtx.BlockHash == nil, err
|
||||
}
|
||||
|
||||
// TransactionCount returns the total number of transactions in the given block.
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ type ChainReader interface {
|
|||
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
|
||||
TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error)
|
||||
TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error)
|
||||
TransactionByHash(ctx context.Context, txHash common.Hash) (*types.Transaction, error)
|
||||
TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
|
||||
TransactionByHash(ctx context.Context, txHash common.Hash) (tx *types.Transaction, isPending bool, err error)
|
||||
}
|
||||
|
||||
// ChainStateReader wraps access to the state trie of the canonical blockchain. Note that
|
||||
|
|
@ -164,6 +164,9 @@ type PendingStateReader interface {
|
|||
PendingTransactionCount(ctx context.Context) (uint, error)
|
||||
}
|
||||
|
||||
// TODO(fjl): PendingNonceAt should have its own interface because it is provided by the tx pool
|
||||
// and more widely available than the others. We could also make it part of TransactionSender.
|
||||
|
||||
// PendingContractCaller can be used to perform calls against the pending state.
|
||||
type PendingContractCaller interface {
|
||||
PendingCallContract(ctx context.Context, call CallMsg) ([]byte, error)
|
||||
|
|
|
|||
|
|
@ -20,15 +20,16 @@ import (
|
|||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/ethash"
|
||||
ethereum "github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"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/crypto"
|
||||
|
|
@ -45,6 +46,8 @@ import (
|
|||
|
||||
const defaultGas = uint64(90000)
|
||||
|
||||
var ErrNoPendingState = errors.New("API backend does not provide access to pending state")
|
||||
|
||||
// PublicEthereumAPI provides an API to access Ethereum related information.
|
||||
// It offers only methods that operate on public data that is freely available to anyone.
|
||||
type PublicEthereumAPI struct {
|
||||
|
|
@ -58,7 +61,7 @@ func NewPublicEthereumAPI(b Backend) *PublicEthereumAPI {
|
|||
|
||||
// GasPrice returns a suggestion for a gas price.
|
||||
func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*big.Int, error) {
|
||||
return s.b.SuggestPrice(ctx)
|
||||
return s.b.SuggestGasPrice(ctx)
|
||||
}
|
||||
|
||||
// ProtocolVersion returns the current Ethereum protocol version this node supports
|
||||
|
|
@ -73,8 +76,11 @@ func (s *PublicEthereumAPI) ProtocolVersion() *rpc.HexNumber {
|
|||
// - highestBlock: block number of the highest block header this node has received from peers
|
||||
// - pulledStates: number of state entries processed until now
|
||||
// - knownStates: number of known state entries that still need to be pulled
|
||||
func (s *PublicEthereumAPI) Syncing() (interface{}, error) {
|
||||
progress := s.b.Downloader().Progress()
|
||||
func (s *PublicEthereumAPI) Syncing(ctx context.Context) (interface{}, error) {
|
||||
progress, err := s.b.SyncProgress(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return not syncing if the synchronisation already completed
|
||||
if progress.CurrentBlock >= progress.HighestBlock {
|
||||
|
|
@ -90,87 +96,6 @@ func (s *PublicEthereumAPI) Syncing() (interface{}, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// PublicTxPoolAPI offers and API for the transaction pool. It only operates on data that is non confidential.
|
||||
type PublicTxPoolAPI struct {
|
||||
b Backend
|
||||
}
|
||||
|
||||
// NewPublicTxPoolAPI creates a new tx pool service that gives information about the transaction pool.
|
||||
func NewPublicTxPoolAPI(b Backend) *PublicTxPoolAPI {
|
||||
return &PublicTxPoolAPI{b}
|
||||
}
|
||||
|
||||
// Content returns the transactions contained within the transaction pool.
|
||||
func (s *PublicTxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction {
|
||||
content := map[string]map[string]map[string]*RPCTransaction{
|
||||
"pending": make(map[string]map[string]*RPCTransaction),
|
||||
"queued": make(map[string]map[string]*RPCTransaction),
|
||||
}
|
||||
pending, queue := s.b.TxPoolContent()
|
||||
|
||||
// Flatten the pending transactions
|
||||
for account, txs := range pending {
|
||||
dump := make(map[string]*RPCTransaction)
|
||||
for nonce, tx := range txs {
|
||||
dump[fmt.Sprintf("%d", nonce)] = newRPCPendingTransaction(tx)
|
||||
}
|
||||
content["pending"][account.Hex()] = dump
|
||||
}
|
||||
// Flatten the queued transactions
|
||||
for account, txs := range queue {
|
||||
dump := make(map[string]*RPCTransaction)
|
||||
for nonce, tx := range txs {
|
||||
dump[fmt.Sprintf("%d", nonce)] = newRPCPendingTransaction(tx)
|
||||
}
|
||||
content["queued"][account.Hex()] = dump
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
// Status returns the number of pending and queued transaction in the pool.
|
||||
func (s *PublicTxPoolAPI) Status() map[string]*rpc.HexNumber {
|
||||
pending, queue := s.b.Stats()
|
||||
return map[string]*rpc.HexNumber{
|
||||
"pending": rpc.NewHexNumber(pending),
|
||||
"queued": rpc.NewHexNumber(queue),
|
||||
}
|
||||
}
|
||||
|
||||
// Inspect retrieves the content of the transaction pool and flattens it into an
|
||||
// easily inspectable list.
|
||||
func (s *PublicTxPoolAPI) Inspect() map[string]map[string]map[string]string {
|
||||
content := map[string]map[string]map[string]string{
|
||||
"pending": make(map[string]map[string]string),
|
||||
"queued": make(map[string]map[string]string),
|
||||
}
|
||||
pending, queue := s.b.TxPoolContent()
|
||||
|
||||
// Define a formatter to flatten a transaction into a string
|
||||
var format = func(tx *types.Transaction) string {
|
||||
if to := tx.To(); to != nil {
|
||||
return fmt.Sprintf("%s: %v wei + %v × %v gas", tx.To().Hex(), tx.Value(), tx.Gas(), tx.GasPrice())
|
||||
}
|
||||
return fmt.Sprintf("contract creation: %v wei + %v × %v gas", tx.Value(), tx.Gas(), tx.GasPrice())
|
||||
}
|
||||
// Flatten the pending transactions
|
||||
for account, txs := range pending {
|
||||
dump := make(map[string]string)
|
||||
for nonce, tx := range txs {
|
||||
dump[fmt.Sprintf("%d", nonce)] = format(tx)
|
||||
}
|
||||
content["pending"][account.Hex()] = dump
|
||||
}
|
||||
// Flatten the queued transactions
|
||||
for account, txs := range queue {
|
||||
dump := make(map[string]string)
|
||||
for nonce, tx := range txs {
|
||||
dump[fmt.Sprintf("%d", nonce)] = format(tx)
|
||||
}
|
||||
content["queued"][account.Hex()] = dump
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
// PublicAccountAPI provides an API to access accounts managed by this node.
|
||||
// It offers only methods that can retrieve accounts.
|
||||
type PublicAccountAPI struct {
|
||||
|
|
@ -265,7 +190,7 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs
|
|||
}
|
||||
|
||||
if args.Nonce == nil {
|
||||
nonce, err := s.b.GetPoolNonce(ctx, args.From)
|
||||
nonce, err := s.b.PendingNonceAt(ctx, args.From)
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
|
|
@ -366,28 +291,16 @@ func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI {
|
|||
|
||||
// BlockNumber returns the block number of the chain head.
|
||||
func (s *PublicBlockChainAPI) BlockNumber() *big.Int {
|
||||
header, _ := s.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available
|
||||
header, _ := s.b.HeaderByNumber(context.Background(), nil) // latest header should always be available
|
||||
return header.Number
|
||||
}
|
||||
|
||||
// GetBalance returns the amount of wei for the given address in the state of the
|
||||
// given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
|
||||
// block numbers are also allowed.
|
||||
func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*big.Int, error) {
|
||||
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
|
||||
if state == nil || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return state.GetBalance(ctx, address)
|
||||
}
|
||||
|
||||
// GetBlockByNumber returns the requested block. When blockNr is -1 the chain head is returned. When fullTx is true all
|
||||
// transactions in the block are returned in full detail, otherwise only the transaction hash is returned.
|
||||
func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
|
||||
block, err := s.b.BlockByNumber(ctx, blockNr)
|
||||
block, err := blockByNumber(ctx, s.b, blockNr)
|
||||
if block != nil {
|
||||
response, err := s.rpcOutputBlock(block, true, fullTx)
|
||||
response, err := s.rpcOutputBlock(ctx, block, true, fullTx)
|
||||
if err == nil && blockNr == rpc.PendingBlockNumber {
|
||||
// Pending blocks need to nil out a few fields
|
||||
for _, field := range []string{"hash", "nonce", "logsBloom", "miner"} {
|
||||
|
|
@ -399,12 +312,27 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.
|
|||
return nil, err
|
||||
}
|
||||
|
||||
func blockByNumber(ctx context.Context, b Backend, blockNr rpc.BlockNumber) (*types.Block, error) {
|
||||
switch blockNr {
|
||||
case rpc.PendingBlockNumber:
|
||||
ps, ok := b.(PendingState)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("can't access the pending block with the current backend")
|
||||
}
|
||||
return ps.PendingBlock()
|
||||
case rpc.LatestBlockNumber:
|
||||
return b.BlockByNumber(ctx, nil)
|
||||
default:
|
||||
return b.BlockByNumber(ctx, big.NewInt(int64(blockNr)))
|
||||
}
|
||||
}
|
||||
|
||||
// GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full
|
||||
// detail, otherwise only the transaction hash is returned.
|
||||
func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (map[string]interface{}, error) {
|
||||
block, err := s.b.GetBlock(ctx, blockHash)
|
||||
block, err := s.b.BlockByHash(ctx, blockHash)
|
||||
if block != nil {
|
||||
return s.rpcOutputBlock(block, true, fullTx)
|
||||
return s.rpcOutputBlock(ctx, block, true, fullTx)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -412,7 +340,7 @@ func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, blockHash comm
|
|||
// GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. When fullTx is true
|
||||
// all transactions in the block are returned in full detail, otherwise only the transaction hash is returned.
|
||||
func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index rpc.HexNumber) (map[string]interface{}, error) {
|
||||
block, err := s.b.BlockByNumber(ctx, blockNr)
|
||||
block, err := blockByNumber(ctx, s.b, blockNr)
|
||||
if block != nil {
|
||||
uncles := block.Uncles()
|
||||
if index.Int() < 0 || index.Int() >= len(uncles) {
|
||||
|
|
@ -420,7 +348,7 @@ func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context,
|
|||
return nil, nil
|
||||
}
|
||||
block = types.NewBlockWithHeader(uncles[index.Int()])
|
||||
return s.rpcOutputBlock(block, false, false)
|
||||
return s.rpcOutputBlock(ctx, block, false, false)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -428,7 +356,7 @@ func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context,
|
|||
// GetUncleByBlockHashAndIndex returns the uncle block for the given block hash and index. When fullTx is true
|
||||
// all transactions in the block are returned in full detail, otherwise only the transaction hash is returned.
|
||||
func (s *PublicBlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index rpc.HexNumber) (map[string]interface{}, error) {
|
||||
block, err := s.b.GetBlock(ctx, blockHash)
|
||||
block, err := s.b.BlockByHash(ctx, blockHash)
|
||||
if block != nil {
|
||||
uncles := block.Uncles()
|
||||
if index.Int() < 0 || index.Int() >= len(uncles) {
|
||||
|
|
@ -436,14 +364,14 @@ func (s *PublicBlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, b
|
|||
return nil, nil
|
||||
}
|
||||
block = types.NewBlockWithHeader(uncles[index.Int()])
|
||||
return s.rpcOutputBlock(block, false, false)
|
||||
return s.rpcOutputBlock(ctx, block, false, false)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// GetUncleCountByBlockNumber returns number of uncles in the block for the given block number
|
||||
func (s *PublicBlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *rpc.HexNumber {
|
||||
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
|
||||
if block, _ := blockByNumber(ctx, s.b, blockNr); block != nil {
|
||||
return rpc.NewHexNumber(len(block.Uncles()))
|
||||
}
|
||||
return nil
|
||||
|
|
@ -451,60 +379,78 @@ func (s *PublicBlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, bl
|
|||
|
||||
// GetUncleCountByBlockHash returns number of uncles in the block for the given block hash
|
||||
func (s *PublicBlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *rpc.HexNumber {
|
||||
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil {
|
||||
if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil {
|
||||
return rpc.NewHexNumber(len(block.Uncles()))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetBalance returns the amount of wei for the given address in the state of the
|
||||
// given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
|
||||
// block numbers are also allowed.
|
||||
func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*big.Int, error) {
|
||||
switch blockNr {
|
||||
case rpc.PendingBlockNumber:
|
||||
ps, ok := s.b.(PendingState)
|
||||
if !ok {
|
||||
return nil, ErrNoPendingState
|
||||
}
|
||||
return ps.PendingBalanceAt(ctx, address)
|
||||
case rpc.LatestBlockNumber:
|
||||
return s.b.BalanceAt(ctx, address, nil)
|
||||
default:
|
||||
return s.b.BalanceAt(ctx, address, big.NewInt(int64(blockNr)))
|
||||
}
|
||||
}
|
||||
|
||||
// GetCode returns the code stored at the given address in the state for the given block number.
|
||||
func (s *PublicBlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (string, error) {
|
||||
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
|
||||
if state == nil || err != nil {
|
||||
return "", err
|
||||
var code []byte
|
||||
var err error
|
||||
switch blockNr {
|
||||
case rpc.PendingBlockNumber:
|
||||
ps, ok := s.b.(PendingState)
|
||||
if !ok {
|
||||
return "", ErrNoPendingState
|
||||
}
|
||||
code, err = ps.PendingCodeAt(ctx, address)
|
||||
case rpc.LatestBlockNumber:
|
||||
code, err = s.b.CodeAt(ctx, address, nil)
|
||||
default:
|
||||
code, err = s.b.CodeAt(ctx, address, big.NewInt(int64(blockNr)))
|
||||
}
|
||||
res, err := state.GetCode(ctx, address)
|
||||
if len(res) == 0 || err != nil { // backwards compatibility
|
||||
|
||||
if len(code) == 0 || err != nil { // backwards compatibility
|
||||
return "0x", err
|
||||
}
|
||||
return common.ToHex(res), nil
|
||||
return common.ToHex(code), nil
|
||||
}
|
||||
|
||||
// GetStorageAt returns the storage from the state at the given address, key and
|
||||
// block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block
|
||||
// numbers are also allowed.
|
||||
func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNr rpc.BlockNumber) (string, error) {
|
||||
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
|
||||
if state == nil || err != nil {
|
||||
func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, key common.Hash, blockNr rpc.BlockNumber) (string, error) {
|
||||
var val []byte
|
||||
var err error
|
||||
switch blockNr {
|
||||
case rpc.PendingBlockNumber:
|
||||
ps, ok := s.b.(PendingState)
|
||||
if !ok {
|
||||
return "", ErrNoPendingState
|
||||
}
|
||||
val, err = ps.PendingStorageAt(ctx, address, key)
|
||||
case rpc.LatestBlockNumber:
|
||||
val, err = s.b.StorageAt(ctx, address, key, nil)
|
||||
default:
|
||||
val, err = s.b.StorageAt(ctx, address, key, big.NewInt(int64(blockNr)))
|
||||
}
|
||||
|
||||
if len(val) == 0 || err != nil { // backwards compatibility
|
||||
return "0x", err
|
||||
}
|
||||
res, err := state.GetState(ctx, address, common.HexToHash(key))
|
||||
if err != nil {
|
||||
return "0x", err
|
||||
}
|
||||
return res.Hex(), nil
|
||||
return common.ToHex(val), nil
|
||||
}
|
||||
|
||||
// callmsg is the message type used for call transations.
|
||||
type callmsg struct {
|
||||
addr common.Address
|
||||
to *common.Address
|
||||
gas, gasPrice *big.Int
|
||||
value *big.Int
|
||||
data []byte
|
||||
}
|
||||
|
||||
// accessor boilerplate to implement core.Message
|
||||
func (m callmsg) From() (common.Address, error) { return m.addr, nil }
|
||||
func (m callmsg) FromFrontier() (common.Address, error) { return m.addr, nil }
|
||||
func (m callmsg) Nonce() uint64 { return 0 }
|
||||
func (m callmsg) CheckNonce() bool { return false }
|
||||
func (m callmsg) To() *common.Address { return m.to }
|
||||
func (m callmsg) GasPrice() *big.Int { return m.gasPrice }
|
||||
func (m callmsg) Gas() *big.Int { return m.gas }
|
||||
func (m callmsg) Value() *big.Int { return m.value }
|
||||
func (m callmsg) Data() []byte { return m.data }
|
||||
|
||||
// CallArgs represents the arguments for a call.
|
||||
type CallArgs struct {
|
||||
From common.Address `json:"from"`
|
||||
|
|
@ -512,74 +458,43 @@ type CallArgs struct {
|
|||
Gas rpc.HexNumber `json:"gas"`
|
||||
GasPrice rpc.HexNumber `json:"gasPrice"`
|
||||
Value rpc.HexNumber `json:"value"`
|
||||
Data string `json:"data"`
|
||||
Data rpc.HexBytes `json:"data"`
|
||||
}
|
||||
|
||||
func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (string, *big.Int, error) {
|
||||
defer func(start time.Time) { glog.V(logger.Debug).Infof("call took %v", time.Since(start)) }(time.Now())
|
||||
|
||||
state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
|
||||
if state == nil || err != nil {
|
||||
return "0x", common.Big0, err
|
||||
func (args CallArgs) Msg() ethereum.CallMsg {
|
||||
return ethereum.CallMsg{
|
||||
From: args.From,
|
||||
To: args.To,
|
||||
Gas: args.Gas.BigInt(),
|
||||
GasPrice: args.GasPrice.BigInt(),
|
||||
Value: args.Value.BigInt(),
|
||||
Data: args.Data,
|
||||
}
|
||||
|
||||
// Set the account address to interact with
|
||||
var addr common.Address
|
||||
if args.From == (common.Address{}) {
|
||||
accounts := s.b.AccountManager().Accounts()
|
||||
if len(accounts) == 0 {
|
||||
addr = common.Address{}
|
||||
} else {
|
||||
addr = accounts[0].Address
|
||||
}
|
||||
} else {
|
||||
addr = args.From
|
||||
}
|
||||
|
||||
// Assemble the CALL invocation
|
||||
msg := callmsg{
|
||||
addr: addr,
|
||||
to: args.To,
|
||||
gas: args.Gas.BigInt(),
|
||||
gasPrice: args.GasPrice.BigInt(),
|
||||
value: args.Value.BigInt(),
|
||||
data: common.FromHex(args.Data),
|
||||
}
|
||||
|
||||
if msg.gas.Cmp(common.Big0) == 0 {
|
||||
msg.gas = big.NewInt(50000000)
|
||||
}
|
||||
|
||||
if msg.gasPrice.Cmp(common.Big0) == 0 {
|
||||
msg.gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
|
||||
}
|
||||
|
||||
// Execute the call and return
|
||||
vmenv, vmError, err := s.b.GetVMEnv(ctx, msg, state, header)
|
||||
if err != nil {
|
||||
return "0x", common.Big0, err
|
||||
}
|
||||
gp := new(core.GasPool).AddGas(common.MaxBig)
|
||||
res, gas, err := core.ApplyMessage(vmenv, msg, gp)
|
||||
if err := vmError(); err != nil {
|
||||
return "0x", common.Big0, err
|
||||
}
|
||||
if len(res) == 0 { // backwards compatability
|
||||
return "0x", gas, err
|
||||
}
|
||||
return common.ToHex(res), gas, err
|
||||
}
|
||||
|
||||
// Call executes the given transaction on the state for the given block number.
|
||||
// It doesn't make and changes in the state/blockchain and is usefull to execute and retrieve values.
|
||||
func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (string, error) {
|
||||
result, _, err := s.doCall(ctx, args, blockNr)
|
||||
return result, err
|
||||
var result []byte
|
||||
var err error
|
||||
switch blockNr {
|
||||
case rpc.PendingBlockNumber:
|
||||
ps, ok := s.b.(PendingState)
|
||||
if !ok {
|
||||
return "", ErrNoPendingState
|
||||
}
|
||||
result, err = ps.PendingCallContract(ctx, args.Msg())
|
||||
case rpc.LatestBlockNumber:
|
||||
result, err = s.b.CallContract(ctx, args.Msg(), nil)
|
||||
default:
|
||||
result, err = s.b.CallContract(ctx, args.Msg(), big.NewInt(int64(blockNr)))
|
||||
}
|
||||
return common.ToHex(result), err
|
||||
}
|
||||
|
||||
// EstimateGas returns an estimate of the amount of gas needed to execute the given transaction.
|
||||
func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*rpc.HexNumber, error) {
|
||||
_, gas, err := s.doCall(ctx, args, rpc.PendingBlockNumber)
|
||||
gas, err := s.b.EstimateGas(ctx, args.Msg())
|
||||
return rpc.NewHexNumber(gas), err
|
||||
}
|
||||
|
||||
|
|
@ -639,7 +554,7 @@ func FormatLogs(structLogs []vm.StructLog) []StructLogRes {
|
|||
// rpcOutputBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are
|
||||
// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain
|
||||
// transaction hashes.
|
||||
func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
|
||||
func (s *PublicBlockChainAPI) rpcOutputBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
|
||||
head := b.Header() // copies the header once
|
||||
fields := map[string]interface{}{
|
||||
"number": rpc.NewHexNumber(head.Number),
|
||||
|
|
@ -652,7 +567,7 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx
|
|||
"stateRoot": head.Root,
|
||||
"miner": head.Coinbase,
|
||||
"difficulty": rpc.NewHexNumber(head.Difficulty),
|
||||
"totalDifficulty": rpc.NewHexNumber(s.b.GetTd(b.Hash())),
|
||||
"totalDifficulty": rpc.NewHexNumber(s.b.BlockTD(b.Hash())),
|
||||
"extraData": rpc.HexBytes(head.Extra),
|
||||
"size": rpc.NewHexNumber(b.Size().Int64()),
|
||||
"gasLimit": rpc.NewHexNumber(head.GasLimit),
|
||||
|
|
@ -663,22 +578,15 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx
|
|||
}
|
||||
|
||||
if inclTx {
|
||||
formatTx := func(tx *types.Transaction) (interface{}, error) {
|
||||
return tx.Hash(), nil
|
||||
}
|
||||
|
||||
if fullTx {
|
||||
formatTx = func(tx *types.Transaction) (interface{}, error) {
|
||||
return newRPCTransaction(b, tx.Hash())
|
||||
}
|
||||
}
|
||||
|
||||
txs := b.Transactions()
|
||||
transactions := make([]interface{}, len(txs))
|
||||
var err error
|
||||
for i, tx := range b.Transactions() {
|
||||
if transactions[i], err = formatTx(tx); err != nil {
|
||||
return nil, err
|
||||
if fullTx {
|
||||
rtx := newRPCTransaction(tx)
|
||||
rtx.setInclusionBlock(b.Hash(), b.NumberU64(), i)
|
||||
transactions = append(transactions, rtx)
|
||||
} else {
|
||||
transactions = append(transactions, tx.Hash())
|
||||
}
|
||||
}
|
||||
fields["transactions"] = transactions
|
||||
|
|
@ -712,8 +620,14 @@ type RPCTransaction struct {
|
|||
S *rpc.HexNumber `json:"s"`
|
||||
}
|
||||
|
||||
// newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation
|
||||
func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction {
|
||||
func (tx *RPCTransaction) setInclusionBlock(blockhash common.Hash, blocknum uint64, index int) {
|
||||
tx.BlockHash = blockhash
|
||||
tx.BlockNumber = rpc.NewHexNumber(blocknum)
|
||||
tx.TransactionIndex = rpc.NewHexNumber(index)
|
||||
}
|
||||
|
||||
// newRPCTransaction returns a pending transaction that will serialize to the RPC representation
|
||||
func newRPCTransaction(tx *types.Transaction) *RPCTransaction {
|
||||
from, _ := tx.FromFrontier()
|
||||
v, r, s := tx.SignatureValues()
|
||||
return &RPCTransaction{
|
||||
|
|
@ -732,33 +646,13 @@ func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction {
|
|||
}
|
||||
|
||||
// newRPCTransaction returns a transaction that will serialize to the RPC representation.
|
||||
func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) (*RPCTransaction, error) {
|
||||
func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) *RPCTransaction {
|
||||
if txIndex >= 0 && txIndex < len(b.Transactions()) {
|
||||
tx := b.Transactions()[txIndex]
|
||||
from, err := tx.FromFrontier()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v, r, s := tx.SignatureValues()
|
||||
return &RPCTransaction{
|
||||
BlockHash: b.Hash(),
|
||||
BlockNumber: rpc.NewHexNumber(b.Number()),
|
||||
From: from,
|
||||
Gas: rpc.NewHexNumber(tx.Gas()),
|
||||
GasPrice: rpc.NewHexNumber(tx.GasPrice()),
|
||||
Hash: tx.Hash(),
|
||||
Input: rpc.HexBytes(tx.Data()),
|
||||
Nonce: rpc.NewHexNumber(tx.Nonce()),
|
||||
To: tx.To(),
|
||||
TransactionIndex: rpc.NewHexNumber(txIndex),
|
||||
Value: rpc.NewHexNumber(tx.Value()),
|
||||
V: rpc.NewHexNumber(v),
|
||||
R: rpc.NewHexNumber(r),
|
||||
S: rpc.NewHexNumber(s),
|
||||
}, nil
|
||||
tx := newRPCTransaction(b.Transactions()[txIndex])
|
||||
tx.setInclusionBlock(b.Hash(), b.NumberU64(), txIndex)
|
||||
return tx
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index.
|
||||
|
|
@ -767,18 +661,6 @@ func newRPCRawTransactionFromBlockIndex(b *types.Block, txIndex int) (rpc.HexByt
|
|||
tx := b.Transactions()[txIndex]
|
||||
return rlp.EncodeToBytes(tx)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// newRPCTransaction returns a transaction that will serialize to the RPC representation.
|
||||
func newRPCTransaction(b *types.Block, txHash common.Hash) (*RPCTransaction, error) {
|
||||
for idx, tx := range b.Transactions() {
|
||||
if tx.Hash() == txHash {
|
||||
return newRPCTransactionFromBlockIndex(b, idx)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
|
@ -792,27 +674,9 @@ func NewPublicTransactionPoolAPI(b Backend) *PublicTransactionPoolAPI {
|
|||
return &PublicTransactionPoolAPI{b}
|
||||
}
|
||||
|
||||
func getTransaction(chainDb ethdb.Database, b Backend, txHash common.Hash) (*types.Transaction, bool, error) {
|
||||
txData, err := chainDb.Get(txHash.Bytes())
|
||||
isPending := false
|
||||
tx := new(types.Transaction)
|
||||
|
||||
if err == nil && len(txData) > 0 {
|
||||
if err := rlp.DecodeBytes(txData, tx); err != nil {
|
||||
return nil, isPending, err
|
||||
}
|
||||
} else {
|
||||
// pending transaction?
|
||||
tx = b.GetPoolTransaction(txHash)
|
||||
isPending = true
|
||||
}
|
||||
|
||||
return tx, isPending, nil
|
||||
}
|
||||
|
||||
// GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number.
|
||||
func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *rpc.HexNumber {
|
||||
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
|
||||
if block, _ := blockByNumber(ctx, s.b, blockNr); block != nil {
|
||||
return rpc.NewHexNumber(len(block.Transactions()))
|
||||
}
|
||||
return nil
|
||||
|
|
@ -820,31 +684,32 @@ func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.
|
|||
|
||||
// GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash.
|
||||
func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *rpc.HexNumber {
|
||||
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil {
|
||||
return rpc.NewHexNumber(len(block.Transactions()))
|
||||
count, err := s.b.TransactionCount(ctx, blockHash)
|
||||
if err == nil {
|
||||
return rpc.NewHexNumber(count)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index.
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index rpc.HexNumber) (*RPCTransaction, error) {
|
||||
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index rpc.HexNumber) *RPCTransaction {
|
||||
if block, _ := blockByNumber(ctx, s.b, blockNr); block != nil {
|
||||
return newRPCTransactionFromBlockIndex(block, index.Int())
|
||||
}
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index.
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index rpc.HexNumber) (*RPCTransaction, error) {
|
||||
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil {
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index rpc.HexNumber) *RPCTransaction {
|
||||
if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil {
|
||||
return newRPCTransactionFromBlockIndex(block, index.Int())
|
||||
}
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index.
|
||||
func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index rpc.HexNumber) (rpc.HexBytes, error) {
|
||||
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
|
||||
if block, _ := blockByNumber(ctx, s.b, blockNr); block != nil {
|
||||
return newRPCRawTransactionFromBlockIndex(block, index.Int())
|
||||
}
|
||||
return nil, nil
|
||||
|
|
@ -852,7 +717,7 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockNumberAndIndex(ctx co
|
|||
|
||||
// GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index.
|
||||
func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index rpc.HexNumber) (rpc.HexBytes, error) {
|
||||
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil {
|
||||
if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil {
|
||||
return newRPCRawTransactionFromBlockIndex(block, index.Int())
|
||||
}
|
||||
return nil, nil
|
||||
|
|
@ -860,11 +725,16 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx cont
|
|||
|
||||
// GetTransactionCount returns the number of transactions the given address has sent for the given block number
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*rpc.HexNumber, error) {
|
||||
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
|
||||
if state == nil || err != nil {
|
||||
return nil, err
|
||||
var nonce uint64
|
||||
var err error
|
||||
switch blockNr {
|
||||
case rpc.PendingBlockNumber:
|
||||
nonce, err = s.b.PendingNonceAt(ctx, address)
|
||||
case rpc.LatestBlockNumber:
|
||||
nonce, err = s.b.NonceAt(ctx, address, nil)
|
||||
default:
|
||||
nonce, err = s.b.NonceAt(ctx, address, big.NewInt(int64(blockNr)))
|
||||
}
|
||||
nonce, err := state.GetNonce(ctx, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -894,82 +764,50 @@ func getTransactionBlockData(chainDb ethdb.Database, txHash common.Hash) (common
|
|||
}
|
||||
|
||||
// GetTransactionByHash returns the transaction for the given hash
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, txHash common.Hash) (*RPCTransaction, error) {
|
||||
var tx *types.Transaction
|
||||
var isPending bool
|
||||
var err error
|
||||
|
||||
if tx, isPending, err = getTransaction(s.b.ChainDb(), s.b, txHash); err != nil {
|
||||
glog.V(logger.Debug).Infof("%v\n", err)
|
||||
return nil, nil
|
||||
} else if tx == nil {
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, txhash common.Hash) (*RPCTransaction, error) {
|
||||
tx, isPending, err := s.b.TransactionByHash(ctx, txhash)
|
||||
if tx == nil || err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
rtx := newRPCTransaction(tx)
|
||||
if isPending {
|
||||
return newRPCPendingTransaction(tx), nil
|
||||
return rtx, nil
|
||||
} else if tib, ok := s.b.(TransactionInclusionBlock); ok {
|
||||
bhash, bnum, index, err := tib.TransactionInclusionBlock(txhash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rtx.setInclusionBlock(bhash, bnum, index)
|
||||
}
|
||||
|
||||
blockHash, _, _, err := getTransactionBlockData(s.b.ChainDb(), txHash)
|
||||
if err != nil {
|
||||
glog.V(logger.Debug).Infof("%v\n", err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil {
|
||||
return newRPCTransaction(block, txHash)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return rtx, nil
|
||||
}
|
||||
|
||||
// GetRawTransactionByHash returns the bytes of the transaction for the given hash.
|
||||
func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, txHash common.Hash) (rpc.HexBytes, error) {
|
||||
var tx *types.Transaction
|
||||
var err error
|
||||
|
||||
if tx, _, err = getTransaction(s.b.ChainDb(), s.b, txHash); err != nil {
|
||||
glog.V(logger.Debug).Infof("%v\n", err)
|
||||
return nil, nil
|
||||
} else if tx == nil {
|
||||
func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, txhash common.Hash) (rpc.HexBytes, error) {
|
||||
tx, _, err := s.b.TransactionByHash(ctx, txhash)
|
||||
if tx == nil || err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return rlp.EncodeToBytes(tx)
|
||||
}
|
||||
|
||||
// GetTransactionReceipt returns the transaction receipt for the given transaction hash.
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (map[string]interface{}, error) {
|
||||
receipt := core.GetReceipt(s.b.ChainDb(), txHash)
|
||||
if receipt == nil {
|
||||
glog.V(logger.Debug).Infof("receipt not found for transaction %s", txHash.Hex())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
tx, _, err := getTransaction(s.b.ChainDb(), s.b, txHash)
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, txhash common.Hash) (map[string]interface{}, error) {
|
||||
receipt, err := s.b.TransactionReceipt(ctx, txhash)
|
||||
if err != nil {
|
||||
glog.V(logger.Debug).Infof("%v\n", err)
|
||||
glog.V(logger.Debug).Infof("receipt not found for transaction %s: %v", txhash.Hex(), err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
txBlock, blockIndex, index, err := getTransactionBlockData(s.b.ChainDb(), txHash)
|
||||
tx, isPending, err := s.b.TransactionByHash(ctx, txhash)
|
||||
if err != nil {
|
||||
glog.V(logger.Debug).Infof("%v\n", err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
from, err := tx.FromFrontier()
|
||||
if err != nil {
|
||||
glog.V(logger.Debug).Infof("%v\n", err)
|
||||
glog.V(logger.Debug).Infof("can't get transaction %s: %v\n", txhash.Hex(), err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
from, _ := tx.FromFrontier()
|
||||
fields := map[string]interface{}{
|
||||
"root": rpc.HexBytes(receipt.PostState),
|
||||
"blockHash": txBlock,
|
||||
"blockNumber": rpc.NewHexNumber(blockIndex),
|
||||
"transactionHash": txHash,
|
||||
"transactionIndex": rpc.NewHexNumber(index),
|
||||
"transactionHash": txhash,
|
||||
"from": from,
|
||||
"to": tx.To(),
|
||||
"gasUsed": rpc.NewHexNumber(receipt.GasUsed),
|
||||
|
|
@ -978,10 +816,21 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma
|
|||
"logs": receipt.Logs,
|
||||
"logsBloom": receipt.Bloom,
|
||||
}
|
||||
// Set block inclusion information if available.
|
||||
if tib, ok := s.b.(TransactionInclusionBlock); !isPending && ok {
|
||||
bhash, bnum, index, err := tib.TransactionInclusionBlock(txhash)
|
||||
if err != nil {
|
||||
glog.V(logger.Debug).Infof("%v\n", err)
|
||||
return nil, nil
|
||||
}
|
||||
fields["blockHash"] = bhash
|
||||
fields["blockNumber"] = rpc.NewHexNumber(bnum)
|
||||
fields["transactionIndex"] = rpc.NewHexNumber(index)
|
||||
}
|
||||
|
||||
if receipt.Logs == nil {
|
||||
fields["logs"] = []vm.Logs{}
|
||||
}
|
||||
// If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation
|
||||
if receipt.ContractAddress != (common.Address{}) {
|
||||
fields["contractAddress"] = receipt.ContractAddress
|
||||
}
|
||||
|
|
@ -1014,7 +863,7 @@ func prepareSendTxArgs(ctx context.Context, args SendTxArgs, b Backend) (SendTxA
|
|||
args.Gas = rpc.NewHexNumber(defaultGas)
|
||||
}
|
||||
if args.GasPrice == nil {
|
||||
price, err := b.SuggestPrice(ctx)
|
||||
price, err := b.SuggestGasPrice(ctx)
|
||||
if err != nil {
|
||||
return args, err
|
||||
}
|
||||
|
|
@ -1033,7 +882,7 @@ func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, si
|
|||
return common.Hash{}, err
|
||||
}
|
||||
|
||||
if err := b.SendTx(ctx, signedTx); err != nil {
|
||||
if err := b.SendTransaction(ctx, signedTx); err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
|
||||
|
|
@ -1058,7 +907,7 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
|
|||
}
|
||||
|
||||
if args.Nonce == nil {
|
||||
nonce, err := s.b.GetPoolNonce(ctx, args.From)
|
||||
nonce, err := s.b.PendingNonceAt(ctx, args.From)
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
|
|
@ -1088,7 +937,7 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
|
|||
return "", err
|
||||
}
|
||||
|
||||
if err := s.b.SendTx(ctx, tx); err != nil {
|
||||
if err := s.b.SendTransaction(ctx, tx); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
|
@ -1224,7 +1073,7 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sig
|
|||
args.Gas = rpc.NewHexNumber(defaultGas)
|
||||
}
|
||||
if args.GasPrice == nil {
|
||||
price, err := s.b.SuggestPrice(ctx)
|
||||
price, err := s.b.SuggestGasPrice(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -1235,7 +1084,7 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sig
|
|||
}
|
||||
|
||||
if args.Nonce == nil {
|
||||
nonce, err := s.b.GetPoolNonce(ctx, args.From)
|
||||
nonce, err := s.b.PendingNonceAt(ctx, args.From)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -1265,12 +1114,12 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sig
|
|||
// PendingTransactions returns the transactions that are in the transaction pool and have a from address that is one of
|
||||
// the accounts this node manages.
|
||||
func (s *PublicTransactionPoolAPI) PendingTransactions() []*RPCTransaction {
|
||||
pending := s.b.GetPoolTransactions()
|
||||
pending := s.b.PendingTransactions()
|
||||
transactions := make([]*RPCTransaction, 0, len(pending))
|
||||
for _, tx := range pending {
|
||||
from, _ := tx.FromFrontier()
|
||||
if s.b.AccountManager().HasAddress(from) {
|
||||
transactions = append(transactions, newRPCPendingTransaction(tx))
|
||||
transactions = append(transactions, newRPCTransaction(tx))
|
||||
}
|
||||
}
|
||||
return transactions
|
||||
|
|
@ -1279,7 +1128,7 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() []*RPCTransaction {
|
|||
// Resend accepts an existing transaction and a new gas price and limit. It will remove the given transaction from the
|
||||
// pool and reinsert it with the new gas price and limit.
|
||||
func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, tx Tx, gasPrice, gasLimit *rpc.HexNumber) (common.Hash, error) {
|
||||
pending := s.b.GetPoolTransactions()
|
||||
pending := s.b.PendingTransactions()
|
||||
for _, p := range pending {
|
||||
if pFrom, err := p.FromFrontier(); err == nil && pFrom == tx.From && p.SigHash() == tx.tx.SigHash() {
|
||||
if gasPrice == nil {
|
||||
|
|
@ -1301,8 +1150,8 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, tx Tx, gasPrice,
|
|||
return common.Hash{}, err
|
||||
}
|
||||
|
||||
s.b.RemoveTx(tx.Hash)
|
||||
if err = s.b.SendTx(ctx, signedTx); err != nil {
|
||||
s.b.RemoveTransaction(tx.Hash)
|
||||
if err = s.b.SendTransaction(ctx, signedTx); err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
|
||||
|
|
@ -1326,8 +1175,8 @@ func NewPublicDebugAPI(b Backend) *PublicDebugAPI {
|
|||
}
|
||||
|
||||
// GetBlockRlp retrieves the RLP encoded for of a single block.
|
||||
func (api *PublicDebugAPI) GetBlockRlp(ctx context.Context, number uint64) (string, error) {
|
||||
block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number))
|
||||
func (api *PublicDebugAPI) GetBlockRlp(ctx context.Context, number rpc.BlockNumber) (string, error) {
|
||||
block, _ := blockByNumber(ctx, api.b, number)
|
||||
if block == nil {
|
||||
return "", fmt.Errorf("block #%d not found", number)
|
||||
}
|
||||
|
|
@ -1339,8 +1188,8 @@ func (api *PublicDebugAPI) GetBlockRlp(ctx context.Context, number uint64) (stri
|
|||
}
|
||||
|
||||
// PrintBlock retrieves a block and returns its pretty printed form.
|
||||
func (api *PublicDebugAPI) PrintBlock(ctx context.Context, number uint64) (string, error) {
|
||||
block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number))
|
||||
func (api *PublicDebugAPI) PrintBlock(ctx context.Context, number rpc.BlockNumber) (string, error) {
|
||||
block, _ := blockByNumber(ctx, api.b, number)
|
||||
if block == nil {
|
||||
return "", fmt.Errorf("block #%d not found", number)
|
||||
}
|
||||
|
|
@ -1349,10 +1198,6 @@ func (api *PublicDebugAPI) PrintBlock(ctx context.Context, number uint64) (strin
|
|||
|
||||
// SeedHash retrieves the seed hash of a block.
|
||||
func (api *PublicDebugAPI) SeedHash(ctx context.Context, number uint64) (string, error) {
|
||||
block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number))
|
||||
if block == nil {
|
||||
return "", fmt.Errorf("block #%d not found", number)
|
||||
}
|
||||
hash, err := ethash.GetSeedHash(number)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
@ -1360,21 +1205,22 @@ func (api *PublicDebugAPI) SeedHash(ctx context.Context, number uint64) (string,
|
|||
return fmt.Sprintf("0x%x", hash), nil
|
||||
}
|
||||
|
||||
// PrivateDebugAPI is the collection of Etheruem APIs exposed over the private
|
||||
// PrivateDebugAPI is the collection of Ethereum APIs exposed over the private
|
||||
// debugging endpoint.
|
||||
type PrivateDebugAPI struct {
|
||||
b Backend
|
||||
b Backend
|
||||
chaindb ethdb.Database
|
||||
}
|
||||
|
||||
// NewPrivateDebugAPI creates a new API definition for the private debug methods
|
||||
// of the Ethereum service.
|
||||
func NewPrivateDebugAPI(b Backend) *PrivateDebugAPI {
|
||||
return &PrivateDebugAPI{b: b}
|
||||
func NewPrivateDebugAPI(b Backend, chaindb ethdb.Database) *PrivateDebugAPI {
|
||||
return &PrivateDebugAPI{b, chaindb}
|
||||
}
|
||||
|
||||
// ChaindbProperty returns leveldb properties of the chain database.
|
||||
func (api *PrivateDebugAPI) ChaindbProperty(property string) (string, error) {
|
||||
ldb, ok := api.b.ChainDb().(interface {
|
||||
ldb, ok := api.chaindb.(interface {
|
||||
LDB() *leveldb.DB
|
||||
})
|
||||
if !ok {
|
||||
|
|
@ -1389,7 +1235,7 @@ func (api *PrivateDebugAPI) ChaindbProperty(property string) (string, error) {
|
|||
}
|
||||
|
||||
func (api *PrivateDebugAPI) ChaindbCompact() error {
|
||||
ldb, ok := api.b.ChainDb().(interface {
|
||||
ldb, ok := api.chaindb.(interface {
|
||||
LDB() *leveldb.DB
|
||||
})
|
||||
if !ok {
|
||||
|
|
@ -1408,7 +1254,7 @@ func (api *PrivateDebugAPI) ChaindbCompact() error {
|
|||
|
||||
// SetHead rewinds the head of the blockchain to a previous block.
|
||||
func (api *PrivateDebugAPI) SetHead(number rpc.HexNumber) {
|
||||
api.b.SetHead(uint64(number.Int64()))
|
||||
api.b.ResetHeadBlock(number.Uint64())
|
||||
}
|
||||
|
||||
// PublicNetAPI offers network related RPC methods
|
||||
|
|
|
|||
|
|
@ -20,52 +20,44 @@ package ethapi
|
|||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"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.
|
||||
// Backend defines most methods required for the RPC API.
|
||||
type Backend interface {
|
||||
// general Ethereum API
|
||||
Downloader() *downloader.Downloader
|
||||
ethereum.ChainReader
|
||||
ethereum.ChainStateReader
|
||||
ethereum.ChainSyncReader
|
||||
ethereum.TransactionSender
|
||||
ethereum.GasPricer
|
||||
ethereum.GasEstimator
|
||||
ethereum.ContractCaller
|
||||
|
||||
ProtocolVersion() int
|
||||
SuggestPrice(ctx context.Context) (*big.Int, error)
|
||||
ChainDb() ethdb.Database
|
||||
EventMux() *event.TypeMux
|
||||
AccountManager() *accounts.Manager
|
||||
// BlockChain API
|
||||
SetHead(number uint64)
|
||||
HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error)
|
||||
BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error)
|
||||
StateAndHeaderByNumber(ctx context.Context, 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]types.Transactions, map[common.Address]types.Transactions)
|
||||
AccountManager() *accounts.Manager // TODO(fjl): this should be a constructor argb
|
||||
BlockTD(common.Hash) *big.Int
|
||||
RemoveTransaction(txhash common.Hash)
|
||||
PendingTransactions() []*types.Transaction
|
||||
PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)
|
||||
ResetHeadBlock(number uint64) // for admin API
|
||||
}
|
||||
|
||||
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)
|
||||
// PendingState is implemented by the eth.Ethereum backend and provides access to optional
|
||||
// features that can only be provided by a full pending state.
|
||||
type PendingState interface {
|
||||
PendingBlock() (*types.Block, error)
|
||||
ethereum.PendingStateReader
|
||||
ethereum.PendingContractCaller
|
||||
}
|
||||
|
||||
type TransactionInclusionBlock interface {
|
||||
// returns the block at which the given transaction was included in the blockchain
|
||||
TransactionInclusionBlock(txhash common.Hash) (blockhash common.Hash, blocknum uint64, index int, err error)
|
||||
}
|
||||
|
||||
func GetAPIs(apiBackend Backend, solcPath string) []rpc.API {
|
||||
|
|
@ -86,20 +78,11 @@ func GetAPIs(apiBackend Backend, solcPath string) []rpc.API {
|
|||
Version: "1.0",
|
||||
Service: NewPublicTransactionPoolAPI(apiBackend),
|
||||
Public: true,
|
||||
}, {
|
||||
Namespace: "txpool",
|
||||
Version: "1.0",
|
||||
Service: NewPublicTxPoolAPI(apiBackend),
|
||||
Public: true,
|
||||
}, {
|
||||
Namespace: "debug",
|
||||
Version: "1.0",
|
||||
Service: NewPublicDebugAPI(apiBackend),
|
||||
Public: true,
|
||||
}, {
|
||||
Namespace: "debug",
|
||||
Version: "1.0",
|
||||
Service: NewPrivateDebugAPI(apiBackend),
|
||||
}, {
|
||||
Namespace: "eth",
|
||||
Version: "1.0",
|
||||
|
|
|
|||
105
internal/ethapi/txpool.go
Normal file
105
internal/ethapi/txpool.go
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
// 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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
type TxPool interface {
|
||||
Stats() (pending int, queued int)
|
||||
Content() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
|
||||
}
|
||||
|
||||
// TxPoolDebugAPI offers and API for the transaction pool. It only operates on data that
|
||||
// is non confidential.
|
||||
type TxPoolDebugAPI struct{ Pool TxPool }
|
||||
|
||||
// Content returns the transactions contained within the transaction pool.
|
||||
func (s TxPoolDebugAPI) Content() map[string]map[string]map[string]*RPCTransaction {
|
||||
content := map[string]map[string]map[string]*RPCTransaction{
|
||||
"pending": make(map[string]map[string]*RPCTransaction),
|
||||
"queued": make(map[string]map[string]*RPCTransaction),
|
||||
}
|
||||
pending, queue := s.Pool.Content()
|
||||
|
||||
// Flatten the pending transactions
|
||||
for account, txs := range pending {
|
||||
dump := make(map[string]*RPCTransaction)
|
||||
for nonce, tx := range txs {
|
||||
dump[fmt.Sprintf("%d", nonce)] = newRPCTransaction(tx)
|
||||
}
|
||||
content["pending"][account.Hex()] = dump
|
||||
}
|
||||
// Flatten the queued transactions
|
||||
for account, txs := range queue {
|
||||
dump := make(map[string]*RPCTransaction)
|
||||
for nonce, tx := range txs {
|
||||
dump[fmt.Sprintf("%d", nonce)] = newRPCTransaction(tx)
|
||||
}
|
||||
content["queued"][account.Hex()] = dump
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
// Status returns the number of pending and queued transaction in the pool.
|
||||
func (s TxPoolDebugAPI) Status() map[string]*rpc.HexNumber {
|
||||
pending, queue := s.Pool.Stats()
|
||||
return map[string]*rpc.HexNumber{
|
||||
"pending": rpc.NewHexNumber(pending),
|
||||
"queued": rpc.NewHexNumber(queue),
|
||||
}
|
||||
}
|
||||
|
||||
// Inspect retrieves the content of the transaction pool and flattens it into an
|
||||
// easily inspectable list.
|
||||
func (s TxPoolDebugAPI) Inspect() map[string]map[string]map[string]string {
|
||||
content := map[string]map[string]map[string]string{
|
||||
"pending": make(map[string]map[string]string),
|
||||
"queued": make(map[string]map[string]string),
|
||||
}
|
||||
pending, queue := s.Pool.Content()
|
||||
|
||||
// Define a formatter to flatten a transaction into a string
|
||||
var format = func(tx *types.Transaction) string {
|
||||
if to := tx.To(); to != nil {
|
||||
return fmt.Sprintf("%s: %v wei + %v × %v gas", tx.To().Hex(), tx.Value(), tx.Gas(), tx.GasPrice())
|
||||
}
|
||||
return fmt.Sprintf("contract creation: %v wei + %v × %v gas", tx.Value(), tx.Gas(), tx.GasPrice())
|
||||
}
|
||||
// Flatten the pending transactions
|
||||
for account, txs := range pending {
|
||||
dump := make(map[string]string)
|
||||
for nonce, tx := range txs {
|
||||
dump[fmt.Sprintf("%d", nonce)] = format(tx)
|
||||
}
|
||||
content["pending"][account.Hex()] = dump
|
||||
}
|
||||
// Flatten the queued transactions
|
||||
for account, txs := range queue {
|
||||
dump := make(map[string]string)
|
||||
for nonce, tx := range txs {
|
||||
dump[fmt.Sprintf("%d", nonce)] = format(tx)
|
||||
}
|
||||
content["queued"][account.Hex()] = dump
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
|
@ -17,128 +17,202 @@
|
|||
package les
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
ethereum "github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"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/eth/gasprice"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/light"
|
||||
rpc "github.com/ethereum/go-ethereum/rpc"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type LesApiBackend struct {
|
||||
eth *LightEthereum
|
||||
gpo *gasprice.LightPriceOracle
|
||||
}
|
||||
var (
|
||||
ErrBlockNotFound = errors.New("block not found")
|
||||
ErrTxNotFound = errors.New("the light client cannot retrieve past transactions by hash")
|
||||
ErrReceiptNotFound = errors.New("the light client cannot retrieve receipts by hash")
|
||||
)
|
||||
|
||||
func (b *LesApiBackend) SetHead(number uint64) {
|
||||
b.eth.blockchain.SetHead(number)
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) {
|
||||
if blockNr == rpc.LatestBlockNumber || blockNr == rpc.PendingBlockNumber {
|
||||
return b.eth.blockchain.CurrentHeader(), nil
|
||||
func (eth *LightEthereum) HeaderByHash(ctx context.Context, blockhash common.Hash) (*types.Header, error) {
|
||||
if h := eth.blockchain.GetHeaderByHash(blockhash); h != nil {
|
||||
return h, nil
|
||||
}
|
||||
|
||||
return b.eth.blockchain.GetHeaderByNumberOdr(ctx, uint64(blockNr))
|
||||
return nil, ErrBlockNotFound
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error) {
|
||||
header, err := b.HeaderByNumber(ctx, blockNr)
|
||||
if header == nil || err != nil {
|
||||
func (eth *LightEthereum) HeaderByNumber(ctx context.Context, blocknum *big.Int) (*types.Header, error) {
|
||||
if blocknum == nil {
|
||||
return eth.blockchain.CurrentHeader(), nil
|
||||
}
|
||||
h, err := eth.blockchain.GetHeaderByNumberOdr(ctx, uint64(blocknum.Uint64()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b.GetBlock(ctx, header.Hash())
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (ethapi.State, *types.Header, error) {
|
||||
header, err := b.HeaderByNumber(ctx, blockNr)
|
||||
if header == nil || err != nil {
|
||||
return nil, nil, err
|
||||
if h == nil {
|
||||
return nil, ErrBlockNotFound
|
||||
}
|
||||
return light.NewLightState(light.StateTrieID(header), b.eth.odr), header, nil
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) {
|
||||
return b.eth.blockchain.GetBlockByHash(ctx, blockHash)
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) {
|
||||
return light.GetBlockReceipts(ctx, b.eth.odr, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash))
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int {
|
||||
return b.eth.blockchain.GetTdByHash(blockHash)
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) {
|
||||
stateDb := state.(*light.LightState).Copy()
|
||||
addr, _ := msg.From()
|
||||
from, err := stateDb.GetOrNewStateObject(ctx, addr)
|
||||
func (eth *LightEthereum) BlockByNumber(ctx context.Context, blocknum *big.Int) (*types.Block, error) {
|
||||
header, err := eth.HeaderByNumber(ctx, blocknum)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
from.SetBalance(common.MaxBig)
|
||||
env := light.NewEnv(ctx, stateDb, b.eth.chainConfig, b.eth.blockchain, msg, header, b.eth.chainConfig.VmConfig)
|
||||
return env, env.Error, nil
|
||||
return eth.BlockByHash(ctx, header.Hash())
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
|
||||
return b.eth.txPool.Add(ctx, signedTx)
|
||||
func (eth *LightEthereum) BlockByHash(ctx context.Context, blockhash common.Hash) (*types.Block, error) {
|
||||
return eth.blockchain.GetBlockByHash(ctx, blockhash)
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) RemoveTx(txHash common.Hash) {
|
||||
b.eth.txPool.RemoveTx(txHash)
|
||||
func (eth *LightEthereum) BlockReceipts(ctx context.Context, blockhash common.Hash, blocknum uint64) ([]*types.Receipt, error) {
|
||||
return light.GetBlockReceipts(ctx, eth.odr, blockhash, blocknum)
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) GetPoolTransactions() types.Transactions {
|
||||
return b.eth.txPool.GetTransactions()
|
||||
func (eth *LightEthereum) BlockTD(blockHash common.Hash) *big.Int {
|
||||
return eth.blockchain.GetTdByHash(blockHash)
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction {
|
||||
return b.eth.txPool.GetTransaction(txHash)
|
||||
func (eth *LightEthereum) TransactionByHash(ctx context.Context, txHash common.Hash) (tx *types.Transaction, isPending bool, err error) {
|
||||
if tx = eth.txPool.GetTransaction(txHash); tx != nil {
|
||||
return tx, true, nil
|
||||
}
|
||||
return nil, false, ErrTxNotFound
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
|
||||
return b.eth.txPool.GetNonce(ctx, addr)
|
||||
func (eth *LightEthereum) TransactionInBlock(ctx context.Context, blockhash common.Hash, index uint) (*types.Transaction, error) {
|
||||
b, err := eth.blockchain.GetBlockByHash(ctx, blockhash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if index >= uint(len(b.Transactions())) {
|
||||
return nil, fmt.Errorf("transaction index out of range")
|
||||
}
|
||||
return b.Transactions()[index], nil
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) Stats() (pending int, queued int) {
|
||||
return b.eth.txPool.Stats(), 0
|
||||
func (eth *LightEthereum) TransactionReceipt(ctx context.Context, txhash common.Hash) (*types.Receipt, error) {
|
||||
return nil, ErrReceiptNotFound
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) {
|
||||
return b.eth.txPool.Content()
|
||||
func (eth *LightEthereum) TransactionCount(ctx context.Context, blockhash common.Hash) (uint, error) {
|
||||
b, err := eth.blockchain.GetBlockByHash(ctx, blockhash)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint(len(b.Transactions())), nil
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) Downloader() *downloader.Downloader {
|
||||
return b.eth.Downloader()
|
||||
func (eth *LightEthereum) BalanceAt(ctx context.Context, addr common.Address, blocknum *big.Int) (*big.Int, error) {
|
||||
st, err := eth.state(ctx, blocknum)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return st.GetBalance(ctx, addr)
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) ProtocolVersion() int {
|
||||
return b.eth.LesVersion() + 10000
|
||||
func (eth *LightEthereum) CodeAt(ctx context.Context, addr common.Address, blocknum *big.Int) ([]byte, error) {
|
||||
st, err := eth.state(ctx, blocknum)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return st.GetCode(ctx, addr)
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
|
||||
return b.gpo.SuggestPrice(ctx)
|
||||
func (eth *LightEthereum) NonceAt(ctx context.Context, addr common.Address, blocknum *big.Int) (uint64, error) {
|
||||
st, err := eth.state(ctx, blocknum)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return st.GetNonce(ctx, addr)
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) ChainDb() ethdb.Database {
|
||||
return b.eth.chainDb
|
||||
func (eth *LightEthereum) StorageAt(ctx context.Context, addr common.Address, key common.Hash, blocknum *big.Int) ([]byte, error) {
|
||||
st, err := eth.state(ctx, blocknum)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v, err := st.GetState(ctx, addr, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v[:], nil
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) EventMux() *event.TypeMux {
|
||||
return b.eth.eventMux
|
||||
func (eth *LightEthereum) PendingCodeAt(ctx context.Context, addr common.Address) ([]byte, error) {
|
||||
// TODO(fjl): find a way to get rid of PendingCodeAt here. CodeAt is a bad emulation
|
||||
// of PendingCodeAt because it forces users to wait for transactions to get mined.
|
||||
return eth.CodeAt(ctx, addr, nil)
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) AccountManager() *accounts.Manager {
|
||||
return b.eth.accountManager
|
||||
func (eth *LightEthereum) state(ctx context.Context, blocknum *big.Int) (*light.LightState, error) {
|
||||
header, err := eth.HeaderByNumber(ctx, blocknum)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return light.NewLightState(light.StateTrieID(header), eth.odr), nil
|
||||
}
|
||||
|
||||
func (eth *LightEthereum) SendTransaction(ctx context.Context, signedTx *types.Transaction) error {
|
||||
return eth.txPool.Add(ctx, signedTx)
|
||||
}
|
||||
|
||||
func (eth *LightEthereum) RemoveTransaction(txHash common.Hash) {
|
||||
eth.txPool.RemoveTx(txHash)
|
||||
}
|
||||
|
||||
func (eth *LightEthereum) PendingTransactions() []*types.Transaction {
|
||||
return eth.txPool.GetTransactions()
|
||||
}
|
||||
|
||||
func (eth *LightEthereum) PendingNonceAt(ctx context.Context, addr common.Address) (uint64, error) {
|
||||
return eth.txPool.GetNonce(ctx, addr)
|
||||
}
|
||||
|
||||
func (eth *LightEthereum) SyncProgress(ctx context.Context) (*ethereum.SyncProgress, error) {
|
||||
return eth.protocolManager.downloader.Progress(), nil
|
||||
}
|
||||
|
||||
func (eth *LightEthereum) ProtocolVersion() int {
|
||||
return int(eth.protocolManager.SubProtocols[0].Version) + 10000
|
||||
}
|
||||
|
||||
func (eth *LightEthereum) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
|
||||
return eth.gpo.SuggestPrice(ctx)
|
||||
}
|
||||
|
||||
func (eth *LightEthereum) AccountManager() *accounts.Manager {
|
||||
return eth.accountManager
|
||||
}
|
||||
|
||||
func (eth *LightEthereum) ResetHeadBlock(number uint64) {
|
||||
eth.blockchain.SetHead(number)
|
||||
}
|
||||
|
||||
func (eth *LightEthereum) EstimateGas(ctx context.Context, call ethereum.CallMsg) (usedGas *big.Int, err error) {
|
||||
_, gas, err := eth.callContract(ctx, call, nil)
|
||||
return gas, err
|
||||
}
|
||||
|
||||
func (eth *LightEthereum) CallContract(ctx context.Context, call ethereum.CallMsg, blocknum *big.Int) ([]byte, error) {
|
||||
val, _, err := eth.callContract(ctx, call, blocknum)
|
||||
return val, err
|
||||
}
|
||||
|
||||
func (eth *LightEthereum) callContract(ctx context.Context, call ethereum.CallMsg, blocknum *big.Int) ([]byte, *big.Int, error) {
|
||||
var head *types.Header
|
||||
if blocknum == nil {
|
||||
head = eth.blockchain.CurrentHeader()
|
||||
} else if head = eth.blockchain.GetHeaderByNumber(blocknum.Uint64()); head == nil {
|
||||
return nil, nil, ErrBlockNotFound
|
||||
}
|
||||
state := light.NewLightState(light.StateTrieID(head), eth.odr)
|
||||
return core.ApplyCallMessage(call, func(msg core.Message) vm.Environment {
|
||||
return light.NewEnv(ctx, state, eth.chainConfig, eth.blockchain, msg, head, vm.Config{})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ type LightEthereum struct {
|
|||
// DB interfaces
|
||||
chainDb ethdb.Database // Block chain database
|
||||
|
||||
ApiBackend *LesApiBackend
|
||||
gpo *gasprice.LightPriceOracle
|
||||
|
||||
eventMux *event.TypeMux
|
||||
pow *ethash.Ethash
|
||||
|
|
@ -124,8 +124,8 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
eth.ApiBackend = &LesApiBackend{eth, nil}
|
||||
eth.ApiBackend.gpo = gasprice.NewLightPriceOracle(eth.ApiBackend)
|
||||
eth.gpo = gasprice.NewLightPriceOracle(eth)
|
||||
|
||||
return eth, nil
|
||||
}
|
||||
|
||||
|
|
@ -153,9 +153,13 @@ func (s *LightDummyAPI) Mining() bool {
|
|||
|
||||
// APIs returns the collection of RPC services the ethereum package offers.
|
||||
// NOTE, some of these services probably need to be moved to somewhere else.
|
||||
func (s *LightEthereum) APIs() []rpc.API {
|
||||
return append(ethapi.GetAPIs(s.ApiBackend, s.solcPath), []rpc.API{
|
||||
func (eth *LightEthereum) APIs() []rpc.API {
|
||||
return append(ethapi.GetAPIs(eth, eth.solcPath), []rpc.API{
|
||||
{
|
||||
Namespace: "debug",
|
||||
Version: "1.0",
|
||||
Service: ethapi.NewPrivateDebugAPI(eth, eth.chainDb),
|
||||
}, {
|
||||
Namespace: "eth",
|
||||
Version: "1.0",
|
||||
Service: &LightDummyAPI{},
|
||||
|
|
@ -163,17 +167,22 @@ func (s *LightEthereum) APIs() []rpc.API {
|
|||
}, {
|
||||
Namespace: "eth",
|
||||
Version: "1.0",
|
||||
Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux),
|
||||
Service: downloader.NewPublicDownloaderAPI(eth.protocolManager.downloader, eth.eventMux),
|
||||
Public: true,
|
||||
}, {
|
||||
Namespace: "eth",
|
||||
Version: "1.0",
|
||||
Service: filters.NewPublicFilterAPI(s.ApiBackend, true),
|
||||
Service: filters.NewPublicFilterAPI(eth, eth.eventMux, eth.chainDb, true),
|
||||
Public: true,
|
||||
}, {
|
||||
Namespace: "txpool",
|
||||
Version: "1.0",
|
||||
Service: ethapi.TxPoolDebugAPI{Pool: eth.txPool},
|
||||
},
|
||||
{
|
||||
Namespace: "net",
|
||||
Version: "1.0",
|
||||
Service: s.netRPCService,
|
||||
Service: eth.netRPCService,
|
||||
Public: true,
|
||||
},
|
||||
}...)
|
||||
|
|
@ -183,11 +192,6 @@ func (s *LightEthereum) ResetWithGenesisBlock(gb *types.Block) {
|
|||
s.blockchain.ResetWithGenesisBlock(gb)
|
||||
}
|
||||
|
||||
func (s *LightEthereum) BlockChain() *light.LightChain { return s.blockchain }
|
||||
func (s *LightEthereum) TxPool() *light.TxPool { return s.txPool }
|
||||
func (s *LightEthereum) LesVersion() int { return int(s.protocolManager.SubProtocols[0].Version) }
|
||||
func (s *LightEthereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
|
||||
|
||||
// Protocols implements node.Service, returning all the currently configured
|
||||
// network protocols to start.
|
||||
func (s *LightEthereum) Protocols() []p2p.Protocol {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/les/flowcontrol"
|
||||
"github.com/ethereum/go-ethereum/light"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
|
|
@ -44,8 +45,8 @@ type LesServer struct {
|
|||
defParams *flowcontrol.ServerParams
|
||||
}
|
||||
|
||||
func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
|
||||
pm, err := NewProtocolManager(config.ChainConfig, false, config.NetworkId, eth.EventMux(), eth.Pow(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil)
|
||||
func NewLesServer(eth *eth.Ethereum, mux *event.TypeMux, config *eth.Config) (*LesServer, error) {
|
||||
pm, err := NewProtocolManager(config.ChainConfig, false, config.NetworkId, mux, eth.Pow(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -321,12 +321,11 @@ func (pool *TxPool) Stop() {
|
|||
}
|
||||
|
||||
// Stats returns the number of currently pending (locally created) transactions
|
||||
func (pool *TxPool) Stats() (pending int) {
|
||||
func (pool *TxPool) Stats() (pending int, queued int) {
|
||||
pool.mu.RLock()
|
||||
defer pool.mu.RUnlock()
|
||||
|
||||
pending = len(pool.pending)
|
||||
return
|
||||
return len(pool.pending), 0
|
||||
}
|
||||
|
||||
// validateTx checks whether a transaction is valid according to the consensus rules.
|
||||
|
|
|
|||
Loading…
Reference in a new issue