diff --git a/CHANGELOG.md b/CHANGELOG.md index 195113088..e5832a15f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +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 @@ -11,6 +11,7 @@ #### Gov Module - ([\#461](https://github.com/forbole/bdjuno/pull/461)) Parse `x/gov` genesis with `genesisDoc.InitialHeight` instead of the hard-coded height 1 - ([\#465](https://github.com/forbole/bdjuno/pull/465)) Get open proposal ids in deposit or voting period by block time instead of current time +- ([\#489](https://github.com/forbole/bdjuno/pull/489)) Remove block height foreign key from proposal_vote and proposal_deposit tables and add column timestamp #### Daily refetch - ([\#454](https://github.com/forbole/bdjuno/pull/454)) Added `daily refetch` module to refetch missing blocks every day diff --git a/database/gov.go b/database/gov.go index 673bf4f68..aa52ffdcf 100644 --- a/database/gov.go +++ b/database/gov.go @@ -248,15 +248,16 @@ func (db *Db) SaveDeposits(deposits []types.Deposit) error { return nil } - query := `INSERT INTO proposal_deposit (proposal_id, depositor_address, amount, height) VALUES ` + query := `INSERT INTO proposal_deposit (proposal_id, depositor_address, amount, timestamp, height) VALUES ` var param []interface{} for i, deposit := range deposits { - vi := i * 4 - query += fmt.Sprintf("($%d,$%d,$%d,$%d),", vi+1, vi+2, vi+3, vi+4) + vi := i * 5 + query += fmt.Sprintf("($%d,$%d,$%d,$%d,$%d),", vi+1, vi+2, vi+3, vi+4, vi+5) param = append(param, deposit.ProposalID, deposit.Depositor, pq.Array(dbtypes.NewDbCoins(deposit.Amount)), + deposit.Timestamp, deposit.Height, ) } @@ -264,6 +265,7 @@ func (db *Db) SaveDeposits(deposits []types.Deposit) error { query += ` ON CONFLICT ON CONSTRAINT unique_deposit DO UPDATE SET amount = excluded.amount, + timestamp = excluded.timestamp, height = excluded.height WHERE proposal_deposit.height <= excluded.height` _, err := db.Sql.Exec(query, param...) @@ -279,10 +281,11 @@ WHERE proposal_deposit.height <= excluded.height` // SaveVote allows to save for the given height and the message vote func (db *Db) SaveVote(vote types.Vote) error { query := ` -INSERT INTO proposal_vote (proposal_id, voter_address, option, height) -VALUES ($1, $2, $3, $4) +INSERT INTO proposal_vote (proposal_id, voter_address, option, timestamp, height) +VALUES ($1, $2, $3, $4, $5) ON CONFLICT ON CONSTRAINT unique_vote DO UPDATE SET option = excluded.option, + timestamp = excluded.timestamp, height = excluded.height WHERE proposal_vote.height <= excluded.height` @@ -292,7 +295,7 @@ WHERE proposal_vote.height <= excluded.height` return fmt.Errorf("error while storing voter account: %s", err) } - _, err = db.Sql.Exec(query, vote.ProposalID, vote.Voter, vote.Option.String(), vote.Height) + _, err = db.Sql.Exec(query, vote.ProposalID, vote.Voter, vote.Option.String(), vote.Timestamp, vote.Height) if err != nil { return fmt.Errorf("error while storing vote: %s", err) } diff --git a/database/gov_test.go b/database/gov_test.go index 04143efe6..63fd0faa5 100644 --- a/database/gov_test.go +++ b/database/gov_test.go @@ -348,19 +348,23 @@ func (suite *DbTestSuite) TestBigDipperDb_SaveDeposits() { depositor3 := suite.getAccount("cosmos1gyds87lg3m52hex9yqta2mtwzw89pfukx3jl7g") amount3 := sdk.NewCoins(sdk.NewCoin("desmos", sdk.NewInt(50000))) + timestamp1 := time.Date(2020, 1, 1, 15, 00, 00, 000, time.UTC) + timestamp2 := time.Date(2020, 1, 1, 16, 00, 00, 000, time.UTC) + timestamp3 := time.Date(2020, 1, 1, 17, 00, 00, 000, time.UTC) + deposit := []types.Deposit{ - types.NewDeposit(proposal.ProposalID, depositor.String(), amount, 10), - types.NewDeposit(proposal.ProposalID, depositor2.String(), amount2, 10), - types.NewDeposit(proposal.ProposalID, depositor3.String(), amount3, 10), + types.NewDeposit(proposal.ProposalID, depositor.String(), amount, timestamp1, 10), + types.NewDeposit(proposal.ProposalID, depositor2.String(), amount2, timestamp2, 10), + types.NewDeposit(proposal.ProposalID, depositor3.String(), amount3, timestamp3, 10), } err := suite.database.SaveDeposits(deposit) suite.Require().NoError(err) expected := []dbtypes.DepositRow{ - dbtypes.NewDepositRow(1, depositor.String(), dbtypes.NewDbCoins(amount), 10), - dbtypes.NewDepositRow(1, depositor2.String(), dbtypes.NewDbCoins(amount2), 10), - dbtypes.NewDepositRow(1, depositor3.String(), dbtypes.NewDbCoins(amount3), 10), + dbtypes.NewDepositRow(1, depositor.String(), dbtypes.NewDbCoins(amount), timestamp1, 10), + dbtypes.NewDepositRow(1, depositor2.String(), dbtypes.NewDbCoins(amount2), timestamp2, 10), + dbtypes.NewDepositRow(1, depositor3.String(), dbtypes.NewDbCoins(amount3), timestamp3, 10), } var result []dbtypes.DepositRow err = suite.database.Sqlx.Select(&result, `SELECT * FROM proposal_deposit`) @@ -377,9 +381,9 @@ func (suite *DbTestSuite) TestBigDipperDb_SaveDeposits() { amount3 = sdk.NewCoins(sdk.NewCoin("desmos", sdk.NewInt(30))) deposit = []types.Deposit{ - types.NewDeposit(proposal.ProposalID, depositor.String(), amount, 9), - types.NewDeposit(proposal.ProposalID, depositor2.String(), amount2, 10), - types.NewDeposit(proposal.ProposalID, depositor3.String(), amount3, 11), + types.NewDeposit(proposal.ProposalID, depositor.String(), amount, timestamp1, 9), + types.NewDeposit(proposal.ProposalID, depositor2.String(), amount2, timestamp2, 10), + types.NewDeposit(proposal.ProposalID, depositor3.String(), amount3, timestamp3, 11), } err = suite.database.SaveDeposits(deposit) @@ -387,9 +391,9 @@ func (suite *DbTestSuite) TestBigDipperDb_SaveDeposits() { expected = []dbtypes.DepositRow{ dbtypes.NewDepositRow(1, depositor.String(), dbtypes.NewDbCoins( - sdk.NewCoins(sdk.NewCoin("desmos", sdk.NewInt(10000)))), 10), - dbtypes.NewDepositRow(1, depositor2.String(), dbtypes.NewDbCoins(amount2), 10), - dbtypes.NewDepositRow(1, depositor3.String(), dbtypes.NewDbCoins(amount3), 11), + sdk.NewCoins(sdk.NewCoin("desmos", sdk.NewInt(10000)))), timestamp1, 10), + dbtypes.NewDepositRow(1, depositor2.String(), dbtypes.NewDbCoins(amount2), timestamp2, 10), + dbtypes.NewDepositRow(1, depositor3.String(), dbtypes.NewDbCoins(amount3), timestamp3, 11), } result = []dbtypes.DepositRow{} @@ -410,11 +414,13 @@ func (suite *DbTestSuite) TestBigDipperDb_SaveVote() { proposal := suite.getProposalRow(1) voter := suite.getAccount("cosmos1z4hfrxvlgl4s8u4n5ngjcw8kdqrcv43599amxs") - vote := types.NewVote(1, voter.String(), govtypes.OptionYes, 1) + timestamp := time.Date(2020, 1, 1, 15, 00, 00, 000, time.UTC) + + vote := types.NewVote(1, voter.String(), govtypes.OptionYes, timestamp, 1) err := suite.database.SaveVote(vote) suite.Require().NoError(err) - expected := dbtypes.NewVoteRow(int64(proposal.ProposalID), voter.String(), govtypes.OptionYes.String(), 1) + expected := dbtypes.NewVoteRow(int64(proposal.ProposalID), voter.String(), govtypes.OptionYes.String(), timestamp, 1) var result []dbtypes.VoteRow err = suite.database.Sqlx.Select(&result, `SELECT * FROM proposal_vote`) @@ -423,7 +429,7 @@ func (suite *DbTestSuite) TestBigDipperDb_SaveVote() { suite.Require().True(expected.Equals(result[0])) // Update with lower height should not change option - vote = types.NewVote(1, voter.String(), govtypes.OptionNo, 0) + vote = types.NewVote(1, voter.String(), govtypes.OptionNo, timestamp, 0) err = suite.database.SaveVote(vote) suite.Require().NoError(err) @@ -434,11 +440,11 @@ func (suite *DbTestSuite) TestBigDipperDb_SaveVote() { suite.Require().True(expected.Equals(result[0])) // Update with same height should change option - vote = types.NewVote(1, voter.String(), govtypes.OptionAbstain, 1) + vote = types.NewVote(1, voter.String(), govtypes.OptionAbstain, timestamp, 1) err = suite.database.SaveVote(vote) suite.Require().NoError(err) - expected = dbtypes.NewVoteRow(int64(proposal.ProposalID), voter.String(), govtypes.OptionAbstain.String(), 1) + expected = dbtypes.NewVoteRow(int64(proposal.ProposalID), voter.String(), govtypes.OptionAbstain.String(), timestamp, 1) result = []dbtypes.VoteRow{} err = suite.database.Sqlx.Select(&result, `SELECT * FROM proposal_vote`) @@ -447,11 +453,11 @@ func (suite *DbTestSuite) TestBigDipperDb_SaveVote() { suite.Require().True(expected.Equals(result[0])) // Update with higher height should change option - vote = types.NewVote(1, voter.String(), govtypes.OptionNoWithVeto, 2) + vote = types.NewVote(1, voter.String(), govtypes.OptionNoWithVeto, timestamp, 2) err = suite.database.SaveVote(vote) suite.Require().NoError(err) - expected = dbtypes.NewVoteRow(int64(proposal.ProposalID), voter.String(), govtypes.OptionNoWithVeto.String(), 2) + expected = dbtypes.NewVoteRow(int64(proposal.ProposalID), voter.String(), govtypes.OptionNoWithVeto.String(), timestamp, 2) result = []dbtypes.VoteRow{} err = suite.database.Sqlx.Select(&result, `SELECT * FROM proposal_vote`) diff --git a/database/schema/08-gov.sql b/database/schema/08-gov.sql index df2ce5c2b..3df6f7598 100644 --- a/database/schema/08-gov.sql +++ b/database/schema/08-gov.sql @@ -30,7 +30,8 @@ CREATE TABLE proposal_deposit proposal_id INTEGER NOT NULL REFERENCES proposal (id), depositor_address TEXT REFERENCES account (address), amount COIN[], - height BIGINT NOT NULL REFERENCES block (height), + timestamp TIMESTAMP, + height BIGINT NOT NULL, CONSTRAINT unique_deposit UNIQUE (proposal_id, depositor_address) ); CREATE INDEX proposal_deposit_proposal_id_index ON proposal_deposit (proposal_id); @@ -42,7 +43,8 @@ CREATE TABLE proposal_vote proposal_id INTEGER NOT NULL REFERENCES proposal (id), voter_address TEXT NOT NULL REFERENCES account (address), option TEXT NOT NULL, - height BIGINT NOT NULL REFERENCES block (height), + timestamp TIMESTAMP, + height BIGINT NOT NULL, CONSTRAINT unique_vote UNIQUE (proposal_id, voter_address) ); CREATE INDEX proposal_vote_proposal_id_index ON proposal_vote (proposal_id); diff --git a/database/types/gov.go b/database/types/gov.go index 9d9a2753c..3781e26e9 100644 --- a/database/types/gov.go +++ b/database/types/gov.go @@ -118,10 +118,11 @@ func (w TallyResultRow) Equals(v TallyResultRow) bool { // VoteRow represents a single row inside the vote table type VoteRow struct { - ProposalID int64 `db:"proposal_id"` - Voter string `db:"voter_address"` - Option string `db:"option"` - Height int64 `db:"height"` + ProposalID int64 `db:"proposal_id"` + Voter string `db:"voter_address"` + Option string `db:"option"` + Timestamp time.Time `db:"timestamp"` + Height int64 `db:"height"` } // NewVoteRow allows to easily create a new VoteRow @@ -129,12 +130,14 @@ func NewVoteRow( proposalID int64, voter string, option string, + timestamp time.Time, height int64, ) VoteRow { return VoteRow{ ProposalID: proposalID, Voter: voter, Option: option, + Timestamp: timestamp, Height: height, } } @@ -144,15 +147,17 @@ func (w VoteRow) Equals(v VoteRow) bool { return w.ProposalID == v.ProposalID && w.Voter == v.Voter && w.Option == v.Option && + w.Timestamp.Equal(v.Timestamp) && w.Height == v.Height } // DepositRow represents a single row inside the deposit table type DepositRow struct { - ProposalID int64 `db:"proposal_id"` - Depositor string `db:"depositor_address"` - Amount DbCoins `db:"amount"` - Height int64 `db:"height"` + ProposalID int64 `db:"proposal_id"` + Depositor string `db:"depositor_address"` + Amount DbCoins `db:"amount"` + Timestamp time.Time `db:"timestamp"` + Height int64 `db:"height"` } // NewDepositRow allows to easily create a new NewDepositRow @@ -160,12 +165,14 @@ func NewDepositRow( proposalID int64, depositor string, amount DbCoins, + timestamp time.Time, height int64, ) DepositRow { return DepositRow{ ProposalID: proposalID, Depositor: depositor, Amount: amount, + Timestamp: timestamp, Height: height, } } @@ -175,6 +182,7 @@ func (w DepositRow) Equals(v DepositRow) bool { return w.ProposalID == v.ProposalID && w.Depositor == v.Depositor && w.Amount.Equal(&v.Amount) && + w.Timestamp.Equal(v.Timestamp) && w.Height == v.Height } diff --git a/hasura/metadata/databases/bdjuno/tables/public_proposal_deposit.yaml b/hasura/metadata/databases/bdjuno/tables/public_proposal_deposit.yaml index 31fe79a39..01e208c16 100644 --- a/hasura/metadata/databases/bdjuno/tables/public_proposal_deposit.yaml +++ b/hasura/metadata/databases/bdjuno/tables/public_proposal_deposit.yaml @@ -24,6 +24,7 @@ select_permissions: - proposal_id - depositor_address - amount + - timestamp - height filter: {} limit: 100 diff --git a/hasura/metadata/databases/bdjuno/tables/public_proposal_vote.yaml b/hasura/metadata/databases/bdjuno/tables/public_proposal_vote.yaml index 115c1cb77..60f3694be 100644 --- a/hasura/metadata/databases/bdjuno/tables/public_proposal_vote.yaml +++ b/hasura/metadata/databases/bdjuno/tables/public_proposal_vote.yaml @@ -7,7 +7,13 @@ object_relationships: foreign_key_constraint_on: voter_address - name: block using: - foreign_key_constraint_on: height + manual_configuration: + column_mapping: + height: height + insertion_order: null + remote_table: + name: block + schema: public - name: proposal using: foreign_key_constraint_on: proposal_id @@ -18,6 +24,7 @@ select_permissions: - proposal_id - voter_address - option + - timestamp - height filter: {} limit: 100 diff --git a/modules/gov/handle_genesis.go b/modules/gov/handle_genesis.go index a0e74e1d7..d362db191 100644 --- a/modules/gov/handle_genesis.go +++ b/modules/gov/handle_genesis.go @@ -24,7 +24,7 @@ func (m *Module) HandleGenesis(doc *tmtypes.GenesisDoc, appState map[string]json } // Save the proposals - err = m.saveProposals(genState.Proposals, doc.InitialHeight) + err = m.saveProposals(genState.Proposals, doc) if err != nil { return fmt.Errorf("error while storing genesis governance proposals: %s", err) } @@ -44,7 +44,7 @@ func (m *Module) HandleGenesis(doc *tmtypes.GenesisDoc, appState map[string]json } // saveProposals save proposals from genesis file -func (m *Module) saveProposals(slice govtypes.Proposals, genHeight int64) error { +func (m *Module) saveProposals(slice govtypes.Proposals, genDoc *tmtypes.GenesisDoc) error { proposals := make([]types.Proposal, len(slice)) tallyResults := make([]types.TallyResult, len(slice)) deposits := make([]types.Deposit, len(slice)) @@ -70,14 +70,15 @@ func (m *Module) saveProposals(slice govtypes.Proposals, genHeight int64) error proposal.FinalTallyResult.Abstain.String(), proposal.FinalTallyResult.No.String(), proposal.FinalTallyResult.NoWithVeto.String(), - genHeight, + genDoc.InitialHeight, ) deposits[index] = types.NewDeposit( proposal.ProposalId, "", proposal.TotalDeposit, - genHeight, + genDoc.GenesisTime, + genDoc.InitialHeight, ) } diff --git a/modules/gov/handle_msg.go b/modules/gov/handle_msg.go index 1c50e17c7..ce5c72a71 100644 --- a/modules/gov/handle_msg.go +++ b/modules/gov/handle_msg.go @@ -2,6 +2,7 @@ package gov import ( "fmt" + "time" "strconv" @@ -74,8 +75,13 @@ func (m *Module) handleMsgSubmitProposal(tx *juno.Tx, index int, msg *govtypes.M return err } + txTimestamp, err := time.Parse(time.RFC3339, tx.Timestamp) + if err != nil { + return fmt.Errorf("error while parsing time: %s", err) + } + // Store the deposit - deposit := types.NewDeposit(proposal.ProposalId, msg.Proposer, msg.InitialDeposit, tx.Height) + deposit := types.NewDeposit(proposal.ProposalId, msg.Proposer, msg.InitialDeposit, txTimestamp, tx.Height) return m.db.SaveDeposits([]types.Deposit{deposit}) } @@ -86,13 +92,24 @@ func (m *Module) handleMsgDeposit(tx *juno.Tx, msg *govtypes.MsgDeposit) error { return fmt.Errorf("error while getting proposal deposit: %s", err) } + txTimestamp, err := time.Parse(time.RFC3339, tx.Timestamp) + if err != nil { + return fmt.Errorf("error while parsing time: %s", err) + } + return m.db.SaveDeposits([]types.Deposit{ - types.NewDeposit(msg.ProposalId, msg.Depositor, deposit.Amount, tx.Height), + types.NewDeposit(msg.ProposalId, msg.Depositor, deposit.Amount, txTimestamp, tx.Height), }) } // handleMsgVote allows to properly handle a handleMsgVote func (m *Module) handleMsgVote(tx *juno.Tx, msg *govtypes.MsgVote) error { - vote := types.NewVote(msg.ProposalId, msg.Voter, msg.Option, tx.Height) + txTimestamp, err := time.Parse(time.RFC3339, tx.Timestamp) + if err != nil { + return fmt.Errorf("error while parsing time: %s", err) + } + + vote := types.NewVote(msg.ProposalId, msg.Voter, msg.Option, txTimestamp, tx.Height) + return m.db.SaveVote(vote) } diff --git a/types/gov.go b/types/gov.go index 411bb477b..2ed1075b9 100644 --- a/types/gov.go +++ b/types/gov.go @@ -156,6 +156,7 @@ type Deposit struct { ProposalID uint64 Depositor string Amount sdk.Coins + Timestamp time.Time Height int64 } @@ -164,12 +165,14 @@ func NewDeposit( proposalID uint64, depositor string, amount sdk.Coins, + timestamp time.Time, height int64, ) Deposit { return Deposit{ ProposalID: proposalID, Depositor: depositor, Amount: amount, + Timestamp: timestamp, Height: height, } } @@ -181,6 +184,7 @@ type Vote struct { ProposalID uint64 Voter string Option govtypes.VoteOption + Timestamp time.Time Height int64 } @@ -189,12 +193,14 @@ func NewVote( proposalID uint64, voter string, option govtypes.VoteOption, + timestamp time.Time, height int64, ) Vote { return Vote{ ProposalID: proposalID, Voter: voter, Option: option, + Timestamp: timestamp, Height: height, } }