You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
5.1 KiB
135 lines
5.1 KiB
6 years ago
|
package hmyapi
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
|
||
|
"github.com/ethereum/go-ethereum/common"
|
||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||
|
"github.com/ethereum/go-ethereum/rlp"
|
||
|
"github.com/ethereum/go-ethereum/rpc"
|
||
|
"github.com/harmony-one/harmony/accounts"
|
||
|
"github.com/harmony-one/harmony/core"
|
||
|
"github.com/harmony-one/harmony/core/rawdb"
|
||
|
"github.com/harmony-one/harmony/core/types"
|
||
|
)
|
||
|
|
||
|
// PublicTransactionPoolAPI exposes methods for the RPC interface
|
||
|
type PublicTransactionPoolAPI struct {
|
||
|
b *core.HmyAPIBackend
|
||
|
nonceLock *AddrLocker
|
||
|
}
|
||
|
|
||
|
// NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool.
|
||
|
func NewPublicTransactionPoolAPI(b *core.HmyAPIBackend, nonceLock *AddrLocker) *PublicTransactionPoolAPI {
|
||
|
return &PublicTransactionPoolAPI{b, nonceLock}
|
||
|
}
|
||
|
|
||
|
// 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 {
|
||
|
n := hexutil.Uint(len(block.Transactions()))
|
||
|
return &n
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash.
|
||
|
func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint {
|
||
|
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil {
|
||
|
n := hexutil.Uint(len(block.Transactions()))
|
||
|
return &n
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// 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 {
|
||
|
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
|
||
|
return newRPCTransactionFromBlockIndex(block, uint64(index))
|
||
|
}
|
||
|
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 {
|
||
|
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil {
|
||
|
return newRPCTransactionFromBlockIndex(block, uint64(index))
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// GetTransactionByHash returns the transaction for the given hash
|
||
|
func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) *RPCTransaction {
|
||
|
// Try to return an already finalized transaction
|
||
|
if tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.b.ChainDb(), hash); tx != nil {
|
||
|
return newRPCTransaction(tx, blockHash, blockNumber, index)
|
||
|
}
|
||
|
// No finalized transaction, try to retrieve it from the pool
|
||
|
if tx := s.b.GetPoolTransaction(hash); tx != nil {
|
||
|
return newRPCPendingTransaction(tx)
|
||
|
}
|
||
|
// Transaction unknown, return as such
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// 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) (*hexutil.Uint64, error) {
|
||
|
// Ask transaction pool for the nonce which includes pending transactions
|
||
|
if blockNr == rpc.PendingBlockNumber {
|
||
|
nonce, err := s.b.GetPoolNonce(ctx, address)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return (*hexutil.Uint64)(&nonce), nil
|
||
|
}
|
||
|
// Resolve block number and use its state to ask for the nonce
|
||
|
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
|
||
|
if state == nil || err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
nonce := state.GetNonce(address)
|
||
|
return (*hexutil.Uint64)(&nonce), state.Error()
|
||
|
}
|
||
|
|
||
|
// SendTransaction creates a transaction for the given argument, sign it and submit it to the
|
||
|
// transaction pool.
|
||
|
func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args SendTxArgs) (common.Hash, error) {
|
||
|
// Look up the wallet containing the requested signer
|
||
|
account := accounts.Account{Address: args.From}
|
||
|
|
||
|
wallet, err := s.b.AccountManager().Find(account)
|
||
|
if err != nil {
|
||
|
return common.Hash{}, err
|
||
|
}
|
||
|
|
||
|
if args.Nonce == nil {
|
||
|
// Hold the addresse's mutex around signing to prevent concurrent assignment of
|
||
|
// the same nonce to multiple accounts.
|
||
|
s.nonceLock.LockAddr(args.From)
|
||
|
defer s.nonceLock.UnlockAddr(args.From)
|
||
|
}
|
||
|
|
||
|
// Set some sanity defaults and terminate on failure
|
||
|
if err := args.setDefaults(ctx, s.b); err != nil {
|
||
|
return common.Hash{}, err
|
||
|
}
|
||
|
// Assemble the transaction and sign with the wallet
|
||
|
tx := args.toTransaction()
|
||
|
|
||
|
signed, err := wallet.SignTx(account, tx, s.b.ChainConfig().ChainID)
|
||
|
if err != nil {
|
||
|
return common.Hash{}, err
|
||
|
}
|
||
|
return SubmitTransaction(ctx, s.b, signed)
|
||
|
}
|
||
|
|
||
|
// 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) (common.Hash, error) {
|
||
|
tx := new(types.Transaction)
|
||
|
if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
|
||
|
return common.Hash{}, err
|
||
|
}
|
||
|
return SubmitTransaction(ctx, s.b, tx)
|
||
|
}
|