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() }