Skip to content

Commit

Permalink
feat: store software upgrade plan and refresh data at upgrade height (f…
Browse files Browse the repository at this point in the history
…orbole#467)

## Description

Closes: #XXXX

jira: https://forbole.atlassian.net/browse/BDU-604

Background: 
Sifchain hard-coded `validator minimum commission` in a new release and updated it with `software upgrade`. Without any `MsgEditValidator` involved, the `validator commission %` could not be updated and were then incorrect. 


This PR stores `software upgrade proposal's upgrade plan` and uses the `upgrade` module to check if there's an upgrade plan at each height, if yes it will proceed with neccessary updates of data. Currently it's only updating the validator infos (the rest of the data I believe we have `periodic task` or `handle block` which should be enough). We can add more  in the future if similar cases pop up. 




---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [ ] targeted the correct branch
- [ ] provided a link to the relevant issue or specification
- [ ] added a changelog entry to `CHANGELOG.md`
- [ ] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
  • Loading branch information
huichiaotsou authored Oct 4, 2022
1 parent 696b0ff commit 739acc8
Show file tree
Hide file tree
Showing 15 changed files with 395 additions and 40 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## Unreleased
### Changes
#### Upgrade Module
- ([\#467](https://github.com/forbole/bdjuno/pull/467)) Store software upgrade plan and refresh data at upgrade height


#### 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
Expand Down
13 changes: 2 additions & 11 deletions cmd/parse/staking/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,9 @@ func validatorsCmd(parseConfig *parsecmdtypes.Config) *cobra.Command {
return fmt.Errorf("error while getting latest block height: %s", err)
}

// Get all validators
validators, err := sources.StakingSource.GetValidatorsWithStatus(height, "")
err = stakingModule.RefreshAllValidatorInfos(height)
if err != nil {
return fmt.Errorf("error while getting validators: %s", err)
}

// Refresh each validator
for _, validator := range validators {
err = stakingModule.RefreshValidatorInfos(height, validator.OperatorAddress)
if err != nil {
return fmt.Errorf("error while refreshing validator: %s", err)
}
return fmt.Errorf("error while refreshing all validators infos: %s", err)
}

return nil
Expand Down
60 changes: 60 additions & 0 deletions database/gov.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
"github.com/gogo/protobuf/proto"

"github.com/forbole/bdjuno/v3/types"
Expand Down Expand Up @@ -397,3 +398,62 @@ WHERE proposal_validator_status_snapshot.height <= excluded.height`

return nil
}

// SaveSoftwareUpgradePlan allows to save the given software upgrade plan with its proposal id
func (db *Db) SaveSoftwareUpgradePlan(proposalID uint64, plan upgradetypes.Plan, height int64) error {

stmt := `
INSERT INTO software_upgrade_plan(proposal_id, plan_name, upgrade_height, info, height)
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (proposal_id) DO UPDATE SET
plan_name = excluded.plan_name,
upgrade_height = excluded.upgrade_height,
info = excluded.info,
height = excluded.height
WHERE software_upgrade_plan.height <= excluded.height`

_, err := db.Sql.Exec(stmt,
proposalID, plan.Name, plan.Height, plan.Info, height)
if err != nil {
return fmt.Errorf("error while storing software upgrade plan: %s", err)
}

return nil
}

// DeleteSoftwareUpgradePlan allows to delete a SoftwareUpgradePlan with proposal ID
func (db *Db) DeleteSoftwareUpgradePlan(proposalID uint64) error {
stmt := `DELETE FROM software_upgrade_plan WHERE proposal_id = $1`

_, err := db.Sql.Exec(stmt, proposalID)
if err != nil {
return fmt.Errorf("error while deleting software upgrade plan: %s", err)
}

return nil
}

// CheckSoftwareUpgradePlan returns true if an upgrade is scheduled at the given height
func (db *Db) CheckSoftwareUpgradePlan(upgradeHeight int64) (bool, error) {
var exist bool

stmt := `SELECT EXISTS (SELECT 1 FROM software_upgrade_plan WHERE upgrade_height=$1)`
err := db.Sql.QueryRow(stmt, upgradeHeight).Scan(&exist)
if err != nil {
return exist, fmt.Errorf("error while checking software upgrade plan existence: %s", err)
}

return exist, nil
}

// TruncateSoftwareUpgradePlan delete software upgrade plans once the upgrade height passed
func (db *Db) TruncateSoftwareUpgradePlan(height int64) error {
stmt := `DELETE FROM software_upgrade_plan WHERE upgrade_height <= $1`

_, err := db.Sql.Exec(stmt, height)
if err != nil {
return fmt.Errorf("error while deleting software upgrade plan: %s", err)
}

return nil
}
130 changes: 130 additions & 0 deletions database/gov_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"time"

stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/gogo/protobuf/proto"
Expand Down Expand Up @@ -825,3 +826,132 @@ func (suite *DbTestSuite) TestBigDipperDb_SaveProposalValidatorsStatusesSnapshot
),
})
}

func (suite *DbTestSuite) TestBigDipperDb_SaveSoftwareUpgradePlan() {
_ = suite.getProposalRow(1)

// ----------------------------------------------------------------------------------------------------------------
// Save software upgrade plan at height 10 with upgrade height at 100
var plan = upgradetypes.Plan{
Name: "name",
Height: 100,
Info: "info",
}

err := suite.database.SaveSoftwareUpgradePlan(1, plan, 10)
suite.Require().NoError(err)

var rows []dbtypes.SoftwareUpgradePlanRow
err = suite.database.Sqlx.Select(&rows, `SELECT * FROM software_upgrade_plan`)
suite.Require().NoError(err)
suite.Require().Len(rows, 1)
suite.Require().Equal(rows, []dbtypes.SoftwareUpgradePlanRow{
dbtypes.NewSoftwareUpgradePlanRow(1, plan.Name, plan.Height, plan.Info, 10),
})

// ----------------------------------------------------------------------------------------------------------------
// Update software upgrade plan with lower height
planEdit1 := upgradetypes.Plan{
Name: "name_edit_1",
Height: 101,
Info: "info_edit_1",
}

err = suite.database.SaveSoftwareUpgradePlan(1, planEdit1, 9)
suite.Require().NoError(err)

rows = []dbtypes.SoftwareUpgradePlanRow{}
err = suite.database.Sqlx.Select(&rows, `SELECT * FROM software_upgrade_plan`)
suite.Require().NoError(err)
suite.Require().Len(rows, 1)
suite.Require().Equal(rows, []dbtypes.SoftwareUpgradePlanRow{
dbtypes.NewSoftwareUpgradePlanRow(1, plan.Name, plan.Height, plan.Info, 10),
})

// ----------------------------------------------------------------------------------------------------------------
// Update software upgrade plan with same height
planEdit2 := upgradetypes.Plan{
Name: "name_edit_2",
Height: 102,
Info: "info_edit_2",
}

err = suite.database.SaveSoftwareUpgradePlan(1, planEdit2, 10)
suite.Require().NoError(err)

rows = []dbtypes.SoftwareUpgradePlanRow{}
err = suite.database.Sqlx.Select(&rows, `SELECT * FROM software_upgrade_plan`)
suite.Require().NoError(err)
suite.Require().Len(rows, 1)
suite.Require().Equal(rows, []dbtypes.SoftwareUpgradePlanRow{
dbtypes.NewSoftwareUpgradePlanRow(1, planEdit2.Name, planEdit2.Height, planEdit2.Info, 10),
})

// ----------------------------------------------------------------------------------------------------------------
// Update software upgrade plan with higher height
planEdit3 := upgradetypes.Plan{
Name: "name_edit_3",
Height: 103,
Info: "info_edit_3",
}

err = suite.database.SaveSoftwareUpgradePlan(1, planEdit3, 11)
suite.Require().NoError(err)

rows = []dbtypes.SoftwareUpgradePlanRow{}
err = suite.database.Sqlx.Select(&rows, `SELECT * FROM software_upgrade_plan`)
suite.Require().NoError(err)
suite.Require().Len(rows, 1)
suite.Require().Equal(rows, []dbtypes.SoftwareUpgradePlanRow{
dbtypes.NewSoftwareUpgradePlanRow(1, planEdit3.Name, planEdit3.Height, planEdit3.Info, 11),
})
}

func (suite *DbTestSuite) TestBigDipperDb_DeleteSoftwareUpgradePlan() {
_ = suite.getProposalRow(1)

// Save software upgrade plan at height 10 with upgrade height at 100
var plan = upgradetypes.Plan{
Name: "name",
Height: 100,
Info: "info",
}

err := suite.database.SaveSoftwareUpgradePlan(1, plan, 10)
suite.Require().NoError(err)

// Delete software upgrade plan
err = suite.database.DeleteSoftwareUpgradePlan(1)
suite.Require().NoError(err)

var rows []dbtypes.SoftwareUpgradePlanRow
err = suite.database.Sqlx.Select(&rows, `SELECT * FROM software_upgrade_plan`)
suite.Require().NoError(err)
suite.Require().Len(rows, 0)

}

func (suite *DbTestSuite) TestBigDipperDb_CheckSoftwareUpgradePlan() {
_ = suite.getProposalRow(1)

// Save software upgrade plan at height 10 with upgrade height at 100
var plan = upgradetypes.Plan{
Name: "name",
// the Height here is the upgrade height
Height: 100,
Info: "info",
}

err := suite.database.SaveSoftwareUpgradePlan(1, plan, 10)
suite.Require().NoError(err)

// Check software upgrade plan at existing height
exist, err := suite.database.CheckSoftwareUpgradePlan(100)
suite.Require().NoError(err)
suite.Require().Equal(true, exist)

// Check software upgrade plan at non-existing height
exist, err = suite.database.CheckSoftwareUpgradePlan(11)
suite.Require().NoError(err)
suite.Require().Equal(false, exist)
}
10 changes: 10 additions & 0 deletions database/schema/12-upgrade.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CREATE TABLE software_upgrade_plan
(
proposal_id INTEGER REFERENCES proposal (id) UNIQUE,
plan_name TEXT NOT NULL,
upgrade_height BIGINT NOT NULL,
info TEXT NOT NULL,
height BIGINT NOT NULL
);
CREATE INDEX software_upgrade_plan_proposal_id_index ON software_upgrade_plan (proposal_id);
CREATE INDEX software_upgrade_plan_height_index ON software_upgrade_plan (height);
21 changes: 21 additions & 0 deletions database/types/upgrade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package types

type SoftwareUpgradePlanRow struct {
ProposalID uint64 `db:"proposal_id"`
PlanName string `db:"plan_name"`
UpgradeHeight int64 `db:"upgrade_height"`
Info string `db:"info"`
Height int64 `db:"height"`
}

func NewSoftwareUpgradePlanRow(
proposalID uint64, planName string, upgradeHeight int64, info string, height int64,
) SoftwareUpgradePlanRow {
return SoftwareUpgradePlanRow{
ProposalID: proposalID,
PlanName: planName,
UpgradeHeight: upgradeHeight,
Info: info,
Height: height,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
table:
name: software_upgrade_plan
schema: public
object_relationships:
- name: proposal
using:
foreign_key_constraint_on: proposal_id
select_permissions:
- permission:
allow_aggregations: true
columns:
- proposal_id
- plan_name
- upgrade_height
- info
- height
filter: {}
role: anonymous
1 change: 1 addition & 0 deletions hasura/metadata/databases/bdjuno/tables/tables.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- "!include public_proposal_validator_status_snapshot.yaml"
- "!include public_proposal_vote.yaml"
- "!include public_slashing_params.yaml"
- "!include public_software_upgrade_plan.yaml"
- "!include public_staking_params.yaml"
- "!include public_staking_pool.yaml"
- "!include public_supply.yaml"
Expand Down
7 changes: 0 additions & 7 deletions modules/gov/handle_msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,6 @@ func (m *Module) handleMsgSubmitProposal(tx *juno.Tx, index int, msg *govtypes.M
return fmt.Errorf("error while getting proposal: %s", err)
}

// Unpack the content
var content govtypes.Content
err = m.cdc.UnpackAny(proposal.Content, &content)
if err != nil {
return fmt.Errorf("error while unpacking proposal content: %s", err)
}

// Store the proposal
proposalObj := types.NewProposal(
proposal.ProposalId,
Expand Down
Loading

0 comments on commit 739acc8

Please sign in to comment.