Node API Refactor (Stage 2.1 of Node API Overhaul) (#3244)

* Add latest dir removal for make clean

Fix docker image in README

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmy] Refactor - Expose Harmony attributes & remove accessors

* Add internals for APIBackend & Harmony fuse
* Add skeleton for refactor of GetTotalStakingSnapshot

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmy] Refactor - Re-implement APIBacked methods in Harmony

* Add 'FIXME:done' comments to indicate implemented methods,
some were left out as they are simple accessors and will transition to using
the exposed harmony attributes.
* Split functions into standalone files for clarity.

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmy] Refactor - Fix GetTotalStakingSnapshot in Harmony implementation

Previous implementation used rps.LatestBlockNumber, which is a constant -1,
thus, the cache was never used

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmy] Refactor - Move ErrFinalizedTransaction to hmy.go

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmyapi] Refactor - Make PublicHarmonyAPI use Harmony instead of Backed

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmyapi] Refactor - Make NewPublicBlockChainAPI use Harmony instead of Backend

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmyapi] Refactor - Make NewPublicTransactionPoolAPI use Harmony instead of Backend

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmyapi] Refactor - Make DebugAPI use Harmony instead of Backend

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmyapi] Refactor - Make filers use Harmony instead of Backend

* Fix unhandled errors

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmy] Refactor - Change NetVersion to ChainID

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmyapi] Refactor - Change API service declaration to use Harmony

* Remove irrelevant TODOs

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [node] Refactor - Move harmony create to APIs fetch

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmy] Refactor - Remove api_backend.go & Backend

* Update hmyapi net.go to return ChainID as Version
* Remove unused err return on New Harmony obj

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmy] Refactor - Prettify var names, structure & comments

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmyapi] Refactor - Prettify var names, structure & comments

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmyapi] Refactor - Remove backend interface

* Fix lint

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmy] Refactor - Remove exposure for eventMux and chainDb

This is to satisfy existing interfaces, mainly the in filters.

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmy + hmyapi] Refactor - Fix imports

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmy] Refactor - Apply changes from #3243

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmyapi] Refactor - Make filters use Backend instead of hmy

This is for testing from eth if we need it in the future

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [hmyapi] Refactor - Fix imports

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>
pull/3245/head
Daniel Van Der Maden 4 years ago committed by GitHub
parent a354b93676
commit d4df3aa039
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      Makefile
  2. 4
      README.md
  3. 949
      hmy/api_backend.go
  4. 114
      hmy/backend.go
  5. 244
      hmy/blockchain.go
  6. 202
      hmy/hmy.go
  7. 33
      hmy/network.go
  8. 48
      hmy/pool.go
  9. 476
      hmy/staking.go
  10. 80
      hmy/transaction.go
  11. 99
      internal/hmyapi/apiv1/backend.go
  12. 509
      internal/hmyapi/apiv1/blockchain.go
  13. 7
      internal/hmyapi/apiv1/debug.go
  14. 16
      internal/hmyapi/apiv1/harmony.go
  15. 12
      internal/hmyapi/apiv1/net.go
  16. 21
      internal/hmyapi/apiv1/sendtxargs.go
  17. 75
      internal/hmyapi/apiv1/transactionpool.go
  18. 14
      internal/hmyapi/apiv1/util.go
  19. 95
      internal/hmyapi/apiv2/backend.go
  20. 492
      internal/hmyapi/apiv2/blockchain.go
  21. 7
      internal/hmyapi/apiv2/debug.go
  22. 16
      internal/hmyapi/apiv2/harmony.go
  23. 12
      internal/hmyapi/apiv2/net.go
  24. 83
      internal/hmyapi/apiv2/sendtxargs.go
  25. 75
      internal/hmyapi/apiv2/transactionpool.go
  26. 11
      internal/hmyapi/apiv2/util.go
  27. 105
      internal/hmyapi/backend.go
  28. 19
      internal/hmyapi/filters/api.go
  29. 4
      internal/hmyapi/filters/filter.go
  30. 2
      internal/hmyapi/filters/filter_criteria.go
  31. 25
      internal/hmyapi/filters/filter_system.go
  32. 16
      node/rpc.go

@ -49,6 +49,7 @@ clean:
rm -rf ./tmp_log* rm -rf ./tmp_log*
rm -rf ./.dht* rm -rf ./.dht*
rm -rf ./db-* rm -rf ./db-*
rm -rf ./latest
rm -f ./*.rlp rm -f ./*.rlp
test: test:

@ -72,13 +72,13 @@ make
``` ```
> Run `bash scripts/install_build_tools.sh` to ensure build tools are of correct versions. > Run `bash scripts/install_build_tools.sh` to ensure build tools are of correct versions.
## Dev Docker Container ## Dev Docker Image
Included in this repo is a Dockerfile that has a full harmony development environment and Included in this repo is a Dockerfile that has a full harmony development environment and
comes with emacs, vim, ag, tig and other creature comforts. Most importantly, it already has the go environment comes with emacs, vim, ag, tig and other creature comforts. Most importantly, it already has the go environment
with our C/C++ based library dependencies (`libbls` and `mcl`) set up correctly for you. with our C/C++ based library dependencies (`libbls` and `mcl`) set up correctly for you.
You can build the docker container for yourself with the following commands: You can build the docker image for yourself with the following commands:
```bash ```bash
cd $(go env GOPATH)/src/github.com/harmony-one/harmony cd $(go env GOPATH)/src/github.com/harmony-one/harmony
make clean make clean

@ -1,949 +0,0 @@
package hmy
import (
"context"
"fmt"
"math/big"
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/api/proto"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/consensus/quorum"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/rawdb"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/crypto/bls"
internal_bls "github.com/harmony-one/harmony/crypto/bls"
internal_common "github.com/harmony-one/harmony/internal/common"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/numeric"
"github.com/harmony-one/harmony/shard"
"github.com/harmony-one/harmony/shard/committee"
"github.com/harmony-one/harmony/staking/availability"
"github.com/harmony-one/harmony/staking/effective"
"github.com/harmony-one/harmony/staking/network"
staking "github.com/harmony-one/harmony/staking/types"
lru "github.com/hashicorp/golang-lru"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/pkg/errors"
"golang.org/x/sync/singleflight"
)
var (
// ErrFinalizedTransaction is returned if the transaction to be submitted is already on-chain
ErrFinalizedTransaction = errors.New("transaction already finalized")
)
// APIBackend An implementation of internal/hmyapi/Backend. Full client.
type APIBackend struct {
hmy *Harmony
TotalStakingCache struct {
sync.Mutex
BlockHeight int64
TotalStaking *big.Int
}
apiCache singleflight.Group
LeaderCache *lru.Cache
}
// SingleFlightRequest ...
func (b *APIBackend) SingleFlightRequest(
key string,
fn func() (interface{}, error),
) (interface{}, error) {
res, err, _ := b.apiCache.Do(key, fn)
return res, err
}
// SingleFlightForgetKey ...
func (b *APIBackend) SingleFlightForgetKey(key string) {
b.apiCache.Forget(key)
}
// ChainDb ...
func (b *APIBackend) ChainDb() ethdb.Database {
return b.hmy.chainDb
}
// GetBlock ...
func (b *APIBackend) GetBlock(ctx context.Context, hash common.Hash) (*types.Block, error) {
return b.hmy.blockchain.GetBlockByHash(hash), nil
}
// GetPoolTransaction ...
func (b *APIBackend) GetPoolTransaction(hash common.Hash) types.PoolTransaction {
return b.hmy.txPool.Get(hash)
}
// BlockByNumber ...
func (b *APIBackend) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error) {
// Pending block is only known by the miner
if blockNr == rpc.PendingBlockNumber {
return nil, errors.New("not implemented")
}
// Otherwise resolve and return the block
if blockNr == rpc.LatestBlockNumber {
return b.hmy.blockchain.CurrentBlock(), nil
}
return b.hmy.blockchain.GetBlockByNumber(uint64(blockNr)), nil
}
// StateAndHeaderByNumber ...
func (b *APIBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.DB, *block.Header, error) {
// Pending state is only known by the miner
if blockNr == rpc.PendingBlockNumber {
return nil, nil, errors.New("not implemented")
}
// Otherwise resolve the block number and return its state
header, err := b.HeaderByNumber(ctx, blockNr)
if header == nil || err != nil {
return nil, nil, err
}
stateDb, err := b.hmy.blockchain.StateAt(header.Root())
return stateDb, header, err
}
// HeaderByNumber ...
func (b *APIBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*block.Header, error) {
// Pending block is only known by the miner
if blockNr == rpc.PendingBlockNumber {
return nil, errors.New("not implemented")
}
// Otherwise resolve and return the block
if blockNr == rpc.LatestBlockNumber {
return b.hmy.blockchain.CurrentBlock().Header(), nil
}
return b.hmy.blockchain.GetHeaderByNumber(uint64(blockNr)), nil
}
// GetPoolNonce ...
func (b *APIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
return b.hmy.txPool.State().GetNonce(addr), nil
}
// SendTx ...
func (b *APIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
tx, _, _, _ := rawdb.ReadTransaction(b.ChainDb(), signedTx.Hash())
if tx == nil {
return b.hmy.nodeAPI.AddPendingTransaction(signedTx)
}
return ErrFinalizedTransaction
}
// ChainConfig ...
func (b *APIBackend) ChainConfig() *params.ChainConfig {
return b.hmy.blockchain.Config()
}
// CurrentBlock ...
func (b *APIBackend) CurrentBlock() *types.Block {
return types.NewBlockWithHeader(b.hmy.blockchain.CurrentHeader())
}
// GetReceipts ...
func (b *APIBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
return b.hmy.blockchain.GetReceiptsByHash(hash), nil
}
// EventMux ...
// TODO: this is not implemented or verified yet for harmony.
func (b *APIBackend) EventMux() *event.TypeMux { return b.hmy.eventMux }
const (
// BloomBitsBlocks is the number of blocks a single bloom bit section vector
// contains on the server side.
BloomBitsBlocks uint64 = 4096
)
// BloomStatus ...
// TODO: this is not implemented or verified yet for harmony.
func (b *APIBackend) BloomStatus() (uint64, uint64) {
sections, _, _ := b.hmy.bloomIndexer.Sections()
return BloomBitsBlocks, sections
}
// ProtocolVersion ...
func (b *APIBackend) ProtocolVersion() int {
return proto.ProtocolVersion
}
// Filter related APIs
// GetLogs ...
func (b *APIBackend) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) {
receipts := b.hmy.blockchain.GetReceiptsByHash(blockHash)
if receipts == nil {
return nil, errors.New("Missing receipts")
}
logs := make([][]*types.Log, len(receipts))
for i, receipt := range receipts {
logs[i] = receipt.Logs
}
return logs, nil
}
// HeaderByHash ...
func (b *APIBackend) HeaderByHash(ctx context.Context, blockHash common.Hash) (*block.Header, error) {
header := b.hmy.blockchain.GetHeaderByHash(blockHash)
if header == nil {
return nil, errors.New("Header is not found")
}
return header, nil
}
// ServiceFilter ...
func (b *APIBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {
// TODO(ricl): implement
}
// SubscribeNewTxsEvent subcribes new tx event.
// TODO: this is not implemented or verified yet for harmony.
func (b *APIBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
return b.hmy.TxPool().SubscribeNewTxsEvent(ch)
}
// SubscribeChainEvent subcribes chain event.
// TODO: this is not implemented or verified yet for harmony.
func (b *APIBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
return b.hmy.BlockChain().SubscribeChainEvent(ch)
}
// SubscribeChainHeadEvent subcribes chain head event.
// TODO: this is not implemented or verified yet for harmony.
func (b *APIBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
return b.hmy.BlockChain().SubscribeChainHeadEvent(ch)
}
// SubscribeChainSideEvent subcribes chain side event.
// TODO: this is not implemented or verified yet for harmony.
func (b *APIBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription {
return b.hmy.BlockChain().SubscribeChainSideEvent(ch)
}
// SubscribeRemovedLogsEvent subcribes removed logs event.
// TODO: this is not implemented or verified yet for harmony.
func (b *APIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
return b.hmy.BlockChain().SubscribeRemovedLogsEvent(ch)
}
// SubscribeLogsEvent subcribes log event.
// TODO: this is not implemented or verified yet for harmony.
func (b *APIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
return b.hmy.BlockChain().SubscribeLogsEvent(ch)
}
// GetPoolTransactions returns pool transactions.
func (b *APIBackend) GetPoolTransactions() (types.PoolTransactions, error) {
pending, err := b.hmy.txPool.Pending()
if err != nil {
return nil, err
}
queued, err := b.hmy.txPool.Queued()
if err != nil {
return nil, err
}
var txs types.PoolTransactions
for _, batch := range pending {
txs = append(txs, batch...)
}
for _, batch := range queued {
txs = append(txs, batch...)
}
return txs, nil
}
// GetPoolStats returns the number of pending and queued transactions
func (b *APIBackend) GetPoolStats() (pendingCount, queuedCount int) {
return b.hmy.txPool.Stats()
}
// GetAccountNonce returns the nonce value of the given address for the given block number
func (b *APIBackend) GetAccountNonce(
ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (uint64, error) {
state, _, err := b.StateAndHeaderByNumber(ctx, blockNr)
if state == nil || err != nil {
return 0, err
}
return state.GetNonce(address), state.Error()
}
// GetBalance returns balance of an given address.
func (b *APIBackend) GetBalance(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*big.Int, error) {
state, _, err := b.StateAndHeaderByNumber(ctx, blockNr)
if state == nil || err != nil {
return nil, err
}
return state.GetBalance(address), state.Error()
}
// GetTransactionsHistory returns list of transactions hashes of address.
func (b *APIBackend) GetTransactionsHistory(address, txType, order string) ([]common.Hash, error) {
return b.hmy.nodeAPI.GetTransactionsHistory(address, txType, order)
}
// GetStakingTransactionsHistory returns list of staking transactions hashes of address.
func (b *APIBackend) GetStakingTransactionsHistory(address, txType, order string) ([]common.Hash, error) {
return b.hmy.nodeAPI.GetStakingTransactionsHistory(address, txType, order)
}
// GetTransactionsCount returns the number of regular transactions of address.
func (b *APIBackend) GetTransactionsCount(address, txType string) (uint64, error) {
return b.hmy.nodeAPI.GetTransactionsCount(address, txType)
}
// GetStakingTransactionsCount returns the number of staking transactions of address.
func (b *APIBackend) GetStakingTransactionsCount(address, txType string) (uint64, error) {
return b.hmy.nodeAPI.GetStakingTransactionsCount(address, txType)
}
// NetVersion returns net version
func (b *APIBackend) NetVersion() uint64 {
return b.hmy.NetVersion()
}
// GetEVM returns a new EVM entity
func (b *APIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.DB, header *block.Header) (*vm.EVM, func() error, error) {
// TODO(ricl): The code is borrowed from [go-ethereum](https://github.com/ethereum/go-ethereum/blob/40cdcf8c47ff094775aca08fd5d94051f9cf1dbb/les/api_backend.go#L114)
// [question](https://ethereum.stackexchange.com/q/72977/54923)
// Might need to reconsider the SetBalance behavior
state.SetBalance(msg.From(), math.MaxBig256)
vmError := func() error { return nil }
context := core.NewEVMContext(msg, header, b.hmy.BlockChain(), nil)
return vm.NewEVM(context, state, b.hmy.blockchain.Config(), *b.hmy.blockchain.GetVMConfig()), vmError, nil
}
// RPCGasCap returns the gas cap of rpc
func (b *APIBackend) RPCGasCap() *big.Int {
return b.hmy.RPCGasCap // TODO(ricl): should be hmy.config.RPCGasCap
}
// GetShardID returns shardID of this node
func (b *APIBackend) GetShardID() uint32 {
return b.hmy.shardID
}
// GetValidators returns validators for a particular epoch.
func (b *APIBackend) GetValidators(epoch *big.Int) (*shard.Committee, error) {
state, err := b.hmy.BlockChain().ReadShardState(epoch)
if err != nil {
return nil, err
}
for _, committee := range state.Shards {
if committee.ShardID == b.GetShardID() {
return &committee, nil
}
}
return nil, nil
}
// ResendCx retrieve blockHash from txID and add blockHash to CxPool for resending
// Note that cross shard txn is only for regular txns, not for staking txns, so the input txn hash
// is expected to be regular txn hash
func (b *APIBackend) ResendCx(ctx context.Context, txID common.Hash) (uint64, bool) {
blockHash, blockNum, index := b.hmy.BlockChain().ReadTxLookupEntry(txID)
if blockHash == (common.Hash{}) {
return 0, false
}
blk := b.hmy.BlockChain().GetBlockByHash(blockHash)
if blk == nil {
return 0, false
}
txs := blk.Transactions()
// a valid index is from 0 to len-1
if int(index) > len(txs)-1 {
return 0, false
}
tx := txs[int(index)]
// check whether it is a valid cross shard tx
if tx.ShardID() == tx.ToShardID() || blk.Header().ShardID() != tx.ShardID() {
return 0, false
}
entry := core.CxEntry{blockHash, tx.ToShardID()}
success := b.hmy.CxPool().Add(entry)
return blockNum, success
}
// IsLeader exposes if node is currently leader
func (b *APIBackend) IsLeader() bool {
return b.hmy.nodeAPI.IsCurrentlyLeader()
}
// SendStakingTx adds a staking transaction
func (b *APIBackend) SendStakingTx(ctx context.Context, signedStakingTx *staking.StakingTransaction) error {
stx, _, _, _ := rawdb.ReadStakingTransaction(b.ChainDb(), signedStakingTx.Hash())
if stx == nil {
return b.hmy.nodeAPI.AddPendingStakingTransaction(signedStakingTx)
}
return ErrFinalizedTransaction
}
// GetElectedValidatorAddresses returns the address of elected validators for current epoch
func (b *APIBackend) GetElectedValidatorAddresses() []common.Address {
list, _ := b.hmy.BlockChain().ReadShardState(b.hmy.BlockChain().CurrentBlock().Epoch())
return list.StakedValidators().Addrs
}
// GetAllValidatorAddresses returns the up to date validator candidates for next epoch
func (b *APIBackend) GetAllValidatorAddresses() []common.Address {
return b.hmy.BlockChain().ValidatorCandidates()
}
var (
zero = numeric.ZeroDec()
)
// GetValidatorInformation returns the information of validator
func (b *APIBackend) GetValidatorInformation(
addr common.Address, block *types.Block,
) (*staking.ValidatorRPCEnhanced, error) {
bc := b.hmy.BlockChain()
wrapper, err := bc.ReadValidatorInformationAt(addr, block.Root())
if err != nil {
s, _ := internal_common.AddressToBech32(addr)
return nil, errors.Wrapf(err, "not found address in current state %s", s)
}
now := block.Epoch()
// At the last block of epoch, block epoch is e while val.LastEpochInCommittee
// is already updated to e+1. So need the >= check rather than ==
inCommittee := wrapper.LastEpochInCommittee.Cmp(now) >= 0
defaultReply := &staking.ValidatorRPCEnhanced{
CurrentlyInCommittee: inCommittee,
Wrapper: *wrapper,
Performance: nil,
ComputedMetrics: nil,
TotalDelegated: wrapper.TotalDelegation(),
EPoSStatus: effective.ValidatorStatus(
inCommittee, wrapper.Status,
).String(),
EPoSWinningStake: nil,
BootedStatus: nil,
ActiveStatus: wrapper.Validator.Status.String(),
Lifetime: &staking.AccumulatedOverLifetime{
wrapper.BlockReward,
wrapper.Counters,
zero,
nil,
},
}
snapshot, err := bc.ReadValidatorSnapshotAtEpoch(
now, addr,
)
if err != nil {
return defaultReply, nil
}
computed := availability.ComputeCurrentSigning(
snapshot.Validator, wrapper,
)
beaconChainBlocks := uint64(
b.hmy.BeaconChain().CurrentBlock().Header().Number().Int64(),
) % shard.Schedule.BlocksPerEpoch()
computed.BlocksLeftInEpoch = shard.Schedule.BlocksPerEpoch() - beaconChainBlocks
if defaultReply.CurrentlyInCommittee {
defaultReply.Performance = &staking.CurrentEpochPerformance{
CurrentSigningPercentage: *computed,
}
}
stats, err := bc.ReadValidatorStats(addr)
if err != nil {
// when validator has no stats, default boot-status to not booted
notBooted := effective.NotBooted.String()
defaultReply.BootedStatus = &notBooted
return defaultReply, nil
}
latestAPR := numeric.ZeroDec()
l := len(stats.APRs)
if l > 0 {
latestAPR = stats.APRs[l-1].Value
}
defaultReply.Lifetime.APR = latestAPR
defaultReply.Lifetime.EpochAPRs = stats.APRs
// average apr cache keys
// key := fmt.Sprintf("apr-%s-%d", addr.Hex(), now.Uint64())
// prevKey := fmt.Sprintf("apr-%s-%d", addr.Hex(), now.Uint64()-1)
// delete entry for previous epoch
// b.apiCache.Forget(prevKey)
// calculate last APRHistoryLength epochs for averaging APR
// epochFrom := bc.Config().StakingEpoch
// nowMinus := big.NewInt(0).Sub(now, big.NewInt(staking.APRHistoryLength))
// if nowMinus.Cmp(epochFrom) > 0 {
// epochFrom = nowMinus
// }
// if len(stats.APRs) > 0 && stats.APRs[0].Epoch.Cmp(epochFrom) > 0 {
// epochFrom = stats.APRs[0].Epoch
// }
// epochToAPRs := map[int64]numeric.Dec{}
// for i := 0; i < len(stats.APRs); i++ {
// entry := stats.APRs[i]
// epochToAPRs[entry.Epoch.Int64()] = entry.Value
// }
// at this point, validator is active and has apr's for the recent 100 epochs
// compute average apr over history
// if avgAPR, err := b.SingleFlightRequest(
// key, func() (interface{}, error) {
// total := numeric.ZeroDec()
// count := 0
// for i := epochFrom.Int64(); i < now.Int64(); i++ {
// if apr, ok := epochToAPRs[i]; ok {
// total = total.Add(apr)
// }
// count++
// }
// if count == 0 {
// return nil, errors.New("no apr snapshots available")
// }
// return total.QuoInt64(int64(count)), nil
// },
// ); err != nil {
// // could not compute average apr from snapshot
// // assign the latest apr available from stats
// defaultReply.Lifetime.APR = numeric.ZeroDec()
// } else {
// defaultReply.Lifetime.APR = avgAPR.(numeric.Dec)
// }
if defaultReply.CurrentlyInCommittee {
defaultReply.ComputedMetrics = stats
defaultReply.EPoSWinningStake = &stats.TotalEffectiveStake
}
if !defaultReply.CurrentlyInCommittee {
reason := stats.BootedStatus.String()
defaultReply.BootedStatus = &reason
}
return defaultReply, nil
}
// GetMedianRawStakeSnapshot ..
func (b *APIBackend) GetMedianRawStakeSnapshot() (
*committee.CompletedEPoSRound, error,
) {
blockNr := b.CurrentBlock().NumberU64()
key := fmt.Sprintf("median-%d", blockNr)
// delete cache for previous block
prevKey := fmt.Sprintf("median-%d", blockNr-1)
b.apiCache.Forget(prevKey)
res, err := b.SingleFlightRequest(
key,
func() (interface{}, error) {
// Compute for next epoch
epoch := big.NewInt(0).Add(b.CurrentBlock().Epoch(), big.NewInt(1))
return committee.NewEPoSRound(epoch, b.hmy.BlockChain())
},
)
if err != nil {
return nil, err
}
return res.(*committee.CompletedEPoSRound), nil
}
// GetLatestChainHeaders ..
func (b *APIBackend) GetLatestChainHeaders() *block.HeaderPair {
return &block.HeaderPair{
BeaconHeader: b.hmy.BeaconChain().CurrentHeader(),
ShardHeader: b.hmy.BlockChain().CurrentHeader(),
}
}
// GetTotalStakingSnapshot ..
func (b *APIBackend) GetTotalStakingSnapshot() *big.Int {
b.TotalStakingCache.Lock()
defer b.TotalStakingCache.Unlock()
if b.TotalStakingCache.BlockHeight != -1 &&
b.TotalStakingCache.BlockHeight > int64(rpc.LatestBlockNumber)-20 {
return b.TotalStakingCache.TotalStaking
}
b.TotalStakingCache.BlockHeight = int64(rpc.LatestBlockNumber)
candidates := b.hmy.BlockChain().ValidatorCandidates()
if len(candidates) == 0 {
b.TotalStakingCache.TotalStaking = big.NewInt(0)
return b.TotalStakingCache.TotalStaking
}
stakes := big.NewInt(0)
for i := range candidates {
snapshot, _ := b.hmy.BlockChain().ReadValidatorSnapshot(candidates[i])
validator, _ := b.hmy.BlockChain().ReadValidatorInformation(candidates[i])
if !committee.IsEligibleForEPoSAuction(
snapshot, validator,
) {
continue
}
for i := range validator.Delegations {
stakes.Add(stakes, validator.Delegations[i].Amount)
}
}
b.TotalStakingCache.TotalStaking = stakes
return b.TotalStakingCache.TotalStaking
}
// GetDelegationsByValidator returns all delegation information of a validator
func (b *APIBackend) GetDelegationsByValidator(validator common.Address) []*staking.Delegation {
wrapper, err := b.hmy.BlockChain().ReadValidatorInformation(validator)
if err != nil || wrapper == nil {
return nil
}
delegations := []*staking.Delegation{}
for i := range wrapper.Delegations {
delegations = append(delegations, &wrapper.Delegations[i])
}
return delegations
}
// GetDelegationsByDelegatorByBlock returns all delegation information of a delegator
func (b *APIBackend) GetDelegationsByDelegatorByBlock(
delegator common.Address, block *types.Block,
) ([]common.Address, []*staking.Delegation) {
addresses := []common.Address{}
delegations := []*staking.Delegation{}
delegationIndexes, err := b.hmy.BlockChain().
ReadDelegationsByDelegatorAt(delegator, block.Number())
if err != nil {
return nil, nil
}
for i := range delegationIndexes {
wrapper, err := b.hmy.BlockChain().ReadValidatorInformationAt(
delegationIndexes[i].ValidatorAddress, block.Root(),
)
if err != nil || wrapper == nil {
return nil, nil
}
if uint64(len(wrapper.Delegations)) > delegationIndexes[i].Index {
delegations = append(delegations, &wrapper.Delegations[delegationIndexes[i].Index])
} else {
delegations = append(delegations, nil)
}
addresses = append(addresses, delegationIndexes[i].ValidatorAddress)
}
return addresses, delegations
}
// GetDelegationsByDelegator returns all delegation information of a delegator
func (b *APIBackend) GetDelegationsByDelegator(
delegator common.Address,
) ([]common.Address, []*staking.Delegation) {
block := b.hmy.BlockChain().CurrentBlock()
return b.GetDelegationsByDelegatorByBlock(delegator, block)
}
// GetValidatorSelfDelegation returns the amount of staking after applying all delegated stakes
func (b *APIBackend) GetValidatorSelfDelegation(addr common.Address) *big.Int {
wrapper, err := b.hmy.BlockChain().ReadValidatorInformation(addr)
if err != nil || wrapper == nil {
return nil
}
if len(wrapper.Delegations) == 0 {
return nil
}
return wrapper.Delegations[0].Amount
}
// GetShardState ...
func (b *APIBackend) GetShardState() (*shard.State, error) {
return b.hmy.BlockChain().ReadShardState(b.hmy.BlockChain().CurrentHeader().Epoch())
}
// GetCurrentStakingErrorSink ..
func (b *APIBackend) GetCurrentStakingErrorSink() types.TransactionErrorReports {
return b.hmy.nodeAPI.ReportStakingErrorSink()
}
// GetCurrentTransactionErrorSink ..
func (b *APIBackend) GetCurrentTransactionErrorSink() types.TransactionErrorReports {
return b.hmy.nodeAPI.ReportPlainErrorSink()
}
// GetPendingCXReceipts ..
func (b *APIBackend) GetPendingCXReceipts() []*types.CXReceiptsProof {
return b.hmy.nodeAPI.PendingCXReceipts()
}
// GetCurrentUtilityMetrics ..
func (b *APIBackend) GetCurrentUtilityMetrics() (*network.UtilityMetric, error) {
return network.NewUtilityMetricSnapshot(b.hmy.BlockChain())
}
func (b *APIBackend) readAndUpdateRawStakes(
epoch *big.Int,
decider quorum.Decider,
comm shard.Committee,
rawStakes []effective.SlotPurchase,
validatorSpreads map[common.Address]numeric.Dec,
) []effective.SlotPurchase {
for i := range comm.Slots {
slot := comm.Slots[i]
slotAddr := slot.EcdsaAddress
slotKey := slot.BLSPublicKey
spread, ok := validatorSpreads[slotAddr]
if !ok {
snapshot, err := b.hmy.BlockChain().ReadValidatorSnapshotAtEpoch(epoch, slotAddr)
if err != nil {
continue
}
wrapper := snapshot.Validator
spread = numeric.NewDecFromBigInt(wrapper.TotalDelegation()).
QuoInt64(int64(len(wrapper.SlotPubKeys)))
validatorSpreads[slotAddr] = spread
}
commonRPC.SetRawStake(decider, slotKey, spread)
// add entry to array for median calculation
rawStakes = append(rawStakes, effective.SlotPurchase{
slotAddr,
slotKey,
spread,
spread,
})
}
return rawStakes
}
func (b *APIBackend) getSuperCommittees() (*quorum.Transition, error) {
nowE := b.hmy.BlockChain().CurrentHeader().Epoch()
thenE := new(big.Int).Sub(nowE, common.Big1)
var (
nowCommittee, prevCommittee *shard.State
err error
)
nowCommittee, err = b.hmy.BlockChain().ReadShardState(nowE)
if err != nil {
return nil, err
}
prevCommittee, err = b.hmy.BlockChain().ReadShardState(thenE)
if err != nil {
return nil, err
}
stakedSlotsNow, stakedSlotsThen :=
shard.ExternalSlotsAvailableForEpoch(nowE),
shard.ExternalSlotsAvailableForEpoch(thenE)
then, now :=
quorum.NewRegistry(stakedSlotsThen),
quorum.NewRegistry(stakedSlotsNow)
rawStakes := []effective.SlotPurchase{}
validatorSpreads := map[common.Address]numeric.Dec{}
for _, comm := range prevCommittee.Shards {
decider := quorum.NewDecider(quorum.SuperMajorityStake, comm.ShardID)
// before staking skip computing
if b.hmy.BlockChain().Config().IsStaking(prevCommittee.Epoch) {
if _, err := decider.SetVoters(&comm, prevCommittee.Epoch); err != nil {
return nil, err
}
}
rawStakes = b.readAndUpdateRawStakes(thenE, decider, comm, rawStakes, validatorSpreads)
then.Deciders[fmt.Sprintf("shard-%d", comm.ShardID)] = decider
}
then.MedianStake = effective.Median(rawStakes)
rawStakes = []effective.SlotPurchase{}
validatorSpreads = map[common.Address]numeric.Dec{}
for _, comm := range nowCommittee.Shards {
decider := quorum.NewDecider(quorum.SuperMajorityStake, comm.ShardID)
if _, err := decider.SetVoters(&comm, nowCommittee.Epoch); err != nil {
return nil, errors.Wrapf(
err,
"committee is only available from staking epoch: %v, current epoch: %v",
b.hmy.BlockChain().Config().StakingEpoch,
b.hmy.BlockChain().CurrentHeader().Epoch(),
)
}
rawStakes = b.readAndUpdateRawStakes(nowE, decider, comm, rawStakes, validatorSpreads)
now.Deciders[fmt.Sprintf("shard-%d", comm.ShardID)] = decider
}
now.MedianStake = effective.Median(rawStakes)
return &quorum.Transition{then, now}, nil
}
// GetSuperCommittees ..
func (b *APIBackend) GetSuperCommittees() (*quorum.Transition, error) {
nowE := b.hmy.BlockChain().CurrentHeader().Epoch()
key := fmt.Sprintf("sc-%s", nowE.String())
res, err := b.SingleFlightRequest(
key, func() (interface{}, error) {
thenE := new(big.Int).Sub(nowE, common.Big1)
thenKey := fmt.Sprintf("sc-%s", thenE.String())
b.apiCache.Forget(thenKey)
return b.getSuperCommittees()
})
if err != nil {
return nil, err
}
return res.(*quorum.Transition), err
}
// GetCurrentBadBlocks ..
func (b *APIBackend) GetCurrentBadBlocks() []core.BadBlock {
return b.hmy.BlockChain().BadBlocks()
}
// GetLastCrossLinks ..
func (b *APIBackend) GetLastCrossLinks() ([]*types.CrossLink, error) {
crossLinks := []*types.CrossLink{}
for i := uint32(1); i < shard.Schedule.InstanceForEpoch(b.CurrentBlock().Epoch()).NumShards(); i++ {
link, err := b.hmy.BlockChain().ReadShardLastCrossLink(i)
if err != nil {
return nil, err
}
crossLinks = append(crossLinks, link)
}
return crossLinks, nil
}
// GetNodeMetadata ..
func (b *APIBackend) GetNodeMetadata() commonRPC.NodeMetadata {
cfg := nodeconfig.GetDefaultConfig()
header := b.CurrentBlock().Header()
var blockEpoch *uint64
if header.ShardID() == shard.BeaconChainShardID {
sched := shard.Schedule.InstanceForEpoch(header.Epoch())
b := sched.BlocksPerEpoch()
blockEpoch = &b
}
blsKeys := []string{}
if cfg.ConsensusPriKey != nil {
for _, key := range cfg.ConsensusPriKey {
blsKeys = append(blsKeys, key.Pub.Bytes.Hex())
}
}
c := commonRPC.C{}
c.TotalKnownPeers, c.Connected, c.NotConnected = b.hmy.nodeAPI.PeerConnectivity()
return commonRPC.NodeMetadata{
blsKeys,
nodeconfig.GetVersion(),
string(cfg.GetNetworkType()),
*b.ChainConfig(),
b.IsLeader(),
b.GetShardID(),
header.Epoch().Uint64(),
blockEpoch,
cfg.Role().String(),
cfg.DNSZone,
cfg.GetArchival(),
b.hmy.nodeAPI.GetNodeBootTime(),
nodeconfig.GetPeerID(),
c,
}
}
// GetPeerInfo returns the peer info to the node, including blocked peer, connected peer, number of peers
func (b *APIBackend) GetPeerInfo() commonRPC.NodePeerInfo {
topics := b.hmy.nodeAPI.ListTopic()
p := make([]commonRPC.P, len(topics))
for i, t := range topics {
topicPeer := b.hmy.nodeAPI.ListPeer(t)
p[i].Topic = t
p[i].Peers = make([]peer.ID, len(topicPeer))
copy(p[i].Peers, topicPeer)
}
return commonRPC.NodePeerInfo{
PeerID: nodeconfig.GetPeerID(),
BlockedPeers: b.hmy.nodeAPI.ListBlockedPeer(),
P: p,
}
}
// GetBlockSigners ..
func (b *APIBackend) GetBlockSigners(ctx context.Context, blockNr rpc.BlockNumber) (shard.SlotList, *internal_bls.Mask, error) {
block, err := b.BlockByNumber(ctx, blockNr)
if err != nil {
return nil, nil, err
}
blockWithSigners, err := b.BlockByNumber(ctx, blockNr+1)
if err != nil {
return nil, nil, err
}
committee, err := b.GetValidators(block.Epoch())
if err != nil {
return nil, nil, err
}
pubkeys := make([]internal_bls.PublicKeyWrapper, len(committee.Slots))
for _, validator := range committee.Slots {
wrapper := internal_bls.PublicKeyWrapper{Bytes: validator.BLSPublicKey}
if wrapper.Object, err = bls.BytesToBLSPublicKey(wrapper.Bytes[:]); err != nil {
return nil, nil, err
}
}
mask, err := internal_bls.NewMask(pubkeys, nil)
if err != nil {
return nil, nil, err
}
err = mask.SetMask(blockWithSigners.Header().LastCommitBitmap())
if err != nil {
return nil, nil, err
}
return committee.Slots, mask, nil
}
// IsStakingEpoch ...
func (b *APIBackend) IsStakingEpoch(epoch *big.Int) bool {
return b.hmy.BlockChain().Config().IsStaking(epoch)
}
// GetLeaderAddress returns the one address of the leader
func (b *APIBackend) GetLeaderAddress(a common.Address, e *big.Int) string {
if b.IsStakingEpoch(e) {
if leader, exists := b.LeaderCache.Get(a); exists {
bech32, _ := internal_common.AddressToBech32(leader.(common.Address))
return bech32
}
committee, err := b.GetValidators(e)
if err != nil {
return ""
}
for _, v := range committee.Slots {
addr := utils.GetAddressFromBLSPubKeyBytes(v.BLSPublicKey[:])
b.LeaderCache.Add(addr, v.EcdsaAddress)
if addr == a {
bech32, _ := internal_common.AddressToBech32(v.EcdsaAddress)
return bech32
}
}
// Did not find matching address
return "missing" // FIXME: Change this to empty string
}
bech32, _ := internal_common.AddressToBech32(a)
return bech32
}

@ -1,114 +0,0 @@
package hmy
import (
"math/big"
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
staking "github.com/harmony-one/harmony/staking/types"
lru "github.com/hashicorp/golang-lru"
"github.com/libp2p/go-libp2p-core/peer"
)
const (
leaderCacheSize = 250 // Approx number of BLS keys in committee
)
// Harmony implements the Harmony full node service.
type Harmony struct {
// Channel for shutting down the service
shutdownChan chan bool // Channel for shutting down the Harmony
bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
blockchain *core.BlockChain
beaconchain *core.BlockChain
txPool *core.TxPool
cxPool *core.CxPool
eventMux *event.TypeMux
// DB interfaces
chainDb ethdb.Database // Block chain database
bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports
APIBackend *APIBackend
nodeAPI NodeAPI
// aka network version, which is used to identify which network we are using
networkID uint64
// RPCGasCap is the global gas cap for eth-call variants.
RPCGasCap *big.Int `toml:",omitempty"`
shardID uint32
}
// NodeAPI is the list of functions from node used to call rpc apis.
type NodeAPI interface {
AddPendingStakingTransaction(*staking.StakingTransaction) error
AddPendingTransaction(newTx *types.Transaction) error
Blockchain() *core.BlockChain
Beaconchain() *core.BlockChain
GetTransactionsHistory(address, txType, order string) ([]common.Hash, error)
GetStakingTransactionsHistory(address, txType, order string) ([]common.Hash, error)
GetTransactionsCount(address, txType string) (uint64, error)
GetStakingTransactionsCount(address, txType string) (uint64, error)
IsCurrentlyLeader() bool
ReportStakingErrorSink() types.TransactionErrorReports
ReportPlainErrorSink() types.TransactionErrorReports
PendingCXReceipts() []*types.CXReceiptsProof
GetNodeBootTime() int64
PeerConnectivity() (int, int, int)
ListPeer(topic string) []peer.ID
ListTopic() []string
ListBlockedPeer() []peer.ID
}
// New creates a new Harmony object (including the
// initialisation of the common Harmony object)
func New(
nodeAPI NodeAPI, txPool *core.TxPool,
cxPool *core.CxPool, eventMux *event.TypeMux, shardID uint32,
) (*Harmony, error) {
chainDb := nodeAPI.Blockchain().ChainDB()
hmy := &Harmony{
shutdownChan: make(chan bool),
bloomRequests: make(chan chan *bloombits.Retrieval),
blockchain: nodeAPI.Blockchain(),
beaconchain: nodeAPI.Beaconchain(),
txPool: txPool,
cxPool: cxPool,
eventMux: eventMux,
chainDb: chainDb,
nodeAPI: nodeAPI,
networkID: 1, // TODO(ricl): this should be from config
shardID: shardID,
}
cache, _ := lru.New(leaderCacheSize)
hmy.APIBackend = &APIBackend{
hmy: hmy,
TotalStakingCache: struct {
sync.Mutex
BlockHeight int64
TotalStaking *big.Int
}{
BlockHeight: -1,
TotalStaking: big.NewInt(0),
},
LeaderCache: cache,
}
return hmy, nil
}
// TxPool ...
func (s *Harmony) TxPool() *core.TxPool { return s.txPool }
// CxPool is used to store the blockHashes, where the corresponding block contains the cross shard receipts to be sent
func (s *Harmony) CxPool() *core.CxPool { return s.cxPool }
// BlockChain ...
func (s *Harmony) BlockChain() *core.BlockChain { return s.blockchain }
//BeaconChain ...
func (s *Harmony) BeaconChain() *core.BlockChain { return s.beaconchain }
// NetVersion returns the network version, i.e. network ID identifying which network we are using
func (s *Harmony) NetVersion() uint64 { return s.networkID }

@ -0,0 +1,244 @@
package hmy
import (
"context"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/crypto/bls"
internal_bls "github.com/harmony-one/harmony/crypto/bls"
internal_common "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/shard"
"github.com/pkg/errors"
)
// ChainConfig ...
func (hmy *Harmony) ChainConfig() *params.ChainConfig {
return hmy.BlockChain.Config()
}
// GetShardState ...
func (hmy *Harmony) GetShardState() (*shard.State, error) {
return hmy.BlockChain.ReadShardState(hmy.BlockChain.CurrentHeader().Epoch())
}
// GetBlockSigners ..
func (hmy *Harmony) GetBlockSigners(
ctx context.Context, blockNr rpc.BlockNumber,
) (shard.SlotList, *internal_bls.Mask, error) {
blk, err := hmy.BlockByNumber(ctx, blockNr)
if err != nil {
return nil, nil, err
}
blockWithSigners, err := hmy.BlockByNumber(ctx, blockNr+1)
if err != nil {
return nil, nil, err
}
committee, err := hmy.GetValidators(blk.Epoch())
if err != nil {
return nil, nil, err
}
pubKeys := make([]internal_bls.PublicKeyWrapper, len(committee.Slots))
for _, validator := range committee.Slots {
wrapper := internal_bls.PublicKeyWrapper{Bytes: validator.BLSPublicKey}
if wrapper.Object, err = bls.BytesToBLSPublicKey(wrapper.Bytes[:]); err != nil {
return nil, nil, err
}
}
mask, err := internal_bls.NewMask(pubKeys, nil)
if err != nil {
return nil, nil, err
}
err = mask.SetMask(blockWithSigners.Header().LastCommitBitmap())
if err != nil {
return nil, nil, err
}
return committee.Slots, mask, nil
}
// GetLatestChainHeaders ..
func (hmy *Harmony) GetLatestChainHeaders() *block.HeaderPair {
return &block.HeaderPair{
BeaconHeader: hmy.BeaconChain.CurrentHeader(),
ShardHeader: hmy.BlockChain.CurrentHeader(),
}
}
// GetLastCrossLinks ..
func (hmy *Harmony) GetLastCrossLinks() ([]*types.CrossLink, error) {
crossLinks := []*types.CrossLink{}
for i := uint32(1); i < shard.Schedule.InstanceForEpoch(hmy.CurrentBlock().Epoch()).NumShards(); i++ {
link, err := hmy.BlockChain.ReadShardLastCrossLink(i)
if err != nil {
return nil, err
}
crossLinks = append(crossLinks, link)
}
return crossLinks, nil
}
// CurrentBlock ...
func (hmy *Harmony) CurrentBlock() *types.Block {
return types.NewBlockWithHeader(hmy.BlockChain.CurrentHeader())
}
// GetBlock ...
func (hmy *Harmony) GetBlock(ctx context.Context, hash common.Hash) (*types.Block, error) {
return hmy.BlockChain.GetBlockByHash(hash), nil
}
// GetCurrentBadBlocks ..
func (hmy *Harmony) GetCurrentBadBlocks() []core.BadBlock {
return hmy.BlockChain.BadBlocks()
}
// GetBalance returns balance of an given address.
func (hmy *Harmony) GetBalance(ctx context.Context, address common.Address, blockNum rpc.BlockNumber) (*big.Int, error) {
s, _, err := hmy.StateAndHeaderByNumber(ctx, blockNum)
if s == nil || err != nil {
return nil, err
}
return s.GetBalance(address), s.Error()
}
// BlockByNumber ...
func (hmy *Harmony) BlockByNumber(ctx context.Context, blockNum rpc.BlockNumber) (*types.Block, error) {
// Pending block is only known by the miner
if blockNum == rpc.PendingBlockNumber {
return nil, errors.New("not implemented")
}
// Otherwise resolve and return the block
if blockNum == rpc.LatestBlockNumber {
return hmy.BlockChain.CurrentBlock(), nil
}
return hmy.BlockChain.GetBlockByNumber(uint64(blockNum)), nil
}
// HeaderByNumber ...
func (hmy *Harmony) HeaderByNumber(ctx context.Context, blockNum rpc.BlockNumber) (*block.Header, error) {
// Pending block is only known by the miner
if blockNum == rpc.PendingBlockNumber {
return nil, errors.New("not implemented")
}
// Otherwise resolve and return the block
if blockNum == rpc.LatestBlockNumber {
return hmy.BlockChain.CurrentBlock().Header(), nil
}
return hmy.BlockChain.GetHeaderByNumber(uint64(blockNum)), nil
}
// HeaderByHash ...
func (hmy *Harmony) HeaderByHash(ctx context.Context, blockHash common.Hash) (*block.Header, error) {
header := hmy.BlockChain.GetHeaderByHash(blockHash)
if header == nil {
return nil, errors.New("Header is not found")
}
return header, nil
}
// StateAndHeaderByNumber ...
func (hmy *Harmony) StateAndHeaderByNumber(ctx context.Context, blockNum rpc.BlockNumber) (*state.DB, *block.Header, error) {
// Pending state is only known by the miner
if blockNum == rpc.PendingBlockNumber {
return nil, nil, errors.New("not implemented")
}
// Otherwise resolve the block number and return its state
header, err := hmy.HeaderByNumber(ctx, blockNum)
if header == nil || err != nil {
return nil, nil, err
}
stateDb, err := hmy.BlockChain.StateAt(header.Root())
return stateDb, header, err
}
// GetLeaderAddress returns the one address of the leader, given the coinbaseAddr.
// Note that the coinbaseAddr is overloaded with the BLS pub key hash in staking era.
func (hmy *Harmony) GetLeaderAddress(coinbaseAddr common.Address, epoch *big.Int) string {
if hmy.IsStakingEpoch(epoch) {
if leader, exists := hmy.leaderCache.Get(coinbaseAddr); exists {
bech32, _ := internal_common.AddressToBech32(leader.(common.Address))
return bech32
}
committee, err := hmy.GetValidators(epoch)
if err != nil {
return ""
}
for _, val := range committee.Slots {
addr := utils.GetAddressFromBLSPubKeyBytes(val.BLSPublicKey[:])
hmy.leaderCache.Add(addr, val.EcdsaAddress)
if addr == coinbaseAddr {
bech32, _ := internal_common.AddressToBech32(val.EcdsaAddress)
return bech32
}
}
return "" // Did not find matching address
}
bech32, _ := internal_common.AddressToBech32(coinbaseAddr)
return bech32
}
// Filter related APIs
// GetLogs ...
func (hmy *Harmony) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) {
receipts := hmy.BlockChain.GetReceiptsByHash(blockHash)
if receipts == nil {
return nil, errors.New("Missing receipts")
}
logs := make([][]*types.Log, len(receipts))
for i, receipt := range receipts {
logs[i] = receipt.Logs
}
return logs, nil
}
// ServiceFilter ...
func (hmy *Harmony) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {
// TODO(dm): implement
}
// SubscribeNewTxsEvent subscribes new tx event.
// TODO: this is not implemented or verified yet for harmony.
func (hmy *Harmony) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
return hmy.TxPool.SubscribeNewTxsEvent(ch)
}
// SubscribeChainEvent subscribes chain event.
// TODO: this is not implemented or verified yet for harmony.
func (hmy *Harmony) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
return hmy.BlockChain.SubscribeChainEvent(ch)
}
// SubscribeChainHeadEvent subcribes chain head event.
// TODO: this is not implemented or verified yet for harmony.
func (hmy *Harmony) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
return hmy.BlockChain.SubscribeChainHeadEvent(ch)
}
// SubscribeChainSideEvent subcribes chain side event.
// TODO: this is not implemented or verified yet for harmony.
func (hmy *Harmony) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription {
return hmy.BlockChain.SubscribeChainSideEvent(ch)
}
// SubscribeRemovedLogsEvent subcribes removed logs event.
// TODO: this is not implemented or verified yet for harmony.
func (hmy *Harmony) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
return hmy.BlockChain.SubscribeRemovedLogsEvent(ch)
}
// SubscribeLogsEvent subcribes log event.
// TODO: this is not implemented or verified yet for harmony.
func (hmy *Harmony) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
return hmy.BlockChain.SubscribeLogsEvent(ch)
}

@ -0,0 +1,202 @@
package hmy
import (
"context"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/harmony-one/harmony/api/proto"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common"
"github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types"
lru "github.com/hashicorp/golang-lru"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/pkg/errors"
"golang.org/x/sync/singleflight"
)
const (
// BloomBitsBlocks is the number of blocks a single bloom bit section vector
// contains on the server side.
BloomBitsBlocks uint64 = 4096
leaderCacheSize = 250 // Approx number of BLS keys in committee
totalStakeCacheDuration = 20 // number of blocks where the returned total stake will remain the same
)
var (
// ErrFinalizedTransaction is returned if the transaction to be submitted is already on-chain
ErrFinalizedTransaction = errors.New("transaction already finalized")
)
// Harmony implements the Harmony full node service.
type Harmony struct {
// Channel for shutting down the service
ShutdownChan chan bool // Channel for shutting down the Harmony
BloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
BlockChain *core.BlockChain
BeaconChain *core.BlockChain
TxPool *core.TxPool
CxPool *core.CxPool // CxPool is used to store the blockHashes of blocks containing cx receipts to be sent
// DB interfaces
BloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports
NodeAPI NodeAPI
// ChainID is used to identify which network we are using
ChainID uint64
// RPCGasCap is the global gas cap for eth-call variants.
RPCGasCap *big.Int `toml:",omitempty"`
ShardID uint32
// Internals
eventMux *event.TypeMux
chainDb ethdb.Database // Block chain database
// group for units of work which can be executed with duplicate suppression.
group singleflight.Group
// leaderCache to save on recomputation every epoch.
leaderCache *lru.Cache
// totalStakeCache to save on recomputation for `totalStakeCacheDuration` blocks.
totalStakeCache *totalStakeCache
}
// NodeAPI is the list of functions from node used to call rpc apis.
type NodeAPI interface {
AddPendingStakingTransaction(*staking.StakingTransaction) error
AddPendingTransaction(newTx *types.Transaction) error
Blockchain() *core.BlockChain
Beaconchain() *core.BlockChain
GetTransactionsHistory(address, txType, order string) ([]common.Hash, error)
GetStakingTransactionsHistory(address, txType, order string) ([]common.Hash, error)
GetTransactionsCount(address, txType string) (uint64, error)
GetStakingTransactionsCount(address, txType string) (uint64, error)
IsCurrentlyLeader() bool
ReportStakingErrorSink() types.TransactionErrorReports
ReportPlainErrorSink() types.TransactionErrorReports
PendingCXReceipts() []*types.CXReceiptsProof
GetNodeBootTime() int64
PeerConnectivity() (int, int, int)
ListPeer(topic string) []peer.ID
ListTopic() []string
ListBlockedPeer() []peer.ID
}
// New creates a new Harmony object (including the
// initialisation of the common Harmony object)
func New(
nodeAPI NodeAPI, txPool *core.TxPool, cxPool *core.CxPool, shardID uint32,
) *Harmony {
chainDb := nodeAPI.Blockchain().ChainDB()
leaderCache, _ := lru.New(leaderCacheSize)
totalStakeCache := newTotalStakeCache(totalStakeCacheDuration)
return &Harmony{
ShutdownChan: make(chan bool),
BloomRequests: make(chan chan *bloombits.Retrieval),
BlockChain: nodeAPI.Blockchain(),
BeaconChain: nodeAPI.Beaconchain(),
TxPool: txPool,
CxPool: cxPool,
eventMux: new(event.TypeMux),
chainDb: chainDb,
NodeAPI: nodeAPI,
ChainID: nodeAPI.Blockchain().Config().ChainID.Uint64(),
ShardID: shardID,
leaderCache: leaderCache,
totalStakeCache: totalStakeCache,
}
}
// SingleFlightRequest ..
func (hmy *Harmony) SingleFlightRequest(
key string,
fn func() (interface{}, error),
) (interface{}, error) {
res, err, _ := hmy.group.Do(key, fn)
return res, err
}
// SingleFlightForgetKey ...
func (hmy *Harmony) SingleFlightForgetKey(key string) {
hmy.group.Forget(key)
}
// ProtocolVersion ...
func (hmy *Harmony) ProtocolVersion() int {
return proto.ProtocolVersion
}
// IsLeader exposes if node is currently leader
func (hmy *Harmony) IsLeader() bool {
return hmy.NodeAPI.IsCurrentlyLeader()
}
// GetNodeMetadata ..
func (hmy *Harmony) GetNodeMetadata() commonRPC.NodeMetadata {
cfg := nodeconfig.GetDefaultConfig()
header := hmy.CurrentBlock().Header()
var blockEpoch *uint64
if header.ShardID() == shard.BeaconChainShardID {
sched := shard.Schedule.InstanceForEpoch(header.Epoch())
b := sched.BlocksPerEpoch()
blockEpoch = &b
}
blsKeys := []string{}
if cfg.ConsensusPriKey != nil {
for _, key := range cfg.ConsensusPriKey {
blsKeys = append(blsKeys, key.Pub.Bytes.Hex())
}
}
c := commonRPC.C{}
c.TotalKnownPeers, c.Connected, c.NotConnected = hmy.NodeAPI.PeerConnectivity()
return commonRPC.NodeMetadata{
BLSPublicKey: blsKeys,
Version: nodeconfig.GetVersion(),
NetworkType: string(cfg.GetNetworkType()),
ChainConfig: *hmy.ChainConfig(),
IsLeader: hmy.IsLeader(),
ShardID: hmy.ShardID,
CurrentEpoch: header.Epoch().Uint64(),
BlocksPerEpoch: blockEpoch,
Role: cfg.Role().String(),
DNSZone: cfg.DNSZone,
Archival: cfg.GetArchival(),
NodeBootTime: hmy.NodeAPI.GetNodeBootTime(),
PeerID: nodeconfig.GetPeerID(),
C: c,
}
}
// GetEVM returns a new EVM entity
func (hmy *Harmony) GetEVM(ctx context.Context, msg core.Message, state *state.DB, header *block.Header) (*vm.EVM, func() error, error) {
state.SetBalance(msg.From(), math.MaxBig256)
vmError := func() error { return nil }
vmCtx := core.NewEVMContext(msg, header, hmy.BlockChain, nil)
return vm.NewEVM(vmCtx, state, hmy.BlockChain.Config(), *hmy.BlockChain.GetVMConfig()), vmError, nil
}
// ChainDb ..
func (hmy *Harmony) ChainDb() ethdb.Database {
return hmy.chainDb
}
// EventMux ..
func (hmy *Harmony) EventMux() *event.TypeMux {
return hmy.eventMux
}
// BloomStatus ...
// TODO: this is not implemented or verified yet for harmony.
func (hmy *Harmony) BloomStatus() (uint64, uint64) {
sections, _, _ := hmy.BloomIndexer.Sections()
return BloomBitsBlocks, sections
}

@ -0,0 +1,33 @@
package hmy
import (
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common"
"github.com/harmony-one/harmony/staking/network"
"github.com/libp2p/go-libp2p-core/peer"
)
// GetCurrentUtilityMetrics ..
func (hmy *Harmony) GetCurrentUtilityMetrics() (*network.UtilityMetric, error) {
return network.NewUtilityMetricSnapshot(hmy.BlockChain)
}
// GetPeerInfo returns the peer info to the node, including blocked peer, connected peer, number of peers
func (hmy *Harmony) GetPeerInfo() commonRPC.NodePeerInfo {
topics := hmy.NodeAPI.ListTopic()
p := make([]commonRPC.P, len(topics))
for i, t := range topics {
topicPeer := hmy.NodeAPI.ListPeer(t)
p[i].Topic = t
p[i].Peers = make([]peer.ID, len(topicPeer))
copy(p[i].Peers, topicPeer)
}
return commonRPC.NodePeerInfo{
PeerID: nodeconfig.GetPeerID(),
BlockedPeers: hmy.NodeAPI.ListBlockedPeer(),
P: p,
}
}

@ -0,0 +1,48 @@
package hmy
import (
"context"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/core/types"
)
// GetPoolStats returns the number of pending and queued transactions
func (hmy *Harmony) GetPoolStats() (pendingCount, queuedCount int) {
return hmy.TxPool.Stats()
}
// GetPoolNonce ...
func (hmy *Harmony) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
return hmy.TxPool.State().GetNonce(addr), nil
}
// GetPoolTransaction ...
func (hmy *Harmony) GetPoolTransaction(hash common.Hash) types.PoolTransaction {
return hmy.TxPool.Get(hash)
}
// GetPendingCXReceipts ..
func (hmy *Harmony) GetPendingCXReceipts() []*types.CXReceiptsProof {
return hmy.NodeAPI.PendingCXReceipts()
}
// GetPoolTransactions returns pool transactions.
func (hmy *Harmony) GetPoolTransactions() (types.PoolTransactions, error) {
pending, err := hmy.TxPool.Pending()
if err != nil {
return nil, err
}
queued, err := hmy.TxPool.Queued()
if err != nil {
return nil, err
}
var txs types.PoolTransactions
for _, batch := range pending {
txs = append(txs, batch...)
}
for _, batch := range queued {
txs = append(txs, batch...)
}
return txs, nil
}

@ -0,0 +1,476 @@
package hmy
import (
"context"
"fmt"
"math/big"
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/consensus/quorum"
"github.com/harmony-one/harmony/core/rawdb"
"github.com/harmony-one/harmony/core/types"
internal_common "github.com/harmony-one/harmony/internal/common"
commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common"
"github.com/harmony-one/harmony/numeric"
"github.com/harmony-one/harmony/shard"
"github.com/harmony-one/harmony/shard/committee"
"github.com/harmony-one/harmony/staking/availability"
"github.com/harmony-one/harmony/staking/effective"
staking "github.com/harmony-one/harmony/staking/types"
"github.com/pkg/errors"
)
var (
zero = numeric.ZeroDec()
)
func (hmy *Harmony) readAndUpdateRawStakes(
epoch *big.Int,
decider quorum.Decider,
comm shard.Committee,
rawStakes []effective.SlotPurchase,
validatorSpreads map[common.Address]numeric.Dec,
) []effective.SlotPurchase {
for i := range comm.Slots {
slot := comm.Slots[i]
slotAddr := slot.EcdsaAddress
slotKey := slot.BLSPublicKey
spread, ok := validatorSpreads[slotAddr]
if !ok {
snapshot, err := hmy.BlockChain.ReadValidatorSnapshotAtEpoch(epoch, slotAddr)
if err != nil {
continue
}
wrapper := snapshot.Validator
spread = numeric.NewDecFromBigInt(wrapper.TotalDelegation()).
QuoInt64(int64(len(wrapper.SlotPubKeys)))
validatorSpreads[slotAddr] = spread
}
commonRPC.SetRawStake(decider, slotKey, spread)
// add entry to array for median calculation
rawStakes = append(rawStakes, effective.SlotPurchase{
Addr: slotAddr,
Key: slotKey,
RawStake: spread,
EPoSStake: spread,
})
}
return rawStakes
}
func (hmy *Harmony) getSuperCommittees() (*quorum.Transition, error) {
nowE := hmy.BlockChain.CurrentHeader().Epoch()
thenE := new(big.Int).Sub(nowE, common.Big1)
var (
nowCommittee, prevCommittee *shard.State
err error
)
nowCommittee, err = hmy.BlockChain.ReadShardState(nowE)
if err != nil {
return nil, err
}
prevCommittee, err = hmy.BlockChain.ReadShardState(thenE)
if err != nil {
return nil, err
}
stakedSlotsNow, stakedSlotsThen :=
shard.ExternalSlotsAvailableForEpoch(nowE),
shard.ExternalSlotsAvailableForEpoch(thenE)
then, now :=
quorum.NewRegistry(stakedSlotsThen),
quorum.NewRegistry(stakedSlotsNow)
rawStakes := []effective.SlotPurchase{}
validatorSpreads := map[common.Address]numeric.Dec{}
for _, comm := range prevCommittee.Shards {
decider := quorum.NewDecider(quorum.SuperMajorityStake, comm.ShardID)
// before staking skip computing
if hmy.BlockChain.Config().IsStaking(prevCommittee.Epoch) {
if _, err := decider.SetVoters(&comm, prevCommittee.Epoch); err != nil {
return nil, err
}
}
rawStakes = hmy.readAndUpdateRawStakes(thenE, decider, comm, rawStakes, validatorSpreads)
then.Deciders[fmt.Sprintf("shard-%d", comm.ShardID)] = decider
}
then.MedianStake = effective.Median(rawStakes)
rawStakes = []effective.SlotPurchase{}
validatorSpreads = map[common.Address]numeric.Dec{}
for _, comm := range nowCommittee.Shards {
decider := quorum.NewDecider(quorum.SuperMajorityStake, comm.ShardID)
if _, err := decider.SetVoters(&comm, nowCommittee.Epoch); err != nil {
return nil, errors.Wrapf(
err,
"committee is only available from staking epoch: %v, current epoch: %v",
hmy.BlockChain.Config().StakingEpoch,
hmy.BlockChain.CurrentHeader().Epoch(),
)
}
rawStakes = hmy.readAndUpdateRawStakes(nowE, decider, comm, rawStakes, validatorSpreads)
now.Deciders[fmt.Sprintf("shard-%d", comm.ShardID)] = decider
}
now.MedianStake = effective.Median(rawStakes)
return &quorum.Transition{Previous: then, Current: now}, nil
}
// IsStakingEpoch ...
func (hmy *Harmony) IsStakingEpoch(epoch *big.Int) bool {
return hmy.BlockChain.Config().IsStaking(epoch)
}
// SendStakingTx adds a staking transaction
func (hmy *Harmony) SendStakingTx(ctx context.Context, signedStakingTx *staking.StakingTransaction) error {
stx, _, _, _ := rawdb.ReadStakingTransaction(hmy.chainDb, signedStakingTx.Hash())
if stx == nil {
return hmy.NodeAPI.AddPendingStakingTransaction(signedStakingTx)
}
return ErrFinalizedTransaction
}
// GetStakingTransactionsHistory returns list of staking transactions hashes of address.
func (hmy *Harmony) GetStakingTransactionsHistory(address, txType, order string) ([]common.Hash, error) {
return hmy.NodeAPI.GetStakingTransactionsHistory(address, txType, order)
}
// GetStakingTransactionsCount returns the number of staking transactions of address.
func (hmy *Harmony) GetStakingTransactionsCount(address, txType string) (uint64, error) {
return hmy.NodeAPI.GetStakingTransactionsCount(address, txType)
}
// GetSuperCommittees ..
func (hmy *Harmony) GetSuperCommittees() (*quorum.Transition, error) {
nowE := hmy.BlockChain.CurrentHeader().Epoch()
key := fmt.Sprintf("sc-%s", nowE.String())
res, err := hmy.SingleFlightRequest(
key, func() (interface{}, error) {
thenE := new(big.Int).Sub(nowE, common.Big1)
thenKey := fmt.Sprintf("sc-%s", thenE.String())
hmy.group.Forget(thenKey)
return hmy.getSuperCommittees()
})
if err != nil {
return nil, err
}
return res.(*quorum.Transition), err
}
// GetValidators returns validators for a particular epoch.
func (hmy *Harmony) GetValidators(epoch *big.Int) (*shard.Committee, error) {
state, err := hmy.BlockChain.ReadShardState(epoch)
if err != nil {
return nil, err
}
for _, cmt := range state.Shards {
if cmt.ShardID == hmy.ShardID {
return &cmt, nil
}
}
return nil, nil
}
// GetValidatorSelfDelegation returns the amount of staking after applying all delegated stakes
func (hmy *Harmony) GetValidatorSelfDelegation(addr common.Address) *big.Int {
wrapper, err := hmy.BlockChain.ReadValidatorInformation(addr)
if err != nil || wrapper == nil {
return nil
}
if len(wrapper.Delegations) == 0 {
return nil
}
return wrapper.Delegations[0].Amount
}
// GetElectedValidatorAddresses returns the address of elected validators for current epoch
func (hmy *Harmony) GetElectedValidatorAddresses() []common.Address {
list, _ := hmy.BlockChain.ReadShardState(hmy.BlockChain.CurrentBlock().Epoch())
return list.StakedValidators().Addrs
}
// GetAllValidatorAddresses returns the up to date validator candidates for next epoch
func (hmy *Harmony) GetAllValidatorAddresses() []common.Address {
return hmy.BlockChain.ValidatorCandidates()
}
// GetValidatorInformation returns the information of validator
func (hmy *Harmony) GetValidatorInformation(
addr common.Address, block *types.Block,
) (*staking.ValidatorRPCEnhanced, error) {
bc := hmy.BlockChain
wrapper, err := bc.ReadValidatorInformationAt(addr, block.Root())
if err != nil {
s, _ := internal_common.AddressToBech32(addr)
return nil, errors.Wrapf(err, "not found address in current state %s", s)
}
now := block.Epoch()
// At the last block of epoch, block epoch is e while val.LastEpochInCommittee
// is already updated to e+1. So need the >= check rather than ==
inCommittee := wrapper.LastEpochInCommittee.Cmp(now) >= 0
defaultReply := &staking.ValidatorRPCEnhanced{
CurrentlyInCommittee: inCommittee,
Wrapper: *wrapper,
Performance: nil,
ComputedMetrics: nil,
TotalDelegated: wrapper.TotalDelegation(),
EPoSStatus: effective.ValidatorStatus(
inCommittee, wrapper.Status,
).String(),
EPoSWinningStake: nil,
BootedStatus: nil,
ActiveStatus: wrapper.Validator.Status.String(),
Lifetime: &staking.AccumulatedOverLifetime{
BlockReward: wrapper.BlockReward,
Signing: wrapper.Counters,
APR: zero,
},
}
snapshot, err := bc.ReadValidatorSnapshotAtEpoch(
now, addr,
)
if err != nil {
return defaultReply, nil
}
computed := availability.ComputeCurrentSigning(
snapshot.Validator, wrapper,
)
beaconChainBlocks := uint64(
hmy.BeaconChain.CurrentBlock().Header().Number().Int64(),
) % shard.Schedule.BlocksPerEpoch()
computed.BlocksLeftInEpoch = shard.Schedule.BlocksPerEpoch() - beaconChainBlocks
if defaultReply.CurrentlyInCommittee {
defaultReply.Performance = &staking.CurrentEpochPerformance{
CurrentSigningPercentage: *computed,
}
}
stats, err := bc.ReadValidatorStats(addr)
if err != nil {
// when validator has no stats, default boot-status to not booted
notBooted := effective.NotBooted.String()
defaultReply.BootedStatus = &notBooted
return defaultReply, nil
}
latestAPR := numeric.ZeroDec()
l := len(stats.APRs)
if l > 0 {
latestAPR = stats.APRs[l-1].Value
}
defaultReply.Lifetime.APR = latestAPR
defaultReply.Lifetime.EpochAPRs = stats.APRs
// average apr cache keys
// key := fmt.Sprintf("apr-%s-%d", addr.Hex(), now.Uint64())
// prevKey := fmt.Sprintf("apr-%s-%d", addr.Hex(), now.Uint64()-1)
// delete entry for previous epoch
// b.apiCache.Forget(prevKey)
// calculate last APRHistoryLength epochs for averaging APR
// epochFrom := bc.Config().StakingEpoch
// nowMinus := big.NewInt(0).Sub(now, big.NewInt(staking.APRHistoryLength))
// if nowMinus.Cmp(epochFrom) > 0 {
// epochFrom = nowMinus
// }
// if len(stats.APRs) > 0 && stats.APRs[0].Epoch.Cmp(epochFrom) > 0 {
// epochFrom = stats.APRs[0].Epoch
// }
// epochToAPRs := map[int64]numeric.Dec{}
// for i := 0; i < len(stats.APRs); i++ {
// entry := stats.APRs[i]
// epochToAPRs[entry.Epoch.Int64()] = entry.Value
// }
// at this point, validator is active and has apr's for the recent 100 epochs
// compute average apr over history
// if avgAPR, err := b.SingleFlightRequest(
// key, func() (interface{}, error) {
// total := numeric.ZeroDec()
// count := 0
// for i := epochFrom.Int64(); i < now.Int64(); i++ {
// if apr, ok := epochToAPRs[i]; ok {
// total = total.Add(apr)
// }
// count++
// }
// if count == 0 {
// return nil, errors.New("no apr snapshots available")
// }
// return total.QuoInt64(int64(count)), nil
// },
// ); err != nil {
// // could not compute average apr from snapshot
// // assign the latest apr available from stats
// defaultReply.Lifetime.APR = numeric.ZeroDec()
// } else {
// defaultReply.Lifetime.APR = avgAPR.(numeric.Dec)
// }
if defaultReply.CurrentlyInCommittee {
defaultReply.ComputedMetrics = stats
defaultReply.EPoSWinningStake = &stats.TotalEffectiveStake
}
if !defaultReply.CurrentlyInCommittee {
reason := stats.BootedStatus.String()
defaultReply.BootedStatus = &reason
}
return defaultReply, nil
}
// GetMedianRawStakeSnapshot ..
func (hmy *Harmony) GetMedianRawStakeSnapshot() (
*committee.CompletedEPoSRound, error,
) {
blockNum := hmy.CurrentBlock().NumberU64()
key := fmt.Sprintf("median-%d", blockNum)
// delete cache for previous block
prevKey := fmt.Sprintf("median-%d", blockNum-1)
hmy.group.Forget(prevKey)
res, err := hmy.SingleFlightRequest(
key,
func() (interface{}, error) {
// Compute for next epoch
epoch := big.NewInt(0).Add(hmy.CurrentBlock().Epoch(), big.NewInt(1))
return committee.NewEPoSRound(epoch, hmy.BlockChain)
},
)
if err != nil {
return nil, err
}
return res.(*committee.CompletedEPoSRound), nil
}
// GetDelegationsByValidator returns all delegation information of a validator
func (hmy *Harmony) GetDelegationsByValidator(validator common.Address) []*staking.Delegation {
wrapper, err := hmy.BlockChain.ReadValidatorInformation(validator)
if err != nil || wrapper == nil {
return nil
}
delegations := []*staking.Delegation{}
for i := range wrapper.Delegations {
delegations = append(delegations, &wrapper.Delegations[i])
}
return delegations
}
// GetDelegationsByDelegator returns all delegation information of a delegator
func (hmy *Harmony) GetDelegationsByDelegator(
delegator common.Address,
) ([]common.Address, []*staking.Delegation) {
block := hmy.BlockChain.CurrentBlock()
return hmy.GetDelegationsByDelegatorByBlock(delegator, block)
}
// GetDelegationsByDelegatorByBlock returns all delegation information of a delegator
func (hmy *Harmony) GetDelegationsByDelegatorByBlock(
delegator common.Address, block *types.Block,
) ([]common.Address, []*staking.Delegation) {
addresses := []common.Address{}
delegations := []*staking.Delegation{}
delegationIndexes, err := hmy.BlockChain.
ReadDelegationsByDelegatorAt(delegator, block.Number())
if err != nil {
return nil, nil
}
for i := range delegationIndexes {
wrapper, err := hmy.BlockChain.ReadValidatorInformationAt(
delegationIndexes[i].ValidatorAddress, block.Root(),
)
if err != nil || wrapper == nil {
return nil, nil
}
if uint64(len(wrapper.Delegations)) > delegationIndexes[i].Index {
delegations = append(delegations, &wrapper.Delegations[delegationIndexes[i].Index])
} else {
delegations = append(delegations, nil)
}
addresses = append(addresses, delegationIndexes[i].ValidatorAddress)
}
return addresses, delegations
}
// GetTotalStakingSnapshot ..
func (hmy *Harmony) GetTotalStakingSnapshot() *big.Int {
if stake := hmy.totalStakeCache.pop(hmy.CurrentBlock().NumberU64()); stake != nil {
return stake
}
currHeight := hmy.CurrentBlock().NumberU64()
candidates := hmy.BlockChain.ValidatorCandidates()
if len(candidates) == 0 {
stake := big.NewInt(0)
hmy.totalStakeCache.push(currHeight, stake)
return stake
}
stakes := big.NewInt(0)
for i := range candidates {
snapshot, _ := hmy.BlockChain.ReadValidatorSnapshot(candidates[i])
validator, _ := hmy.BlockChain.ReadValidatorInformation(candidates[i])
if !committee.IsEligibleForEPoSAuction(
snapshot, validator,
) {
continue
}
for i := range validator.Delegations {
stakes.Add(stakes, validator.Delegations[i].Amount)
}
}
hmy.totalStakeCache.push(currHeight, stakes)
return stakes
}
// GetCurrentStakingErrorSink ..
func (hmy *Harmony) GetCurrentStakingErrorSink() types.TransactionErrorReports {
return hmy.NodeAPI.ReportStakingErrorSink()
}
// totalStakeCache ..
type totalStakeCache struct {
sync.Mutex
cachedBlockHeight uint64
stake *big.Int
// duration is in blocks
duration uint64
}
// newTotalStakeCache ..
func newTotalStakeCache(duration uint64) *totalStakeCache {
return &totalStakeCache{
cachedBlockHeight: 0,
stake: nil,
duration: duration,
}
}
func (c *totalStakeCache) push(currBlockHeight uint64, stake *big.Int) {
c.Lock()
defer c.Unlock()
c.cachedBlockHeight = currBlockHeight
c.stake = stake
}
func (c *totalStakeCache) pop(currBlockHeight uint64) *big.Int {
if currBlockHeight > c.cachedBlockHeight+c.duration {
return nil
}
return c.stake
}

@ -0,0 +1,80 @@
package hmy
import (
"context"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/rawdb"
"github.com/harmony-one/harmony/core/types"
)
// SendTx ...
func (hmy *Harmony) SendTx(ctx context.Context, signedTx *types.Transaction) error {
tx, _, _, _ := rawdb.ReadTransaction(hmy.chainDb, signedTx.Hash())
if tx == nil {
return hmy.NodeAPI.AddPendingTransaction(signedTx)
}
return ErrFinalizedTransaction
}
// ResendCx retrieve blockHash from txID and add blockHash to CxPool for resending
// Note that cross shard txn is only for regular txns, not for staking txns, so the input txn hash
// is expected to be regular txn hash
func (hmy *Harmony) ResendCx(ctx context.Context, txID common.Hash) (uint64, bool) {
blockHash, blockNum, index := hmy.BlockChain.ReadTxLookupEntry(txID)
if blockHash == (common.Hash{}) {
return 0, false
}
blk := hmy.BlockChain.GetBlockByHash(blockHash)
if blk == nil {
return 0, false
}
txs := blk.Transactions()
// a valid index is from 0 to len-1
if int(index) > len(txs)-1 {
return 0, false
}
tx := txs[int(index)]
// check whether it is a valid cross shard tx
if tx.ShardID() == tx.ToShardID() || blk.Header().ShardID() != tx.ShardID() {
return 0, false
}
entry := core.CxEntry{blockHash, tx.ToShardID()}
success := hmy.CxPool.Add(entry)
return blockNum, success
}
// GetReceipts ...
func (hmy *Harmony) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
return hmy.BlockChain.GetReceiptsByHash(hash), nil
}
// GetTransactionsHistory returns list of transactions hashes of address.
func (hmy *Harmony) GetTransactionsHistory(address, txType, order string) ([]common.Hash, error) {
return hmy.NodeAPI.GetTransactionsHistory(address, txType, order)
}
// GetAccountNonce returns the nonce value of the given address for the given block number
func (hmy *Harmony) GetAccountNonce(
ctx context.Context, address common.Address, blockNum rpc.BlockNumber) (uint64, error) {
state, _, err := hmy.StateAndHeaderByNumber(ctx, blockNum)
if state == nil || err != nil {
return 0, err
}
return state.GetNonce(address), state.Error()
}
// GetTransactionsCount returns the number of regular transactions of address.
func (hmy *Harmony) GetTransactionsCount(address, txType string) (uint64, error) {
return hmy.NodeAPI.GetTransactionsCount(address, txType)
}
// GetCurrentTransactionErrorSink ..
func (hmy *Harmony) GetCurrentTransactionErrorSink() types.TransactionErrorReports {
return hmy.NodeAPI.ReportPlainErrorSink()
}

@ -1,99 +0,0 @@
package apiv1
import (
"context"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/consensus/quorum"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/crypto/bls"
commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/shard"
"github.com/harmony-one/harmony/shard/committee"
"github.com/harmony-one/harmony/staking/network"
staking "github.com/harmony-one/harmony/staking/types"
)
// Backend interface provides the common API services (that are provided by
// both full and light clients) with access to necessary functions.
// implementations:
// * hmy/api_backend.go
type Backend interface {
NetVersion() uint64
ProtocolVersion() int
ChainDb() ethdb.Database
SingleFlightRequest(key string, fn func() (interface{}, error)) (interface{}, error)
SingleFlightForgetKey(key string)
EventMux() *event.TypeMux
RPCGasCap() *big.Int // global gas cap for hmy_call over rpc: DoS protection
HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*block.Header, error)
BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error)
StateAndHeaderByNumber(
ctx context.Context, blockNr rpc.BlockNumber,
) (*state.DB, *block.Header, error)
GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error)
GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
GetEVM(ctx context.Context, msg core.Message, state *state.DB, header *block.Header) (*vm.EVM, func() error, error)
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription
// TxPool API
SendTx(ctx context.Context, signedTx *types.Transaction) error
// GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error)
GetPoolTransactions() (types.PoolTransactions, error)
GetPoolTransaction(txHash common.Hash) types.PoolTransaction
GetPoolStats() (pendingCount, queuedCount int)
GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error)
// Get account nonce
GetAccountNonce(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (uint64, error)
// TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
ChainConfig() *params.ChainConfig
CurrentBlock() *types.Block
// Get balance
GetBalance(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*big.Int, error)
// Get validators for a particular epoch
GetValidators(epoch *big.Int) (*shard.Committee, error)
GetShardID() uint32
GetTransactionsHistory(address, txType, order string) ([]common.Hash, error)
GetStakingTransactionsHistory(address, txType, order string) ([]common.Hash, error)
GetTransactionsCount(address, txType string) (uint64, error)
GetStakingTransactionsCount(address, txType string) (uint64, error)
// retrieve the blockHash using txID and add blockHash to CxPool for resending
ResendCx(ctx context.Context, txID common.Hash) (uint64, bool)
IsLeader() bool
SendStakingTx(ctx context.Context, newStakingTx *staking.StakingTransaction) error
GetElectedValidatorAddresses() []common.Address
GetAllValidatorAddresses() []common.Address
GetValidatorInformation(addr common.Address, block *types.Block) (*staking.ValidatorRPCEnhanced, error)
GetDelegationsByValidator(validator common.Address) []*staking.Delegation
GetDelegationsByDelegator(delegator common.Address) ([]common.Address, []*staking.Delegation)
GetDelegationsByDelegatorByBlock(delegator common.Address, block *types.Block) ([]common.Address, []*staking.Delegation)
GetValidatorSelfDelegation(addr common.Address) *big.Int
GetShardState() (*shard.State, error)
GetCurrentStakingErrorSink() types.TransactionErrorReports
GetCurrentTransactionErrorSink() types.TransactionErrorReports
GetMedianRawStakeSnapshot() (*committee.CompletedEPoSRound, error)
GetPendingCXReceipts() []*types.CXReceiptsProof
GetCurrentUtilityMetrics() (*network.UtilityMetric, error)
GetSuperCommittees() (*quorum.Transition, error)
GetTotalStakingSnapshot() *big.Int
GetCurrentBadBlocks() []core.BadBlock
GetLastCrossLinks() ([]*types.CrossLink, error)
GetLatestChainHeaders() *block.HeaderPair
GetNodeMetadata() commonRPC.NodeMetadata
GetBlockSigners(ctx context.Context, blockNr rpc.BlockNumber) (shard.SlotList, *bls.Mask, error)
IsStakingEpoch(epoch *big.Int) bool
GetLeaderAddress(a common.Address, e *big.Int) string
GetPeerInfo() commonRPC.NodePeerInfo
}

@ -17,6 +17,7 @@ import (
"github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm" "github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/hmy"
internal_common "github.com/harmony-one/harmony/internal/common" internal_common "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/params" "github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
@ -39,12 +40,12 @@ const (
// PublicBlockChainAPI provides an API to access the Harmony blockchain. // PublicBlockChainAPI provides an API to access the Harmony blockchain.
// It offers only methods that operate on public data that is freely available to anyone. // It offers only methods that operate on public data that is freely available to anyone.
type PublicBlockChainAPI struct { type PublicBlockChainAPI struct {
b Backend hmy *hmy.Harmony
} }
// NewPublicBlockChainAPI creates a new Harmony blockchain API. // NewPublicBlockChainAPI creates a new Harmony blockchain API.
func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI { func NewPublicBlockChainAPI(hmy *hmy.Harmony) *PublicBlockChainAPI {
return &PublicBlockChainAPI{b} return &PublicBlockChainAPI{hmy}
} }
// BlockArgs is struct to include optional block formatting params. // BlockArgs is struct to include optional block formatting params.
@ -57,7 +58,7 @@ type BlockArgs struct {
} }
func (s *PublicBlockChainAPI) isBeaconShard() error { func (s *PublicBlockChainAPI) isBeaconShard() error {
if s.b.GetShardID() != shard.BeaconChainShardID { if s.hmy.ShardID != shard.BeaconChainShardID {
return ErrNotBeaconShard return ErrNotBeaconShard
} }
return nil return nil
@ -69,24 +70,24 @@ func (s *PublicBlockChainAPI) isBlockGreaterThanLatest(blockNum rpc.BlockNumber)
// since they are never greater than latest // since they are never greater than latest
if blockNum != rpc.PendingBlockNumber && if blockNum != rpc.PendingBlockNumber &&
blockNum != rpc.LatestBlockNumber && blockNum != rpc.LatestBlockNumber &&
uint64(blockNum) > s.b.CurrentBlock().NumberU64() { uint64(blockNum) > s.hmy.CurrentBlock().NumberU64() {
return ErrRequestedBlockTooHigh return ErrRequestedBlockTooHigh
} }
return nil return nil
} }
// GetBlockByNumber returns the requested block. When blockNr is -1 the chain head is returned. When fullTx is true all // GetBlockByNumber returns the requested block. When blockNum 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. // 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) { func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNum rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
if err := s.isBlockGreaterThanLatest(blockNr); err != nil { if err := s.isBlockGreaterThanLatest(blockNum); err != nil {
return nil, err return nil, err
} }
block, err := s.b.BlockByNumber(ctx, blockNr) blk, err := s.hmy.BlockByNumber(ctx, blockNum)
if block != nil { if blk != nil {
blockArgs := BlockArgs{WithSigners: false, InclTx: true, FullTx: fullTx, InclStaking: true} blockArgs := BlockArgs{WithSigners: false, InclTx: true, FullTx: fullTx, InclStaking: true}
leader := s.b.GetLeaderAddress(block.Header().Coinbase(), block.Header().Epoch()) leader := s.hmy.GetLeaderAddress(blk.Header().Coinbase(), blk.Header().Epoch())
response, err := RPCMarshalBlock(block, blockArgs, leader) response, err := RPCMarshalBlock(blk, blockArgs, leader)
if err == nil && blockNr == rpc.PendingBlockNumber { if err == nil && blockNum == rpc.PendingBlockNumber {
// Pending blocks need to nil out a few fields // Pending blocks need to nil out a few fields
for _, field := range []string{"hash", "nonce", "miner"} { for _, field := range []string{"hash", "nonce", "miner"} {
response[field] = nil response[field] = nil
@ -100,34 +101,34 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.
// GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full // 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. // detail, otherwise only the transaction hash is returned.
func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (map[string]interface{}, error) { func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (map[string]interface{}, error) {
block, err := s.b.GetBlock(ctx, blockHash) blk, err := s.hmy.GetBlock(ctx, blockHash)
if block != nil { if blk != nil {
blockArgs := BlockArgs{WithSigners: false, InclTx: true, FullTx: fullTx, InclStaking: true} blockArgs := BlockArgs{WithSigners: false, InclTx: true, FullTx: fullTx, InclStaking: true}
leader := s.b.GetLeaderAddress(block.Header().Coinbase(), block.Header().Epoch()) leader := s.hmy.GetLeaderAddress(blk.Header().Coinbase(), blk.Header().Epoch())
return RPCMarshalBlock(block, blockArgs, leader) return RPCMarshalBlock(blk, blockArgs, leader)
} }
return nil, err return nil, err
} }
// GetBlockByNumberNew returns the requested block. When blockNr is -1 the chain head is returned. When fullTx in blockArgs is true all // GetBlockByNumberNew returns the requested block. When blockNum is -1 the chain head is returned. When fullTx in blockArgs is true all
// transactions in the block are returned in full detail, otherwise only the transaction hash is returned. When withSigners in BlocksArgs is true // transactions in the block are returned in full detail, otherwise only the transaction hash is returned. When withSigners in BlocksArgs is true
// it shows block signers for this block in list of one addresses. // it shows block signers for this block in list of one addresses.
func (s *PublicBlockChainAPI) GetBlockByNumberNew(ctx context.Context, blockNr rpc.BlockNumber, blockArgs BlockArgs) (map[string]interface{}, error) { func (s *PublicBlockChainAPI) GetBlockByNumberNew(ctx context.Context, blockNum rpc.BlockNumber, blockArgs BlockArgs) (map[string]interface{}, error) {
if err := s.isBlockGreaterThanLatest(blockNr); err != nil { if err := s.isBlockGreaterThanLatest(blockNum); err != nil {
return nil, err return nil, err
} }
block, err := s.b.BlockByNumber(ctx, blockNr) blk, err := s.hmy.BlockByNumber(ctx, blockNum)
blockArgs.InclTx = true blockArgs.InclTx = true
if blockArgs.WithSigners { if blockArgs.WithSigners {
blockArgs.Signers, err = s.GetBlockSigners(ctx, blockNr) blockArgs.Signers, err = s.GetBlockSigners(ctx, blockNum)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
if block != nil { if blk != nil {
leader := s.b.GetLeaderAddress(block.Header().Coinbase(), block.Header().Epoch()) leader := s.hmy.GetLeaderAddress(blk.Header().Coinbase(), blk.Header().Epoch())
response, err := RPCMarshalBlock(block, blockArgs, leader) response, err := RPCMarshalBlock(blk, blockArgs, leader)
if err == nil && blockNr == rpc.PendingBlockNumber { if err == nil && blockNum == rpc.PendingBlockNumber {
// Pending blocks need to nil out a few fields // Pending blocks need to nil out a few fields
for _, field := range []string{"hash", "nonce", "miner"} { for _, field := range []string{"hash", "nonce", "miner"} {
response[field] = nil response[field] = nil
@ -142,26 +143,26 @@ func (s *PublicBlockChainAPI) GetBlockByNumberNew(ctx context.Context, blockNr r
// detail, otherwise only the transaction hash is returned. When withSigners in BlocksArgs is true // detail, otherwise only the transaction hash is returned. When withSigners in BlocksArgs is true
// it shows block signers for this block in list of one addresses. // it shows block signers for this block in list of one addresses.
func (s *PublicBlockChainAPI) GetBlockByHashNew(ctx context.Context, blockHash common.Hash, blockArgs BlockArgs) (map[string]interface{}, error) { func (s *PublicBlockChainAPI) GetBlockByHashNew(ctx context.Context, blockHash common.Hash, blockArgs BlockArgs) (map[string]interface{}, error) {
block, err := s.b.GetBlock(ctx, blockHash) blk, err := s.hmy.GetBlock(ctx, blockHash)
if err != nil {
return nil, err
}
blockArgs.InclTx = true blockArgs.InclTx = true
if blockArgs.WithSigners { if blockArgs.WithSigners {
blockArgs.Signers, err = s.GetBlockSigners(ctx, rpc.BlockNumber(block.NumberU64())) blockArgs.Signers, err = s.GetBlockSigners(ctx, rpc.BlockNumber(blk.NumberU64()))
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
if block != nil { leader := s.hmy.GetLeaderAddress(blk.Header().Coinbase(), blk.Header().Epoch())
leader := s.b.GetLeaderAddress(block.Header().Coinbase(), block.Header().Epoch()) return RPCMarshalBlock(blk, blockArgs, leader)
return RPCMarshalBlock(block, blockArgs, leader)
}
return nil, err
} }
// GetBlocks method returns blocks in range blockStart, blockEnd just like GetBlockByNumber but all at once. // GetBlocks method returns blocks in range blockStart, blockEnd just like GetBlockByNumber but all at once.
func (s *PublicBlockChainAPI) GetBlocks(ctx context.Context, blockStart rpc.BlockNumber, blockEnd rpc.BlockNumber, blockArgs BlockArgs) ([]map[string]interface{}, error) { func (s *PublicBlockChainAPI) GetBlocks(ctx context.Context, blockStart rpc.BlockNumber, blockEnd rpc.BlockNumber, blockArgs BlockArgs) ([]map[string]interface{}, error) {
result := make([]map[string]interface{}, 0) result := make([]map[string]interface{}, 0)
for i := blockStart; i <= blockEnd; i++ { for i := blockStart; i <= blockEnd; i++ {
block, err := s.b.BlockByNumber(ctx, i) blk, err := s.hmy.BlockByNumber(ctx, i)
blockArgs.InclTx = true blockArgs.InclTx = true
if blockArgs.WithSigners { if blockArgs.WithSigners {
blockArgs.Signers, err = s.GetBlockSigners(ctx, rpc.BlockNumber(i)) blockArgs.Signers, err = s.GetBlockSigners(ctx, rpc.BlockNumber(i))
@ -169,9 +170,9 @@ func (s *PublicBlockChainAPI) GetBlocks(ctx context.Context, blockStart rpc.Bloc
return nil, err return nil, err
} }
} }
if block != nil { if blk != nil {
leader := s.b.GetLeaderAddress(block.Header().Coinbase(), block.Header().Epoch()) leader := s.hmy.GetLeaderAddress(blk.Header().Coinbase(), blk.Header().Epoch())
rpcBlock, err := RPCMarshalBlock(block, blockArgs, leader) rpcBlock, err := RPCMarshalBlock(blk, blockArgs, leader)
if err == nil && i == rpc.PendingBlockNumber { if err == nil && i == rpc.PendingBlockNumber {
// Pending blocks need to nil out a few fields // Pending blocks need to nil out a few fields
for _, field := range []string{"hash", "nonce", "miner"} { for _, field := range []string{"hash", "nonce", "miner"} {
@ -186,16 +187,16 @@ func (s *PublicBlockChainAPI) GetBlocks(ctx context.Context, blockStart rpc.Bloc
// GetValidators returns validators list for a particular epoch. // GetValidators returns validators list for a particular epoch.
func (s *PublicBlockChainAPI) GetValidators(ctx context.Context, epoch int64) (map[string]interface{}, error) { func (s *PublicBlockChainAPI) GetValidators(ctx context.Context, epoch int64) (map[string]interface{}, error) {
committee, err := s.b.GetValidators(big.NewInt(epoch)) cmt, err := s.hmy.GetValidators(big.NewInt(epoch))
if err != nil { if err != nil {
return nil, err return nil, err
} }
balanceQueryBlock := shard.Schedule.EpochLastBlock(uint64(epoch)) balanceQueryBlock := shard.Schedule.EpochLastBlock(uint64(epoch))
if balanceQueryBlock > s.b.CurrentBlock().NumberU64() { if balanceQueryBlock > s.hmy.CurrentBlock().NumberU64() {
balanceQueryBlock = s.b.CurrentBlock().NumberU64() balanceQueryBlock = s.hmy.CurrentBlock().NumberU64()
} }
validators := make([]map[string]interface{}, 0) validators := make([]map[string]interface{}, 0)
for _, validator := range committee.Slots { for _, validator := range cmt.Slots {
oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress) oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress)
if err != nil { if err != nil {
return nil, err return nil, err
@ -211,7 +212,7 @@ func (s *PublicBlockChainAPI) GetValidators(ctx context.Context, epoch int64) (m
validators = append(validators, validatorsFields) validators = append(validators, validatorsFields)
} }
result := map[string]interface{}{ result := map[string]interface{}{
"shardID": committee.ShardID, "shardID": cmt.ShardID,
"validators": validators, "validators": validators,
} }
return result, nil return result, nil
@ -219,13 +220,13 @@ func (s *PublicBlockChainAPI) GetValidators(ctx context.Context, epoch int64) (m
// GetValidatorKeys returns list of bls public keys in the committee for a particular epoch. // GetValidatorKeys returns list of bls public keys in the committee for a particular epoch.
func (s *PublicBlockChainAPI) GetValidatorKeys(ctx context.Context, epoch int64) ([]string, error) { func (s *PublicBlockChainAPI) GetValidatorKeys(ctx context.Context, epoch int64) ([]string, error) {
committee, err := s.b.GetValidators(big.NewInt(epoch)) cmt, err := s.hmy.GetValidators(big.NewInt(epoch))
if err != nil { if err != nil {
return nil, err return nil, err
} }
validators := make([]string, len(committee.Slots)) validators := make([]string, len(cmt.Slots))
for i, v := range committee.Slots { for i, v := range cmt.Slots {
validators[i] = v.BLSPublicKey.Hex() validators[i] = v.BLSPublicKey.Hex()
} }
return validators, nil return validators, nil
@ -248,14 +249,14 @@ func (s *PublicBlockChainAPI) EpochLastBlock(epoch uint64) (uint64, error) {
} }
// GetBlockSigners returns signers for a particular block. // GetBlockSigners returns signers for a particular block.
func (s *PublicBlockChainAPI) GetBlockSigners(ctx context.Context, blockNr rpc.BlockNumber) ([]string, error) { func (s *PublicBlockChainAPI) GetBlockSigners(ctx context.Context, blockNum rpc.BlockNumber) ([]string, error) {
if uint64(blockNr) == 0 { if uint64(blockNum) == 0 {
return []string{}, nil return []string{}, nil
} }
if err := s.isBlockGreaterThanLatest(blockNr); err != nil { if err := s.isBlockGreaterThanLatest(blockNum); err != nil {
return nil, err return nil, err
} }
slots, mask, err := s.b.GetBlockSigners(ctx, blockNr) slots, mask, err := s.hmy.GetBlockSigners(ctx, blockNum)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -273,14 +274,14 @@ func (s *PublicBlockChainAPI) GetBlockSigners(ctx context.Context, blockNr rpc.B
} }
// GetBlockSignerKeys returns bls public keys that signed the block. // GetBlockSignerKeys returns bls public keys that signed the block.
func (s *PublicBlockChainAPI) GetBlockSignerKeys(ctx context.Context, blockNr rpc.BlockNumber) ([]string, error) { func (s *PublicBlockChainAPI) GetBlockSignerKeys(ctx context.Context, blockNum rpc.BlockNumber) ([]string, error) {
if uint64(blockNr) == 0 { if uint64(blockNum) == 0 {
return []string{}, nil return []string{}, nil
} }
if err := s.isBlockGreaterThanLatest(blockNr); err != nil { if err := s.isBlockGreaterThanLatest(blockNum); err != nil {
return nil, err return nil, err
} }
slots, mask, err := s.b.GetBlockSigners(ctx, blockNr) slots, mask, err := s.hmy.GetBlockSigners(ctx, blockNum)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -293,15 +294,15 @@ func (s *PublicBlockChainAPI) GetBlockSignerKeys(ctx context.Context, blockNr rp
return signers, nil return signers, nil
} }
// IsBlockSigner returns true if validator with address signed blockNr block. // IsBlockSigner returns true if validator with address signed blockNum block.
func (s *PublicBlockChainAPI) IsBlockSigner(ctx context.Context, blockNr rpc.BlockNumber, address string) (bool, error) { func (s *PublicBlockChainAPI) IsBlockSigner(ctx context.Context, blockNum rpc.BlockNumber, address string) (bool, error) {
if uint64(blockNr) == 0 { if uint64(blockNum) == 0 {
return false, nil return false, nil
} }
if err := s.isBlockGreaterThanLatest(blockNr); err != nil { if err := s.isBlockGreaterThanLatest(blockNum); err != nil {
return false, err return false, err
} }
slots, mask, err := s.b.GetBlockSigners(ctx, blockNr) slots, mask, err := s.hmy.GetBlockSigners(ctx, blockNum)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -352,7 +353,7 @@ func (s *PublicBlockChainAPI) GetValidatorSelfDelegation(ctx context.Context, ad
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return hexutil.Uint64(0), err return hexutil.Uint64(0), err
} }
return hexutil.Uint64(s.b.GetValidatorSelfDelegation(internal_common.ParseAddr(address)).Uint64()), nil return hexutil.Uint64(s.hmy.GetValidatorSelfDelegation(internal_common.ParseAddr(address)).Uint64()), nil
} }
// GetValidatorTotalDelegation returns total balace stacking for validator with delegation. // GetValidatorTotalDelegation returns total balace stacking for validator with delegation.
@ -360,7 +361,7 @@ func (s *PublicBlockChainAPI) GetValidatorTotalDelegation(ctx context.Context, a
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return hexutil.Uint64(0), err return hexutil.Uint64(0), err
} }
delegations := s.b.GetDelegationsByValidator(internal_common.ParseAddr(address)) delegations := s.hmy.GetDelegationsByValidator(internal_common.ParseAddr(address))
totalStake := big.NewInt(0) totalStake := big.NewInt(0)
for _, delegation := range delegations { for _, delegation := range delegations {
totalStake.Add(totalStake, delegation.Amount) totalStake.Add(totalStake, delegation.Amount)
@ -376,18 +377,18 @@ func (s *PublicBlockChainAPI) GetShardingStructure(ctx context.Context) ([]map[s
numShard := shard.Schedule.InstanceForEpoch(big.NewInt(int64(epoch))).NumShards() numShard := shard.Schedule.InstanceForEpoch(big.NewInt(int64(epoch))).NumShards()
// Return shareding structure for each case. // Return shareding structure for each case.
return shard.Schedule.GetShardingStructure(int(numShard), int(s.b.GetShardID())), nil return shard.Schedule.GetShardingStructure(int(numShard), int(s.hmy.ShardID)), nil
} }
// GetShardID returns shard ID of the requested node. // GetShardID returns shard ID of the requested node.
func (s *PublicBlockChainAPI) GetShardID(ctx context.Context) (int, error) { func (s *PublicBlockChainAPI) GetShardID(ctx context.Context) (int, error) {
return int(s.b.GetShardID()), nil return int(s.hmy.ShardID), nil
} }
// GetCode returns the code stored at the given address in the state for the given block number. // GetCode returns the code stored at the given address in the state for the given block number.
func (s *PublicBlockChainAPI) GetCode(ctx context.Context, addr string, blockNr rpc.BlockNumber) (hexutil.Bytes, error) { func (s *PublicBlockChainAPI) GetCode(ctx context.Context, addr string, blockNr rpc.BlockNumber) (hexutil.Bytes, error) {
address := internal_common.ParseAddr(addr) address := internal_common.ParseAddr(addr)
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) state, _, err := s.hmy.StateAndHeaderByNumber(ctx, blockNr)
if state == nil || err != nil { if state == nil || err != nil {
return nil, err return nil, err
} }
@ -400,7 +401,7 @@ func (s *PublicBlockChainAPI) GetCode(ctx context.Context, addr string, blockNr
// numbers are also allowed. // numbers are also allowed.
func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, addr string, key string, blockNr rpc.BlockNumber) (hexutil.Bytes, error) { func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, addr string, key string, blockNr rpc.BlockNumber) (hexutil.Bytes, error) {
address := internal_common.ParseAddr(addr) address := internal_common.ParseAddr(addr)
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) state, _, err := s.hmy.StateAndHeaderByNumber(ctx, blockNr)
if state == nil || err != nil { if state == nil || err != nil {
return nil, err return nil, err
} }
@ -410,7 +411,7 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, addr string, key
func (s *PublicBlockChainAPI) getBalanceByBlockNumber(ctx context.Context, address string, blockNr rpc.BlockNumber) (*hexutil.Big, error) { func (s *PublicBlockChainAPI) getBalanceByBlockNumber(ctx context.Context, address string, blockNr rpc.BlockNumber) (*hexutil.Big, error) {
addr := internal_common.ParseAddr(address) addr := internal_common.ParseAddr(address)
balance, err := s.b.GetBalance(ctx, addr, blockNr) balance, err := s.hmy.GetBalance(ctx, addr, blockNr)
if balance == nil { if balance == nil {
return nil, err return nil, err
} }
@ -428,7 +429,7 @@ func (s *PublicBlockChainAPI) GetBalanceByBlockNumber(ctx context.Context, addre
// GetAccountNonce returns the nonce value of the given address for the given block number // GetAccountNonce returns the nonce value of the given address for the given block number
func (s *PublicBlockChainAPI) GetAccountNonce(ctx context.Context, address string, blockNr rpc.BlockNumber) (uint64, error) { func (s *PublicBlockChainAPI) GetAccountNonce(ctx context.Context, address string, blockNr rpc.BlockNumber) (uint64, error) {
addr := internal_common.ParseAddr(address) addr := internal_common.ParseAddr(address)
return s.b.GetAccountNonce(ctx, addr, rpc.BlockNumber(blockNr)) return s.hmy.GetAccountNonce(ctx, addr, rpc.BlockNumber(blockNr))
} }
// GetBalance returns the amount of Atto for the given address in the state of the // GetBalance returns the amount of Atto for the given address in the state of the
@ -440,7 +441,7 @@ func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address string, bl
// BlockNumber returns the block number of the chain head. // BlockNumber returns the block number of the chain head.
func (s *PublicBlockChainAPI) BlockNumber() hexutil.Uint64 { func (s *PublicBlockChainAPI) BlockNumber() hexutil.Uint64 {
header, _ := s.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available header, _ := s.hmy.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available
if header == nil { if header == nil {
return 0 return 0
} }
@ -453,118 +454,21 @@ func (s *PublicBlockChainAPI) BlockNumber() hexutil.Uint64 {
// withdrawn already from the source shard but not credited yet in the // withdrawn already from the source shard but not credited yet in the
// destination account due to transient failures. // destination account due to transient failures.
func (s *PublicBlockChainAPI) ResendCx(ctx context.Context, txID common.Hash) (bool, error) { func (s *PublicBlockChainAPI) ResendCx(ctx context.Context, txID common.Hash) (bool, error) {
_, success := s.b.ResendCx(ctx, txID) _, success := s.hmy.ResendCx(ctx, txID)
return success, nil return success, nil
} }
// Call executes the given transaction on the state for the given block number. // 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. // 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) { func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Bytes, error) {
result, _, _, err := doCall(ctx, s.b, args, blockNr, vm.Config{}, 5*time.Second, s.b.RPCGasCap()) result, _, _, err := doCall(ctx, s.hmy, args, blockNr, vm.Config{}, 5*time.Second, s.hmy.RPCGasCap)
return (hexutil.Bytes)(result), err return (hexutil.Bytes)(result), err
} }
func doCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config, timeout time.Duration, globalGasCap *big.Int) ([]byte, uint64, bool, error) {
defer func(start time.Time) {
utils.Logger().Debug().
Dur("runtime", time.Since(start)).
Msg("Executing EVM call finished")
}(time.Now())
state, header, err := b.StateAndHeaderByNumber(ctx, blockNr)
if state == nil || err != nil {
return nil, 0, false, err
}
// Set sender address or use a default if none specified
var addr common.Address
if args.From == nil {
// TODO(ricl): this logic was borrowed from [go-ethereum](https://github.com/ethereum/go-ethereum/blob/f578d41ee6b3087f8021fd561a0b5665aea3dba6/internal/ethapi/api.go#L738)
// [question](https://ethereum.stackexchange.com/questions/72979/why-does-the-docall-function-use-the-first-account-by-default)
// Might need to reconsider the logic
// if wallets := b.AccountManager().Wallets(); len(wallets) > 0 {
// if accounts := wallets[0].Accounts(); len(accounts) > 0 {
// addr = accounts[0].Address
// }
// }
// The logic in ethereum is to pick a random address managed under the account manager.
// Currently Harmony no longers support the account manager.
// Any address does not affect the logic of this call.
addr = common.HexToAddress(defaultFromAddress)
} else {
addr = *args.From
}
// Set default gas & gas price if none were set
gas := uint64(math.MaxUint64 / 2)
if args.Gas != nil {
gas = uint64(*args.Gas)
}
if globalGasCap != nil && globalGasCap.Uint64() < gas {
utils.Logger().Warn().
Uint64("requested", gas).
Uint64("cap", globalGasCap.Uint64()).
Msg("Caller gas above allowance, capping")
gas = globalGasCap.Uint64()
}
gasPrice := new(big.Int).SetUint64(defaultGasPrice)
if args.GasPrice != nil {
gasPrice = args.GasPrice.ToInt()
}
value := new(big.Int)
if args.Value != nil {
value = args.Value.ToInt()
}
var data []byte
if args.Data != nil {
data = []byte(*args.Data)
}
// Create new call message
msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, false)
// Setup context so it may be cancelled the call has completed
// or, in case of unmetered gas, setup a context with a timeout.
var cancel context.CancelFunc
if timeout > 0 {
ctx, cancel = context.WithTimeout(ctx, timeout)
} else {
ctx, cancel = context.WithCancel(ctx)
}
// Make sure the context is cancelled when the call has completed
// this makes sure resources are cleaned up.
defer cancel()
// Get a new instance of the EVM.
evm, vmError, err := b.GetEVM(ctx, msg, state, header)
if err != nil {
return nil, 0, 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() {
<-ctx.Done()
evm.Cancel()
}()
// Setup the gas pool (also for unmetered requests)
// and apply the message.
gp := new(core.GasPool).AddGas(math.MaxUint64)
res, gas, failed, err := core.ApplyMessage(evm, msg, gp)
if err := vmError(); err != nil {
return nil, 0, false, err
}
// If the timer caused an abort, return an appropriate error message
if evm.Cancelled() {
return nil, 0, false, fmt.Errorf("execution aborted (timeout = %v)", timeout)
}
return res, gas, failed, err
}
// LatestHeader returns the latest header information // LatestHeader returns the latest header information
func (s *PublicBlockChainAPI) LatestHeader(ctx context.Context) *HeaderInformation { func (s *PublicBlockChainAPI) LatestHeader(ctx context.Context) *HeaderInformation {
header, _ := s.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available header, _ := s.hmy.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available
leader := s.b.GetLeaderAddress(header.Coinbase(), header.Epoch()) leader := s.hmy.GetLeaderAddress(header.Coinbase(), header.Epoch())
return newHeaderInformation(header, leader) return newHeaderInformation(header, leader)
} }
@ -573,11 +477,11 @@ func (s *PublicBlockChainAPI) GetHeaderByNumber(ctx context.Context, blockNum rp
if err := s.isBlockGreaterThanLatest(blockNum); err != nil { if err := s.isBlockGreaterThanLatest(blockNum); err != nil {
return nil, err return nil, err
} }
header, err := s.b.HeaderByNumber(context.Background(), blockNum) header, err := s.hmy.HeaderByNumber(context.Background(), blockNum)
if err != nil { if err != nil {
return nil, err return nil, err
} }
leader := s.b.GetLeaderAddress(header.Coinbase(), header.Epoch()) leader := s.hmy.GetLeaderAddress(header.Coinbase(), header.Epoch())
return newHeaderInformation(header, leader), nil return newHeaderInformation(header, leader), nil
} }
@ -587,7 +491,7 @@ func (s *PublicBlockChainAPI) GetTotalStaking() (*big.Int, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
return s.b.GetTotalStakingSnapshot(), nil return s.hmy.GetTotalStakingSnapshot(), nil
} }
// GetMedianRawStakeSnapshot returns the raw median stake, only meant to be called on beaconchain // GetMedianRawStakeSnapshot returns the raw median stake, only meant to be called on beaconchain
@ -598,12 +502,12 @@ func (s *PublicBlockChainAPI) GetMedianRawStakeSnapshot() (
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
return s.b.GetMedianRawStakeSnapshot() return s.hmy.GetMedianRawStakeSnapshot()
} }
// GetLatestChainHeaders .. // GetLatestChainHeaders ..
func (s *PublicBlockChainAPI) GetLatestChainHeaders() *block.HeaderPair { func (s *PublicBlockChainAPI) GetLatestChainHeaders() *block.HeaderPair {
return s.b.GetLatestChainHeaders() return s.hmy.GetLatestChainHeaders()
} }
// GetAllValidatorAddresses returns all validator addresses. // GetAllValidatorAddresses returns all validator addresses.
@ -611,7 +515,7 @@ func (s *PublicBlockChainAPI) GetAllValidatorAddresses() ([]string, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
validatorAddresses := s.b.GetAllValidatorAddresses() validatorAddresses := s.hmy.GetAllValidatorAddresses()
addresses := make([]string, len(validatorAddresses)) addresses := make([]string, len(validatorAddresses))
for i, addr := range validatorAddresses { for i, addr := range validatorAddresses {
oneAddr, _ := internal_common.AddressToBech32(addr) oneAddr, _ := internal_common.AddressToBech32(addr)
@ -625,7 +529,7 @@ func (s *PublicBlockChainAPI) GetElectedValidatorAddresses() ([]string, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
electedAddresses := s.b.GetElectedValidatorAddresses() electedAddresses := s.hmy.GetElectedValidatorAddresses()
addresses := make([]string, len(electedAddresses)) addresses := make([]string, len(electedAddresses))
for i, addr := range electedAddresses { for i, addr := range electedAddresses {
oneAddr, _ := internal_common.AddressToBech32(addr) oneAddr, _ := internal_common.AddressToBech32(addr)
@ -641,12 +545,12 @@ func (s *PublicBlockChainAPI) GetValidatorInformation(
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(rpc.LatestBlockNumber)) blk, err := s.hmy.BlockByNumber(ctx, rpc.BlockNumber(rpc.LatestBlockNumber))
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "could not retrieve the latest block information") return nil, errors.Wrapf(err, "could not retrieve the latest blk information")
} }
return s.b.GetValidatorInformation( return s.hmy.GetValidatorInformation(
internal_common.ParseAddr(address), block, internal_common.ParseAddr(address), blk,
) )
} }
@ -660,12 +564,12 @@ func (s *PublicBlockChainAPI) GetValidatorInformationByBlockNumber(
if err := s.isBlockGreaterThanLatest(blockNr); err != nil { if err := s.isBlockGreaterThanLatest(blockNr); err != nil {
return nil, err return nil, err
} }
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr)) blk, err := s.hmy.BlockByNumber(ctx, rpc.BlockNumber(blockNr))
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "could not retrieve the block information for block number: %d", blockNr) return nil, errors.Wrapf(err, "could not retrieve the blk information for blk number: %d", blockNr)
} }
return s.b.GetValidatorInformation( return s.hmy.GetValidatorInformation(
internal_common.ParseAddr(address), block, internal_common.ParseAddr(address), blk,
) )
} }
@ -675,7 +579,7 @@ func (s *PublicBlockChainAPI) getAllValidatorInformation(
if page < -1 { if page < -1 {
return nil, errors.Errorf("page given %d cannot be less than -1", page) return nil, errors.Errorf("page given %d cannot be less than -1", page)
} }
addresses := s.b.GetAllValidatorAddresses() addresses := s.hmy.GetAllValidatorAddresses()
if page != -1 && len(addresses) <= page*validatorsPageSize { if page != -1 && len(addresses) <= page*validatorsPageSize {
return make([]*staking.ValidatorRPCEnhanced, 0), nil return make([]*staking.ValidatorRPCEnhanced, 0), nil
} }
@ -689,12 +593,12 @@ func (s *PublicBlockChainAPI) getAllValidatorInformation(
} }
} }
validators := []*staking.ValidatorRPCEnhanced{} validators := []*staking.ValidatorRPCEnhanced{}
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr)) blk, err := s.hmy.BlockByNumber(ctx, rpc.BlockNumber(blockNr))
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "could not retrieve the block information for block number: %d", blockNr) return nil, errors.Wrapf(err, "could not retrieve the blk information for blk number: %d", blockNr)
} }
for i := start; i < start+validatorsNum; i++ { for i := start; i < start+validatorsNum; i++ {
information, err := s.b.GetValidatorInformation(addresses[i], block) information, err := s.hmy.GetValidatorInformation(addresses[i], blk)
if err == nil { if err == nil {
validators = append(validators, information) validators = append(validators, information)
} }
@ -710,14 +614,14 @@ func (s *PublicBlockChainAPI) GetAllValidatorInformation(
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
blockNr := s.b.CurrentBlock().NumberU64() blockNr := s.hmy.CurrentBlock().NumberU64()
// delete cache for previous block // delete cache for previous block
prevKey := fmt.Sprintf("all-info-%d", blockNr-1) prevKey := fmt.Sprintf("all-info-%d", blockNr-1)
s.b.SingleFlightForgetKey(prevKey) s.hmy.SingleFlightForgetKey(prevKey)
key := fmt.Sprintf("all-info-%d", blockNr) key := fmt.Sprintf("all-info-%d", blockNr)
res, err := s.b.SingleFlightRequest( res, err := s.hmy.SingleFlightRequest(
key, key,
func() (interface{}, error) { func() (interface{}, error) {
return s.getAllValidatorInformation(ctx, page, rpc.LatestBlockNumber) return s.getAllValidatorInformation(ctx, page, rpc.LatestBlockNumber)
@ -753,7 +657,7 @@ func (s *PublicBlockChainAPI) GetAllDelegationInformation(ctx context.Context, p
if page < -1 { if page < -1 {
return make([][]*RPCDelegation, 0), nil return make([][]*RPCDelegation, 0), nil
} }
addresses := s.b.GetAllValidatorAddresses() addresses := s.hmy.GetAllValidatorAddresses()
if page != -1 && len(addresses) <= page*validatorsPageSize { if page != -1 && len(addresses) <= page*validatorsPageSize {
return make([][]*RPCDelegation, 0), nil return make([][]*RPCDelegation, 0), nil
} }
@ -783,7 +687,7 @@ func (s *PublicBlockChainAPI) GetDelegationsByDelegator(ctx context.Context, add
return nil, err return nil, err
} }
delegatorAddress := internal_common.ParseAddr(address) delegatorAddress := internal_common.ParseAddr(address)
validators, delegations := s.b.GetDelegationsByDelegator(delegatorAddress) validators, delegations := s.hmy.GetDelegationsByDelegator(delegatorAddress)
result := []*RPCDelegation{} result := []*RPCDelegation{}
for i := range delegations { for i := range delegations {
delegation := delegations[i] delegation := delegations[i]
@ -820,11 +724,11 @@ func (s *PublicBlockChainAPI) GetDelegationsByDelegatorByBlockNumber(
return nil, err return nil, err
} }
delegatorAddress := internal_common.ParseAddr(address) delegatorAddress := internal_common.ParseAddr(address)
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNum)) blk, err := s.hmy.BlockByNumber(ctx, rpc.BlockNumber(blockNum))
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "could not retrieve the block information for block number: %d", blockNum) return nil, errors.Wrapf(err, "could not retrieve the blk information for blk number: %d", blockNum)
} }
validators, delegations := s.b.GetDelegationsByDelegatorByBlock(delegatorAddress, block) validators, delegations := s.hmy.GetDelegationsByDelegatorByBlock(delegatorAddress, blk)
result := make([]*RPCDelegation, len(delegations)) result := make([]*RPCDelegation, len(delegations))
for i := range delegations { for i := range delegations {
delegation := delegations[i] delegation := delegations[i]
@ -856,7 +760,7 @@ func (s *PublicBlockChainAPI) GetDelegationsByValidator(ctx context.Context, add
return nil, err return nil, err
} }
validatorAddress := internal_common.ParseAddr(address) validatorAddress := internal_common.ParseAddr(address)
delegations := s.b.GetDelegationsByValidator(validatorAddress) delegations := s.hmy.GetDelegationsByValidator(validatorAddress)
result := make([]*RPCDelegation, 0) result := make([]*RPCDelegation, 0)
for _, delegation := range delegations { for _, delegation := range delegations {
@ -888,7 +792,7 @@ func (s *PublicBlockChainAPI) GetDelegationByDelegatorAndValidator(ctx context.C
} }
delegatorAddress := internal_common.ParseAddr(address) delegatorAddress := internal_common.ParseAddr(address)
validatorAddress := internal_common.ParseAddr(validator) validatorAddress := internal_common.ParseAddr(validator)
validators, delegations := s.b.GetDelegationsByDelegator(delegatorAddress) validators, delegations := s.hmy.GetDelegationsByDelegator(delegatorAddress)
for i := range delegations { for i := range delegations {
if validators[i] != validatorAddress { if validators[i] != validatorAddress {
continue continue
@ -916,67 +820,10 @@ func (s *PublicBlockChainAPI) GetDelegationByDelegatorAndValidator(ctx context.C
return nil, nil return nil, nil
} }
// doEstimateGas ..
func doEstimateGas(ctx context.Context, b Backend, args CallArgs, gasCap *big.Int) (hexutil.Uint64, error) {
// Binary search the gas requirement, as it may be higher than the amount used
var (
lo = params.TxGas - 1
hi uint64
cap uint64
)
blockNum := rpc.LatestBlockNumber
if args.Gas != nil && uint64(*args.Gas) >= params.TxGas {
hi = uint64(*args.Gas)
} else {
// Retrieve the block to act as the gas ceiling
block, err := b.BlockByNumber(ctx, blockNum)
if err != nil {
return 0, err
}
hi = block.GasLimit()
}
if gasCap != nil && hi > gasCap.Uint64() {
// log.Warn("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
hi = gasCap.Uint64()
}
cap = hi
// Use zero-address if none other is available
if args.From == nil {
args.From = &common.Address{}
}
// Create a helper to check if a gas allowance results in an executable transaction
executable := func(gas uint64) bool {
args.Gas = (*hexutil.Uint64)(&gas)
_, _, failed, err := doCall(ctx, b, args, blockNum, vm.Config{}, 0, big.NewInt(int64(cap)))
if err != nil || failed {
return false
}
return true
}
// Execute the binary search and hone in on an executable gas limit
for lo+1 < hi {
mid := (hi + lo) / 2
if !executable(mid) {
lo = mid
} else {
hi = mid
}
}
// Reject the transaction as invalid if it still fails at the highest allowance
if hi == cap {
if !executable(hi) {
return 0, fmt.Errorf("gas required exceeds allowance (%d) or always failing transaction", cap)
}
}
return hexutil.Uint64(hi), nil
}
// EstimateGas returns an estimate of the amount of gas needed to execute the // EstimateGas returns an estimate of the amount of gas needed to execute the
// given transaction against the current pending block. // given transaction against the current pending block.
func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (hexutil.Uint64, error) { func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (hexutil.Uint64, error) {
return doEstimateGas(ctx, s.b, args, nil) return doEstimateGas(ctx, s.hmy, args, nil)
} }
// GetCurrentUtilityMetrics .. // GetCurrentUtilityMetrics ..
@ -984,7 +831,7 @@ func (s *PublicBlockChainAPI) GetCurrentUtilityMetrics() (*network.UtilityMetric
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
return s.b.GetCurrentUtilityMetrics() return s.hmy.GetCurrentUtilityMetrics()
} }
// GetSuperCommittees .. // GetSuperCommittees ..
@ -992,12 +839,12 @@ func (s *PublicBlockChainAPI) GetSuperCommittees() (*quorum.Transition, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
return s.b.GetSuperCommittees() return s.hmy.GetSuperCommittees()
} }
// GetCurrentBadBlocks .. // GetCurrentBadBlocks ..
func (s *PublicBlockChainAPI) GetCurrentBadBlocks() []core.BadBlock { func (s *PublicBlockChainAPI) GetCurrentBadBlocks() []core.BadBlock {
return s.b.GetCurrentBadBlocks() return s.hmy.GetCurrentBadBlocks()
} }
// GetTotalSupply .. // GetTotalSupply ..
@ -1038,5 +885,149 @@ func (s *PublicBlockChainAPI) GetLastCrossLinks() ([]*types.CrossLink, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
return s.b.GetLastCrossLinks() return s.hmy.GetLastCrossLinks()
}
// docall executes an EVM call
func doCall(ctx context.Context, hmy *hmy.Harmony, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config, timeout time.Duration, globalGasCap *big.Int) ([]byte, uint64, bool, error) {
defer func(start time.Time) {
utils.Logger().Debug().
Dur("runtime", time.Since(start)).
Msg("Executing EVM call finished")
}(time.Now())
state, header, err := hmy.StateAndHeaderByNumber(ctx, blockNr)
if state == nil || err != nil {
return nil, 0, false, err
}
// Set sender address or use a default if none specified
var addr common.Address
if args.From == nil {
// Any address does not affect the logic of this call.
addr = common.HexToAddress(defaultFromAddress)
} else {
addr = *args.From
}
// Set default gas & gas price if none were set
gas := uint64(math.MaxUint64 / 2)
if args.Gas != nil {
gas = uint64(*args.Gas)
}
if globalGasCap != nil && globalGasCap.Uint64() < gas {
utils.Logger().Warn().
Uint64("requested", gas).
Uint64("cap", globalGasCap.Uint64()).
Msg("Caller gas above allowance, capping")
gas = globalGasCap.Uint64()
}
gasPrice := new(big.Int).SetUint64(defaultGasPrice)
if args.GasPrice != nil {
gasPrice = args.GasPrice.ToInt()
}
value := new(big.Int)
if args.Value != nil {
value = args.Value.ToInt()
}
var data []byte
if args.Data != nil {
data = []byte(*args.Data)
}
// Create new call message
msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, false)
// Setup context so it may be cancelled the call has completed
// or, in case of unmetered gas, setup a context with a timeout.
var cancel context.CancelFunc
if timeout > 0 {
ctx, cancel = context.WithTimeout(ctx, timeout)
} else {
ctx, cancel = context.WithCancel(ctx)
}
// Make sure the context is cancelled when the call has completed
// this makes sure resources are cleaned up.
defer cancel()
// Get a new instance of the EVM.
evm, vmError, err := hmy.GetEVM(ctx, msg, state, header)
if err != nil {
return nil, 0, 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() {
<-ctx.Done()
evm.Cancel()
}()
// Setup the gas pool (also for unmetered requests)
// and apply the message.
gp := new(core.GasPool).AddGas(math.MaxUint64)
res, gas, failed, err := core.ApplyMessage(evm, msg, gp)
if err := vmError(); err != nil {
return nil, 0, false, err
}
// If the timer caused an abort, return an appropriate error message
if evm.Cancelled() {
return nil, 0, false, fmt.Errorf("execution aborted (timeout = %v)", timeout)
}
return res, gas, failed, err
}
// doEstimateGas ..
func doEstimateGas(ctx context.Context, hmy *hmy.Harmony, args CallArgs, gasCap *big.Int) (hexutil.Uint64, error) {
// Binary search the gas requirement, as it may be higher than the amount used
var (
lo = params.TxGas - 1
hi uint64
max uint64
)
blockNum := rpc.LatestBlockNumber
if args.Gas != nil && uint64(*args.Gas) >= params.TxGas {
hi = uint64(*args.Gas)
} else {
// Retrieve the blk to act as the gas ceiling
blk, err := hmy.BlockByNumber(ctx, blockNum)
if err != nil {
return 0, err
}
hi = blk.GasLimit()
}
if gasCap != nil && hi > gasCap.Uint64() {
hi = gasCap.Uint64()
}
max = hi
// Use zero-address if none other is available
if args.From == nil {
args.From = &common.Address{}
}
// Create a helper to check if a gas allowance results in an executable transaction
executable := func(gas uint64) bool {
args.Gas = (*hexutil.Uint64)(&gas)
_, _, failed, err := doCall(ctx, hmy, args, blockNum, vm.Config{}, 0, big.NewInt(int64(max)))
if err != nil || failed {
return false
}
return true
}
// Execute the binary search and hone in on an executable gas limit
for lo+1 < hi {
mid := (hi + lo) / 2
if !executable(mid) {
lo = mid
} else {
hi = mid
}
}
// Reject the transaction as invalid if it still fails at the highest allowance
if hi == max {
if !executable(hi) {
return 0, fmt.Errorf("gas required exceeds allowance (%d) or always failing transaction", max)
}
}
return hexutil.Uint64(hi), nil
} }

@ -4,17 +4,18 @@ import (
"context" "context"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/harmony-one/harmony/hmy"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
) )
// DebugAPI Internal JSON RPC for debugging purpose // DebugAPI Internal JSON RPC for debugging purpose
type DebugAPI struct { type DebugAPI struct {
b Backend hmy *hmy.Harmony
} }
// NewDebugAPI Creates a new DebugAPI instance // NewDebugAPI Creates a new DebugAPI instance
func NewDebugAPI(b Backend) *DebugAPI { func NewDebugAPI(hmy *hmy.Harmony) *DebugAPI {
return &DebugAPI{b} return &DebugAPI{hmy}
} }
// SetLogVerbosity Sets log verbosity on runtime // SetLogVerbosity Sets log verbosity on runtime

@ -5,24 +5,24 @@ import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/harmony-one/harmony/api/proto" "github.com/harmony-one/harmony/hmy"
commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common" commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common"
) )
// PublicHarmonyAPI provides an API to access Harmony related information. // PublicHarmonyAPI provides an API to access Harmony related information.
// It offers only methods that operate on public data that is freely available to anyone. // It offers only methods that operate on public data that is freely available to anyone.
type PublicHarmonyAPI struct { type PublicHarmonyAPI struct {
b Backend hmy *hmy.Harmony
} }
// NewPublicHarmonyAPI ... // NewPublicHarmonyAPI ...
func NewPublicHarmonyAPI(b Backend) *PublicHarmonyAPI { func NewPublicHarmonyAPI(hmy *hmy.Harmony) *PublicHarmonyAPI {
return &PublicHarmonyAPI{b} return &PublicHarmonyAPI{hmy}
} }
// ProtocolVersion returns the current Harmony protocol version this node supports // ProtocolVersion returns the current Harmony protocol version this node supports
func (s *PublicHarmonyAPI) ProtocolVersion() hexutil.Uint { func (s *PublicHarmonyAPI) ProtocolVersion() hexutil.Uint {
return hexutil.Uint(proto.ProtocolVersion) return hexutil.Uint(s.hmy.ProtocolVersion())
} }
// Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not // Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not
@ -33,7 +33,7 @@ func (s *PublicHarmonyAPI) ProtocolVersion() hexutil.Uint {
// - pulledStates: number of state entries processed until now // - pulledStates: number of state entries processed until now
// - knownStates: number of known state entries that still need to be pulled // - knownStates: number of known state entries that still need to be pulled
func (s *PublicHarmonyAPI) Syncing() (interface{}, error) { func (s *PublicHarmonyAPI) Syncing() (interface{}, error) {
// TODO(ricl): find our Downloader module for syncing blocks // TODO(dm): find our Downloader module for syncing blocks
return false, nil return false, nil
} }
@ -45,10 +45,10 @@ func (s *PublicHarmonyAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) {
// GetNodeMetadata produces a NodeMetadata record, data is from the answering RPC node // GetNodeMetadata produces a NodeMetadata record, data is from the answering RPC node
func (s *PublicHarmonyAPI) GetNodeMetadata() commonRPC.NodeMetadata { func (s *PublicHarmonyAPI) GetNodeMetadata() commonRPC.NodeMetadata {
return s.b.GetNodeMetadata() return s.hmy.GetNodeMetadata()
} }
// GetPeerInfo produces a NodePeerInfo record // GetPeerInfo produces a NodePeerInfo record
func (s *PublicHarmonyAPI) GetPeerInfo() commonRPC.NodePeerInfo { func (s *PublicHarmonyAPI) GetPeerInfo() commonRPC.NodePeerInfo {
return s.b.GetPeerInfo() return s.hmy.GetPeerInfo()
} }

@ -9,13 +9,13 @@ import (
// PublicNetAPI offers network related RPC methods // PublicNetAPI offers network related RPC methods
type PublicNetAPI struct { type PublicNetAPI struct {
net p2p.Host net p2p.Host
networkVersion uint64 chainID uint64
} }
// NewPublicNetAPI creates a new net API instance. // NewPublicNetAPI creates a new net API instance.
func NewPublicNetAPI(net p2p.Host, networkVersion uint64) *PublicNetAPI { func NewPublicNetAPI(net p2p.Host, chainID uint64) *PublicNetAPI {
return &PublicNetAPI{net, networkVersion} return &PublicNetAPI{net, chainID}
} }
// PeerCount returns the number of connected peers // PeerCount returns the number of connected peers
@ -23,7 +23,7 @@ func (s *PublicNetAPI) PeerCount() hexutil.Uint {
return hexutil.Uint(s.net.GetPeerCount()) return hexutil.Uint(s.net.GetPeerCount())
} }
// Version returns the network version, i.e. network ID identifying which network we are using // Version returns the network version, i.e. ChainID identifying which network we are using
func (s *PublicNetAPI) Version() string { func (s *PublicNetAPI) Version() string {
return fmt.Sprintf("%d", s.networkVersion) // TODO(ricl): we should add support for network id (https://github.com/ethereum/wiki/wiki/JSON-RPC#net_version) return fmt.Sprintf("%d", s.chainID)
} }

@ -1,21 +0,0 @@
package apiv1
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
// SendTxArgs represents the arguments to sumbit a new transaction into the transaction pool.
type SendTxArgs struct {
From common.Address `json:"from"`
To *common.Address `json:"to"`
ShardID uint32 `json:"shardID"`
Gas *hexutil.Uint64 `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"`
Value *hexutil.Big `json:"value"`
Nonce *hexutil.Uint64 `json:"nonce"`
// We accept "data" and "input" for backwards-compatibility reasons. "input" is the
// newer name and should be preferred by clients.
Data *hexutil.Bytes `json:"data"`
Input *hexutil.Bytes `json:"input"`
}

@ -11,6 +11,7 @@ import (
"github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/rawdb" "github.com/harmony-one/harmony/core/rawdb"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/hmy"
internal_common "github.com/harmony-one/harmony/internal/common" internal_common "github.com/harmony-one/harmony/internal/common"
staking "github.com/harmony-one/harmony/staking/types" staking "github.com/harmony-one/harmony/staking/types"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -28,13 +29,13 @@ type TxHistoryArgs struct {
// PublicTransactionPoolAPI exposes methods for the RPC interface // PublicTransactionPoolAPI exposes methods for the RPC interface
type PublicTransactionPoolAPI struct { type PublicTransactionPoolAPI struct {
b Backend hmy *hmy.Harmony
nonceLock *AddrLocker nonceLock *AddrLocker
} }
// NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool. // NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool.
func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransactionPoolAPI { func NewPublicTransactionPoolAPI(hmy *hmy.Harmony, nonceLock *AddrLocker) *PublicTransactionPoolAPI {
return &PublicTransactionPoolAPI{b, nonceLock} return &PublicTransactionPoolAPI{hmy, nonceLock}
} }
// GetTransactionsHistory returns the list of transactions hashes that involve a particular address. // GetTransactionsHistory returns the list of transactions hashes that involve a particular address.
@ -51,7 +52,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionsHistory(ctx context.Context, a
return nil, err return nil, err
} }
} }
hashes, err := s.b.GetTransactionsHistory(address, args.TxType, args.Order) hashes, err := s.hmy.GetTransactionsHistory(address, args.TxType, args.Order)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -68,8 +69,8 @@ func (s *PublicTransactionPoolAPI) GetTransactionsHistory(ctx context.Context, a
} }
// GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number. // 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 { func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNum rpc.BlockNumber) *hexutil.Uint {
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { if block, _ := s.hmy.BlockByNumber(ctx, blockNum); block != nil {
n := hexutil.Uint(len(block.Transactions())) n := hexutil.Uint(len(block.Transactions()))
return &n return &n
} }
@ -78,7 +79,7 @@ func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.
// GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash. // 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 { func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint {
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { if block, _ := s.hmy.GetBlock(ctx, blockHash); block != nil {
n := hexutil.Uint(len(block.Transactions())) n := hexutil.Uint(len(block.Transactions()))
return &n return &n
} }
@ -86,8 +87,8 @@ func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Co
} }
// GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. // 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 { func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNum rpc.BlockNumber, index hexutil.Uint) *RPCTransaction {
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { if block, _ := s.hmy.BlockByNumber(ctx, blockNum); block != nil {
return newRPCTransactionFromBlockIndex(block, uint64(index)) return newRPCTransactionFromBlockIndex(block, uint64(index))
} }
return nil return nil
@ -95,7 +96,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx conte
// GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. // 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 { func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction {
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { if block, _ := s.hmy.GetBlock(ctx, blockHash); block != nil {
return newRPCTransactionFromBlockIndex(block, uint64(index)) return newRPCTransactionFromBlockIndex(block, uint64(index))
} }
return nil return nil
@ -104,8 +105,8 @@ func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context
// GetTransactionByHash returns the plain transaction for the given hash // GetTransactionByHash returns the plain transaction for the given hash
func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) *RPCTransaction { func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) *RPCTransaction {
// Try to return an already finalized transaction // Try to return an already finalized transaction
tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.b.ChainDb(), hash) tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.hmy.ChainDb(), hash)
block, _ := s.b.GetBlock(ctx, blockHash) block, _ := s.hmy.GetBlock(ctx, blockHash)
if block == nil { if block == nil {
return nil return nil
} }
@ -119,8 +120,8 @@ func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, has
// GetStakingTransactionByHash returns the staking transaction for the given hash // GetStakingTransactionByHash returns the staking transaction for the given hash
func (s *PublicTransactionPoolAPI) GetStakingTransactionByHash(ctx context.Context, hash common.Hash) *RPCStakingTransaction { func (s *PublicTransactionPoolAPI) GetStakingTransactionByHash(ctx context.Context, hash common.Hash) *RPCStakingTransaction {
// Try to return an already finalized transaction // Try to return an already finalized transaction
stx, blockHash, blockNumber, index := rawdb.ReadStakingTransaction(s.b.ChainDb(), hash) stx, blockHash, blockNumber, index := rawdb.ReadStakingTransaction(s.hmy.ChainDb(), hash)
block, _ := s.b.GetBlock(ctx, blockHash) block, _ := s.hmy.GetBlock(ctx, blockHash)
if block == nil { if block == nil {
return nil return nil
} }
@ -132,8 +133,8 @@ func (s *PublicTransactionPoolAPI) GetStakingTransactionByHash(ctx context.Conte
} }
// GetStakingTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. // GetStakingTransactionByBlockNumberAndIndex returns the transaction for the given block number and index.
func (s *PublicTransactionPoolAPI) GetStakingTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCStakingTransaction { func (s *PublicTransactionPoolAPI) GetStakingTransactionByBlockNumberAndIndex(ctx context.Context, blockNum rpc.BlockNumber, index hexutil.Uint) *RPCStakingTransaction {
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { if block, _ := s.hmy.BlockByNumber(ctx, blockNum); block != nil {
return newRPCStakingTransactionFromBlockIndex(block, uint64(index)) return newRPCStakingTransactionFromBlockIndex(block, uint64(index))
} }
return nil return nil
@ -141,7 +142,7 @@ func (s *PublicTransactionPoolAPI) GetStakingTransactionByBlockNumberAndIndex(ct
// GetStakingTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. // GetStakingTransactionByBlockHashAndIndex returns the transaction for the given block hash and index.
func (s *PublicTransactionPoolAPI) GetStakingTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCStakingTransaction { func (s *PublicTransactionPoolAPI) GetStakingTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCStakingTransaction {
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { if block, _ := s.hmy.GetBlock(ctx, blockHash); block != nil {
return newRPCStakingTransactionFromBlockIndex(block, uint64(index)) return newRPCStakingTransactionFromBlockIndex(block, uint64(index))
} }
return nil return nil
@ -150,18 +151,18 @@ func (s *PublicTransactionPoolAPI) GetStakingTransactionByBlockHashAndIndex(ctx
// GetTransactionCount returns the number of transactions the given address has sent for the given block number. // GetTransactionCount returns the number of transactions the given address has sent for the given block number.
// Legacy for apiv1. For apiv2, please use getAccountNonce/getPoolNonce/getTransactionsCount/getStakingTransactionsCount apis for // Legacy for apiv1. For apiv2, please use getAccountNonce/getPoolNonce/getTransactionsCount/getStakingTransactionsCount apis for
// more granular transaction counts queries // more granular transaction counts queries
func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, addr string, blockNr rpc.BlockNumber) (*hexutil.Uint64, error) { func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, addr string, blockNum rpc.BlockNumber) (*hexutil.Uint64, error) {
address := internal_common.ParseAddr(addr) address := internal_common.ParseAddr(addr)
// Ask transaction pool for the nonce which includes pending transactions // Ask transaction pool for the nonce which includes pending transactions
if blockNr == rpc.PendingBlockNumber { if blockNum == rpc.PendingBlockNumber {
nonce, err := s.b.GetPoolNonce(ctx, address) nonce, err := s.hmy.GetPoolNonce(ctx, address)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return (*hexutil.Uint64)(&nonce), nil return (*hexutil.Uint64)(&nonce), nil
} }
// Resolve block number and use its state to ask for the nonce // Resolve block number and use its state to ask for the nonce
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) state, _, err := s.hmy.StateAndHeaderByNumber(ctx, blockNum)
if state == nil || err != nil { if state == nil || err != nil {
return nil, err return nil, err
} }
@ -179,7 +180,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionsCount(ctx context.Context, add
return 0, err return 0, err
} }
} }
return s.b.GetTransactionsCount(address, txType) return s.hmy.GetTransactionsCount(address, txType)
} }
// GetStakingTransactionsCount returns the number of staking transactions from genesis of input type ("SENT", "RECEIVED", "ALL") // GetStakingTransactionsCount returns the number of staking transactions from genesis of input type ("SENT", "RECEIVED", "ALL")
@ -192,7 +193,7 @@ func (s *PublicTransactionPoolAPI) GetStakingTransactionsCount(ctx context.Conte
return 0, err return 0, err
} }
} }
return s.b.GetStakingTransactionsCount(address, txType) return s.hmy.GetStakingTransactionsCount(address, txType)
} }
// SendRawStakingTransaction will add the signed transaction to the transaction pool. // SendRawStakingTransaction will add the signed transaction to the transaction pool.
@ -208,13 +209,13 @@ func (s *PublicTransactionPoolAPI) SendRawStakingTransaction(
if err := rlp.DecodeBytes(encodedTx, tx); err != nil { if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
c := s.b.ChainConfig().ChainID c := s.hmy.ChainConfig().ChainID
if id := tx.ChainID(); id.Cmp(c) != 0 { if id := tx.ChainID(); id.Cmp(c) != 0 {
return common.Hash{}, errors.Wrapf( return common.Hash{}, errors.Wrapf(
ErrInvalidChainID, "blockchain chain id:%s, given %s", c.String(), id.String(), ErrInvalidChainID, "blockchain chain id:%s, given %s", c.String(), id.String(),
) )
} }
return SubmitStakingTransaction(ctx, s.b, tx) return SubmitStakingTransaction(ctx, s.hmy, tx)
} }
// SendRawTransaction will add the signed transaction to the transaction pool. // SendRawTransaction will add the signed transaction to the transaction pool.
@ -230,13 +231,13 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(
if err := rlp.DecodeBytes(encodedTx, tx); err != nil { if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
c := s.b.ChainConfig().ChainID c := s.hmy.ChainConfig().ChainID
if id := tx.ChainID(); id.Cmp(c) != 0 { if id := tx.ChainID(); id.Cmp(c) != 0 {
return common.Hash{}, errors.Wrapf( return common.Hash{}, errors.Wrapf(
ErrInvalidChainID, "blockchain chain id:%s, given %s", c.String(), id.String(), ErrInvalidChainID, "blockchain chain id:%s, given %s", c.String(), id.String(),
) )
} }
return SubmitTransaction(ctx, s.b, tx) return SubmitTransaction(ctx, s.hmy, tx)
} }
func (s *PublicTransactionPoolAPI) fillTransactionFields(tx *types.Transaction, fields map[string]interface{}) error { func (s *PublicTransactionPoolAPI) fillTransactionFields(tx *types.Transaction, fields map[string]interface{}) error {
@ -281,14 +282,14 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha
var stx *staking.StakingTransaction var stx *staking.StakingTransaction
var blockHash common.Hash var blockHash common.Hash
var blockNumber, index uint64 var blockNumber, index uint64
tx, blockHash, blockNumber, index = rawdb.ReadTransaction(s.b.ChainDb(), hash) tx, blockHash, blockNumber, index = rawdb.ReadTransaction(s.hmy.ChainDb(), hash)
if tx == nil { if tx == nil {
stx, blockHash, blockNumber, index = rawdb.ReadStakingTransaction(s.b.ChainDb(), hash) stx, blockHash, blockNumber, index = rawdb.ReadStakingTransaction(s.hmy.ChainDb(), hash)
if stx == nil { if stx == nil {
return nil, nil return nil, nil
} }
} }
receipts, err := s.b.GetReceipts(ctx, blockHash) receipts, err := s.hmy.GetReceipts(ctx, blockHash)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -334,7 +335,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha
// GetPoolStats returns stats for the tx-pool // GetPoolStats returns stats for the tx-pool
func (s *PublicTransactionPoolAPI) GetPoolStats() map[string]interface{} { func (s *PublicTransactionPoolAPI) GetPoolStats() map[string]interface{} {
pendingCount, queuedCount := s.b.GetPoolStats() pendingCount, queuedCount := s.hmy.GetPoolStats()
return map[string]interface{}{ return map[string]interface{}{
"executable-count": pendingCount, "executable-count": pendingCount,
"non-executable-count": queuedCount, "non-executable-count": queuedCount,
@ -343,7 +344,7 @@ func (s *PublicTransactionPoolAPI) GetPoolStats() map[string]interface{} {
// PendingTransactions returns the plain transactions that are in the transaction pool // PendingTransactions returns the plain transactions that are in the transaction pool
func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, error) { func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, error) {
pending, err := s.b.GetPoolTransactions() pending, err := s.hmy.GetPoolTransactions()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -364,7 +365,7 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, err
// PendingStakingTransactions returns the staking transactions that are in the transaction pool // PendingStakingTransactions returns the staking transactions that are in the transaction pool
func (s *PublicTransactionPoolAPI) PendingStakingTransactions() ([]*RPCStakingTransaction, error) { func (s *PublicTransactionPoolAPI) PendingStakingTransactions() ([]*RPCStakingTransaction, error) {
pending, err := s.b.GetPoolTransactions() pending, err := s.hmy.GetPoolTransactions()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -385,19 +386,19 @@ func (s *PublicTransactionPoolAPI) PendingStakingTransactions() ([]*RPCStakingTr
// GetCurrentTransactionErrorSink .. // GetCurrentTransactionErrorSink ..
func (s *PublicTransactionPoolAPI) GetCurrentTransactionErrorSink() types.TransactionErrorReports { func (s *PublicTransactionPoolAPI) GetCurrentTransactionErrorSink() types.TransactionErrorReports {
return s.b.GetCurrentTransactionErrorSink() return s.hmy.GetCurrentTransactionErrorSink()
} }
// GetCurrentStakingErrorSink .. // GetCurrentStakingErrorSink ..
func (s *PublicTransactionPoolAPI) GetCurrentStakingErrorSink() types.TransactionErrorReports { func (s *PublicTransactionPoolAPI) GetCurrentStakingErrorSink() types.TransactionErrorReports {
return s.b.GetCurrentStakingErrorSink() return s.hmy.GetCurrentStakingErrorSink()
} }
// GetCXReceiptByHash returns the transaction for the given hash // GetCXReceiptByHash returns the transaction for the given hash
func (s *PublicTransactionPoolAPI) GetCXReceiptByHash( func (s *PublicTransactionPoolAPI) GetCXReceiptByHash(
ctx context.Context, hash common.Hash, ctx context.Context, hash common.Hash,
) *RPCCXReceipt { ) *RPCCXReceipt {
if cx, blockHash, blockNumber, _ := rawdb.ReadCXReceipt(s.b.ChainDb(), hash); cx != nil { if cx, blockHash, blockNumber, _ := rawdb.ReadCXReceipt(s.hmy.ChainDb(), hash); cx != nil {
return newRPCCXReceipt(cx, blockHash, blockNumber) return newRPCCXReceipt(cx, blockHash, blockNumber)
} }
return nil return nil
@ -405,5 +406,5 @@ func (s *PublicTransactionPoolAPI) GetCXReceiptByHash(
// GetPendingCXReceipts .. // GetPendingCXReceipts ..
func (s *PublicTransactionPoolAPI) GetPendingCXReceipts(ctx context.Context) []*types.CXReceiptsProof { func (s *PublicTransactionPoolAPI) GetPendingCXReceipts(ctx context.Context) []*types.CXReceiptsProof {
return s.b.GetPendingCXReceipts() return s.hmy.GetPendingCXReceipts()
} }

@ -6,6 +6,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/hmy"
common2 "github.com/harmony-one/harmony/internal/common" common2 "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
staking "github.com/harmony-one/harmony/staking/types" staking "github.com/harmony-one/harmony/staking/types"
@ -33,14 +34,14 @@ func ReturnWithPagination(hashes []common.Hash, pageIndex uint32, pageSize uint3
// SubmitTransaction is a helper function that submits tx to txPool and logs a message. // SubmitTransaction is a helper function that submits tx to txPool and logs a message.
func SubmitTransaction( func SubmitTransaction(
ctx context.Context, b Backend, tx *types.Transaction, ctx context.Context, hmy *hmy.Harmony, tx *types.Transaction,
) (common.Hash, error) { ) (common.Hash, error) {
if err := b.SendTx(ctx, tx); err != nil { if err := hmy.SendTx(ctx, tx); err != nil {
utils.Logger().Warn().Err(err).Msg("Could not submit transaction") utils.Logger().Warn().Err(err).Msg("Could not submit transaction")
return tx.Hash(), err return tx.Hash(), err
} }
if tx.To() == nil { if tx.To() == nil {
signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Epoch()) signer := types.MakeSigner(hmy.ChainConfig(), hmy.CurrentBlock().Epoch())
from, err := types.Sender(signer, tx) from, err := types.Sender(signer, tx)
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
@ -61,12 +62,11 @@ func SubmitTransaction(
// SubmitStakingTransaction is a helper function that submits tx to txPool and logs a message. // SubmitStakingTransaction is a helper function that submits tx to txPool and logs a message.
func SubmitStakingTransaction( func SubmitStakingTransaction(
ctx context.Context, b Backend, tx *staking.StakingTransaction, ctx context.Context, hmy *hmy.Harmony, tx *staking.StakingTransaction,
) (common.Hash, error) { ) (common.Hash, error) {
if err := b.SendStakingTx(ctx, tx); err != nil { if err := hmy.SendStakingTx(ctx, tx); err != nil {
// legacy behavior is to never return error and always return tx hash
utils.Logger().Warn().Err(err).Msg("Could not submit staking transaction") utils.Logger().Warn().Err(err).Msg("Could not submit staking transaction")
return tx.Hash(), nil return tx.Hash(), err
} }
utils.Logger().Info().Str("fullhash", tx.Hash().Hex()).Msg("Submitted Staking transaction") utils.Logger().Info().Str("fullhash", tx.Hash().Hex()).Msg("Submitted Staking transaction")
return tx.Hash(), nil return tx.Hash(), nil

@ -1,95 +0,0 @@
package apiv2
import (
"context"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/consensus/quorum"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/crypto/bls"
commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/shard"
"github.com/harmony-one/harmony/shard/committee"
"github.com/harmony-one/harmony/staking/network"
staking "github.com/harmony-one/harmony/staking/types"
)
// Backend interface provides the common API services (that are provided by
// both full and light clients) with access to necessary functions.
// implementations:
// * hmy/api_backend.go
type Backend interface {
NetVersion() uint64
ProtocolVersion() int
SingleFlightRequest(key string, fn func() (interface{}, error)) (interface{}, error)
SingleFlightForgetKey(key string)
ChainDb() ethdb.Database
EventMux() *event.TypeMux
RPCGasCap() *big.Int // global gas cap for hmy_call over rpc: DoS protection
HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*block.Header, error)
BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error)
StateAndHeaderByNumber(
ctx context.Context, blockNr rpc.BlockNumber,
) (*state.DB, *block.Header, error)
GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error)
GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
GetEVM(
ctx context.Context, msg core.Message,
state *state.DB, header *block.Header,
) (*vm.EVM, func() error, error)
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription
SendTx(ctx context.Context, signedTx *types.Transaction) error
GetPoolTransactions() (types.PoolTransactions, error)
GetPoolTransaction(txHash common.Hash) types.PoolTransaction
GetPoolStats() (pendingCount, queuedCount int)
GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error)
GetAccountNonce(ctx context.Context, addr common.Address, blockNr rpc.BlockNumber) (uint64, error)
SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
ChainConfig() *params.ChainConfig
CurrentBlock() *types.Block
GetBalance(
ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*big.Int, error)
GetValidators(epoch *big.Int) (*shard.Committee, error)
GetShardID() uint32
GetTransactionsHistory(address, txType, order string) ([]common.Hash, error)
GetStakingTransactionsHistory(address, txType, order string) ([]common.Hash, error)
GetTransactionsCount(address, txType string) (uint64, error)
GetStakingTransactionsCount(address, txType string) (uint64, error)
ResendCx(ctx context.Context, txID common.Hash) (uint64, bool)
IsLeader() bool
SendStakingTx(ctx context.Context, newStakingTx *staking.StakingTransaction) error
GetElectedValidatorAddresses() []common.Address
GetAllValidatorAddresses() []common.Address
GetValidatorInformation(addr common.Address, block *types.Block) (*staking.ValidatorRPCEnhanced, error)
GetDelegationsByValidator(validator common.Address) []*staking.Delegation
GetDelegationsByDelegator(delegator common.Address) ([]common.Address, []*staking.Delegation)
GetDelegationsByDelegatorByBlock(delegator common.Address, block *types.Block) ([]common.Address, []*staking.Delegation)
GetValidatorSelfDelegation(addr common.Address) *big.Int
GetShardState() (*shard.State, error)
GetCurrentStakingErrorSink() types.TransactionErrorReports
GetCurrentTransactionErrorSink() types.TransactionErrorReports
GetMedianRawStakeSnapshot() (*committee.CompletedEPoSRound, error)
GetPendingCXReceipts() []*types.CXReceiptsProof
GetCurrentUtilityMetrics() (*network.UtilityMetric, error)
GetSuperCommittees() (*quorum.Transition, error)
GetTotalStakingSnapshot() *big.Int
GetCurrentBadBlocks() []core.BadBlock
GetLastCrossLinks() ([]*types.CrossLink, error)
GetLatestChainHeaders() *block.HeaderPair
GetNodeMetadata() commonRPC.NodeMetadata
GetBlockSigners(ctx context.Context, blockNr rpc.BlockNumber) (shard.SlotList, *bls.Mask, error)
IsStakingEpoch(epoch *big.Int) bool
GetLeaderAddress(a common.Address, e *big.Int) string
GetPeerInfo() commonRPC.NodePeerInfo
}

@ -17,6 +17,7 @@ import (
"github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm" "github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/hmy"
internal_common "github.com/harmony-one/harmony/internal/common" internal_common "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/params" "github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
@ -39,12 +40,12 @@ const (
// PublicBlockChainAPI provides an API to access the Harmony blockchain. // PublicBlockChainAPI provides an API to access the Harmony blockchain.
// It offers only methods that operate on public data that is freely available to anyone. // It offers only methods that operate on public data that is freely available to anyone.
type PublicBlockChainAPI struct { type PublicBlockChainAPI struct {
b Backend hmy *hmy.Harmony
} }
// NewPublicBlockChainAPI creates a new Harmony blockchain API. // NewPublicBlockChainAPI creates a new Harmony blockchain API.
func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI { func NewPublicBlockChainAPI(hmy *hmy.Harmony) *PublicBlockChainAPI {
return &PublicBlockChainAPI{b} return &PublicBlockChainAPI{hmy}
} }
// BlockArgs is struct to include optional block formatting params. // BlockArgs is struct to include optional block formatting params.
@ -57,14 +58,14 @@ type BlockArgs struct {
} }
func (s *PublicBlockChainAPI) isBeaconShard() error { func (s *PublicBlockChainAPI) isBeaconShard() error {
if s.b.GetShardID() != shard.BeaconChainShardID { if s.hmy.ShardID != shard.BeaconChainShardID {
return ErrNotBeaconShard return ErrNotBeaconShard
} }
return nil return nil
} }
func (s *PublicBlockChainAPI) isBlockGreaterThanLatest(blockNum uint64) error { func (s *PublicBlockChainAPI) isBlockGreaterThanLatest(blockNum uint64) error {
if blockNum > s.b.CurrentBlock().NumberU64() { if blockNum > s.hmy.CurrentBlock().NumberU64() {
return ErrRequestedBlockTooHigh return ErrRequestedBlockTooHigh
} }
return nil return nil
@ -72,22 +73,22 @@ func (s *PublicBlockChainAPI) isBlockGreaterThanLatest(blockNum uint64) error {
// GetBlockByNumber returns the requested block. When fullTx in blockArgs is true all transactions in the block are returned in full detail, // GetBlockByNumber returns the requested block. When fullTx in blockArgs is true all transactions in the block are returned in full detail,
// otherwise only the transaction hash is returned. When withSigners in BlocksArgs is true it shows block signers for this block in list of one addresses. // otherwise only the transaction hash is returned. When withSigners in BlocksArgs is true it shows block signers for this block in list of one addresses.
func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr uint64, blockArgs BlockArgs) (map[string]interface{}, error) { func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNum uint64, blockArgs BlockArgs) (map[string]interface{}, error) {
if err := s.isBlockGreaterThanLatest(blockNr); err != nil { if err := s.isBlockGreaterThanLatest(blockNum); err != nil {
return nil, err return nil, err
} }
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr)) blk, err := s.hmy.BlockByNumber(ctx, rpc.BlockNumber(blockNum))
blockArgs.InclTx = true blockArgs.InclTx = true
if block != nil { if blk != nil {
if blockArgs.WithSigners { if blockArgs.WithSigners {
blockArgs.Signers, err = s.GetBlockSigners(ctx, blockNr) blockArgs.Signers, err = s.GetBlockSigners(ctx, blockNum)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
leader := s.b.GetLeaderAddress(block.Header().Coinbase(), block.Header().Epoch()) leader := s.hmy.GetLeaderAddress(blk.Header().Coinbase(), blk.Header().Epoch())
response, err := RPCMarshalBlock(block, blockArgs, leader) response, err := RPCMarshalBlock(blk, blockArgs, leader)
if err == nil && rpc.BlockNumber(blockNr) == rpc.PendingBlockNumber { if err == nil && rpc.BlockNumber(blockNum) == rpc.PendingBlockNumber {
// Pending blocks need to nil out a few fields // Pending blocks need to nil out a few fields
for _, field := range []string{"hash", "nonce", "miner"} { for _, field := range []string{"hash", "nonce", "miner"} {
response[field] = nil response[field] = nil
@ -102,17 +103,17 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr uint
// detail, otherwise only the transaction hash is returned. When withSigners in BlocksArgs is true // detail, otherwise only the transaction hash is returned. When withSigners in BlocksArgs is true
// it shows block signers for this block in list of one addresses. // it shows block signers for this block in list of one addresses.
func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, blockArgs BlockArgs) (map[string]interface{}, error) { func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, blockArgs BlockArgs) (map[string]interface{}, error) {
block, err := s.b.GetBlock(ctx, blockHash) blk, err := s.hmy.GetBlock(ctx, blockHash)
blockArgs.InclTx = true blockArgs.InclTx = true
if block != nil { if blk != nil {
if blockArgs.WithSigners { if blockArgs.WithSigners {
blockArgs.Signers, err = s.GetBlockSigners(ctx, block.NumberU64()) blockArgs.Signers, err = s.GetBlockSigners(ctx, blk.NumberU64())
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
leader := s.b.GetLeaderAddress(block.Header().Coinbase(), block.Header().Epoch()) leader := s.hmy.GetLeaderAddress(blk.Header().Coinbase(), blk.Header().Epoch())
return RPCMarshalBlock(block, blockArgs, leader) return RPCMarshalBlock(blk, blockArgs, leader)
} }
return nil, err return nil, err
} }
@ -121,7 +122,7 @@ func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, blockHash comm
func (s *PublicBlockChainAPI) GetBlocks(ctx context.Context, blockStart, blockEnd uint64, blockArgs BlockArgs) ([]map[string]interface{}, error) { func (s *PublicBlockChainAPI) GetBlocks(ctx context.Context, blockStart, blockEnd uint64, blockArgs BlockArgs) ([]map[string]interface{}, error) {
result := make([]map[string]interface{}, 0) result := make([]map[string]interface{}, 0)
for i := blockStart; i <= blockEnd; i++ { for i := blockStart; i <= blockEnd; i++ {
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(i)) blk, err := s.hmy.BlockByNumber(ctx, rpc.BlockNumber(i))
blockArgs.InclTx = true blockArgs.InclTx = true
if blockArgs.WithSigners { if blockArgs.WithSigners {
blockArgs.Signers, err = s.GetBlockSigners(ctx, i) blockArgs.Signers, err = s.GetBlockSigners(ctx, i)
@ -129,9 +130,9 @@ func (s *PublicBlockChainAPI) GetBlocks(ctx context.Context, blockStart, blockEn
return nil, err return nil, err
} }
} }
if block != nil { if blk != nil {
leader := s.b.GetLeaderAddress(block.Header().Coinbase(), block.Header().Epoch()) leader := s.hmy.GetLeaderAddress(blk.Header().Coinbase(), blk.Header().Epoch())
rpcBlock, err := RPCMarshalBlock(block, blockArgs, leader) rpcBlock, err := RPCMarshalBlock(blk, blockArgs, leader)
if err == nil && rpc.BlockNumber(i) == rpc.PendingBlockNumber { if err == nil && rpc.BlockNumber(i) == rpc.PendingBlockNumber {
// Pending blocks need to nil out a few fields // Pending blocks need to nil out a few fields
for _, field := range []string{"hash", "nonce", "miner"} { for _, field := range []string{"hash", "nonce", "miner"} {
@ -146,22 +147,22 @@ func (s *PublicBlockChainAPI) GetBlocks(ctx context.Context, blockStart, blockEn
// GetValidators returns validators list for a particular epoch. // GetValidators returns validators list for a particular epoch.
func (s *PublicBlockChainAPI) GetValidators(ctx context.Context, epoch int64) (map[string]interface{}, error) { func (s *PublicBlockChainAPI) GetValidators(ctx context.Context, epoch int64) (map[string]interface{}, error) {
committee, err := s.b.GetValidators(big.NewInt(epoch)) cmt, err := s.hmy.GetValidators(big.NewInt(epoch))
if err != nil { if err != nil {
return nil, err return nil, err
} }
balanceQueryBlock := shard.Schedule.EpochLastBlock(uint64(epoch)) balanceQueryBlock := shard.Schedule.EpochLastBlock(uint64(epoch))
if balanceQueryBlock > s.b.CurrentBlock().NumberU64() { if balanceQueryBlock > s.hmy.CurrentBlock().NumberU64() {
balanceQueryBlock = s.b.CurrentBlock().NumberU64() balanceQueryBlock = s.hmy.CurrentBlock().NumberU64()
} }
validators := make([]map[string]interface{}, 0) validators := make([]map[string]interface{}, 0)
for _, validator := range committee.Slots { for _, validator := range cmt.Slots {
oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress) oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress)
if err != nil { if err != nil {
return nil, err return nil, err
} }
addr := internal_common.ParseAddr(oneAddress) addr := internal_common.ParseAddr(oneAddress)
validatorBalance, err := s.b.GetBalance(ctx, addr, rpc.BlockNumber(balanceQueryBlock)) validatorBalance, err := s.hmy.GetBalance(ctx, addr, rpc.BlockNumber(balanceQueryBlock))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -172,7 +173,7 @@ func (s *PublicBlockChainAPI) GetValidators(ctx context.Context, epoch int64) (m
validators = append(validators, validatorsFields) validators = append(validators, validatorsFields)
} }
result := map[string]interface{}{ result := map[string]interface{}{
"shardID": committee.ShardID, "shardID": cmt.ShardID,
"validators": validators, "validators": validators,
} }
return result, nil return result, nil
@ -180,13 +181,13 @@ func (s *PublicBlockChainAPI) GetValidators(ctx context.Context, epoch int64) (m
// GetValidatorKeys returns list of bls public keys in the committee for a particular epoch. // GetValidatorKeys returns list of bls public keys in the committee for a particular epoch.
func (s *PublicBlockChainAPI) GetValidatorKeys(ctx context.Context, epoch int64) ([]string, error) { func (s *PublicBlockChainAPI) GetValidatorKeys(ctx context.Context, epoch int64) ([]string, error) {
committee, err := s.b.GetValidators(big.NewInt(epoch)) cmt, err := s.hmy.GetValidators(big.NewInt(epoch))
if err != nil { if err != nil {
return nil, err return nil, err
} }
validators := make([]string, len(committee.Slots)) validators := make([]string, len(cmt.Slots))
for i, v := range committee.Slots { for i, v := range cmt.Slots {
validators[i] = v.BLSPublicKey.Hex() validators[i] = v.BLSPublicKey.Hex()
} }
return validators, nil return validators, nil
@ -209,14 +210,14 @@ func (s *PublicBlockChainAPI) EpochLastBlock(epoch uint64) (uint64, error) {
} }
// GetBlockSigners returns signers for a particular block. // GetBlockSigners returns signers for a particular block.
func (s *PublicBlockChainAPI) GetBlockSigners(ctx context.Context, blockNr uint64) ([]string, error) { func (s *PublicBlockChainAPI) GetBlockSigners(ctx context.Context, blockNum uint64) ([]string, error) {
if blockNr == 0 || blockNr >= uint64(s.BlockNumber()) { if blockNum == 0 || blockNum >= uint64(s.BlockNumber()) {
return []string{}, nil return []string{}, nil
} }
if err := s.isBlockGreaterThanLatest(blockNr); err != nil { if err := s.isBlockGreaterThanLatest(blockNum); err != nil {
return nil, err return nil, err
} }
slots, mask, err := s.b.GetBlockSigners(ctx, rpc.BlockNumber(blockNr)) slots, mask, err := s.hmy.GetBlockSigners(ctx, rpc.BlockNumber(blockNum))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -234,14 +235,14 @@ func (s *PublicBlockChainAPI) GetBlockSigners(ctx context.Context, blockNr uint6
} }
// GetBlockSignerKeys returns bls public keys that signed the block. // GetBlockSignerKeys returns bls public keys that signed the block.
func (s *PublicBlockChainAPI) GetBlockSignerKeys(ctx context.Context, blockNr uint64) ([]string, error) { func (s *PublicBlockChainAPI) GetBlockSignerKeys(ctx context.Context, blockNum uint64) ([]string, error) {
if blockNr == 0 || blockNr >= uint64(s.BlockNumber()) { if blockNum == 0 || blockNum >= uint64(s.BlockNumber()) {
return []string{}, nil return []string{}, nil
} }
if err := s.isBlockGreaterThanLatest(blockNr); err != nil { if err := s.isBlockGreaterThanLatest(blockNum); err != nil {
return nil, err return nil, err
} }
slots, mask, err := s.b.GetBlockSigners(ctx, rpc.BlockNumber(blockNr)) slots, mask, err := s.hmy.GetBlockSigners(ctx, rpc.BlockNumber(blockNum))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -254,15 +255,15 @@ func (s *PublicBlockChainAPI) GetBlockSignerKeys(ctx context.Context, blockNr ui
return signers, nil return signers, nil
} }
// IsBlockSigner returns true if validator with address signed blockNr block. // IsBlockSigner returns true if validator with address signed blockNum block.
func (s *PublicBlockChainAPI) IsBlockSigner(ctx context.Context, blockNr uint64, address string) (bool, error) { func (s *PublicBlockChainAPI) IsBlockSigner(ctx context.Context, blockNum uint64, address string) (bool, error) {
if blockNr == 0 { if blockNum == 0 {
return false, nil return false, nil
} }
if err := s.isBlockGreaterThanLatest(blockNr); err != nil { if err := s.isBlockGreaterThanLatest(blockNum); err != nil {
return false, err return false, err
} }
slots, mask, err := s.b.GetBlockSigners(ctx, rpc.BlockNumber(blockNr)) slots, mask, err := s.hmy.GetBlockSigners(ctx, rpc.BlockNumber(blockNum))
if err != nil { if err != nil {
return false, err return false, err
} }
@ -313,7 +314,7 @@ func (s *PublicBlockChainAPI) GetValidatorSelfDelegation(ctx context.Context, ad
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
return s.b.GetValidatorSelfDelegation(internal_common.ParseAddr(address)), nil return s.hmy.GetValidatorSelfDelegation(internal_common.ParseAddr(address)), nil
} }
// GetValidatorTotalDelegation returns total balace stacking for validator with delegation. // GetValidatorTotalDelegation returns total balace stacking for validator with delegation.
@ -321,7 +322,7 @@ func (s *PublicBlockChainAPI) GetValidatorTotalDelegation(ctx context.Context, a
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
delegations := s.b.GetDelegationsByValidator(internal_common.ParseAddr(address)) delegations := s.hmy.GetDelegationsByValidator(internal_common.ParseAddr(address))
totalStake := big.NewInt(0) totalStake := big.NewInt(0)
for _, delegation := range delegations { for _, delegation := range delegations {
totalStake.Add(totalStake, delegation.Amount) totalStake.Add(totalStake, delegation.Amount)
@ -336,18 +337,18 @@ func (s *PublicBlockChainAPI) GetShardingStructure(ctx context.Context) ([]map[s
numShard := shard.Schedule.InstanceForEpoch(big.NewInt(int64(epoch))).NumShards() numShard := shard.Schedule.InstanceForEpoch(big.NewInt(int64(epoch))).NumShards()
// Return shareding structure for each case. // Return shareding structure for each case.
return shard.Schedule.GetShardingStructure(int(numShard), int(s.b.GetShardID())), nil return shard.Schedule.GetShardingStructure(int(numShard), int(s.hmy.ShardID)), nil
} }
// GetShardID returns shard ID of the requested node. // GetShardID returns shard ID of the requested node.
func (s *PublicBlockChainAPI) GetShardID(ctx context.Context) (int, error) { func (s *PublicBlockChainAPI) GetShardID(ctx context.Context) (int, error) {
return int(s.b.GetShardID()), nil return int(s.hmy.ShardID), nil
} }
// GetCode returns the code stored at the given address in the state for the given block number. // GetCode returns the code stored at the given address in the state for the given block number.
func (s *PublicBlockChainAPI) GetCode(ctx context.Context, addr string, blockNr uint64) (hexutil.Bytes, error) { func (s *PublicBlockChainAPI) GetCode(ctx context.Context, addr string, blockNum uint64) (hexutil.Bytes, error) {
address := internal_common.ParseAddr(addr) address := internal_common.ParseAddr(addr)
state, _, err := s.b.StateAndHeaderByNumber(ctx, rpc.BlockNumber(blockNr)) state, _, err := s.hmy.StateAndHeaderByNumber(ctx, rpc.BlockNumber(blockNum))
if state == nil || err != nil { if state == nil || err != nil {
return nil, err return nil, err
} }
@ -358,9 +359,9 @@ func (s *PublicBlockChainAPI) GetCode(ctx context.Context, addr string, blockNr
// GetStorageAt returns the storage from the state at the given address, key and // GetStorageAt returns the storage from the state at the given address, key and
// block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block // block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block
// numbers are also allowed. // numbers are also allowed.
func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, addr string, key string, blockNr uint64) (hexutil.Bytes, error) { func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, addr string, key string, blockNum uint64) (hexutil.Bytes, error) {
address := internal_common.ParseAddr(addr) address := internal_common.ParseAddr(addr)
state, _, err := s.b.StateAndHeaderByNumber(ctx, rpc.BlockNumber(blockNr)) state, _, err := s.hmy.StateAndHeaderByNumber(ctx, rpc.BlockNumber(blockNum))
if state == nil || err != nil { if state == nil || err != nil {
return nil, err return nil, err
} }
@ -369,18 +370,18 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, addr string, key
} }
// GetBalanceByBlockNumber returns balance by block number. // GetBalanceByBlockNumber returns balance by block number.
func (s *PublicBlockChainAPI) GetBalanceByBlockNumber(ctx context.Context, address string, blockNr uint64) (*big.Int, error) { func (s *PublicBlockChainAPI) GetBalanceByBlockNumber(ctx context.Context, address string, blockNum uint64) (*big.Int, error) {
if err := s.isBlockGreaterThanLatest(blockNr); err != nil { if err := s.isBlockGreaterThanLatest(blockNum); err != nil {
return nil, err return nil, err
} }
addr := internal_common.ParseAddr(address) addr := internal_common.ParseAddr(address)
return s.b.GetBalance(ctx, addr, rpc.BlockNumber(blockNr)) return s.hmy.GetBalance(ctx, addr, rpc.BlockNumber(blockNum))
} }
// GetAccountNonce returns the nonce value of the given address for the given block number // GetAccountNonce returns the nonce value of the given address for the given block number
func (s *PublicBlockChainAPI) GetAccountNonce(ctx context.Context, address string, blockNr rpc.BlockNumber) (uint64, error) { func (s *PublicBlockChainAPI) GetAccountNonce(ctx context.Context, address string, blockNr rpc.BlockNumber) (uint64, error) {
addr := internal_common.ParseAddr(address) addr := internal_common.ParseAddr(address)
return s.b.GetAccountNonce(ctx, addr, rpc.BlockNumber(blockNr)) return s.hmy.GetAccountNonce(ctx, addr, blockNr)
} }
// GetBalance returns the amount of Atto for the given address in the state of the // GetBalance returns the amount of Atto for the given address in the state of the
@ -388,12 +389,12 @@ func (s *PublicBlockChainAPI) GetAccountNonce(ctx context.Context, address strin
// block numbers are also allowed. // block numbers are also allowed.
func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address string) (*big.Int, error) { func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address string) (*big.Int, error) {
addr := internal_common.ParseAddr(address) addr := internal_common.ParseAddr(address)
return s.b.GetBalance(ctx, addr, rpc.BlockNumber(-1)) return s.hmy.GetBalance(ctx, addr, rpc.BlockNumber(-1))
} }
// BlockNumber returns the block number of the chain head. // BlockNumber returns the block number of the chain head.
func (s *PublicBlockChainAPI) BlockNumber() uint64 { func (s *PublicBlockChainAPI) BlockNumber() uint64 {
header, _ := s.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available header, _ := s.hmy.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available
return header.Number().Uint64() return header.Number().Uint64()
} }
@ -403,118 +404,21 @@ func (s *PublicBlockChainAPI) BlockNumber() uint64 {
// withdrawn already from the source shard but not credited yet in the // withdrawn already from the source shard but not credited yet in the
// destination account due to transient failures. // destination account due to transient failures.
func (s *PublicBlockChainAPI) ResendCx(ctx context.Context, txID common.Hash) (bool, error) { func (s *PublicBlockChainAPI) ResendCx(ctx context.Context, txID common.Hash) (bool, error) {
_, success := s.b.ResendCx(ctx, txID) _, success := s.hmy.ResendCx(ctx, txID)
return success, nil return success, nil
} }
// Call executes the given transaction on the state for the given block number. // 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. // 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 uint64) (hexutil.Bytes, error) { func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr uint64) (hexutil.Bytes, error) {
result, _, _, err := doCall(ctx, s.b, args, rpc.BlockNumber(blockNr), vm.Config{}, 5*time.Second, s.b.RPCGasCap()) result, _, _, err := doCall(ctx, s.hmy, args, rpc.BlockNumber(blockNr), vm.Config{}, 5*time.Second, s.hmy.RPCGasCap)
return (hexutil.Bytes)(result), err return (hexutil.Bytes)(result), err
} }
func doCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config, timeout time.Duration, globalGasCap *big.Int) ([]byte, uint64, bool, error) {
defer func(start time.Time) {
utils.Logger().Debug().
Dur("runtime", time.Since(start)).
Msg("Executing EVM call finished")
}(time.Now())
state, header, err := b.StateAndHeaderByNumber(ctx, blockNr)
if state == nil || err != nil {
return nil, 0, false, err
}
// Set sender address or use a default if none specified
var addr common.Address
if args.From == nil {
// TODO(ricl): this logic was borrowed from [go-ethereum](https://github.com/ethereum/go-ethereum/blob/f578d41ee6b3087f8021fd561a0b5665aea3dba6/internal/ethapi/api.go#L738)
// [question](https://ethereum.stackexchange.com/questions/72979/why-does-the-docall-function-use-the-first-account-by-default)
// Might need to reconsider the logic
// if wallets := b.AccountManager().Wallets(); len(wallets) > 0 {
// if accounts := wallets[0].Accounts(); len(accounts) > 0 {
// addr = accounts[0].Address
// }
// }
// The logic in ethereum is to pick a random address managed under the account manager.
// Currently Harmony no longers support the account manager.
// Any address does not affect the logic of this call.
addr = common.HexToAddress(defaultFromAddress)
} else {
addr = *args.From
}
// Set default gas & gas price if none were set
gas := uint64(math.MaxUint64 / 2)
if args.Gas != nil {
gas = uint64(*args.Gas)
}
if globalGasCap != nil && globalGasCap.Uint64() < gas {
utils.Logger().Warn().
Uint64("requested", gas).
Uint64("cap", globalGasCap.Uint64()).
Msg("Caller gas above allowance, capping")
gas = globalGasCap.Uint64()
}
gasPrice := new(big.Int).SetUint64(defaultGasPrice)
if args.GasPrice != nil {
gasPrice = args.GasPrice.ToInt()
}
value := new(big.Int)
if args.Value != nil {
value = args.Value.ToInt()
}
var data []byte
if args.Data != nil {
data = []byte(*args.Data)
}
// Create new call message
msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, false)
// Setup context so it may be cancelled the call has completed
// or, in case of unmetered gas, setup a context with a timeout.
var cancel context.CancelFunc
if timeout > 0 {
ctx, cancel = context.WithTimeout(ctx, timeout)
} else {
ctx, cancel = context.WithCancel(ctx)
}
// Make sure the context is cancelled when the call has completed
// this makes sure resources are cleaned up.
defer cancel()
// Get a new instance of the EVM.
evm, vmError, err := b.GetEVM(ctx, msg, state, header)
if err != nil {
return nil, 0, 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() {
<-ctx.Done()
evm.Cancel()
}()
// Setup the gas pool (also for unmetered requests)
// and apply the message.
gp := new(core.GasPool).AddGas(math.MaxUint64)
res, gas, failed, err := core.ApplyMessage(evm, msg, gp)
if err := vmError(); err != nil {
return nil, 0, false, err
}
// If the timer caused an abort, return an appropriate error message
if evm.Cancelled() {
return nil, 0, false, fmt.Errorf("execution aborted (timeout = %v)", timeout)
}
return res, gas, failed, err
}
// LatestHeader returns the latest header information // LatestHeader returns the latest header information
func (s *PublicBlockChainAPI) LatestHeader(ctx context.Context) *HeaderInformation { func (s *PublicBlockChainAPI) LatestHeader(ctx context.Context) *HeaderInformation {
header, _ := s.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available header, _ := s.hmy.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available
leader := s.b.GetLeaderAddress(header.Coinbase(), header.Epoch()) leader := s.hmy.GetLeaderAddress(header.Coinbase(), header.Epoch())
return newHeaderInformation(header, leader) return newHeaderInformation(header, leader)
} }
@ -523,11 +427,11 @@ func (s *PublicBlockChainAPI) GetHeaderByNumber(ctx context.Context, blockNum ui
if err := s.isBlockGreaterThanLatest(blockNum); err != nil { if err := s.isBlockGreaterThanLatest(blockNum); err != nil {
return nil, err return nil, err
} }
header, err := s.b.HeaderByNumber(context.Background(), rpc.BlockNumber(blockNum)) header, err := s.hmy.HeaderByNumber(context.Background(), rpc.BlockNumber(blockNum))
if err != nil { if err != nil {
return nil, err return nil, err
} }
leader := s.b.GetLeaderAddress(header.Coinbase(), header.Epoch()) leader := s.hmy.GetLeaderAddress(header.Coinbase(), header.Epoch())
return newHeaderInformation(header, leader), nil return newHeaderInformation(header, leader), nil
} }
@ -537,7 +441,7 @@ func (s *PublicBlockChainAPI) GetTotalStaking() (*big.Int, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
return s.b.GetTotalStakingSnapshot(), nil return s.hmy.GetTotalStakingSnapshot(), nil
} }
// GetMedianRawStakeSnapshot returns the raw median stake, only meant to be called on beaconchain // GetMedianRawStakeSnapshot returns the raw median stake, only meant to be called on beaconchain
@ -548,7 +452,7 @@ func (s *PublicBlockChainAPI) GetMedianRawStakeSnapshot() (
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
return s.b.GetMedianRawStakeSnapshot() return s.hmy.GetMedianRawStakeSnapshot()
} }
// GetAllValidatorAddresses returns all validator addresses. // GetAllValidatorAddresses returns all validator addresses.
@ -556,7 +460,7 @@ func (s *PublicBlockChainAPI) GetAllValidatorAddresses() ([]string, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
validatorAddresses := s.b.GetAllValidatorAddresses() validatorAddresses := s.hmy.GetAllValidatorAddresses()
addresses := make([]string, len(validatorAddresses)) addresses := make([]string, len(validatorAddresses))
for i, addr := range validatorAddresses { for i, addr := range validatorAddresses {
oneAddr, _ := internal_common.AddressToBech32(addr) oneAddr, _ := internal_common.AddressToBech32(addr)
@ -570,7 +474,7 @@ func (s *PublicBlockChainAPI) GetElectedValidatorAddresses() ([]string, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
electedAddresses := s.b.GetElectedValidatorAddresses() electedAddresses := s.hmy.GetElectedValidatorAddresses()
addresses := make([]string, len(electedAddresses)) addresses := make([]string, len(electedAddresses))
for i, addr := range electedAddresses { for i, addr := range electedAddresses {
oneAddr, _ := internal_common.AddressToBech32(addr) oneAddr, _ := internal_common.AddressToBech32(addr)
@ -586,12 +490,12 @@ func (s *PublicBlockChainAPI) GetValidatorInformation(
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(rpc.LatestBlockNumber)) blk, err := s.hmy.BlockByNumber(ctx, rpc.BlockNumber(rpc.LatestBlockNumber))
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "could not retrieve the latest block information") return nil, errors.Wrapf(err, "could not retrieve the latest blk information")
} }
return s.b.GetValidatorInformation( return s.hmy.GetValidatorInformation(
internal_common.ParseAddr(address), block, internal_common.ParseAddr(address), blk,
) )
} }
@ -605,12 +509,12 @@ func (s *PublicBlockChainAPI) GetValidatorInformationByBlockNumber(
if err := s.isBlockGreaterThanLatest(blockNr); err != nil { if err := s.isBlockGreaterThanLatest(blockNr); err != nil {
return nil, err return nil, err
} }
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr)) blk, err := s.hmy.BlockByNumber(ctx, rpc.BlockNumber(blockNr))
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "could not retrieve the block information for block number: %d", blockNr) return nil, errors.Wrapf(err, "could not retrieve the blk information for blk number: %d", blockNr)
} }
return s.b.GetValidatorInformation( return s.hmy.GetValidatorInformation(
internal_common.ParseAddr(address), block, internal_common.ParseAddr(address), blk,
) )
} }
@ -620,7 +524,7 @@ func (s *PublicBlockChainAPI) getAllValidatorInformation(
if page < -1 { if page < -1 {
return nil, errors.Errorf("page given %d cannot be less than -1", page) return nil, errors.Errorf("page given %d cannot be less than -1", page)
} }
addresses := s.b.GetAllValidatorAddresses() addresses := s.hmy.GetAllValidatorAddresses()
if page != -1 && len(addresses) <= page*validatorsPageSize { if page != -1 && len(addresses) <= page*validatorsPageSize {
return make([]*staking.ValidatorRPCEnhanced, 0), nil return make([]*staking.ValidatorRPCEnhanced, 0), nil
} }
@ -634,12 +538,12 @@ func (s *PublicBlockChainAPI) getAllValidatorInformation(
} }
} }
validators := []*staking.ValidatorRPCEnhanced{} validators := []*staking.ValidatorRPCEnhanced{}
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr)) blk, err := s.hmy.BlockByNumber(ctx, rpc.BlockNumber(blockNr))
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "could not retrieve the block information for block number: %d", blockNr) return nil, errors.Wrapf(err, "could not retrieve the blk information for blk number: %d", blockNr)
} }
for i := start; i < start+validatorsNum; i++ { for i := start; i < start+validatorsNum; i++ {
information, err := s.b.GetValidatorInformation(addresses[i], block) information, err := s.hmy.GetValidatorInformation(addresses[i], blk)
if err == nil { if err == nil {
validators = append(validators, information) validators = append(validators, information)
} }
@ -656,14 +560,14 @@ func (s *PublicBlockChainAPI) GetAllValidatorInformation(
return nil, err return nil, err
} }
blockNr := s.b.CurrentBlock().NumberU64() blockNr := s.hmy.CurrentBlock().NumberU64()
// delete cache for previous block // delete cache for previous block
prevKey := fmt.Sprintf("all-info-%d", blockNr-1) prevKey := fmt.Sprintf("all-info-%d", blockNr-1)
s.b.SingleFlightForgetKey(prevKey) s.hmy.SingleFlightForgetKey(prevKey)
key := fmt.Sprintf("all-info-%d", blockNr) key := fmt.Sprintf("all-info-%d", blockNr)
res, err := s.b.SingleFlightRequest( res, err := s.hmy.SingleFlightRequest(
key, key,
func() (interface{}, error) { func() (interface{}, error) {
return s.getAllValidatorInformation(ctx, page, rpc.LatestBlockNumber) return s.getAllValidatorInformation(ctx, page, rpc.LatestBlockNumber)
@ -701,7 +605,7 @@ func (s *PublicBlockChainAPI) GetAllDelegationInformation(ctx context.Context, p
if page < -1 { if page < -1 {
return make([][]*RPCDelegation, 0), nil return make([][]*RPCDelegation, 0), nil
} }
addresses := s.b.GetAllValidatorAddresses() addresses := s.hmy.GetAllValidatorAddresses()
if page != -1 && len(addresses) <= page*validatorsPageSize { if page != -1 && len(addresses) <= page*validatorsPageSize {
return make([][]*RPCDelegation, 0), nil return make([][]*RPCDelegation, 0), nil
} }
@ -731,7 +635,7 @@ func (s *PublicBlockChainAPI) GetDelegationsByDelegator(ctx context.Context, add
return nil, err return nil, err
} }
delegatorAddress := internal_common.ParseAddr(address) delegatorAddress := internal_common.ParseAddr(address)
validators, delegations := s.b.GetDelegationsByDelegator(delegatorAddress) validators, delegations := s.hmy.GetDelegationsByDelegator(delegatorAddress)
result := []*RPCDelegation{} result := []*RPCDelegation{}
for i := range delegations { for i := range delegations {
delegation := delegations[i] delegation := delegations[i]
@ -768,11 +672,11 @@ func (s *PublicBlockChainAPI) GetDelegationsByDelegatorByBlockNumber(
return nil, err return nil, err
} }
delegatorAddress := internal_common.ParseAddr(address) delegatorAddress := internal_common.ParseAddr(address)
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNum)) blk, err := s.hmy.BlockByNumber(ctx, rpc.BlockNumber(blockNum))
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "could not retrieve the block information for block number: %d", blockNum) return nil, errors.Wrapf(err, "could not retrieve the blk information for blk number: %d", blockNum)
} }
validators, delegations := s.b.GetDelegationsByDelegatorByBlock(delegatorAddress, block) validators, delegations := s.hmy.GetDelegationsByDelegatorByBlock(delegatorAddress, blk)
result := make([]*RPCDelegation, len(delegations)) result := make([]*RPCDelegation, len(delegations))
for i := range delegations { for i := range delegations {
delegation := delegations[i] delegation := delegations[i]
@ -804,7 +708,7 @@ func (s *PublicBlockChainAPI) GetDelegationsByValidator(ctx context.Context, add
return nil, err return nil, err
} }
validatorAddress := internal_common.ParseAddr(address) validatorAddress := internal_common.ParseAddr(address)
delegations := s.b.GetDelegationsByValidator(validatorAddress) delegations := s.hmy.GetDelegationsByValidator(validatorAddress)
result := make([]*RPCDelegation, 0) result := make([]*RPCDelegation, 0)
for _, delegation := range delegations { for _, delegation := range delegations {
@ -836,7 +740,7 @@ func (s *PublicBlockChainAPI) GetDelegationByDelegatorAndValidator(ctx context.C
} }
delegatorAddress := internal_common.ParseAddr(address) delegatorAddress := internal_common.ParseAddr(address)
validatorAddress := internal_common.ParseAddr(validator) validatorAddress := internal_common.ParseAddr(validator)
validators, delegations := s.b.GetDelegationsByDelegator(delegatorAddress) validators, delegations := s.hmy.GetDelegationsByDelegator(delegatorAddress)
for i := range delegations { for i := range delegations {
if validators[i] != validatorAddress { if validators[i] != validatorAddress {
continue continue
@ -864,67 +768,10 @@ func (s *PublicBlockChainAPI) GetDelegationByDelegatorAndValidator(ctx context.C
return nil, nil return nil, nil
} }
// doEstimateGas ..
func doEstimateGas(ctx context.Context, b Backend, args CallArgs, gasCap *big.Int) (hexutil.Uint64, error) {
// Binary search the gas requirement, as it may be higher than the amount used
var (
lo = params.TxGas - 1
hi uint64
cap uint64
)
blockNum := rpc.LatestBlockNumber
if args.Gas != nil && uint64(*args.Gas) >= params.TxGas {
hi = uint64(*args.Gas)
} else {
// Retrieve the block to act as the gas ceiling
block, err := b.BlockByNumber(ctx, blockNum)
if err != nil {
return 0, err
}
hi = block.GasLimit()
}
if gasCap != nil && hi > gasCap.Uint64() {
// log.Warn("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
hi = gasCap.Uint64()
}
cap = hi
// Use zero-address if none other is available
if args.From == nil {
args.From = &common.Address{}
}
// Create a helper to check if a gas allowance results in an executable transaction
executable := func(gas uint64) bool {
args.Gas = (*hexutil.Uint64)(&gas)
_, _, failed, err := doCall(ctx, b, args, blockNum, vm.Config{}, 0, big.NewInt(int64(cap)))
if err != nil || failed {
return false
}
return true
}
// Execute the binary search and hone in on an executable gas limit
for lo+1 < hi {
mid := (hi + lo) / 2
if !executable(mid) {
lo = mid
} else {
hi = mid
}
}
// Reject the transaction as invalid if it still fails at the highest allowance
if hi == cap {
if !executable(hi) {
return 0, fmt.Errorf("gas required exceeds allowance (%d) or always failing transaction", cap)
}
}
return hexutil.Uint64(hi), nil
}
// EstimateGas returns an estimate of the amount of gas needed to execute the // EstimateGas returns an estimate of the amount of gas needed to execute the
// given transaction against the current pending block. // given transaction against the current pending block.
func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (hexutil.Uint64, error) { func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (hexutil.Uint64, error) {
return doEstimateGas(ctx, s.b, args, nil) return doEstimateGas(ctx, s.hmy, args, nil)
} }
// GetCurrentUtilityMetrics .. // GetCurrentUtilityMetrics ..
@ -932,7 +779,7 @@ func (s *PublicBlockChainAPI) GetCurrentUtilityMetrics() (*network.UtilityMetric
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
return s.b.GetCurrentUtilityMetrics() return s.hmy.GetCurrentUtilityMetrics()
} }
// GetSuperCommittees .. // GetSuperCommittees ..
@ -940,12 +787,12 @@ func (s *PublicBlockChainAPI) GetSuperCommittees() (*quorum.Transition, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
return s.b.GetSuperCommittees() return s.hmy.GetSuperCommittees()
} }
// GetCurrentBadBlocks .. // GetCurrentBadBlocks ..
func (s *PublicBlockChainAPI) GetCurrentBadBlocks() []core.BadBlock { func (s *PublicBlockChainAPI) GetCurrentBadBlocks() []core.BadBlock {
return s.b.GetCurrentBadBlocks() return s.hmy.GetCurrentBadBlocks()
} }
// GetTotalSupply .. // GetTotalSupply ..
@ -986,10 +833,155 @@ func (s *PublicBlockChainAPI) GetLastCrossLinks() ([]*types.CrossLink, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
return s.b.GetLastCrossLinks() return s.hmy.GetLastCrossLinks()
} }
// GetLatestChainHeaders .. // GetLatestChainHeaders ..
func (s *PublicBlockChainAPI) GetLatestChainHeaders() *block.HeaderPair { func (s *PublicBlockChainAPI) GetLatestChainHeaders() *block.HeaderPair {
return s.b.GetLatestChainHeaders() return s.hmy.GetLatestChainHeaders()
}
// docall executes an EVM call
func doCall(ctx context.Context, hmy *hmy.Harmony, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config, timeout time.Duration, globalGasCap *big.Int) ([]byte, uint64, bool, error) {
defer func(start time.Time) {
utils.Logger().Debug().
Dur("runtime", time.Since(start)).
Msg("Executing EVM call finished")
}(time.Now())
state, header, err := hmy.StateAndHeaderByNumber(ctx, blockNr)
if state == nil || err != nil {
return nil, 0, false, err
}
// Set sender address or use a default if none specified
var addr common.Address
if args.From == nil {
// Any address does not affect the logic of this call.
addr = common.HexToAddress(defaultFromAddress)
} else {
addr = *args.From
}
// Set default gas & gas price if none were set
gas := uint64(math.MaxUint64 / 2)
if args.Gas != nil {
gas = uint64(*args.Gas)
}
if globalGasCap != nil && globalGasCap.Uint64() < gas {
utils.Logger().Warn().
Uint64("requested", gas).
Uint64("cap", globalGasCap.Uint64()).
Msg("Caller gas above allowance, capping")
gas = globalGasCap.Uint64()
}
gasPrice := new(big.Int).SetUint64(defaultGasPrice)
if args.GasPrice != nil {
gasPrice = args.GasPrice.ToInt()
}
value := new(big.Int)
if args.Value != nil {
value = args.Value.ToInt()
}
var data []byte
if args.Data != nil {
data = []byte(*args.Data)
}
// Create new call message
msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, false)
// Setup context so it may be cancelled the call has completed
// or, in case of unmetered gas, setup a context with a timeout.
var cancel context.CancelFunc
if timeout > 0 {
ctx, cancel = context.WithTimeout(ctx, timeout)
} else {
ctx, cancel = context.WithCancel(ctx)
}
// Make sure the context is cancelled when the call has completed
// this makes sure resources are cleaned up.
defer cancel()
// Get a new instance of the EVM.
evm, vmError, err := hmy.GetEVM(ctx, msg, state, header)
if err != nil {
return nil, 0, 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() {
<-ctx.Done()
evm.Cancel()
}()
// Setup the gas pool (also for unmetered requests)
// and apply the message.
gp := new(core.GasPool).AddGas(math.MaxUint64)
res, gas, failed, err := core.ApplyMessage(evm, msg, gp)
if err := vmError(); err != nil {
return nil, 0, false, err
}
// If the timer caused an abort, return an appropriate error message
if evm.Cancelled() {
return nil, 0, false, fmt.Errorf("execution aborted (timeout = %v)", timeout)
}
return res, gas, failed, err
}
// doEstimateGas ..
func doEstimateGas(ctx context.Context, hmy *hmy.Harmony, args CallArgs, gasCap *big.Int) (hexutil.Uint64, error) {
// Binary search the gas requirement, as it may be higher than the amount used
var (
lo = params.TxGas - 1
hi uint64
max uint64
)
blockNum := rpc.LatestBlockNumber
if args.Gas != nil && uint64(*args.Gas) >= params.TxGas {
hi = uint64(*args.Gas)
} else {
// Retrieve the blk to act as the gas ceiling
blk, err := hmy.BlockByNumber(ctx, blockNum)
if err != nil {
return 0, err
}
hi = blk.GasLimit()
}
if gasCap != nil && hi > gasCap.Uint64() {
// log.Warn("Caller gas above allowance, capping", "requested", hi, "max", gasCap)
hi = gasCap.Uint64()
}
max = hi
// Use zero-address if none other is available
if args.From == nil {
args.From = &common.Address{}
}
// Create a helper to check if a gas allowance results in an executable transaction
executable := func(gas uint64) bool {
args.Gas = (*hexutil.Uint64)(&gas)
_, _, failed, err := doCall(ctx, hmy, args, blockNum, vm.Config{}, 0, big.NewInt(int64(max)))
if err != nil || failed {
return false
}
return true
}
// Execute the binary search and hone in on an executable gas limit
for lo+1 < hi {
mid := (hi + lo) / 2
if !executable(mid) {
lo = mid
} else {
hi = mid
}
}
// Reject the transaction as invalid if it still fails at the highest allowance
if hi == max {
if !executable(hi) {
return 0, fmt.Errorf("gas required exceeds allowance (%d) or always failing transaction", max)
}
}
return hexutil.Uint64(hi), nil
} }

@ -4,17 +4,18 @@ import (
"context" "context"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/harmony-one/harmony/hmy"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
) )
// DebugAPI Internal JSON RPC for debugging purpose // DebugAPI Internal JSON RPC for debugging purpose
type DebugAPI struct { type DebugAPI struct {
b Backend hmy *hmy.Harmony
} }
// NewDebugAPI Creates a new DebugAPI instance // NewDebugAPI Creates a new DebugAPI instance
func NewDebugAPI(b Backend) *DebugAPI { func NewDebugAPI(hmy *hmy.Harmony) *DebugAPI {
return &DebugAPI{b} return &DebugAPI{hmy}
} }
// SetLogVerbosity Sets log verbosity on runtime // SetLogVerbosity Sets log verbosity on runtime

@ -4,7 +4,7 @@ import (
"context" "context"
"math/big" "math/big"
"github.com/harmony-one/harmony/api/proto" "github.com/harmony-one/harmony/hmy"
commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common" commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common"
"github.com/harmony-one/harmony/internal/params" "github.com/harmony-one/harmony/internal/params"
) )
@ -12,17 +12,17 @@ import (
// PublicHarmonyAPI provides an API to access Harmony related information. // PublicHarmonyAPI provides an API to access Harmony related information.
// It offers only methods that operate on public data that is freely available to anyone. // It offers only methods that operate on public data that is freely available to anyone.
type PublicHarmonyAPI struct { type PublicHarmonyAPI struct {
b Backend hmy *hmy.Harmony
} }
// NewPublicHarmonyAPI ... // NewPublicHarmonyAPI ...
func NewPublicHarmonyAPI(b Backend) *PublicHarmonyAPI { func NewPublicHarmonyAPI(hmy *hmy.Harmony) *PublicHarmonyAPI {
return &PublicHarmonyAPI{b} return &PublicHarmonyAPI{hmy}
} }
// ProtocolVersion returns the current Harmony protocol version this node supports // ProtocolVersion returns the current Harmony protocol version this node supports
func (s *PublicHarmonyAPI) ProtocolVersion() int { func (s *PublicHarmonyAPI) ProtocolVersion() int {
return proto.ProtocolVersion return s.hmy.ProtocolVersion()
} }
// Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not // Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not
@ -33,7 +33,7 @@ func (s *PublicHarmonyAPI) ProtocolVersion() int {
// - pulledStates: number of state entries processed until now // - pulledStates: number of state entries processed until now
// - knownStates: number of known state entries that still need to be pulled // - knownStates: number of known state entries that still need to be pulled
func (s *PublicHarmonyAPI) Syncing() (interface{}, error) { func (s *PublicHarmonyAPI) Syncing() (interface{}, error) {
// TODO(ricl): find our Downloader module for syncing blocks // TODO(dm): find our Downloader module for syncing blocks
return false, nil return false, nil
} }
@ -60,10 +60,10 @@ type NodeMetadata struct {
// GetNodeMetadata produces a NodeMetadata record, data is from the answering RPC node // GetNodeMetadata produces a NodeMetadata record, data is from the answering RPC node
func (s *PublicHarmonyAPI) GetNodeMetadata() commonRPC.NodeMetadata { func (s *PublicHarmonyAPI) GetNodeMetadata() commonRPC.NodeMetadata {
return s.b.GetNodeMetadata() return s.hmy.GetNodeMetadata()
} }
// GetPeerInfo produces a NodePeerInfo record, containing peer info of the node // GetPeerInfo produces a NodePeerInfo record, containing peer info of the node
func (s *PublicHarmonyAPI) GetPeerInfo() commonRPC.NodePeerInfo { func (s *PublicHarmonyAPI) GetPeerInfo() commonRPC.NodePeerInfo {
return s.b.GetPeerInfo() return s.hmy.GetPeerInfo()
} }

@ -8,13 +8,13 @@ import (
// PublicNetAPI offers network related RPC methods // PublicNetAPI offers network related RPC methods
type PublicNetAPI struct { type PublicNetAPI struct {
net p2p.Host net p2p.Host
networkVersion uint64 chainID uint64
} }
// NewPublicNetAPI creates a new net API instance. // NewPublicNetAPI creates a new net API instance.
func NewPublicNetAPI(net p2p.Host, networkVersion uint64) *PublicNetAPI { func NewPublicNetAPI(net p2p.Host, chainID uint64) *PublicNetAPI {
return &PublicNetAPI{net, networkVersion} return &PublicNetAPI{net, chainID}
} }
// PeerCount returns the number of connected peers // PeerCount returns the number of connected peers
@ -22,7 +22,7 @@ func (s *PublicNetAPI) PeerCount() int {
return s.net.GetPeerCount() return s.net.GetPeerCount()
} }
// Version returns the network version, i.e. network ID identifying which network we are using // Version returns the network version, i.e. ChainID identifying which network we are using
func (s *PublicNetAPI) Version() string { func (s *PublicNetAPI) Version() string {
return fmt.Sprintf("%d", s.networkVersion) // TODO(ricl): we should add support for network id (https://github.com/ethereum/wiki/wiki/JSON-RPC#net_version) return fmt.Sprintf("%d", s.chainID)
} }

@ -1,83 +0,0 @@
package apiv2
import (
"bytes"
"context"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/harmony-one/harmony/core/types"
)
// SendTxArgs represents the arguments to sumbit a new transaction into the transaction pool.
type SendTxArgs struct {
From common.Address `json:"from"`
To *common.Address `json:"to"`
ShardID uint32 `json:"shardID"`
Gas *hexutil.Uint64 `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"`
Value *hexutil.Big `json:"value"`
Nonce *hexutil.Uint64 `json:"nonce"`
// We accept "data" and "input" for backwards-compatibility reasons. "input" is the
// newer name and should be preferred by clients.
Data *hexutil.Bytes `json:"data"`
Input *hexutil.Bytes `json:"input"`
}
// setDefaults is a helper function that fills in default values for unspecified tx fields.
func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
if args.Gas == nil {
args.Gas = new(hexutil.Uint64)
*(*uint64)(args.Gas) = 90000
}
// TODO(ricl): add check for shardID
// if args.GasPrice == nil {
// TODO(ricl): port
// price, err := b.SuggestPrice(ctx)
// if err != nil {
// return err
// }
// args.GasPrice = (*hexutil.Big)(price)
// }
if args.Value == nil {
args.Value = new(hexutil.Big)
}
if args.Nonce == nil {
nonce, err := b.GetPoolNonce(ctx, args.From)
if err != nil {
return err
}
args.Nonce = (*hexutil.Uint64)(&nonce)
}
if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) {
return errors.New(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`)
}
if args.To == nil {
// Contract creation
var input []byte
if args.Data != nil {
input = *args.Data
} else if args.Input != nil {
input = *args.Input
}
if len(input) == 0 {
return errors.New(`contract creation without any data provided`)
}
}
return nil
}
func (args *SendTxArgs) toTransaction() *types.Transaction {
var input []byte
if args.Data != nil {
input = *args.Data
} else if args.Input != nil {
input = *args.Input
}
if args.To == nil {
return types.NewContractCreation(uint64(*args.Nonce), args.ShardID, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input)
}
return types.NewTransaction(uint64(*args.Nonce), *args.To, args.ShardID, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input)
}

@ -11,6 +11,7 @@ import (
"github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/rawdb" "github.com/harmony-one/harmony/core/rawdb"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/hmy"
internal_common "github.com/harmony-one/harmony/internal/common" internal_common "github.com/harmony-one/harmony/internal/common"
staking "github.com/harmony-one/harmony/staking/types" staking "github.com/harmony-one/harmony/staking/types"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -28,13 +29,13 @@ type TxHistoryArgs struct {
// PublicTransactionPoolAPI exposes methods for the RPC interface // PublicTransactionPoolAPI exposes methods for the RPC interface
type PublicTransactionPoolAPI struct { type PublicTransactionPoolAPI struct {
b Backend hmy *hmy.Harmony
nonceLock *AddrLocker nonceLock *AddrLocker
} }
// NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool. // NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool.
func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransactionPoolAPI { func NewPublicTransactionPoolAPI(hmy *hmy.Harmony, nonceLock *AddrLocker) *PublicTransactionPoolAPI {
return &PublicTransactionPoolAPI{b, nonceLock} return &PublicTransactionPoolAPI{hmy, nonceLock}
} }
// GetTransactionsHistory returns the list of transactions hashes that involve a particular address. // GetTransactionsHistory returns the list of transactions hashes that involve a particular address.
@ -51,7 +52,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionsHistory(ctx context.Context, a
return nil, err return nil, err
} }
} }
hashes, err := s.b.GetTransactionsHistory(address, args.TxType, args.Order) hashes, err := s.hmy.GetTransactionsHistory(address, args.TxType, args.Order)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -70,8 +71,8 @@ func (s *PublicTransactionPoolAPI) GetTransactionsHistory(ctx context.Context, a
} }
// GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number. // GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number.
func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr uint64) int { func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNum uint64) int {
if block, _ := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr)); block != nil { if block, _ := s.hmy.BlockByNumber(ctx, rpc.BlockNumber(blockNum)); block != nil {
return len(block.Transactions()) return len(block.Transactions())
} }
return 0 return 0
@ -79,15 +80,15 @@ func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.
// GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash. // GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash.
func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) int { func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) int {
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { if block, _ := s.hmy.GetBlock(ctx, blockHash); block != nil {
return len(block.Transactions()) return len(block.Transactions())
} }
return 0 return 0
} }
// GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index.
func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr uint64, index uint64) *RPCTransaction { func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNum uint64, index uint64) *RPCTransaction {
if block, _ := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr)); block != nil { if block, _ := s.hmy.BlockByNumber(ctx, rpc.BlockNumber(blockNum)); block != nil {
return newRPCTransactionFromBlockIndex(block, index) return newRPCTransactionFromBlockIndex(block, index)
} }
return nil return nil
@ -95,7 +96,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx conte
// GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. // GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index.
func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index uint64) *RPCTransaction { func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index uint64) *RPCTransaction {
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { if block, _ := s.hmy.GetBlock(ctx, blockHash); block != nil {
return newRPCTransactionFromBlockIndex(block, index) return newRPCTransactionFromBlockIndex(block, index)
} }
return nil return nil
@ -104,8 +105,8 @@ func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context
// GetTransactionByHash returns the plain transaction for the given hash // GetTransactionByHash returns the plain transaction for the given hash
func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) *RPCTransaction { func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) *RPCTransaction {
// Try to return an already finalized transaction // Try to return an already finalized transaction
tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.b.ChainDb(), hash) tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.hmy.ChainDb(), hash)
block, _ := s.b.GetBlock(ctx, blockHash) block, _ := s.hmy.GetBlock(ctx, blockHash)
if block == nil { if block == nil {
return nil return nil
} }
@ -130,7 +131,7 @@ func (s *PublicTransactionPoolAPI) GetStakingTransactionsHistory(ctx context.Con
return nil, err return nil, err
} }
} }
hashes, err := s.b.GetStakingTransactionsHistory(address, args.TxType, args.Order) hashes, err := s.hmy.GetStakingTransactionsHistory(address, args.TxType, args.Order)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -149,8 +150,8 @@ func (s *PublicTransactionPoolAPI) GetStakingTransactionsHistory(ctx context.Con
} }
// GetBlockStakingTransactionCountByNumber returns the number of staking transactions in the block with the given block number. // GetBlockStakingTransactionCountByNumber returns the number of staking transactions in the block with the given block number.
func (s *PublicTransactionPoolAPI) GetBlockStakingTransactionCountByNumber(ctx context.Context, blockNr uint64) int { func (s *PublicTransactionPoolAPI) GetBlockStakingTransactionCountByNumber(ctx context.Context, blockNum uint64) int {
if block, _ := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr)); block != nil { if block, _ := s.hmy.BlockByNumber(ctx, rpc.BlockNumber(blockNum)); block != nil {
return len(block.StakingTransactions()) return len(block.StakingTransactions())
} }
return 0 return 0
@ -158,15 +159,15 @@ func (s *PublicTransactionPoolAPI) GetBlockStakingTransactionCountByNumber(ctx c
// GetBlockStakingTransactionCountByHash returns the number of staking transactions in the block with the given hash. // GetBlockStakingTransactionCountByHash returns the number of staking transactions in the block with the given hash.
func (s *PublicTransactionPoolAPI) GetBlockStakingTransactionCountByHash(ctx context.Context, blockHash common.Hash) int { func (s *PublicTransactionPoolAPI) GetBlockStakingTransactionCountByHash(ctx context.Context, blockHash common.Hash) int {
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { if block, _ := s.hmy.GetBlock(ctx, blockHash); block != nil {
return len(block.StakingTransactions()) return len(block.StakingTransactions())
} }
return 0 return 0
} }
// GetStakingTransactionByBlockNumberAndIndex returns the staking transaction for the given block number and index. // GetStakingTransactionByBlockNumberAndIndex returns the staking transaction for the given block number and index.
func (s *PublicTransactionPoolAPI) GetStakingTransactionByBlockNumberAndIndex(ctx context.Context, blockNr uint64, index uint64) *RPCStakingTransaction { func (s *PublicTransactionPoolAPI) GetStakingTransactionByBlockNumberAndIndex(ctx context.Context, blockNum uint64, index uint64) *RPCStakingTransaction {
if block, _ := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr)); block != nil { if block, _ := s.hmy.BlockByNumber(ctx, rpc.BlockNumber(blockNum)); block != nil {
return newRPCStakingTransactionFromBlockIndex(block, index) return newRPCStakingTransactionFromBlockIndex(block, index)
} }
return nil return nil
@ -174,7 +175,7 @@ func (s *PublicTransactionPoolAPI) GetStakingTransactionByBlockNumberAndIndex(ct
// GetStakingTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. // GetStakingTransactionByBlockHashAndIndex returns the transaction for the given block hash and index.
func (s *PublicTransactionPoolAPI) GetStakingTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index uint64) *RPCStakingTransaction { func (s *PublicTransactionPoolAPI) GetStakingTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index uint64) *RPCStakingTransaction {
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { if block, _ := s.hmy.GetBlock(ctx, blockHash); block != nil {
return newRPCStakingTransactionFromBlockIndex(block, index) return newRPCStakingTransactionFromBlockIndex(block, index)
} }
return nil return nil
@ -183,8 +184,8 @@ func (s *PublicTransactionPoolAPI) GetStakingTransactionByBlockHashAndIndex(ctx
// GetStakingTransactionByHash returns the staking transaction for the given hash // GetStakingTransactionByHash returns the staking transaction for the given hash
func (s *PublicTransactionPoolAPI) GetStakingTransactionByHash(ctx context.Context, hash common.Hash) *RPCStakingTransaction { func (s *PublicTransactionPoolAPI) GetStakingTransactionByHash(ctx context.Context, hash common.Hash) *RPCStakingTransaction {
// Try to return an already finalized transaction // Try to return an already finalized transaction
stx, blockHash, blockNumber, index := rawdb.ReadStakingTransaction(s.b.ChainDb(), hash) stx, blockHash, blockNumber, index := rawdb.ReadStakingTransaction(s.hmy.ChainDb(), hash)
block, _ := s.b.GetBlock(ctx, blockHash) block, _ := s.hmy.GetBlock(ctx, blockHash)
if block == nil { if block == nil {
return nil return nil
} }
@ -205,7 +206,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionsCount(ctx context.Context, add
return 0, err return 0, err
} }
} }
return s.b.GetTransactionsCount(address, txType) return s.hmy.GetTransactionsCount(address, txType)
} }
// GetStakingTransactionsCount returns the number of staking transactions from genesis of input type ("SENT", "RECEIVED", "ALL") // GetStakingTransactionsCount returns the number of staking transactions from genesis of input type ("SENT", "RECEIVED", "ALL")
@ -218,7 +219,7 @@ func (s *PublicTransactionPoolAPI) GetStakingTransactionsCount(ctx context.Conte
return 0, err return 0, err
} }
} }
return s.b.GetStakingTransactionsCount(address, txType) return s.hmy.GetStakingTransactionsCount(address, txType)
} }
// SendRawStakingTransaction will add the signed transaction to the transaction pool. // SendRawStakingTransaction will add the signed transaction to the transaction pool.
@ -234,13 +235,13 @@ func (s *PublicTransactionPoolAPI) SendRawStakingTransaction(
if err := rlp.DecodeBytes(encodedTx, tx); err != nil { if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
c := s.b.ChainConfig().ChainID c := s.hmy.ChainConfig().ChainID
if id := tx.ChainID(); id.Cmp(c) != 0 { if id := tx.ChainID(); id.Cmp(c) != 0 {
return common.Hash{}, errors.Wrapf( return common.Hash{}, errors.Wrapf(
ErrInvalidChainID, "blockchain chain id:%s, given %s", c.String(), id.String(), ErrInvalidChainID, "blockchain chain id:%s, given %s", c.String(), id.String(),
) )
} }
return SubmitStakingTransaction(ctx, s.b, tx) return SubmitStakingTransaction(ctx, s.hmy, tx)
} }
// SendRawTransaction will add the signed transaction to the transaction pool. // SendRawTransaction will add the signed transaction to the transaction pool.
@ -254,13 +255,13 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
if err := rlp.DecodeBytes(encodedTx, tx); err != nil { if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
c := s.b.ChainConfig().ChainID c := s.hmy.ChainConfig().ChainID
if id := tx.ChainID(); id.Cmp(c) != 0 { if id := tx.ChainID(); id.Cmp(c) != 0 {
return common.Hash{}, errors.Wrapf( return common.Hash{}, errors.Wrapf(
ErrInvalidChainID, "blockchain chain id:%s, given %s", c.String(), id.String(), ErrInvalidChainID, "blockchain chain id:%s, given %s", c.String(), id.String(),
) )
} }
return SubmitTransaction(ctx, s.b, tx) return SubmitTransaction(ctx, s.hmy, tx)
} }
func (s *PublicTransactionPoolAPI) fillTransactionFields(tx *types.Transaction, fields map[string]interface{}) error { func (s *PublicTransactionPoolAPI) fillTransactionFields(tx *types.Transaction, fields map[string]interface{}) error {
@ -305,14 +306,14 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha
var stx *staking.StakingTransaction var stx *staking.StakingTransaction
var blockHash common.Hash var blockHash common.Hash
var blockNumber, index uint64 var blockNumber, index uint64
tx, blockHash, blockNumber, index = rawdb.ReadTransaction(s.b.ChainDb(), hash) tx, blockHash, blockNumber, index = rawdb.ReadTransaction(s.hmy.ChainDb(), hash)
if tx == nil { if tx == nil {
stx, blockHash, blockNumber, index = rawdb.ReadStakingTransaction(s.b.ChainDb(), hash) stx, blockHash, blockNumber, index = rawdb.ReadStakingTransaction(s.hmy.ChainDb(), hash)
if stx == nil { if stx == nil {
return nil, nil return nil, nil
} }
} }
receipts, err := s.b.GetReceipts(ctx, blockHash) receipts, err := s.hmy.GetReceipts(ctx, blockHash)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -358,7 +359,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha
// GetPoolStats returns stats for the tx-pool // GetPoolStats returns stats for the tx-pool
func (s *PublicTransactionPoolAPI) GetPoolStats() map[string]interface{} { func (s *PublicTransactionPoolAPI) GetPoolStats() map[string]interface{} {
pendingCount, queuedCount := s.b.GetPoolStats() pendingCount, queuedCount := s.hmy.GetPoolStats()
return map[string]interface{}{ return map[string]interface{}{
"executable-count": pendingCount, "executable-count": pendingCount,
"non-executable-count": queuedCount, "non-executable-count": queuedCount,
@ -367,7 +368,7 @@ func (s *PublicTransactionPoolAPI) GetPoolStats() map[string]interface{} {
// PendingTransactions returns the plain transactions that are in the transaction pool // PendingTransactions returns the plain transactions that are in the transaction pool
func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, error) { func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, error) {
pending, err := s.b.GetPoolTransactions() pending, err := s.hmy.GetPoolTransactions()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -388,7 +389,7 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, err
// PendingStakingTransactions returns the staking transactions that are in the transaction pool // PendingStakingTransactions returns the staking transactions that are in the transaction pool
func (s *PublicTransactionPoolAPI) PendingStakingTransactions() ([]*RPCStakingTransaction, error) { func (s *PublicTransactionPoolAPI) PendingStakingTransactions() ([]*RPCStakingTransaction, error) {
pending, err := s.b.GetPoolTransactions() pending, err := s.hmy.GetPoolTransactions()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -409,17 +410,17 @@ func (s *PublicTransactionPoolAPI) PendingStakingTransactions() ([]*RPCStakingTr
// GetCurrentTransactionErrorSink .. // GetCurrentTransactionErrorSink ..
func (s *PublicTransactionPoolAPI) GetCurrentTransactionErrorSink() types.TransactionErrorReports { func (s *PublicTransactionPoolAPI) GetCurrentTransactionErrorSink() types.TransactionErrorReports {
return s.b.GetCurrentTransactionErrorSink() return s.hmy.GetCurrentTransactionErrorSink()
} }
// GetCurrentStakingErrorSink .. // GetCurrentStakingErrorSink ..
func (s *PublicTransactionPoolAPI) GetCurrentStakingErrorSink() types.TransactionErrorReports { func (s *PublicTransactionPoolAPI) GetCurrentStakingErrorSink() types.TransactionErrorReports {
return s.b.GetCurrentStakingErrorSink() return s.hmy.GetCurrentStakingErrorSink()
} }
// GetCXReceiptByHash returns the transaction for the given hash // GetCXReceiptByHash returns the transaction for the given hash
func (s *PublicTransactionPoolAPI) GetCXReceiptByHash(ctx context.Context, hash common.Hash) *RPCCXReceipt { func (s *PublicTransactionPoolAPI) GetCXReceiptByHash(ctx context.Context, hash common.Hash) *RPCCXReceipt {
if cx, blockHash, blockNumber, _ := rawdb.ReadCXReceipt(s.b.ChainDb(), hash); cx != nil { if cx, blockHash, blockNumber, _ := rawdb.ReadCXReceipt(s.hmy.ChainDb(), hash); cx != nil {
return newRPCCXReceipt(cx, blockHash, blockNumber) return newRPCCXReceipt(cx, blockHash, blockNumber)
} }
return nil return nil
@ -427,5 +428,5 @@ func (s *PublicTransactionPoolAPI) GetCXReceiptByHash(ctx context.Context, hash
// GetPendingCXReceipts .. // GetPendingCXReceipts ..
func (s *PublicTransactionPoolAPI) GetPendingCXReceipts(ctx context.Context) []*types.CXReceiptsProof { func (s *PublicTransactionPoolAPI) GetPendingCXReceipts(ctx context.Context) []*types.CXReceiptsProof {
return s.b.GetPendingCXReceipts() return s.hmy.GetPendingCXReceipts()
} }

@ -6,6 +6,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/hmy"
common2 "github.com/harmony-one/harmony/internal/common" common2 "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
staking "github.com/harmony-one/harmony/staking/types" staking "github.com/harmony-one/harmony/staking/types"
@ -33,14 +34,14 @@ func ReturnWithPagination(hashes []common.Hash, pageIndex uint32, pageSize uint3
// SubmitTransaction is a helper function that submits tx to txPool and logs a message. // SubmitTransaction is a helper function that submits tx to txPool and logs a message.
func SubmitTransaction( func SubmitTransaction(
ctx context.Context, b Backend, tx *types.Transaction, ctx context.Context, hmy *hmy.Harmony, tx *types.Transaction,
) (common.Hash, error) { ) (common.Hash, error) {
if err := b.SendTx(ctx, tx); err != nil { if err := hmy.SendTx(ctx, tx); err != nil {
utils.Logger().Warn().Err(err).Msg("Could not submit transaction") utils.Logger().Warn().Err(err).Msg("Could not submit transaction")
return tx.Hash(), err return tx.Hash(), err
} }
if tx.To() == nil { if tx.To() == nil {
signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Epoch()) signer := types.MakeSigner(hmy.ChainConfig(), hmy.CurrentBlock().Epoch())
from, err := types.Sender(signer, tx) from, err := types.Sender(signer, tx)
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
@ -61,9 +62,9 @@ func SubmitTransaction(
// SubmitStakingTransaction is a helper function that submits tx to txPool and logs a message. // SubmitStakingTransaction is a helper function that submits tx to txPool and logs a message.
func SubmitStakingTransaction( func SubmitStakingTransaction(
ctx context.Context, b Backend, tx *staking.StakingTransaction, ctx context.Context, hmy *hmy.Harmony, tx *staking.StakingTransaction,
) (common.Hash, error) { ) (common.Hash, error) {
if err := b.SendStakingTx(ctx, tx); err != nil { if err := hmy.SendStakingTx(ctx, tx); err != nil {
// legacy behavior is to never return error and always return tx hash // legacy behavior is to never return error and always return tx hash
utils.Logger().Warn().Err(err).Msg("Could not submit staking transaction") utils.Logger().Warn().Err(err).Msg("Could not submit staking transaction")
return tx.Hash(), nil return tx.Hash(), nil

@ -1,145 +1,64 @@
package hmyapi package hmyapi
import ( import (
"context"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/hmy"
"github.com/harmony-one/harmony/consensus/quorum"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/hmyapi/apiv1" "github.com/harmony-one/harmony/internal/hmyapi/apiv1"
"github.com/harmony-one/harmony/internal/hmyapi/apiv2" "github.com/harmony-one/harmony/internal/hmyapi/apiv2"
commonRPC "github.com/harmony-one/harmony/internal/hmyapi/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/shard"
"github.com/harmony-one/harmony/shard/committee"
"github.com/harmony-one/harmony/staking/network"
staking "github.com/harmony-one/harmony/staking/types"
) )
// Backend ..
type Backend interface {
NetVersion() uint64
ProtocolVersion() int
ChainDb() ethdb.Database
SingleFlightRequest(key string, fn func() (interface{}, error)) (interface{}, error)
SingleFlightForgetKey(key string)
EventMux() *event.TypeMux
RPCGasCap() *big.Int // global gas cap for hmy_call over rpc: DoS protection
HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*block.Header, error)
BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error)
StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.DB, *block.Header, error)
GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error)
GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
GetEVM(ctx context.Context, msg core.Message, state *state.DB, header *block.Header) (*vm.EVM, func() error, error)
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription
// TxPool API
SendTx(ctx context.Context, signedTx *types.Transaction) error
GetPoolTransactions() (types.PoolTransactions, error)
GetPoolTransaction(txHash common.Hash) types.PoolTransaction
GetPoolStats() (pendingCount, queuedCount int)
GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error)
GetAccountNonce(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (uint64, error)
SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
ChainConfig() *params.ChainConfig
CurrentBlock() *types.Block
GetBalance(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*big.Int, error)
GetValidators(epoch *big.Int) (*shard.Committee, error)
GetShardID() uint32
GetTransactionsHistory(address, txType, order string) ([]common.Hash, error)
GetStakingTransactionsHistory(address, txType, order string) ([]common.Hash, error)
GetTransactionsCount(address, txType string) (uint64, error)
GetStakingTransactionsCount(address, txType string) (uint64, error)
ResendCx(ctx context.Context, txID common.Hash) (uint64, bool)
IsLeader() bool
SendStakingTx(ctx context.Context, newStakingTx *staking.StakingTransaction) error
GetElectedValidatorAddresses() []common.Address
GetAllValidatorAddresses() []common.Address
GetValidatorInformation(addr common.Address, block *types.Block) (*staking.ValidatorRPCEnhanced, error)
GetDelegationsByValidator(validator common.Address) []*staking.Delegation
GetDelegationsByDelegator(delegator common.Address) ([]common.Address, []*staking.Delegation)
GetDelegationsByDelegatorByBlock(delegator common.Address, block *types.Block) ([]common.Address, []*staking.Delegation)
GetValidatorSelfDelegation(addr common.Address) *big.Int
GetShardState() (*shard.State, error)
GetCurrentStakingErrorSink() types.TransactionErrorReports
GetCurrentTransactionErrorSink() types.TransactionErrorReports
GetMedianRawStakeSnapshot() (*committee.CompletedEPoSRound, error)
GetPendingCXReceipts() []*types.CXReceiptsProof
GetCurrentUtilityMetrics() (*network.UtilityMetric, error)
GetSuperCommittees() (*quorum.Transition, error)
GetTotalStakingSnapshot() *big.Int
GetCurrentBadBlocks() []core.BadBlock
GetLastCrossLinks() ([]*types.CrossLink, error)
GetLatestChainHeaders() *block.HeaderPair
GetNodeMetadata() commonRPC.NodeMetadata
GetBlockSigners(ctx context.Context, blockNr rpc.BlockNumber) (shard.SlotList, *bls.Mask, error)
IsStakingEpoch(epoch *big.Int) bool
GetLeaderAddress(a common.Address, e *big.Int) string
GetPeerInfo() commonRPC.NodePeerInfo
}
// GetAPIs returns all the APIs. // GetAPIs returns all the APIs.
func GetAPIs(b Backend) []rpc.API { func GetAPIs(hmy *hmy.Harmony) []rpc.API {
nonceLock := new(apiv1.AddrLocker) nonceLock := new(apiv1.AddrLocker)
nonceLockV2 := new(apiv2.AddrLocker) nonceLockV2 := new(apiv2.AddrLocker)
return []rpc.API{ return []rpc.API{
{ {
Namespace: "hmy", Namespace: "hmy",
Version: "1.0", Version: "1.0",
Service: apiv1.NewPublicHarmonyAPI(b), Service: apiv1.NewPublicHarmonyAPI(hmy),
Public: true, Public: true,
}, },
{ {
Namespace: "hmy", Namespace: "hmy",
Version: "1.0", Version: "1.0",
Service: apiv1.NewPublicBlockChainAPI(b), Service: apiv1.NewPublicBlockChainAPI(hmy),
Public: true, Public: true,
}, },
{ {
Namespace: "hmy", Namespace: "hmy",
Version: "1.0", Version: "1.0",
Service: apiv1.NewPublicTransactionPoolAPI(b, nonceLock), Service: apiv1.NewPublicTransactionPoolAPI(hmy, nonceLock),
Public: true, Public: true,
}, },
{ {
Namespace: "hmy", Namespace: "hmy",
Version: "1.0", Version: "1.0",
Service: apiv1.NewDebugAPI(b), Service: apiv1.NewDebugAPI(hmy),
Public: true, // FIXME: change to false once IPC implemented Public: false,
}, },
{ {
Namespace: "hmyv2", Namespace: "hmyv2",
Version: "1.0", Version: "1.0",
Service: apiv2.NewPublicHarmonyAPI(b), Service: apiv2.NewPublicHarmonyAPI(hmy),
Public: true, Public: true,
}, },
{ {
Namespace: "hmyv2", Namespace: "hmyv2",
Version: "1.0", Version: "1.0",
Service: apiv2.NewPublicBlockChainAPI(b), Service: apiv2.NewPublicBlockChainAPI(hmy),
Public: true, Public: true,
}, },
{ {
Namespace: "hmyv2", Namespace: "hmyv2",
Version: "1.0", Version: "1.0",
Service: apiv2.NewPublicTransactionPoolAPI(b, nonceLockV2), Service: apiv2.NewPublicTransactionPoolAPI(hmy, nonceLockV2),
Public: true, Public: true,
}, },
{ {
Namespace: "hmyv2", Namespace: "hmyv2",
Version: "1.0", Version: "1.0",
Service: apiv2.NewDebugAPI(b), Service: apiv2.NewDebugAPI(hmy),
Public: true, // FIXME: change to false once IPC implemented Public: false,
}, },
} }
} }

@ -6,12 +6,9 @@ import (
"sync" "sync"
"time" "time"
ethereum "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
) )
@ -35,9 +32,7 @@ type filter struct {
// information related to the Ethereum protocol such als blocks, transactions and logs. // information related to the Ethereum protocol such als blocks, transactions and logs.
type PublicFilterAPI struct { type PublicFilterAPI struct {
backend Backend backend Backend
mux *event.TypeMux
quit chan struct{} quit chan struct{}
chainDb ethdb.Database
events *EventSystem events *EventSystem
filtersMu sync.Mutex filtersMu sync.Mutex
filters map[rpc.ID]*filter filters map[rpc.ID]*filter
@ -47,9 +42,7 @@ type PublicFilterAPI struct {
func NewPublicFilterAPI(backend Backend, lightMode bool) *PublicFilterAPI { func NewPublicFilterAPI(backend Backend, lightMode bool) *PublicFilterAPI {
api := &PublicFilterAPI{ api := &PublicFilterAPI{
backend: backend, backend: backend,
mux: backend.EventMux(), events: NewEventSystem(backend, lightMode),
chainDb: backend.ChainDb(),
events: NewEventSystem(backend.EventMux(), backend, lightMode),
filters: make(map[rpc.ID]*filter), filters: make(map[rpc.ID]*filter),
} }
go api.timeoutLoop() go api.timeoutLoop()
@ -134,9 +127,9 @@ func (api *PublicFilterAPI) NewPendingTransactions(ctx context.Context) (*rpc.Su
select { select {
case hashes := <-txHashes: case hashes := <-txHashes:
// To keep the original behaviour, send a single tx hash in one notification. // To keep the original behaviour, send a single tx hash in one notification.
// TODO(rjl493456442) Send a batch of tx hashes in one notification // TODO(dm) Send a batch of tx hashes in one notification
for _, h := range hashes { for _, h := range hashes {
notifier.Notify(rpcSub.ID, h) _ = notifier.Notify(rpcSub.ID, h)
} }
case <-rpcSub.Err(): case <-rpcSub.Err():
pendingTxSub.Unsubscribe() pendingTxSub.Unsubscribe()
@ -202,7 +195,7 @@ func (api *PublicFilterAPI) NewHeads(ctx context.Context) (*rpc.Subscription, er
for { for {
select { select {
case h := <-headers: case h := <-headers:
notifier.Notify(rpcSub.ID, h) _ = notifier.Notify(rpcSub.ID, h)
case <-rpcSub.Err(): case <-rpcSub.Err():
headersSub.Unsubscribe() headersSub.Unsubscribe()
return return
@ -291,7 +284,7 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc
select { select {
case logs := <-matchedLogs: case logs := <-matchedLogs:
for _, log := range logs { for _, log := range logs {
notifier.Notify(rpcSub.ID, &log) _ = notifier.Notify(rpcSub.ID, &log)
} }
case <-rpcSub.Err(): // client send an unsubscribe request case <-rpcSub.Err(): // client send an unsubscribe request
logsSub.Unsubscribe() logsSub.Unsubscribe()

@ -27,7 +27,6 @@ import (
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
@ -37,7 +36,7 @@ import (
type Backend interface { type Backend interface {
ChainDb() ethdb.Database ChainDb() ethdb.Database
EventMux() *event.TypeMux EventMux() *event.TypeMux
HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*block.Header, error) HeaderByNumber(ctx context.Context, blockNum rpc.BlockNumber) (*block.Header, error)
HeaderByHash(ctx context.Context, blockHash common.Hash) (*block.Header, error) HeaderByHash(ctx context.Context, blockHash common.Hash) (*block.Header, error)
GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error)
@ -114,7 +113,6 @@ func newFilter(backend Backend, addresses []common.Address, topics [][]common.Ha
backend: backend, backend: backend,
addresses: addresses, addresses: addresses,
topics: topics, topics: topics,
db: backend.ChainDb(),
} }
} }

@ -6,7 +6,7 @@ import (
"fmt" "fmt"
"math/big" "math/big"
ethereum "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"

@ -24,12 +24,11 @@ import (
"sync" "sync"
"time" "time"
ethereum "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/rawdb" "github.com/harmony-one/harmony/core/rawdb"
@ -113,9 +112,9 @@ type EventSystem struct {
// //
// The returned manager has a loop that needs to be stopped with the Stop function // The returned manager has a loop that needs to be stopped with the Stop function
// or by stopping the given mux. // or by stopping the given mux.
func NewEventSystem(mux *event.TypeMux, backend Backend, lightMode bool) *EventSystem { func NewEventSystem(backend Backend, lightMode bool) *EventSystem {
m := &EventSystem{ m := &EventSystem{
mux: mux, mux: backend.EventMux(),
backend: backend, backend: backend,
lightMode: lightMode, lightMode: lightMode,
install: make(chan *subscription), install: make(chan *subscription),
@ -131,7 +130,7 @@ func NewEventSystem(mux *event.TypeMux, backend Backend, lightMode bool) *EventS
m.logsSub = m.backend.SubscribeLogsEvent(m.logsCh) m.logsSub = m.backend.SubscribeLogsEvent(m.logsCh)
m.rmLogsSub = m.backend.SubscribeRemovedLogsEvent(m.rmLogsCh) m.rmLogsSub = m.backend.SubscribeRemovedLogsEvent(m.rmLogsCh)
m.chainSub = m.backend.SubscribeChainEvent(m.chainCh) m.chainSub = m.backend.SubscribeChainEvent(m.chainCh)
// TODO(rjl493456442): use feed to subscribe pending log event // TODO(dm): use feed to subscribe pending log event
m.pendingLogSub = m.mux.Subscribe(core.PendingLogsEvent{}) m.pendingLogSub = m.mux.Subscribe(core.PendingLogsEvent{})
// Make sure none of the subscriptions are empty // Make sure none of the subscriptions are empty
@ -413,10 +412,10 @@ func (es *EventSystem) lightFilterLogs(header *block.Header, addresses []common.
} }
var unfiltered []*types.Log var unfiltered []*types.Log
for _, logs := range logsList { for _, logs := range logsList {
for _, log := range logs { for _, lg := range logs {
logcopy := *log logCopy := *lg
logcopy.Removed = remove logCopy.Removed = remove
unfiltered = append(unfiltered, &logcopy) unfiltered = append(unfiltered, &logCopy)
} }
} }
logs := filterLogs(unfiltered, nil, nil, addresses, topics) logs := filterLogs(unfiltered, nil, nil, addresses, topics)
@ -428,10 +427,10 @@ func (es *EventSystem) lightFilterLogs(header *block.Header, addresses []common.
} }
unfiltered = unfiltered[:0] unfiltered = unfiltered[:0]
for _, receipt := range receipts { for _, receipt := range receipts {
for _, log := range receipt.Logs { for _, lg := range receipt.Logs {
logcopy := *log logCopy := *lg
logcopy.Removed = remove logCopy.Removed = remove
unfiltered = append(unfiltered, &logcopy) unfiltered = append(unfiltered, &logCopy)
} }
} }
logs = filterLogs(unfiltered, nil, nil, addresses, topics) logs = filterLogs(unfiltered, nil, nil, addresses, topics)

@ -6,7 +6,6 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/hmy" "github.com/harmony-one/harmony/hmy"
@ -93,10 +92,6 @@ func (node *Node) ReportPlainErrorSink() types.TransactionErrorReports {
// StartRPC start RPC service // StartRPC start RPC service
func (node *Node) StartRPC(nodePort string) error { func (node *Node) StartRPC(nodePort string) error {
// Gather all the possible APIs to surface // Gather all the possible APIs to surface
harmony, _ = hmy.New(
node, node.TxPool, node.CxPool, new(event.TypeMux), node.Consensus.ShardID,
)
apis := node.APIs() apis := node.APIs()
for _, service := range node.serviceManager.GetServices() { for _, service := range node.serviceManager.GetServices() {
@ -180,26 +175,29 @@ func (node *Node) startWS(
// APIs return the collection of RPC services the ethereum package offers. // APIs return the collection of RPC services the ethereum package offers.
// NOTE, some of these services probably need to be moved to somewhere else. // NOTE, some of these services probably need to be moved to somewhere else.
func (node *Node) APIs() []rpc.API { func (node *Node) APIs() []rpc.API {
if harmony == nil {
harmony = hmy.New(node, node.TxPool, node.CxPool, node.Consensus.ShardID)
}
// Gather all the possible APIs to surface // Gather all the possible APIs to surface
apis := hmyapi.GetAPIs(harmony.APIBackend) apis := hmyapi.GetAPIs(harmony)
// Append all the local APIs and return // Append all the local APIs and return
return append(apis, []rpc.API{ return append(apis, []rpc.API{
{ {
Namespace: "hmy", Namespace: "hmy",
Version: "1.0", Version: "1.0",
Service: filters.NewPublicFilterAPI(harmony.APIBackend, false), Service: filters.NewPublicFilterAPI(harmony, false),
Public: true, Public: true,
}, },
{ {
Namespace: "net", Namespace: "net",
Version: "1.0", Version: "1.0",
Service: apiv1.NewPublicNetAPI(node.host, harmony.APIBackend.NetVersion()), Service: apiv1.NewPublicNetAPI(node.host, harmony.ChainID),
Public: true, Public: true,
}, },
{ {
Namespace: "netv2", Namespace: "netv2",
Version: "1.0", Version: "1.0",
Service: apiv2.NewPublicNetAPI(node.host, harmony.APIBackend.NetVersion()), Service: apiv2.NewPublicNetAPI(node.host, harmony.ChainID),
Public: true, Public: true,
}, },
}...) }...)

Loading…
Cancel
Save