Skip to content

Commit

Permalink
Merge pull request #327 from stratosnet/dev
Browse files Browse the repository at this point in the history
Release v0.11.3 Metrics API
  • Loading branch information
jinzuo-qsn authored Nov 10, 2023
2 parents dbf8e3a + dded533 commit 610250a
Show file tree
Hide file tree
Showing 13 changed files with 1,474 additions and 190 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
BUILDDIR ?= $(CURDIR)/build
LEDGER_ENABLED ?= false

APP_VER := v0.11.2
APP_VER := v0.11.3
COMMIT := $(GIT_COMMIT_HASH)
TEST_DOCKER_REPO=stratos-chain-e2e

Expand Down
77 changes: 76 additions & 1 deletion proto/stratos/pot/v1/pot.proto
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,79 @@ message TotalReward {
(gogoproto.moretags) = "yaml:\"traffic_reward\"",
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
];
}
}

message Metrics {
string total_supply = 1 [
(gogoproto.nullable) = false,
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.jsontag) = "total_supply",
(gogoproto.moretags) = "yaml:\"total_supply\""
];
string total_mining_supply = 2 [
(gogoproto.nullable) = false,
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.jsontag) = "total_mining_supply",
(gogoproto.moretags) = "yaml:\"total_mining_supply\""
];
string total_mined_tokens = 3 [
(gogoproto.nullable) = false,
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.jsontag) = "total_mined_tokens",
(gogoproto.moretags) = "yaml:\"total_mined_tokens\""
];
string total_resource_nodes_deposit = 4 [
(gogoproto.nullable) = false,
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.jsontag) = "total_resource_nodes_deposit",
(gogoproto.moretags) = "yaml:\"total_resource_nodes_deposit\""
];
string total_bonded_delegation = 5 [
(gogoproto.nullable) = false,
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.jsontag) = "total_bonded_delegation",
(gogoproto.moretags) = "yaml:\"total_bonded_delegation\""
];
string total_unbonded_delegation = 6 [
(gogoproto.nullable) = false,
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.jsontag) = "total_unbonded_delegation",
(gogoproto.moretags) = "yaml:\"total_unbonded_delegation\""
];
string total_unbonding_delegation = 7 [
(gogoproto.nullable) = false,
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.jsontag) = "total_unbonding_delegation",
(gogoproto.moretags) = "yaml:\"total_unbonding_delegation\""
];
string circulation_supply = 8 [
(gogoproto.nullable) = false,
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.jsontag) = "circulation_supply",
(gogoproto.moretags) = "yaml:\"circulation_supply\""
];
string total_mining_reward = 9 [
(gogoproto.nullable) = false,
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.jsontag) = "total_mining_reward",
(gogoproto.moretags) = "yaml:\"total_mining_reward\""
];
string chain_mining_reward = 10 [
(gogoproto.nullable) = false,
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.jsontag) = "chain_mining_reward",
(gogoproto.moretags) = "yaml:\"chain_mining_reward\""
];
string resource_mining_reward = 11 [
(gogoproto.nullable) = false,
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.jsontag) = "resource_mining_reward",
(gogoproto.moretags) = "yaml:\"resource_mining_reward\""
];
string meta_mining_reward = 12 [
(gogoproto.nullable) = false,
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.jsontag) = "meta_mining_reward",
(gogoproto.moretags) = "yaml:\"meta_mining_reward\""
];
}
11 changes: 11 additions & 0 deletions proto/stratos/pot/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ service Query {
rpc TotalRewardByEpoch(QueryTotalRewardByEpochRequest) returns (QueryTotalRewardByEpochResponse) {
option (google.api.http).get = "/stratos/pot/v1/total-reward/{epoch}";
}

rpc Metrics(QueryMetricsRequest) returns (QueryMetricsResponse) {
option (google.api.http).get = "/stratos/pot/v1/metrics";
}
}

// QueryVolumeReportRequest is request type for the Query/VolumeReport RPC method
Expand Down Expand Up @@ -158,3 +162,10 @@ message QueryTotalRewardByEpochResponse {
];
}

message QueryMetricsRequest {}

message QueryMetricsResponse {
Metrics metrics = 1 [
(gogoproto.nullable) = false
];
}
139 changes: 96 additions & 43 deletions x/evm/pool/tx_pool.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pool

import (
"errors"
"fmt"
"math/big"
"sync"
Expand Down Expand Up @@ -34,33 +35,29 @@ const (
)

var (
initInterval = 5 * time.Second // Time interval to prepare some after tendermint initializations
evictionInterval = time.Minute // Time interval to check for evictable transactions
statsReportInterval = 8 * time.Second // Time interval to report transaction pool stats
processQueueInterval = 5 * time.Second // Time interval to process queue transactions in case if their ready and move to pending stage
processPendingInterval = 5 * time.Second // Time interval of pending tx broadcating to a tm mempool
)

type txpoolResetRequest struct {
oldHead, newHead *types.Header
}

// TxPool contains all currently known transactions. Transactions
// enter the pool when they are received from the local network or submitted
// locally. They exit the pool when they are included in the blockchain.
type TxPool struct {
config core.TxPoolConfig
srvCfg config.Config
logger log.Logger
clientCtx client.Context
evmCtx *evm.Context
signer types.Signer
mempool mempl.Mempool
mu sync.RWMutex

evmkeeper *evmkeeper.Keeper // Active keeper to get current state
pendingNonces *txNoncer // Pending state tracking virtual nonces
currentMaxGas uint64 // Current gas limit for transaction caps
config core.TxPoolConfig
srvCfg config.Config
logger log.Logger
clientCtx client.Context
evmCtx *evm.Context
signerCache types.Signer // should be loaded in dynamic as potentially will not exist during chain initialization
mempool mempl.Mempool
mu sync.RWMutex
imu sync.Mutex // only for initializations

evmkeeper *evmkeeper.Keeper // Active keeper to get current state
pendingNonces *txNoncer // Pending state tracking virtual nonces
maxGasLimitCache uint64 // Current gas limit for transaction caps, only for cache

beats map[common.Address]time.Time // Last heartbeat from each known account

Expand All @@ -69,32 +66,34 @@ type TxPool struct {
all *txLookup // All transactions to allow lookups
}

// catchInitPanic used only in methods which are dependent from the store and potentially could be down
// due to not initialized chain
func catchInitPanic(err *error) {
if errRec := recover(); errRec != nil {
log.Warn("storage still not initialized, value could not be loaded")
*err = errors.New("chain not started yet")
}
}

// NewTxPool creates a new transaction pool to gather, sort and filter inbound
// transactions from the network.
func NewTxPool(config core.TxPoolConfig, srvCfg config.Config, clientCtx client.Context, mempool mempl.Mempool, evmkeeper *evmkeeper.Keeper, evmCtx *evm.Context) (*TxPool, error) {
sdkCtx := evmCtx.GetSdkContext()
params := evmkeeper.GetParams(sdkCtx)
pool := &TxPool{
config: config,
srvCfg: srvCfg,
clientCtx: clientCtx,
evmCtx: evmCtx,
signer: types.LatestSignerForChainID(params.ChainConfig.ChainID.BigInt()),
mempool: mempool,
evmkeeper: evmkeeper,
beats: make(map[common.Address]time.Time),
pending: make(map[common.Address]*txList),
queue: make(map[common.Address]*txList),
all: newTxLookup(),
config: config,
srvCfg: srvCfg,
clientCtx: clientCtx,
evmCtx: evmCtx,
mempool: mempool,
evmkeeper: evmkeeper,
signerCache: nil,
maxGasLimitCache: 0,
beats: make(map[common.Address]time.Time),
pending: make(map[common.Address]*txList),
queue: make(map[common.Address]*txList),
all: newTxLookup(),
}
pool.pendingNonces = newTxNoncer(pool.evmCtx, pool.evmkeeper)

gasLimit, err := evmtypes.BlockMaxGasFromConsensusParams(nil)
if err != nil {
return nil, fmt.Errorf("failed to get tx pool current max gas: %w (possible DB not started?)", err)
}
pool.currentMaxGas = uint64(gasLimit)

go pool.eventLoop()

return pool, nil
Expand Down Expand Up @@ -161,6 +160,42 @@ func (pool *TxPool) eventLoop() {
}
}

// getSigner return signer for existing chain id
func (pool *TxPool) getSigner() (_ types.Signer, err error) {
defer catchInitPanic(&err)

if pool.signerCache == nil {
pool.imu.Lock()
defer pool.imu.Unlock()

if pool.signerCache == nil {
sdkCtx := pool.evmCtx.GetSdkContext()
params := pool.evmkeeper.GetParams(sdkCtx)
pool.signerCache = types.LatestSignerForChainID(params.ChainConfig.ChainID.BigInt())
}
}
return pool.signerCache, nil
}

// getMaxGasLimit return current gas limit for transaction caps
func (pool *TxPool) getMaxGasLimit() (_ uint64, err error) {
defer catchInitPanic(&err)

if pool.maxGasLimitCache == 0 {
pool.imu.Lock()
defer pool.imu.Unlock()

if pool.maxGasLimitCache == 0 {
gasLimit, err := evmtypes.BlockMaxGasFromConsensusParams(nil)
if err != nil {
return 0, fmt.Errorf("failed to get tx pool current max gas: %w (possible DB not started?)", err)
}
pool.maxGasLimitCache = uint64(gasLimit)
}
}
return pool.maxGasLimitCache, nil
}

// Get returns a transaction if it is contained in the pool and nil otherwise.
func (pool *TxPool) Get(hash common.Hash) *types.Transaction {
return pool.all.Get(hash)
Expand Down Expand Up @@ -220,6 +255,16 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
log.Trace("Validating tx", "hash", tx.Hash())
sdkCtx := pool.evmCtx.GetSdkContext()

currentMaxGas, err := pool.getMaxGasLimit()
if err != nil {
return err
}

signer, err := pool.getSigner()
if err != nil {
return err
}

// Accept only legacy transactions until EIP-2718/2930 activates.
if !tx.Protected() {
return core.ErrTxTypeNotSupported
Expand All @@ -238,7 +283,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
return core.ErrNegativeValue
}
// Ensure the transaction doesn't exceed the current block limit gas.
if pool.currentMaxGas < tx.Gas() {
if currentMaxGas < tx.Gas() {
return core.ErrGasLimit
}
// Sanity check for extremely large numbers
Expand All @@ -253,7 +298,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
return core.ErrTipAboveFeeCap
}
// Make sure the transaction is signed properly.
from, err := types.Sender(pool.signer, tx)
from, err := types.Sender(signer, tx)
if err != nil {
return core.ErrInvalidSender
}
Expand Down Expand Up @@ -327,8 +372,10 @@ func (pool *TxPool) Add(tx *types.Transaction) (replaced bool, err error) {
if err != nil {
return false, err
}

signer, _ := pool.getSigner()
// Try to replace an existing transaction in the pending pool
from, _ := types.Sender(pool.signer, tx) // already validated
from, _ := types.Sender(signer, tx) // already validated
if list := pool.pending[from]; list != nil && list.Overlaps(tx) {
log.Trace("Tx overlap", "hash", tx.Hash())
// Nonce already pending, check if required price bump is met
Expand All @@ -354,7 +401,9 @@ func (pool *TxPool) Add(tx *types.Transaction) (replaced bool, err error) {
// Note, this method assumes the pool lock is held!
func (pool *TxPool) enqueueTx(tx *types.Transaction, addAll bool) (bool, error) {
log.Trace("Tx enqeue", "hash", tx.Hash())
from, _ := types.Sender(pool.signer, tx) // already validated

signer, _ := pool.getSigner()
from, _ := types.Sender(signer, tx) // already validated
if pool.queue[from] == nil {
pool.queue[from] = newTxList(false)
}
Expand Down Expand Up @@ -389,7 +438,8 @@ func (pool *TxPool) removeTx(hash common.Hash) {
log.Error("Tx not found during removal", "hash", hash)
return
}
addr, _ := types.Sender(pool.signer, tx) // already validated during insertion
signer, _ := pool.getSigner()
addr, _ := types.Sender(signer, tx) // already validated during insertion

// Remove it from the list of known transactions
pool.all.Remove(hash)
Expand Down Expand Up @@ -477,6 +527,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans
var promoted []*types.Transaction

sdkCtx := pool.evmCtx.GetSdkContext()
currentMaxGas, _ := pool.getMaxGasLimit()

// Iterate over all accounts and promote any executable transactions
for _, addr := range accounts {
Expand All @@ -492,7 +543,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans
}
log.Trace("Removed old queued transactions", "count", len(forwards))
// Drop all transactions that are too costly (low balance or out of gas)
drops, _ := list.Filter(pool.evmkeeper.GetBalance(sdkCtx, addr), pool.currentMaxGas)
drops, _ := list.Filter(pool.evmkeeper.GetBalance(sdkCtx, addr), currentMaxGas)
for _, tx := range drops {
hash := tx.Hash()
pool.all.Remove(hash)
Expand Down Expand Up @@ -526,6 +577,8 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans
// to trigger a re-heap is this function
func (pool *TxPool) demoteUnexecutables() {
sdkCtx := pool.evmCtx.GetSdkContext()
currentMaxGas, _ := pool.getMaxGasLimit()

// Iterate over all accounts and demote any non-executable transactions
for addr, list := range pool.pending {
nonce := pool.evmkeeper.GetNonce(sdkCtx, addr)
Expand All @@ -538,7 +591,7 @@ func (pool *TxPool) demoteUnexecutables() {
log.Trace("Removed old pending transaction", "hash", hash)
}
// Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later
drops, invalids := list.Filter(pool.evmkeeper.GetBalance(sdkCtx, addr), pool.currentMaxGas)
drops, invalids := list.Filter(pool.evmkeeper.GetBalance(sdkCtx, addr), currentMaxGas)
for _, tx := range drops {
hash := tx.Hash()
log.Trace("Removed unpayable pending transaction", "hash", hash)
Expand Down
19 changes: 19 additions & 0 deletions x/pot/client/rest/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func registerQueryRoutes(clientCtx client.Context, r *mux.Router) {
r.HandleFunc("/pot/total-mined-token", getTotalMinedTokenHandlerFn(clientCtx, types.QueryTotalMinedToken)).Methods("GET")
r.HandleFunc("/pot/circulation-supply", getCirculationSupplyHandlerFn(clientCtx, types.QueryCirculationSupply)).Methods("GET")
r.HandleFunc("/pot/total-reward/{epoch}", getTotalRewardByEpochHandlerFn(clientCtx, types.QueryTotalRewardByEpoch)).Methods("GET")
r.HandleFunc("/pot/metrics", getMetricsHandlerFn(clientCtx, types.QueryMetrics)).Methods("GET")
}

// GET request handler to query params of POT module
Expand Down Expand Up @@ -259,3 +260,21 @@ func getTotalRewardByEpochHandlerFn(clientCtx client.Context, queryPath string)
rest.PostProcessResponse(w, cliCtx, res)
}
}

func getMetricsHandlerFn(clientCtx client.Context, queryPath string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, clientCtx, r)
if !ok {
return
}

route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, queryPath)
res, height, err := cliCtx.Query(route)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
cliCtx = cliCtx.WithHeight(height)
rest.PostProcessResponse(w, cliCtx, res)
}
}
Loading

0 comments on commit 610250a

Please sign in to comment.