Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: updated staking pool values #455

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
### Changes
#### Staking Module
- ([\#443](https://github.com/forbole/bdjuno/pull/443)) Remove tombstone status from staking module(already stored in slashing module)
- ([\#455](https://github.com/forbole/bdjuno/pull/455)) Added `unbonding_tokens` and `staked_not_bonded_tokens` values to staking pool table


## Version v3.2.0
### Changes
Expand Down
8 changes: 8 additions & 0 deletions database/gov_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,8 @@ func (suite *DbTestSuite) TestBigDipperDb_SaveProposalStakingPoolSnapshot() {
snapshot := types.NewProposalStakingPoolSnapshot(1, types.NewPool(
sdk.NewInt(100),
sdk.NewInt(200),
sdk.NewInt(20),
sdk.NewInt(30),
10,
))
err := suite.database.SaveProposalStakingPoolSnapshot(snapshot)
Expand All @@ -530,6 +532,8 @@ func (suite *DbTestSuite) TestBigDipperDb_SaveProposalStakingPoolSnapshot() {
err = suite.database.SaveProposalStakingPoolSnapshot(types.NewProposalStakingPoolSnapshot(1, types.NewPool(
sdk.NewInt(200),
sdk.NewInt(500),
sdk.NewInt(14),
sdk.NewInt(10),
9,
)))
suite.Require().NoError(err)
Expand All @@ -551,6 +555,8 @@ func (suite *DbTestSuite) TestBigDipperDb_SaveProposalStakingPoolSnapshot() {
err = suite.database.SaveProposalStakingPoolSnapshot(types.NewProposalStakingPoolSnapshot(1, types.NewPool(
sdk.NewInt(500),
sdk.NewInt(1000),
sdk.NewInt(20),
sdk.NewInt(30),
10,
)))
suite.Require().NoError(err)
Expand All @@ -572,6 +578,8 @@ func (suite *DbTestSuite) TestBigDipperDb_SaveProposalStakingPoolSnapshot() {
err = suite.database.SaveProposalStakingPoolSnapshot(types.NewProposalStakingPoolSnapshot(1, types.NewPool(
sdk.NewInt(1000),
sdk.NewInt(2000),
sdk.NewInt(80),
sdk.NewInt(40),
11,
)))
suite.Require().NoError(err)
Expand Down
10 changes: 6 additions & 4 deletions database/schema/03-staking.sql
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ CREATE INDEX staking_params_height_index ON staking_params (height);

CREATE TABLE staking_pool
(
one_row_id BOOLEAN NOT NULL DEFAULT TRUE PRIMARY KEY,
bonded_tokens TEXT NOT NULL,
not_bonded_tokens TEXT NOT NULL,
height BIGINT NOT NULL,
one_row_id BOOLEAN NOT NULL DEFAULT TRUE PRIMARY KEY,
bonded_tokens TEXT NOT NULL,
not_bonded_tokens TEXT NOT NULL,
unbonding_tokens TEXT NOT NULL,
staked_not_bonded_tokens TEXT NOT NULL,
height BIGINT NOT NULL,
CHECK (one_row_id)
);
CREATE INDEX staking_pool_height_index ON staking_pool (height);
Expand Down
13 changes: 10 additions & 3 deletions database/staking_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,22 @@ import (
// SaveStakingPool allows to save for the given height the given stakingtypes pool
func (db *Db) SaveStakingPool(pool *types.Pool) error {
stmt := `
INSERT INTO staking_pool (bonded_tokens, not_bonded_tokens, height)
VALUES ($1, $2, $3)
INSERT INTO staking_pool (bonded_tokens, not_bonded_tokens, unbonding_tokens, staked_not_bonded_tokens, height)
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (one_row_id) DO UPDATE
SET bonded_tokens = excluded.bonded_tokens,
not_bonded_tokens = excluded.not_bonded_tokens,
unbonding_tokens = excluded.unbonding_tokens,
staked_not_bonded_tokens = excluded.staked_not_bonded_tokens,
height = excluded.height
WHERE staking_pool.height <= excluded.height`

_, err := db.Sql.Exec(stmt, pool.BondedTokens.String(), pool.NotBondedTokens.String(), pool.Height)
_, err := db.Sql.Exec(stmt,
pool.BondedTokens.String(),
pool.NotBondedTokens.String(),
pool.UnbondingTokens.String(),
pool.StakedNotBondedTokens.String(),
pool.Height)
if err != nil {
return fmt.Errorf("error while storing staking pool: %s", err)
}
Expand Down
14 changes: 7 additions & 7 deletions database/staking_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import (

func (suite *DbTestSuite) TestBigDipperDb_SaveStakingPool() {
// Save the data
original := types.NewPool(sdk.NewInt(50), sdk.NewInt(100), 10)
original := types.NewPool(sdk.NewInt(50), sdk.NewInt(100), sdk.NewInt(5), sdk.NewInt(1), 10)
err := suite.database.SaveStakingPool(original)
suite.Require().NoError(err)

// Verify the data
expected := dbtypes.NewStakingPoolRow(50, 100, 10)
expected := dbtypes.NewStakingPoolRow(50, 100, 5, 1, 10)

var rows []dbtypes.StakingPoolRow
err = suite.database.Sqlx.Select(&rows, `SELECT * FROM staking_pool`)
Expand All @@ -25,7 +25,7 @@ func (suite *DbTestSuite) TestBigDipperDb_SaveStakingPool() {
// ----------------------------------------------------------------------------------------------------------------

// Try updating using a lower height
pool := types.NewPool(sdk.NewInt(1), sdk.NewInt(1), 8)
pool := types.NewPool(sdk.NewInt(1), sdk.NewInt(1), sdk.NewInt(1), sdk.NewInt(1), 8)
err = suite.database.SaveStakingPool(pool)
suite.Require().NoError(err)

Expand All @@ -39,12 +39,12 @@ func (suite *DbTestSuite) TestBigDipperDb_SaveStakingPool() {
// ----------------------------------------------------------------------------------------------------------------

// Try updating with the same height
pool = types.NewPool(sdk.NewInt(1), sdk.NewInt(1), 10)
pool = types.NewPool(sdk.NewInt(1), sdk.NewInt(1), sdk.NewInt(1), sdk.NewInt(1), 10)
err = suite.database.SaveStakingPool(pool)
suite.Require().NoError(err)

// Verify the data
expected = dbtypes.NewStakingPoolRow(1, 1, 10)
expected = dbtypes.NewStakingPoolRow(1, 1, 1, 1, 10)

rows = []dbtypes.StakingPoolRow{}
err = suite.database.Sqlx.Select(&rows, `SELECT * FROM staking_pool`)
Expand All @@ -55,12 +55,12 @@ func (suite *DbTestSuite) TestBigDipperDb_SaveStakingPool() {
// ----------------------------------------------------------------------------------------------------------------

// Try updating with a higher height
pool = types.NewPool(sdk.NewInt(1000000), sdk.NewInt(1000000), 20)
pool = types.NewPool(sdk.NewInt(1000000), sdk.NewInt(1000000), sdk.NewInt(20), sdk.NewInt(15), 20)
err = suite.database.SaveStakingPool(pool)
suite.Require().NoError(err)

// Verify the data
expected = dbtypes.NewStakingPoolRow(1000000, 1000000, 20)
expected = dbtypes.NewStakingPoolRow(1000000, 1000000, 20, 15, 20)

rows = []dbtypes.StakingPoolRow{}
err = suite.database.Sqlx.Select(&rows, `SELECT * FROM staking_pool`)
Expand Down
24 changes: 15 additions & 9 deletions database/types/staking_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,31 @@ package types

// StakingPoolRow represents a single row inside the staking_pool table
type StakingPoolRow struct {
OneRowID bool `db:"one_row_id"`
BondedTokens int64 `db:"bonded_tokens"`
NotBondedTokens int64 `db:"not_bonded_tokens"`
Height int64 `db:"height"`
OneRowID bool `db:"one_row_id"`
BondedTokens int64 `db:"bonded_tokens"`
NotBondedTokens int64 `db:"not_bonded_tokens"`
UnbondingTokens int64 `db:"unbonding_tokens"`
StakedNotBondedTokens int64 `db:"staked_not_bonded_tokens"`
Height int64 `db:"height"`
}

// NewStakingPoolRow allows to easily create a new StakingPoolRow
func NewStakingPoolRow(bondedTokens, notBondedTokens int64, height int64) StakingPoolRow {
func NewStakingPoolRow(bondedTokens, notBondedTokens, unbondingTokens, stakedNotBondedTokens int64, height int64) StakingPoolRow {
return StakingPoolRow{
OneRowID: true,
BondedTokens: bondedTokens,
NotBondedTokens: notBondedTokens,
Height: height,
OneRowID: true,
BondedTokens: bondedTokens,
NotBondedTokens: notBondedTokens,
UnbondingTokens: unbondingTokens,
StakedNotBondedTokens: stakedNotBondedTokens,
Height: height,
}
}

// Equal allows to tells whether r and as represent the same rows
func (r StakingPoolRow) Equal(s StakingPoolRow) bool {
return r.BondedTokens == s.BondedTokens &&
r.NotBondedTokens == s.NotBondedTokens &&
r.UnbondingTokens == s.UnbondingTokens &&
r.StakedNotBondedTokens == s.StakedNotBondedTokens &&
r.Height == s.Height
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ select_permissions:
- height
- bonded_tokens
- not_bonded_tokens
- unbonding_tokens
- staked_not_bonded_tokens
filter: {}
role: anonymous
23 changes: 0 additions & 23 deletions modules/staking/handle_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ func (m *Module) HandleBlock(
// Updated the double sign evidences
go m.updateDoubleSignEvidence(block.Block.Height, block.Block.Evidence.Evidence)

// Update the staking pool
go m.updateStakingPool(block.Block.Height)

return nil
}

Expand Down Expand Up @@ -123,23 +120,3 @@ func (m *Module) updateDoubleSignEvidence(height int64, evidenceList tmtypes.Evi

}
}

// updateStakingPool reads from the LCD the current staking pool and stores its value inside the database
func (m *Module) updateStakingPool(height int64) {
log.Debug().Str("module", "staking").Int64("height", height).
Msg("updating staking pool")

pool, err := m.GetStakingPool(height)
if err != nil {
log.Error().Str("module", "staking").Err(err).Int64("height", height).
Msg("error while getting staking pool")
return
}

err = m.db.SaveStakingPool(pool)
if err != nil {
log.Error().Str("module", "staking").Err(err).Int64("height", height).
Msg("error while saving staking pool")
return
}
}
48 changes: 48 additions & 0 deletions modules/staking/handle_periodic_operations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package staking

import (
"fmt"

"github.com/go-co-op/gocron"
"github.com/rs/zerolog/log"

"github.com/forbole/bdjuno/v3/modules/utils"
)

// RegisterPeriodicOperations implements modules.PeriodicOperationsModule
func (m *Module) RegisterPeriodicOperations(scheduler *gocron.Scheduler) error {
log.Debug().Str("module", "staking").Msg("setting up periodic tasks")

// Update the staking pool every 5 mins
if _, err := scheduler.Every(5).Minutes().Do(func() {
utils.WatchMethod(m.updateStakingPool)
}); err != nil {
return fmt.Errorf("error while scheduling staking pool periodic operation: %s", err)
}

return nil
}

// updateStakingPool reads from the LCD the current staking pool and stores its value inside the database
func (m *Module) updateStakingPool() error {
height, err := m.db.GetLastBlockHeight()
if err != nil {
return fmt.Errorf("error while getting latest block height: %s", err)
}
log.Debug().Str("module", "staking").Int64("height", height).
Msg("updating staking pool")

pool, err := m.GetStakingPool(height)
if err != nil {
return fmt.Errorf("error while getting staking pool: %s", err)

}

err = m.db.SaveStakingPool(pool)
if err != nil {
return fmt.Errorf("error while saving staking pool: %s", err)

}

return nil
}
9 changes: 5 additions & 4 deletions modules/staking/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import (
)

var (
_ modules.Module = &Module{}
_ modules.GenesisModule = &Module{}
_ modules.BlockModule = &Module{}
_ modules.MessageModule = &Module{}
_ modules.Module = &Module{}
_ modules.GenesisModule = &Module{}
_ modules.BlockModule = &Module{}
_ modules.MessageModule = &Module{}
_ modules.PeriodicOperationsModule = &Module{}
)

// Module represents the x/staking module
Expand Down
49 changes: 48 additions & 1 deletion modules/staking/utils_staking_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package staking
import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/query"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/forbole/bdjuno/v3/types"
)

Expand All @@ -12,5 +15,49 @@ func (m *Module) GetStakingPool(height int64) (*types.Pool, error) {
return nil, fmt.Errorf("error while getting staking pool: %s", err)
}

return types.NewPool(pool.BondedTokens, pool.NotBondedTokens, height), nil
validatorsList, err := m.db.GetValidators()
if err != nil {
return nil, fmt.Errorf("error while getting validators list: %s", err)
}

var unbondingTokens = sdk.NewInt(0)

for _, validator := range validatorsList {
// get list of all unbonding delegations for each validator
unbondingDelegations := m.getTotalUnbondingDelegationsFromValidator(height, validator.GetOperator())
if len(unbondingDelegations) > 0 {
// calculate total value of unbonding tokens
for _, unbonding := range unbondingDelegations {
for _, entry := range unbonding.Entries {
unbondingTokens = unbondingTokens.Add(entry.Balance)
}
}
}

}

// calculate total value of staked tokens that are not bonded
stakedNotBondedTokens := pool.NotBondedTokens.Sub(unbondingTokens)

return types.NewPool(pool.BondedTokens, pool.NotBondedTokens, unbondingTokens, stakedNotBondedTokens, height), nil
}

func (m *Module) getTotalUnbondingDelegationsFromValidator(height int64, valOperatorAddress string) []stakingtypes.UnbondingDelegation {
var unbondingDelegations []stakingtypes.UnbondingDelegation
var nextKey []byte
var stop = false
for !stop {
res, err := m.source.GetUnbondingDelegationsFromValidator(height,
valOperatorAddress,
&query.PageRequest{Key: nextKey},
)
if err != nil {
return []stakingtypes.UnbondingDelegation{}
}

nextKey = res.Pagination.NextKey
stop = len(res.Pagination.NextKey) == 0
unbondingDelegations = append(unbondingDelegations, res.UnbondingResponses...)
}
return unbondingDelegations
}
18 changes: 11 additions & 7 deletions types/staking_pool_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,21 @@ import (

// Pool contains the data of the staking pool at the given height
type Pool struct {
BondedTokens sdk.Int
NotBondedTokens sdk.Int
Height int64
BondedTokens sdk.Int
NotBondedTokens sdk.Int
UnbondingTokens sdk.Int
StakedNotBondedTokens sdk.Int
Height int64
}

// NewPool allows to build a new Pool instance
func NewPool(bondedTokens, notBondedTokens sdk.Int, height int64) *Pool {
func NewPool(bondedTokens, notBondedTokens, unbondingTokens, stakedNotBondedTokens sdk.Int, height int64) *Pool {
return &Pool{
BondedTokens: bondedTokens,
NotBondedTokens: notBondedTokens,
Height: height,
BondedTokens: bondedTokens,
NotBondedTokens: notBondedTokens,
UnbondingTokens: unbondingTokens,
StakedNotBondedTokens: stakedNotBondedTokens,
Height: height,
}
}

Expand Down