diff --git a/accounts/abi/bind/auth.go b/accounts/abi/bind/auth.go
index a20852fca0..65237955f8 100644
--- a/accounts/abi/bind/auth.go
+++ b/accounts/abi/bind/auth.go
@@ -56,7 +56,7 @@ func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts {
if err != nil {
return nil, err
}
- return tx.WithSignature(signer, signature)
+ return tx.WithSignature(signer, signature), nil
},
}
}
diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go
index 00a8cd3e92..41eb072bd9 100644
--- a/accounts/abi/bind/backends/simulated.go
+++ b/accounts/abi/bind/backends/simulated.go
@@ -167,7 +167,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
}
@@ -177,7 +177,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
}
@@ -203,32 +203,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.
@@ -256,17 +240,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 { return m.CallMsg.From }
-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 }
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index fc7685b77f..ac5fe562c0 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -776,7 +776,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
diff --git a/contracts/release/release.go b/contracts/release/release.go
index cd79112cd1..346005e903 100644
--- a/contracts/release/release.go
+++ b/contracts/release/release.go
@@ -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
}
diff --git a/core/database_util.go b/core/database_util.go
index 84669de35b..7771e02479 100644
--- a/core/database_util.go
+++ b/core/database_util.go
@@ -86,7 +86,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
@@ -95,7 +95,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 {
@@ -251,7 +251,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 {
@@ -274,7 +274,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
diff --git a/core/database_util_test.go b/core/database_util_test.go
index 83750aa60a..e1613699dd 100644
--- a/core/database_util_test.go
+++ b/core/database_util_test.go
@@ -369,7 +369,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() {
diff --git a/core/headerchain.go b/core/headerchain.go
index c536945712..60552fd43c 100644
--- a/core/headerchain.go
+++ b/core/headerchain.go
@@ -124,7 +124,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
diff --git a/core/helper_test.go b/core/helper_test.go
deleted file mode 100644
index fd6a5491c5..0000000000
--- a/core/helper_test.go
+++ /dev/null
@@ -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 .
-
-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
-}
diff --git a/core/state_transition.go b/core/state_transition.go
index 8abe17b0a2..5322bed8fd 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -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 {
f := self.msg.From()
if !self.state.Exist(f) {
@@ -283,3 +317,17 @@ 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 { return m.CallMsg.From }
+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 }
diff --git a/core/tx_pool.go b/core/tx_pool.go
index edcbc21ebf..e38d963ee0 100644
--- a/core/tx_pool.go
+++ b/core/tx_pool.go
@@ -195,11 +195,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
diff --git a/core/types/block_test.go b/core/types/block_test.go
index b95bddcfce..9316125aba 100644
--- a/core/types/block_test.go
+++ b/core/types/block_test.go
@@ -18,7 +18,6 @@ package types
import (
"bytes"
- "fmt"
"math/big"
"reflect"
"testing"
@@ -52,11 +51,10 @@ func TestBlockEncoding(t *testing.T) {
check("Size", block.Size(), common.StorageSize(len(blockEnc)))
tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), big.NewInt(50000), big.NewInt(10), nil)
-
- tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b11b"))
- fmt.Println(block.Transactions()[0].Hash())
- fmt.Println(tx1.data)
- fmt.Println(tx1.Hash())
+ tx1 = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b11b"))
+ t.Log(block.Transactions()[0].Hash())
+ t.Log(tx1.data)
+ t.Log(tx1.Hash())
check("len(Transactions)", len(block.Transactions()), 1)
check("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash())
diff --git a/core/types/transaction.go b/core/types/transaction.go
index 323bfaee60..6c255e2637 100644
--- a/core/types/transaction.go
+++ b/core/types/transaction.go
@@ -340,12 +340,12 @@ func (tx *Transaction) AsMessage(s Signer) (Message, error) {
// XXX This only makes for a nice API: NewTx(...).SignECDSA(signer, prv). Should
// we keep this?
func (tx *Transaction) SignECDSA(signer Signer, prv *ecdsa.PrivateKey) (*Transaction, error) {
- return signer.SignECDSA(tx, prv)
+ return SignECDSA(signer, tx, prv)
}
// WithSignature returns a new transaction with the given signature.
// This signature needs to be formatted as described in the yellow paper (v+27).
-func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) {
+func (tx *Transaction) WithSignature(signer Signer, sig []byte) *Transaction {
return signer.WithSignature(tx, sig)
}
diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go
index 7d571643f2..f5335a49c1 100644
--- a/core/types/transaction_signing.go
+++ b/core/types/transaction_signing.go
@@ -57,7 +57,7 @@ func SignECDSA(s Signer, tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction,
if err != nil {
return nil, err
}
- return s.WithSignature(tx, sig)
+ return s.WithSignature(tx, sig), nil
}
// Sender derives the sender from the tx using the signer derivation
@@ -101,10 +101,9 @@ type Signer interface {
Hash(tx *Transaction) common.Hash
// PubilcKey returns the public key derived from the signature
PublicKey(tx *Transaction) ([]byte, error)
- // SignECDSA signs the transaction with the given and returns a copy of the tx
- SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error)
- // WithSignature returns a copy of the transaction with the given signature
- WithSignature(tx *Transaction, sig []byte) (*Transaction, error)
+ // WithSignature returns a copy of the transaction with the given signature.
+ // It panics if the signature has the wrong size.
+ WithSignature(tx *Transaction, sig []byte) *Transaction
// Checks for equality on the signers
Equal(Signer) bool
}
@@ -129,10 +128,6 @@ func (s EIP155Signer) Equal(s2 Signer) bool {
return ok && eip155.chainId.Cmp(s.chainId) == 0
}
-func (s EIP155Signer) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
- return SignECDSA(s, tx, prv)
-}
-
func (s EIP155Signer) PublicKey(tx *Transaction) ([]byte, error) {
// if the transaction is not protected fall back to homestead signer
if !tx.Protected() {
@@ -169,7 +164,7 @@ func (s EIP155Signer) PublicKey(tx *Transaction) ([]byte, error) {
// WithSignature returns a new transaction with the given signature.
// This signature needs to be formatted as described in the yellow paper (v+27).
-func (s EIP155Signer) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
+func (s EIP155Signer) WithSignature(tx *Transaction, sig []byte) *Transaction {
if len(sig) != 65 {
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
}
@@ -182,7 +177,7 @@ func (s EIP155Signer) WithSignature(tx *Transaction, sig []byte) (*Transaction,
cpy.data.V = big.NewInt(int64(sig[64] - 27 + 35))
cpy.data.V.Add(cpy.data.V, s.chainIdMul)
}
- return cpy, nil
+ return cpy
}
// Hash returns the hash to be signed by the sender.
@@ -199,15 +194,6 @@ func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
})
}
-func (s EIP155Signer) SigECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
- h := s.Hash(tx)
- sig, err := crypto.SignEthereum(h[:], prv)
- if err != nil {
- return nil, err
- }
- return s.WithSignature(tx, sig)
-}
-
// HomesteadTransaction implements TransactionInterface using the
// homestead rules.
type HomesteadSigner struct{ FrontierSigner }
@@ -219,7 +205,7 @@ func (s HomesteadSigner) Equal(s2 Signer) bool {
// WithSignature returns a new transaction with the given snature.
// This snature needs to be formatted as described in the yellow paper (v+27).
-func (hs HomesteadSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
+func (hs HomesteadSigner) WithSignature(tx *Transaction, sig []byte) *Transaction {
if len(sig) != 65 {
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
}
@@ -227,16 +213,7 @@ func (hs HomesteadSigner) WithSignature(tx *Transaction, sig []byte) (*Transacti
cpy.data.R = new(big.Int).SetBytes(sig[:32])
cpy.data.S = new(big.Int).SetBytes(sig[32:64])
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]})
- return cpy, nil
-}
-
-func (hs HomesteadSigner) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
- h := hs.Hash(tx)
- sig, err := crypto.SignEthereum(h[:], prv)
- if err != nil {
- return nil, err
- }
- return hs.WithSignature(tx, sig)
+ return cpy
}
func (hs HomesteadSigner) PublicKey(tx *Transaction) ([]byte, error) {
@@ -275,7 +252,7 @@ func (s FrontierSigner) Equal(s2 Signer) bool {
// WithSignature returns a new transaction with the given snature.
// This snature needs to be formatted as described in the yellow paper (v+27).
-func (fs FrontierSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
+func (fs FrontierSigner) WithSignature(tx *Transaction, sig []byte) *Transaction {
if len(sig) != 65 {
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
}
@@ -283,16 +260,7 @@ func (fs FrontierSigner) WithSignature(tx *Transaction, sig []byte) (*Transactio
cpy.data.R = new(big.Int).SetBytes(sig[:32])
cpy.data.S = new(big.Int).SetBytes(sig[32:64])
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]})
- return cpy, nil
-}
-
-func (fs FrontierSigner) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
- h := fs.Hash(tx)
- sig, err := crypto.SignEthereum(h[:], prv)
- if err != nil {
- return nil, err
- }
- return fs.WithSignature(tx, sig)
+ return cpy
}
// Hash returns the hash to be sned by the sender.
diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go
index ca105566ad..e2c8191d5d 100644
--- a/core/types/transaction_test.go
+++ b/core/types/transaction_test.go
@@ -37,8 +37,7 @@ var (
big.NewInt(0), big.NewInt(0), big.NewInt(0),
nil,
)
-
- rightvrsTx, _ = NewTransaction(
+ rightvrsTx = NewTransaction(
3,
common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
big.NewInt(10),
diff --git a/eth/api.go b/eth/api.go
index b3185c3926..f026174fb6 100644
--- a/eth/api.go
+++ b/eth/api.go
@@ -516,7 +516,7 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common.
return nil, fmt.Errorf("sender retrieval failed: %v", err)
}
// 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 {
diff --git a/eth/api_backend.go b/eth/api_backend.go
index 0925132ef0..8fc06ce09a 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -17,197 +17,305 @@
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"
"github.com/ethereum/go-ethereum/params"
- 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) ChainConfig() *params.ChainConfig {
- return b.eth.chainConfig
-}
+var (
+ ErrBlockNotFound = errors.New("block not found")
+ ErrTxNotFound = errors.New("transaction not found")
+)
-func (b *EthApiBackend) CurrentBlock() *types.Block {
- return b.eth.blockchain.CurrentBlock()
-}
-
-func (b *EthApiBackend) SetHead(number uint64) {
- b.eth.blockchain.SetHead(number)
-}
-
-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
- from := statedb.GetOrNewStateObject(msg.From())
- from.SetBalance(common.MaxBig)
- vmError := func() error { return nil }
- return core.NewEnv(statedb, b.eth.chainConfig, b.eth.blockchain, msg, header, vm.Config{}), 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()
+// ChainConfig returns the active chain configuration.
+func (eth *Ethereum) ChainConfig() *params.ChainConfig {
+ return eth.chainConfig
}
-func (b *EthApiBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
- return b.gpo.SuggestPrice(), nil
+// 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) ChainDb() ethdb.Database {
- return b.eth.ChainDb()
+// 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) EventMux() *event.TypeMux {
- return b.eth.EventMux()
+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) AccountManager() *accounts.Manager {
- return b.eth.AccountManager()
+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
}
-type EthApiState struct {
- state *state.StateDB
+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
}
-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{})
+ })
}
diff --git a/eth/backend.go b/eth/backend.go
index d20efdabdc..34ebe1dadc 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -31,7 +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/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/downloader"
@@ -128,14 +127,13 @@ type Ethereum struct {
pow *ethash.Ethash
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
@@ -215,14 +213,14 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
eth.chainConfig = config.ChainConfig
- 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
@@ -239,10 +237,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,
@@ -251,8 +252,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
}
@@ -306,50 +306,58 @@ 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,
},
}...)
@@ -388,20 +396,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.
@@ -416,7 +420,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()
}
@@ -518,12 +522,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) - 2) full-R-
func dagFiles(epoch uint64) (string, string) {
diff --git a/eth/bind.go b/eth/bind.go
deleted file mode 100644
index 747965d370..0000000000
--- a/eth/bind.go
+++ /dev/null
@@ -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 .
-
-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
-}
diff --git a/eth/downloader/api.go b/eth/downloader/api.go
index e41376810f..672f6124c1 100644
--- a/eth/downloader/api.go
+++ b/eth/downloader/api.go
@@ -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
diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go
index b1f4b8169b..5cd7fb2491 100644
--- a/eth/downloader/downloader.go
+++ b/eth/downloader/downloader.go
@@ -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,
diff --git a/eth/filters/api.go b/eth/filters/api.go
index 8345132629..9c0c3fcab0 100644
--- a/eth/filters/api.go
+++ b/eth/filters/api.go
@@ -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)
diff --git a/eth/filters/filter.go b/eth/filters/filter.go
index 4004af3002..ce012df10e 100644
--- a/eth/filters/filter.go
+++ b/eth/filters/filter.go
@@ -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
}
diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go
index c2c072a9f9..b3dd8838a0 100644
--- a/eth/filters/filter_system.go
+++ b/eth/filters/filter_system.go
@@ -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
}
diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go
index d6d4199cc2..3220b73203 100644
--- a/eth/filters/filter_system_test.go
+++ b/eth/filters/filter_system_test.go
@@ -38,7 +38,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 {
@@ -46,30 +46,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.
diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go
index a8c767ead6..96bb09f3f2 100644
--- a/eth/filters/filter_test.go
+++ b/eth/filters/filter_test.go
@@ -104,7 +104,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)
@@ -206,7 +206,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)
@@ -217,7 +217,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)
@@ -230,7 +230,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)
@@ -243,7 +243,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)
@@ -254,7 +254,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)
@@ -265,7 +265,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)
@@ -275,7 +275,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)
diff --git a/eth/gasprice/lightprice.go b/eth/gasprice/lightprice.go
index 8886d32d7d..c96288a026 100644
--- a/eth/gasprice/lightprice.go
+++ b/eth/gasprice/lightprice.go
@@ -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
diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go
index a095aa0767..9e0a87dae4 100644
--- a/ethclient/ethclient.go
+++ b/ethclient/ethclient.go
@@ -19,6 +19,7 @@ package ethclient
import (
"encoding/json"
+ "errors"
"fmt"
"math/big"
@@ -143,15 +144,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.RawSignatureValues(); r == nil {
- return nil, fmt.Errorf("server returned transaction without signature")
+ return nil, false, errors.New("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.
diff --git a/interfaces.go b/interfaces.go
index aab0e2029c..c9a2e40a73 100644
--- a/interfaces.go
+++ b/interfaces.go
@@ -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)
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index a25eff5ed8..ba918700ee 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -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
}
@@ -279,13 +204,17 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs
tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data))
}
- signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
+ head, err := s.b.HeaderByNumber(ctx, nil)
+ if err != nil {
+ return common.Hash{}, err
+ }
+ signer := types.MakeSigner(s.b.ChainConfig(), head.Number)
signature, err := s.am.SignWithPassphrase(args.From, passwd, signer.Hash(tx).Bytes())
if err != nil {
return common.Hash{}, err
}
- return submitTransaction(ctx, s.b, tx, signature)
+ return submitTransaction(ctx, s.b, tx, signer, signature)
}
// signHash is a helper function that calculates a hash for the given message that can be
@@ -367,28 +296,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"} {
@@ -400,12 +317,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
}
@@ -413,7 +345,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) {
@@ -421,7 +353,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
}
@@ -429,7 +361,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) {
@@ -437,14 +369,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
@@ -452,60 +384,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"`
@@ -513,66 +463,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
- gas, gasPrice := args.Gas.BigInt(), args.GasPrice.BigInt()
- if gas.Cmp(common.Big0) == 0 {
- gas = big.NewInt(50000000)
- }
- if gasPrice.Cmp(common.Big0) == 0 {
- gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
- }
- msg := types.NewMessage(addr, args.To, 0, args.Value.BigInt(), gas, gasPrice, common.FromHex(args.Data), false)
-
- // 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
}
@@ -632,7 +559,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),
@@ -645,7 +572,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),
@@ -656,22 +583,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
@@ -705,14 +625,20 @@ 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 {
var signer types.Signer = types.FrontierSigner{}
if tx.Protected() {
signer = types.NewEIP155Signer(tx.ChainId())
}
from, _ := types.Sender(signer, tx)
- v, r, s := types.SignatureValues(signer, tx)
+ v, r, s := tx.RawSignatureValues()
return &RPCTransaction{
From: from,
Gas: rpc.NewHexNumber(tx.Gas()),
@@ -729,34 +655,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]
- var signer types.Signer = types.FrontierSigner{}
- if tx.Protected() {
- signer = types.NewEIP155Signer(tx.ChainId())
- }
- from, _ := types.Sender(signer, tx)
- v, r, s := tx.RawSignatureValues()
- 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.
@@ -765,18 +670,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
}
@@ -790,27 +683,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
@@ -818,31 +693,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
@@ -850,7 +726,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
@@ -858,11 +734,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
}
@@ -892,82 +773,57 @@ 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("can't find receipt 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)
+ glog.V(logger.Debug).Infof("can't find transaction %s: %v\n", txhash.Hex(), err)
return nil, nil
}
-
var signer types.Signer = types.FrontierSigner{}
if tx.Protected() {
signer = types.NewEIP155Signer(tx.ChainId())
}
- from, _ := types.Sender(signer, tx)
+ from, err := types.Sender(signer, tx)
+ if err != nil {
+ return nil, err
+ }
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),
@@ -976,10 +832,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
}
@@ -987,14 +854,14 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma
}
// sign is a helper function that signs a transaction with the private key of the given address.
-func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
- signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
-
- signature, err := s.b.AccountManager().SignEthereum(addr, signer.Hash(tx).Bytes())
+func (s *PublicTransactionPoolAPI) sign(ctx context.Context, addr common.Address, tx *types.Transaction) ([]byte, types.Signer, error) {
+ head, err := s.b.HeaderByNumber(ctx, nil)
if err != nil {
- return nil, err
+ return nil, nil, err
}
- return tx.WithSignature(signer, signature)
+ signer := types.MakeSigner(s.b.ChainConfig(), head.Number)
+ sig, err := s.b.AccountManager().SignEthereum(addr, signer.Hash(tx).Bytes())
+ return sig, signer, err
}
// SendTxArgs represents the arguments to sumbit a new transaction into the transaction pool.
@@ -1014,7 +881,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
}
@@ -1027,18 +894,11 @@ func prepareSendTxArgs(ctx context.Context, args SendTxArgs, b Backend) (SendTxA
}
// submitTransaction is a helper function that submits tx to txPool and creates a log entry.
-func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, signature []byte) (common.Hash, error) {
- signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number())
-
- signedTx, err := tx.WithSignature(signer, signature)
- if err != nil {
+func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, signer types.Signer, signature []byte) (common.Hash, error) {
+ signedTx := signer.WithSignature(tx, signature)
+ if err := b.SendTransaction(ctx, signedTx); err != nil {
return common.Hash{}, err
}
-
- if err := b.SendTx(ctx, signedTx); err != nil {
- return common.Hash{}, err
- }
-
if signedTx.To() == nil {
from, _ := types.Sender(signer, signedTx)
addr := crypto.CreateAddress(from, signedTx.Nonce())
@@ -1060,7 +920,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
}
@@ -1074,13 +934,17 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data))
}
- signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
+ head, err := s.b.HeaderByNumber(ctx, nil)
+ if err != nil {
+ return common.Hash{}, err
+ }
+ signer := types.MakeSigner(s.b.ChainConfig(), head.Number)
signature, err := s.b.AccountManager().SignEthereum(args.From, signer.Hash(tx).Bytes())
if err != nil {
return common.Hash{}, err
}
- return submitTransaction(ctx, s.b, tx, signature)
+ return submitTransaction(ctx, s.b, tx, signer, signature)
}
// SendRawTransaction will add the signed transaction to the transaction pool.
@@ -1090,23 +954,9 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
if err := rlp.DecodeBytes(common.FromHex(encodedTx), tx); err != nil {
return "", err
}
-
- if err := s.b.SendTx(ctx, tx); err != nil {
+ if err := s.b.SendTransaction(ctx, tx); err != nil {
return "", err
}
-
- signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
- if tx.To() == nil {
- from, err := types.Sender(signer, tx)
- if err != nil {
- return "", err
- }
- addr := crypto.CreateAddress(from, tx.Nonce())
- glog.V(logger.Info).Infof("Tx(%x) created: %x\n", tx.Hash(), addr)
- } else {
- glog.V(logger.Info).Infof("Tx(%x) to: %x\n", tx.Hash(), tx.To())
- }
-
return tx.Hash().Hex(), nil
}
@@ -1233,7 +1083,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
}
@@ -1244,7 +1094,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
}
@@ -1258,11 +1108,11 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sig
tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data))
}
- signedTx, err := s.sign(args.From, tx)
+ signature, signer, err := s.sign(ctx, args.From, tx)
if err != nil {
return nil, err
}
-
+ signedTx := signer.WithSignature(tx, signature)
data, err := rlp.EncodeToBytes(signedTx)
if err != nil {
return nil, err
@@ -1274,7 +1124,7 @@ 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 {
var signer types.Signer = types.HomesteadSigner{}
@@ -1283,7 +1133,7 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() []*RPCTransaction {
}
from, _ := types.Sender(signer, tx)
if s.b.AccountManager().HasAddress(from) {
- transactions = append(transactions, newRPCPendingTransaction(tx))
+ transactions = append(transactions, newRPCTransaction(tx))
}
}
return transactions
@@ -1292,7 +1142,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 {
var signer types.Signer = types.HomesteadSigner{}
if p.Protected() {
@@ -1314,17 +1164,14 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, tx Tx, gasPrice,
newTx = types.NewTransaction(tx.tx.Nonce(), *tx.tx.To(), tx.tx.Value(), gasLimit.BigInt(), gasPrice.BigInt(), tx.tx.Data())
}
- signedTx, err := s.sign(tx.From, newTx)
+ signature, signer, err := s.sign(ctx, tx.From, newTx)
if err != nil {
return common.Hash{}, err
}
+ newTx = signer.WithSignature(newTx, signature)
- s.b.RemoveTx(tx.Hash)
- if err = s.b.SendTx(ctx, signedTx); err != nil {
- return common.Hash{}, err
- }
-
- return signedTx.Hash(), nil
+ s.b.RemoveTransaction(tx.Hash)
+ return submitTransaction(ctx, s.b, newTx, signer, signature)
}
}
@@ -1344,8 +1191,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)
}
@@ -1357,8 +1204,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)
}
@@ -1367,10 +1214,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
@@ -1378,21 +1221,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 {
@@ -1407,7 +1251,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 {
@@ -1426,7 +1270,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
diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go
index fdc4a39dc8..7c52e311b2 100644
--- a/internal/ethapi/backend.go
+++ b/internal/ethapi/backend.go
@@ -20,56 +20,46 @@ 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/params"
"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
- 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)
+ ethereum.ChainReader
+ ethereum.ChainStateReader
+ ethereum.ChainSyncReader
+ ethereum.TransactionSender
+ ethereum.GasPricer
+ ethereum.GasEstimator
+ ethereum.ContractCaller
+ ProtocolVersion() int
ChainConfig() *params.ChainConfig
- CurrentBlock() *types.Block
+ 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 {
@@ -90,20 +80,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",
diff --git a/internal/ethapi/txpool.go b/internal/ethapi/txpool.go
new file mode 100644
index 0000000000..1f458edf54
--- /dev/null
+++ b/internal/ethapi/txpool.go
@@ -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 .
+
+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
+}
diff --git a/les/api_backend.go b/les/api_backend.go
index b77767ed70..413784c9a5 100644
--- a/les/api_backend.go
+++ b/les/api_backend.go
@@ -17,137 +17,208 @@
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"
"github.com/ethereum/go-ethereum/params"
- 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) ChainConfig() *params.ChainConfig {
- return b.eth.chainConfig
-}
-
-func (b *LesApiBackend) CurrentBlock() *types.Block {
- return types.NewBlockWithHeader(b.eth.BlockChain().CurrentHeader())
-}
-
-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, vm.Config{})
- 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
+}
+
+// ChainConfig returns the active chain configuration.
+func (eth *LightEthereum) ChainConfig() *params.ChainConfig {
+ return eth.chainConfig
+}
+
+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{})
+ })
}
diff --git a/les/backend.go b/les/backend.go
index 1264acfd18..ea260a8a28 100644
--- a/les/backend.go
+++ b/les/backend.go
@@ -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
@@ -120,8 +120,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
}
@@ -149,9 +149,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{},
@@ -159,17 +163,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,
},
}...)
@@ -179,11 +188,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 {
diff --git a/les/server.go b/les/server.go
index c763e8c632..924bf7c800 100644
--- a/les/server.go
+++ b/les/server.go
@@ -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
}
diff --git a/light/txpool.go b/light/txpool.go
index 309bc3a322..ef0947b05a 100644
--- a/light/txpool.go
+++ b/light/txpool.go
@@ -325,12 +325,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.
diff --git a/mobile/ethclient.go b/mobile/ethclient.go
index 668d65e322..002de5fcdf 100644
--- a/mobile/ethclient.go
+++ b/mobile/ethclient.go
@@ -73,7 +73,8 @@ func (ec *EthereumClient) GetHeaderByNumber(ctx *Context, number int64) (*Header
// GetTransactionByHash returns the transaction with the given hash.
func (ec *EthereumClient) GetTransactionByHash(ctx *Context, hash *Hash) (*Transaction, error) {
- tx, err := ec.client.TransactionByHash(ctx.context, hash.hash)
+ // TODO(karalabe): use isPending result
+ tx, _, err := ec.client.TransactionByHash(ctx.context, hash.hash)
return &Transaction{tx}, err
}
diff --git a/mobile/types.go b/mobile/types.go
index bb5ccc6251..6382f43671 100644
--- a/mobile/types.go
+++ b/mobile/types.go
@@ -154,9 +154,9 @@ func (tx *Transaction) GetTo() *Address {
return nil
}
-func (tx *Transaction) WithSignature(sig []byte) (*Transaction, error) {
- t, err := tx.tx.WithSignature(types.HomesteadSigner{}, sig)
- return &Transaction{t}, err
+func (tx *Transaction) WithSignature(sig []byte) *Transaction {
+ t := tx.tx.WithSignature(types.HomesteadSigner{}, sig)
+ return &Transaction{t}
}
// Transactions represents a slice of transactions.