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.
223 lines
8.8 KiB
223 lines
8.8 KiB
package hmyapi
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
"github.com/ethereum/go-ethereum/p2p"
|
|
"github.com/harmony-one/harmony/api/proto"
|
|
"github.com/harmony-one/harmony/core"
|
|
"github.com/harmony-one/harmony/core/rawdb"
|
|
"github.com/harmony-one/harmony/core/types"
|
|
"github.com/harmony-one/harmony/rpc"
|
|
)
|
|
|
|
// PublicBlockChainAPI provides an API to access the Harmony blockchain.
|
|
// It offers only methods that operate on public data that is freely available to anyone.
|
|
type PublicBlockChainAPI struct {
|
|
b *rpc.HmyAPIBackend
|
|
}
|
|
|
|
// NewPublicBlockChainAPI creates a new Harmony blockchain API.
|
|
func NewPublicBlockChainAPI(b *rpc.HmyAPIBackend) *PublicBlockChainAPI {
|
|
return &PublicBlockChainAPI{b}
|
|
}
|
|
|
|
// 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)
|
|
if block != nil {
|
|
response, err := RPCMarshalBlock(block, false, false)
|
|
if err == nil && blockNr == rpc.PendingBlockNumber {
|
|
// Pending blocks need to nil out a few fields
|
|
for _, field := range []string{"hash", "nonce", "miner"} {
|
|
response[field] = nil
|
|
}
|
|
}
|
|
return response, err
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
// 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)
|
|
if block != nil {
|
|
return RPCMarshalBlock(block, false, false)
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
// 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() == hash {
|
|
return newRPCTransactionFromBlockIndex(b, uint64(idx))
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
|
|
// 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) (*hexutil.Big, error) {
|
|
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
|
|
if state == nil || err != nil {
|
|
return nil, err
|
|
}
|
|
return (*hexutil.Big)(state.GetBalance(address)), state.Error()
|
|
}
|
|
|
|
// PublicHarmonyAPI provides an API to access Harmony related information.
|
|
// It offers only methods that operate on public data that is freely available to anyone.
|
|
type PublicHarmonyAPI struct {
|
|
b *core.BlockChain
|
|
}
|
|
|
|
// TODO(ricl): update the following two functions.
|
|
|
|
// ProtocolVersion returns the current Harmony protocol version this node supports
|
|
func (s *PublicHarmonyAPI) ProtocolVersion() hexutil.Uint {
|
|
return hexutil.Uint(proto.ProtocolVersion)
|
|
}
|
|
|
|
// Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not
|
|
// yet received the latest block headers from its pears. In case it is synchronizing:
|
|
// - startingBlock: block number this node started to synchronise from
|
|
// - currentBlock: block number this node is currently importing
|
|
// - 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 *PublicHarmonyAPI) Syncing() (interface{}, error) {
|
|
// TODO(ricl): port
|
|
return false, nil
|
|
}
|
|
|
|
// PublicNetAPI offers network related RPC methods
|
|
type PublicNetAPI struct {
|
|
net *p2p.Server
|
|
networkVersion uint64
|
|
}
|
|
|
|
// NewPublicNetAPI creates a new net API instance.
|
|
func NewPublicNetAPI(net *p2p.Server, networkVersion uint64) *PublicNetAPI {
|
|
return &PublicNetAPI{net, networkVersion}
|
|
}
|
|
|
|
// PeerCount returns the number of connected peers
|
|
func (s *PublicNetAPI) PeerCount() hexutil.Uint {
|
|
return hexutil.Uint(s.net.PeerCount())
|
|
}
|
|
|
|
// PublicTransactionPoolAPI exposes methods for the RPC interface
|
|
type PublicTransactionPoolAPI struct {
|
|
b *rpc.HmyAPIBackend
|
|
nonceLock *AddrLocker
|
|
}
|
|
|
|
// NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool.
|
|
func NewPublicTransactionPoolAPI(b *rpc.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
|
|
}
|
|
|
|
// 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) (hexutil.Bytes, error) {
|
|
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
|
|
if state == nil || err != nil {
|
|
return nil, err
|
|
}
|
|
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) (hexutil.Bytes, error) {
|
|
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
|
|
if state == nil || err != nil {
|
|
return nil, err
|
|
}
|
|
res := state.GetState(address, common.HexToHash(key))
|
|
return res[:], state.Error()
|
|
}
|
|
|
|
// 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()
|
|
}
|
|
|