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
parent
a354b93676
commit
d4df3aa039
@ -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 = ¬Booted |
||||
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 = ¬Booted |
||||
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 |
||||
} |
@ -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"` |
||||
} |
@ -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 |
||||
} |
@ -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) |
||||
} |
@ -1,145 +1,64 @@ |
||||
package hmyapi |
||||
|
||||
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" |
||||
"github.com/harmony-one/harmony/hmy" |
||||
"github.com/harmony-one/harmony/internal/hmyapi/apiv1" |
||||
"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.
|
||||
func GetAPIs(b Backend) []rpc.API { |
||||
func GetAPIs(hmy *hmy.Harmony) []rpc.API { |
||||
nonceLock := new(apiv1.AddrLocker) |
||||
nonceLockV2 := new(apiv2.AddrLocker) |
||||
return []rpc.API{ |
||||
{ |
||||
Namespace: "hmy", |
||||
Version: "1.0", |
||||
Service: apiv1.NewPublicHarmonyAPI(b), |
||||
Service: apiv1.NewPublicHarmonyAPI(hmy), |
||||
Public: true, |
||||
}, |
||||
{ |
||||
Namespace: "hmy", |
||||
Version: "1.0", |
||||
Service: apiv1.NewPublicBlockChainAPI(b), |
||||
Service: apiv1.NewPublicBlockChainAPI(hmy), |
||||
Public: true, |
||||
}, |
||||
{ |
||||
Namespace: "hmy", |
||||
Version: "1.0", |
||||
Service: apiv1.NewPublicTransactionPoolAPI(b, nonceLock), |
||||
Service: apiv1.NewPublicTransactionPoolAPI(hmy, nonceLock), |
||||
Public: true, |
||||
}, |
||||
{ |
||||
Namespace: "hmy", |
||||
Version: "1.0", |
||||
Service: apiv1.NewDebugAPI(b), |
||||
Public: true, // FIXME: change to false once IPC implemented
|
||||
Service: apiv1.NewDebugAPI(hmy), |
||||
Public: false, |
||||
}, |
||||
{ |
||||
Namespace: "hmyv2", |
||||
Version: "1.0", |
||||
Service: apiv2.NewPublicHarmonyAPI(b), |
||||
Service: apiv2.NewPublicHarmonyAPI(hmy), |
||||
Public: true, |
||||
}, |
||||
{ |
||||
Namespace: "hmyv2", |
||||
Version: "1.0", |
||||
Service: apiv2.NewPublicBlockChainAPI(b), |
||||
Service: apiv2.NewPublicBlockChainAPI(hmy), |
||||
Public: true, |
||||
}, |
||||
{ |
||||
Namespace: "hmyv2", |
||||
Version: "1.0", |
||||
Service: apiv2.NewPublicTransactionPoolAPI(b, nonceLockV2), |
||||
Service: apiv2.NewPublicTransactionPoolAPI(hmy, nonceLockV2), |
||||
Public: true, |
||||
}, |
||||
{ |
||||
Namespace: "hmyv2", |
||||
Version: "1.0", |
||||
Service: apiv2.NewDebugAPI(b), |
||||
Public: true, // FIXME: change to false once IPC implemented
|
||||
Service: apiv2.NewDebugAPI(hmy), |
||||
Public: false, |
||||
}, |
||||
} |
||||
} |
||||
|
Loading…
Reference in new issue