diff options
Diffstat (limited to 'internal/ethapi/api.go')
-rw-r--r-- | internal/ethapi/api.go | 415 |
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 |