aboutsummaryrefslogtreecommitdiffstats
path: root/internal/ethapi/api.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/ethapi/api.go')
-rw-r--r--internal/ethapi/api.go415
1 files changed, 168 insertions, 247 deletions
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index da5dc5d58..59a29d722 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -17,7 +17,6 @@
package ethapi
import (
- "bytes"
"context"
"errors"
"fmt"
@@ -35,7 +34,6 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params"
@@ -48,7 +46,6 @@ import (
const (
defaultGas = 90000
defaultGasPrice = 50 * params.Shannon
- emptyHex = "0x"
)
// PublicEthereumAPI provides an API to access Ethereum related information.
@@ -57,7 +54,7 @@ type PublicEthereumAPI struct {
b Backend
}
-// NewPublicEthereumAPI creates a new Etheruem protocol API.
+// NewPublicEthereumAPI creates a new Ethereum protocol API.
func NewPublicEthereumAPI(b Backend) *PublicEthereumAPI {
return &PublicEthereumAPI{b}
}
@@ -233,22 +230,45 @@ func (s *PrivateAccountAPI) ListAccounts() []common.Address {
type rawWallet struct {
URL string `json:"url"`
Status string `json:"status"`
- Accounts []accounts.Account `json:"accounts"`
+ Failure string `json:"failure,omitempty"`
+ Accounts []accounts.Account `json:"accounts,omitempty"`
}
// ListWallets will return a list of wallets this node manages.
func (s *PrivateAccountAPI) ListWallets() []rawWallet {
wallets := make([]rawWallet, 0) // return [] instead of nil if empty
for _, wallet := range s.am.Wallets() {
- wallets = append(wallets, rawWallet{
+ status, failure := wallet.Status()
+
+ raw := rawWallet{
URL: wallet.URL().String(),
- Status: wallet.Status(),
+ Status: status,
Accounts: wallet.Accounts(),
- })
+ }
+ if failure != nil {
+ raw.Failure = failure.Error()
+ }
+ wallets = append(wallets, raw)
}
return wallets
}
+// OpenWallet initiates a hardware wallet opening procedure, establishing a USB
+// connection and attempting to authenticate via the provided passphrase. Note,
+// the method may return an extra challenge requiring a second open (e.g. the
+// Trezor PIN matrix challenge).
+func (s *PrivateAccountAPI) OpenWallet(url string, passphrase *string) error {
+ wallet, err := s.am.Wallet(url)
+ if err != nil {
+ return err
+ }
+ pass := ""
+ if passphrase != nil {
+ pass = *passphrase
+ }
+ return wallet.Open(pass)
+}
+
// DeriveAccount requests a HD wallet to derive a new account, optionally pinning
// it for later reuse.
func (s *PrivateAccountAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) {
@@ -428,7 +448,7 @@ type PublicBlockChainAPI struct {
b Backend
}
-// NewPublicBlockChainAPI creates a new Etheruem blockchain API.
+// NewPublicBlockChainAPI creates a new Ethereum blockchain API.
func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI {
return &PublicBlockChainAPI{b}
}
@@ -447,8 +467,8 @@ func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Add
if state == nil || err != nil {
return nil, err
}
-
- return state.GetBalance(ctx, address)
+ b := state.GetBalance(address)
+ return b, state.Error()
}
// GetBlockByNumber returns the requested block. When blockNr is -1 the chain head is returned. When fullTx is true all
@@ -529,53 +549,27 @@ func (s *PublicBlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, bloc
}
// 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) {
+func (s *PublicBlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (hexutil.Bytes, error) {
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
if state == nil || err != nil {
- return "", err
- }
- res, err := state.GetCode(ctx, address)
- if len(res) == 0 || err != nil { // backwards compatibility
- return "0x", err
+ return nil, err
}
- return common.ToHex(res), nil
+ code := state.GetCode(address)
+ return code, state.Error()
}
// 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) {
+func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNr rpc.BlockNumber) (hexutil.Bytes, error) {
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
if state == nil || err != nil {
- return "0x", err
- }
- res, err := state.GetState(ctx, address, common.HexToHash(key))
- if err != nil {
- return "0x", err
+ return nil, err
}
- return res.Hex(), nil
-}
-
-// callmsg is the message type used for call transitions.
-type callmsg struct {
- addr common.Address
- to *common.Address
- gas, gasPrice *big.Int
- value *big.Int
- data []byte
+ res := state.GetState(address, common.HexToHash(key))
+ return res[:], state.Error()
}
-// 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"`
@@ -586,12 +580,12 @@ type CallArgs struct {
Data hexutil.Bytes `json:"data"`
}
-func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config) ([]byte, *big.Int, error) {
+func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config) ([]byte, *big.Int, bool, error) {
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
if state == nil || err != nil {
- return nil, common.Big0, err
+ return nil, common.Big0, false, err
}
// Set sender address or use a default if none specified
addr := args.From
@@ -629,39 +623,42 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
// Get a new instance of the EVM.
evm, vmError, err := s.b.GetEVM(ctx, msg, state, header, vmCfg)
if err != nil {
- return nil, common.Big0, err
+ return nil, common.Big0, false, err
}
// Wait for the context to be done and cancel the evm. Even if the
// EVM has finished, cancelling may be done (repeatedly)
go func() {
- select {
- case <-ctx.Done():
- evm.Cancel()
- }
+ <-ctx.Done()
+ evm.Cancel()
}()
// Setup the gas pool (also for unmetered requests)
// and apply the message.
gp := new(core.GasPool).AddGas(math.MaxBig256)
- res, gas, err := core.ApplyMessage(evm, msg, gp)
+ res, gas, failed, err := core.ApplyMessage(evm, msg, gp)
if err := vmError(); err != nil {
- return nil, common.Big0, err
+ return nil, common.Big0, false, err
}
- return res, gas, err
+ return res, gas, failed, 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 useful to execute and retrieve values.
func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Bytes, error) {
- result, _, err := s.doCall(ctx, args, blockNr, vm.Config{DisableGasMetering: true})
+ result, _, _, err := s.doCall(ctx, args, blockNr, vm.Config{DisableGasMetering: true})
return (hexutil.Bytes)(result), err
}
-// EstimateGas returns an estimate of the amount of gas needed to execute the given transaction.
+// EstimateGas returns an estimate of the amount of gas needed to execute the
+// given transaction against the current pending block.
func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*hexutil.Big, error) {
- // Binary search the gas requirement, as it may be higher than the amount used
- var lo, hi uint64
- if (*big.Int)(&args.Gas).Sign() != 0 {
+ // Determine the lowest and highest possible gas limits to binary search in between
+ var (
+ lo uint64 = params.TxGas - 1
+ hi uint64
+ cap uint64
+ )
+ if (*big.Int)(&args.Gas).Uint64() >= params.TxGas {
hi = (*big.Int)(&args.Gas).Uint64()
} else {
// Retrieve the current pending block to act as the gas ceiling
@@ -671,29 +668,41 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*
}
hi = block.GasLimit().Uint64()
}
+ cap = hi
+
+ // Create a helper to check if a gas allowance results in an executable transaction
+ executable := func(gas uint64) bool {
+ (*big.Int)(&args.Gas).SetUint64(gas)
+ _, _, failed, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{})
+ if err != nil || failed {
+ return false
+ }
+ return true
+ }
+ // Execute the binary search and hone in on an executable gas limit
for lo+1 < hi {
- // Take a guess at the gas, and check transaction validity
mid := (hi + lo) / 2
- (*big.Int)(&args.Gas).SetUint64(mid)
-
- _, gas, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{})
-
- // If the transaction became invalid or used all the gas (failed), raise the gas limit
- if err != nil || gas.Cmp((*big.Int)(&args.Gas)) == 0 {
+ if !executable(mid) {
lo = mid
- continue
+ } else {
+ hi = mid
+ }
+ }
+ // Reject the transaction as invalid if it still fails at the highest allowance
+ if hi == cap {
+ if !executable(hi) {
+ return nil, fmt.Errorf("gas required exceeds allowance or always failing transaction")
}
- // Otherwise assume the transaction succeeded, lower the gas limit
- hi = mid
}
return (*hexutil.Big)(new(big.Int).SetUint64(hi)), nil
}
// ExecutionResult groups all structured logs emitted by the EVM
-// while replaying a transaction in debug mode as well as the amount of
-// gas used and the return value
+// while replaying a transaction in debug mode as well as transaction
+// execution status, the amount of gas used and the return value
type ExecutionResult struct {
Gas *big.Int `json:"gas"`
+ Failed bool `json:"failed"`
ReturnValue string `json:"returnValue"`
StructLogs []StructLogRes `json:"structLogs"`
}
@@ -775,7 +784,7 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx
if fullTx {
formatTx = func(tx *types.Transaction) (interface{}, error) {
- return newRPCTransaction(b, tx.Hash())
+ return newRPCTransactionFromBlockHash(b, tx.Hash()), nil
}
}
@@ -818,15 +827,17 @@ type RPCTransaction struct {
S *hexutil.Big `json:"s"`
}
-// newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation
-func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction {
+// newRPCTransaction returns a transaction that will serialize to the RPC
+// representation, with the given location metadata set (if available).
+func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) *RPCTransaction {
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{
+
+ result := &RPCTransaction{
From: from,
Gas: (*hexutil.Big)(tx.Gas()),
GasPrice: (*hexutil.Big)(tx.GasPrice()),
@@ -839,58 +850,46 @@ func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction {
R: (*hexutil.Big)(r),
S: (*hexutil.Big)(s),
}
+ if blockHash != (common.Hash{}) {
+ result.BlockHash = blockHash
+ result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
+ result.TransactionIndex = hexutil.Uint(index)
+ }
+ return result
}
-// newRPCTransaction returns a transaction that will serialize to the RPC representation.
-func newRPCTransactionFromBlockIndex(b *types.Block, txIndex uint) (*RPCTransaction, error) {
- if txIndex < uint(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: (*hexutil.Big)(b.Number()),
- From: from,
- Gas: (*hexutil.Big)(tx.Gas()),
- GasPrice: (*hexutil.Big)(tx.GasPrice()),
- Hash: tx.Hash(),
- Input: hexutil.Bytes(tx.Data()),
- Nonce: hexutil.Uint64(tx.Nonce()),
- To: tx.To(),
- TransactionIndex: hexutil.Uint(txIndex),
- Value: (*hexutil.Big)(tx.Value()),
- V: (*hexutil.Big)(v),
- R: (*hexutil.Big)(r),
- S: (*hexutil.Big)(s),
- }, nil
- }
-
- return nil, nil
+// newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation
+func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction {
+ return newRPCTransaction(tx, common.Hash{}, 0, 0)
}
-// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index.
-func newRPCRawTransactionFromBlockIndex(b *types.Block, txIndex uint) (hexutil.Bytes, error) {
- if txIndex < uint(len(b.Transactions())) {
- tx := b.Transactions()[txIndex]
- return rlp.EncodeToBytes(tx)
+// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation.
+func newRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransaction {
+ txs := b.Transactions()
+ if index >= uint64(len(txs)) {
+ return nil
}
+ return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index)
+}
- return nil, nil
+// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index.
+func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.Bytes {
+ txs := b.Transactions()
+ if index >= uint64(len(txs)) {
+ return nil
+ }
+ blob, _ := rlp.EncodeToBytes(txs[index])
+ return blob
}
-// newRPCTransaction returns a transaction that will serialize to the RPC representation.
-func newRPCTransaction(b *types.Block, txHash common.Hash) (*RPCTransaction, error) {
+// newRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation.
+func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransaction {
for idx, tx := range b.Transactions() {
- if tx.Hash() == txHash {
- return newRPCTransactionFromBlockIndex(b, uint(idx))
+ if tx.Hash() == hash {
+ return newRPCTransactionFromBlockIndex(b, uint64(idx))
}
}
-
- return nil, nil
+ return nil
}
// PublicTransactionPoolAPI exposes methods for the RPC interface
@@ -904,24 +903,6 @@ func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransa
return &PublicTransactionPoolAPI{b, nonceLock}
}
-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) *hexutil.Uint {
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
@@ -941,35 +922,35 @@ func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Co
}
// GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index.
-func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (*RPCTransaction, error) {
+func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction {
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
- return newRPCTransactionFromBlockIndex(block, uint(index))
+ return newRPCTransactionFromBlockIndex(block, uint64(index))
}
- 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 hexutil.Uint) (*RPCTransaction, error) {
+func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction {
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil {
- return newRPCTransactionFromBlockIndex(block, uint(index))
+ return newRPCTransactionFromBlockIndex(block, uint64(index))
}
- 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 hexutil.Uint) (hexutil.Bytes, error) {
+func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) hexutil.Bytes {
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
- return newRPCRawTransactionFromBlockIndex(block, uint(index))
+ return newRPCRawTransactionFromBlockIndex(block, uint64(index))
}
- return nil, nil
+ return nil
}
// 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 hexutil.Uint) (hexutil.Bytes, error) {
+func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) hexutil.Bytes {
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil {
- return newRPCRawTransactionFromBlockIndex(block, uint(index))
+ return newRPCRawTransactionFromBlockIndex(block, uint64(index))
}
- return nil, nil
+ return nil
}
// GetTransactionCount returns the number of transactions the given address has sent for the given block number
@@ -978,97 +959,46 @@ func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, addr
if state == nil || err != nil {
return nil, err
}
- nonce, err := state.GetNonce(ctx, address)
- if err != nil {
- return nil, err
- }
- return (*hexutil.Uint64)(&nonce), nil
-}
-
-// getTransactionBlockData fetches the meta data for the given transaction from the chain database. This is useful to
-// retrieve block information for a hash. It returns the block hash, block index and transaction index.
-func getTransactionBlockData(chainDb ethdb.Database, txHash common.Hash) (common.Hash, uint64, uint64, error) {
- var txBlock struct {
- BlockHash common.Hash
- BlockIndex uint64
- Index uint64
- }
-
- blockData, err := chainDb.Get(append(txHash.Bytes(), 0x0001))
- if err != nil {
- return common.Hash{}, uint64(0), uint64(0), err
- }
-
- reader := bytes.NewReader(blockData)
- if err = rlp.Decode(reader, &txBlock); err != nil {
- return common.Hash{}, uint64(0), uint64(0), err
- }
-
- return txBlock.BlockHash, txBlock.BlockIndex, txBlock.Index, nil
+ nonce := state.GetNonce(address)
+ return (*hexutil.Uint64)(&nonce), state.Error()
}
// GetTransactionByHash returns the transaction for the given hash
-func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) {
- var tx *types.Transaction
- var isPending bool
- var err error
-
- if tx, isPending, err = getTransaction(s.b.ChainDb(), s.b, hash); err != nil {
- log.Debug("Failed to retrieve transaction", "hash", hash, "err", err)
- return nil, nil
- } else if tx == nil {
- return nil, nil
+func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) *RPCTransaction {
+ // Try to return an already finalized transaction
+ if tx, blockHash, blockNumber, index := core.GetTransaction(s.b.ChainDb(), hash); tx != nil {
+ return newRPCTransaction(tx, blockHash, blockNumber, index)
}
- if isPending {
- return newRPCPendingTransaction(tx), nil
+ // No finalized transaction, try to retrieve it from the pool
+ if tx := s.b.GetPoolTransaction(hash); tx != nil {
+ return newRPCPendingTransaction(tx)
}
-
- blockHash, _, _, err := getTransactionBlockData(s.b.ChainDb(), hash)
- if err != nil {
- log.Debug("Failed to retrieve transaction block", "hash", hash, "err", err)
- return nil, nil
- }
-
- if block, _ := s.b.GetBlock(ctx, blockHash); block != nil {
- return newRPCTransaction(block, hash)
- }
- return nil, nil
+ // Transaction unknown, return as such
+ return nil
}
// GetRawTransactionByHash returns the bytes of the transaction for the given hash.
func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
var tx *types.Transaction
- var err error
- if tx, _, err = getTransaction(s.b.ChainDb(), s.b, hash); err != nil {
- log.Debug("Failed to retrieve transaction", "hash", hash, "err", err)
- return nil, nil
- } else if tx == nil {
- return nil, nil
+ // Retrieve a finalized transaction, or a pooled otherwise
+ if tx, _, _, _ = core.GetTransaction(s.b.ChainDb(), hash); tx == nil {
+ if tx = s.b.GetPoolTransaction(hash); tx == nil {
+ // Transaction not found anywhere, abort
+ return nil, nil
+ }
}
-
+ // Serialize to RLP and return
return rlp.EncodeToBytes(tx)
}
// GetTransactionReceipt returns the transaction receipt for the given transaction hash.
func (s *PublicTransactionPoolAPI) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) {
- receipt := core.GetReceipt(s.b.ChainDb(), hash)
- if receipt == nil {
- log.Debug("Receipt not found for transaction", "hash", hash)
- return nil, nil
- }
-
- tx, _, err := getTransaction(s.b.ChainDb(), s.b, hash)
- if err != nil {
- log.Debug("Failed to retrieve transaction", "hash", hash, "err", err)
- return nil, nil
- }
-
- txBlock, blockIndex, index, err := getTransactionBlockData(s.b.ChainDb(), hash)
- if err != nil {
- log.Debug("Failed to retrieve transaction block", "hash", hash, "err", err)
+ tx, blockHash, blockNumber, index := core.GetTransaction(s.b.ChainDb(), hash)
+ if tx == nil {
return nil, nil
}
+ receipt, _, _, _ := core.GetReceipt(s.b.ChainDb(), hash) // Old receipts don't have the lookup data available
var signer types.Signer = types.FrontierSigner{}
if tx.Protected() {
@@ -1077,9 +1007,8 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(hash common.Hash) (map[
from, _ := types.Sender(signer, tx)
fields := map[string]interface{}{
- "root": hexutil.Bytes(receipt.PostState),
- "blockHash": txBlock,
- "blockNumber": hexutil.Uint64(blockIndex),
+ "blockHash": blockHash,
+ "blockNumber": hexutil.Uint64(blockNumber),
"transactionHash": hash,
"transactionIndex": hexutil.Uint64(index),
"from": from,
@@ -1090,6 +1019,13 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(hash common.Hash) (map[
"logs": receipt.Logs,
"logsBloom": receipt.Bloom,
}
+
+ // Assign receipt status or post state.
+ if len(receipt.PostState) > 0 {
+ fields["root"] = hexutil.Bytes(receipt.PostState)
+ } else {
+ fields["status"] = hexutil.Uint(receipt.Status)
+ }
if receipt.Logs == nil {
fields["logs"] = [][]*types.Log{}
}
@@ -1167,7 +1103,10 @@ func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (c
}
if tx.To() == nil {
signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number())
- from, _ := types.Sender(signer, tx)
+ from, err := types.Sender(signer, tx)
+ if err != nil {
+ return common.Hash{}, err
+ }
addr := crypto.CreateAddress(from, tx.Nonce())
log.Info("Submitted contract creation", "fullhash", tx.Hash().Hex(), "contract", addr.Hex())
} else {
@@ -1215,29 +1154,12 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
// SendRawTransaction will add the signed transaction to the transaction pool.
// The sender is responsible for signing the transaction and using the correct nonce.
-func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx hexutil.Bytes) (string, error) {
+func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx hexutil.Bytes) (common.Hash, error) {
tx := new(types.Transaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
- return "", err
- }
-
- if err := s.b.SendTx(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())
- log.Info("Submitted contract creation", "fullhash", tx.Hash().Hex(), "contract", addr.Hex())
- } else {
- log.Info("Submitted transaction", "fullhash", tx.Hash().Hex(), "recipient", tx.To())
+ return common.Hash{}, err
}
-
- return tx.Hash().Hex(), nil
+ return submitTransaction(ctx, s.b, tx)
}
// Sign calculates an ECDSA signature for:
@@ -1351,7 +1273,6 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr
if err != nil {
return common.Hash{}, err
}
- s.b.RemoveTx(p.Hash())
if err = s.b.SendTx(ctx, signedTx); err != nil {
return common.Hash{}, err
}
@@ -1362,7 +1283,7 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr
return common.Hash{}, fmt.Errorf("Transaction %#x not found", matchTx.Hash())
}
-// PublicDebugAPI is the collection of Etheruem APIs exposed over the public
+// PublicDebugAPI is the collection of Ethereum APIs exposed over the public
// debugging endpoint.
type PublicDebugAPI struct {
b Backend
@@ -1393,7 +1314,7 @@ func (api *PublicDebugAPI) PrintBlock(ctx context.Context, number uint64) (strin
if block == nil {
return "", fmt.Errorf("block #%d not found", number)
}
- return fmt.Sprintf("%s", block), nil
+ return block.String(), nil
}
// SeedHash retrieves the seed hash of a block.
@@ -1405,7 +1326,7 @@ func (api *PublicDebugAPI) SeedHash(ctx context.Context, number uint64) (string,
return fmt.Sprintf("0x%x", ethash.SeedHash(number)), 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