diff --git a/cmd/parse/gov/proposal.go b/cmd/parse/gov/proposal.go index 045da2ffa..fcbf67c3b 100644 --- a/cmd/parse/gov/proposal.go +++ b/cmd/parse/gov/proposal.go @@ -11,6 +11,7 @@ import ( modulestypes "github.com/forbole/bdjuno/v4/modules/types" govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + legacyTypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" parsecmdtypes "github.com/forbole/juno/v5/cmd/parse/types" "github.com/forbole/juno/v5/parser" "github.com/forbole/juno/v5/types/config" @@ -113,14 +114,15 @@ func refreshProposalDetails(parseCtx *parser.Context, proposalID uint64, govModu // Handle the MsgSubmitProposal messages for index, msg := range tx.GetMsgs() { - if _, ok := msg.(*govtypesv1.MsgSubmitProposal); !ok { + switch msg.(type) { + case *govtypesv1.MsgSubmitProposal, *legacyTypes.MsgSubmitProposal: + err = govModule.HandleMsg(index, msg, tx) + if err != nil { + return fmt.Errorf("error while handling MsgSubmitProposal: %s", err) + } + default: continue } - - err = govModule.HandleMsg(index, msg, tx) - if err != nil { - return fmt.Errorf("error while handling MsgSubmitProposal: %s", err) - } } return nil @@ -144,14 +146,15 @@ func refreshProposalDeposits(parseCtx *parser.Context, proposalID uint64, govMod // Handle the MsgDeposit messages for index, msg := range junoTx.GetMsgs() { - if _, ok := msg.(*govtypesv1.MsgDeposit); !ok { + switch msg.(type) { + case *govtypesv1.MsgDeposit, *legacyTypes.MsgDeposit: + err = govModule.HandleMsg(index, msg, junoTx) + if err != nil { + return fmt.Errorf("error while handling MsgDeposit: %s", err) + } + default: continue } - - err = govModule.HandleMsg(index, msg, junoTx) - if err != nil { - return fmt.Errorf("error while handling MsgDeposit: %s", err) - } } } @@ -176,14 +179,15 @@ func refreshProposalVotes(parseCtx *parser.Context, proposalID uint64, govModule // Handle the MsgVote messages for index, msg := range junoTx.GetMsgs() { - if _, ok := msg.(*govtypesv1.MsgVote); !ok { + switch msg.(type) { + case *govtypesv1.MsgVote, *legacyTypes.MsgVote: + err = govModule.HandleMsg(index, msg, junoTx) + if err != nil { + return fmt.Errorf("error while handling MsgVote: %s", err) + } + default: continue } - - err = govModule.HandleMsg(index, msg, junoTx) - if err != nil { - return fmt.Errorf("error while handling MsgVote: %s", err) - } } } diff --git a/database/gov.go b/database/gov.go index 136fc9bcb..ffcefc3cc 100644 --- a/database/gov.go +++ b/database/gov.go @@ -278,6 +278,30 @@ WHERE proposal_vote.height <= excluded.height` return nil } +func (db *Db) SaveLegacyVote(vote types.LegacyVote) error { + query := ` +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` + + // Store the voter account + err := db.SaveAccounts([]types.Account{types.NewAccount(vote.Voter)}) + if err != nil { + return fmt.Errorf("error while storing voter account: %s", err) + } + + _, 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) + } + + return nil +} + func (db *Db) SaveWeightedVote(weightedVote types.WeightedVote) error { query := ` INSERT INTO proposal_vote_weighted (proposal_id, voter_address, option, weight, height) diff --git a/modules/gov/handle_msg.go b/modules/gov/handle_msg.go index 12d4341d4..9e59e8169 100644 --- a/modules/gov/handle_msg.go +++ b/modules/gov/handle_msg.go @@ -9,6 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + legacyTypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" gov "github.com/cosmos/cosmos-sdk/x/gov/types" juno "github.com/forbole/juno/v5/types" @@ -21,23 +22,25 @@ func (m *Module) HandleMsg(index int, msg sdk.Msg, tx *juno.Tx) error { } switch cosmosMsg := msg.(type) { - case *govtypesv1.MsgSubmitProposal: - return m.handleMsgSubmitProposal(tx, index, cosmosMsg) + case *govtypesv1.MsgSubmitProposal, *legacyTypes.MsgSubmitProposal: + return m.handleMsgSubmitProposalWithLegacySupport(tx, index, cosmosMsg) - case *govtypesv1.MsgDeposit: - return m.handleMsgDeposit(tx, cosmosMsg) + case *govtypesv1.MsgDeposit, *legacyTypes.MsgDeposit: + return m.handleMsgDepositWithLegacySupport(tx, cosmosMsg) - case *govtypesv1.MsgVote: - return m.handleMsgVote(tx, cosmosMsg) + case *govtypesv1.MsgVote, *legacyTypes.MsgVote: + return m.handleMsgVoteWithLegacySupport(tx, cosmosMsg) - case *govtypesv1.MsgVoteWeighted: - return m.handleMsgVoteWeighted(tx, cosmosMsg) + case *govtypesv1.MsgVoteWeighted, *legacyTypes.MsgVoteWeighted: + return m.handleMsgVoteWeightedWithLegacySupport(tx, cosmosMsg) } return nil } // handleMsgSubmitProposal allows to properly handle a handleMsgSubmitProposal +// +//lint:ignore U1000 we might need the original implementation later func (m *Module) handleMsgSubmitProposal(tx *juno.Tx, index int, msg *govtypesv1.MsgSubmitProposal) error { // Get the proposal id event, err := tx.FindEventByType(index, gov.EventTypeSubmitProposal) @@ -92,6 +95,8 @@ func (m *Module) handleMsgSubmitProposal(tx *juno.Tx, index int, msg *govtypesv1 } // handleMsgDeposit allows to properly handle a handleMsgDeposit +// +//lint:ignore U1000 we might need the original implementation later func (m *Module) handleMsgDeposit(tx *juno.Tx, msg *govtypesv1.MsgDeposit) error { deposit, err := m.source.ProposalDeposit(tx.Height, msg.ProposalId, msg.Depositor) if err != nil { @@ -108,6 +113,8 @@ func (m *Module) handleMsgDeposit(tx *juno.Tx, msg *govtypesv1.MsgDeposit) error } // handleMsgVote allows to properly handle a handleMsgVote +// +//lint:ignore U1000 we might need the original implementation later func (m *Module) handleMsgVote(tx *juno.Tx, msg *govtypesv1.MsgVote) error { txTimestamp, err := time.Parse(time.RFC3339, tx.Timestamp) if err != nil { @@ -119,7 +126,160 @@ func (m *Module) handleMsgVote(tx *juno.Tx, msg *govtypesv1.MsgVote) error { return m.db.SaveVote(vote) } +//lint:ignore U1000 we might need the original implementation later func (m *Module) handleMsgVoteWeighted(tx *juno.Tx, msg *govtypesv1.MsgVoteWeighted) error { weightedVote := types.NewWeightedVote(msg.ProposalId, msg.Voter, msg.Options, tx.Height) return m.db.SaveWeightedVote(weightedVote) } + +// handleMsgSubmitProposal allows to properly handle a handleMsgSubmitProposal +func (m *Module) handleMsgSubmitProposalWithLegacySupport(tx *juno.Tx, index int, msg interface{}) error { + // Get the proposal id + event, err := tx.FindEventByType(index, gov.EventTypeSubmitProposal) + if err != nil { + return fmt.Errorf("error while searching for EventTypeSubmitProposal: %s", err) + } + + id, err := tx.FindAttributeByKey(event, gov.AttributeKeyProposalID) + if err != nil { + return fmt.Errorf("error while searching for AttributeKeyProposalID: %s", err) + } + + proposalID, err := strconv.ParseUint(id, 10, 64) + if err != nil { + return fmt.Errorf("error while parsing proposal id: %s", err) + } + + // Get the proposal + proposal, err := m.source.Proposal(tx.Height, proposalID) + if err != nil { + return fmt.Errorf("error while getting proposal: %s", err) + } + + // Prepare the proposalObj + var proposalObj types.Proposal + switch msg.(type) { + case *govtypesv1.MsgSubmitProposal, *legacyTypes.MsgSubmitProposal: + proposalObj = types.NewProposal( + proposal.Id, + proposal.Title, + proposal.Summary, + proposal.Metadata, + proposal.Messages, + proposal.Status.String(), + *proposal.SubmitTime, + *proposal.DepositEndTime, + proposal.VotingStartTime, + proposal.VotingEndTime, + proposal.Proposer, + ) + default: + return fmt.Errorf("unexpected type %T", msg) + } + + // Get the initialDeposit + var initialDeposit []sdk.Coin + switch msgType := msg.(type) { + case *govtypesv1.MsgSubmitProposal: + initialDeposit = msgType.InitialDeposit + case *legacyTypes.MsgSubmitProposal: + initialDeposit = msgType.InitialDeposit + } + + err = m.db.SaveProposals([]types.Proposal{proposalObj}) + if err != nil { + 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.Id, proposal.Proposer, initialDeposit, txTimestamp, tx.Height) + return m.db.SaveDeposits([]types.Deposit{deposit}) +} + +func (m *Module) handleMsgDepositWithLegacySupport(tx *juno.Tx, msg interface{}) error { + + var proposalID uint64 + var depositor string + switch msgType := msg.(type) { + case *govtypesv1.MsgDeposit: + proposalID = msgType.ProposalId + depositor = msgType.Depositor + case *legacyTypes.MsgDeposit: + proposalID = msgType.ProposalId + depositor = msgType.Depositor + } + + deposit, err := m.source.ProposalDeposit(tx.Height, proposalID, depositor) + if err != nil { + 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(proposalID, depositor, deposit.Amount, txTimestamp, tx.Height), + }) +} + +func (m *Module) handleMsgVoteWithLegacySupport(tx *juno.Tx, msg interface{}) error { + txTimestamp, err := time.Parse(time.RFC3339, tx.Timestamp) + if err != nil { + return fmt.Errorf("error while parsing time: %s", err) + } + + switch msgType := msg.(type) { + case *govtypesv1.MsgVote: + return m.db.SaveVote( + types.NewVote( + msgType.ProposalId, + msgType.Voter, + msgType.Option, + txTimestamp, + tx.Height, + ), + ) + case *legacyTypes.MsgVote: + return m.db.SaveLegacyVote( + types.NewLegacyVote( + msgType.ProposalId, + msgType.Voter, + msgType.Option, + txTimestamp, + tx.Height, + ), + ) + } + + return fmt.Errorf("error while saving vote") +} + +func (m *Module) handleMsgVoteWeightedWithLegacySupport(tx *juno.Tx, msg interface{}) error { + var weightedVote types.WeightedVote + switch msgType := msg.(type) { + case *govtypesv1.MsgVoteWeighted: + weightedVote = types.NewWeightedVote( + msgType.ProposalId, + msgType.Voter, + msgType.Options, + tx.Height, + ) + case *legacyTypes.MsgVoteWeighted: + weightedVote = types.NewLegacyWeightedVote( + msgType.ProposalId, + msgType.Voter, + msgType.Options, + tx.Height, + ) + default: + return fmt.Errorf("error while saving weighted vote") + } + + return m.db.SaveWeightedVote(weightedVote) +} diff --git a/types/gov.go b/types/gov.go index 375addc79..f4b2cb5da 100644 --- a/types/gov.go +++ b/types/gov.go @@ -7,6 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + legacyTypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" ) const ( @@ -129,6 +130,14 @@ type Vote struct { Height int64 } +type LegacyVote struct { + ProposalID uint64 + Voter string + Option legacyTypes.VoteOption + Timestamp time.Time + Height int64 +} + // NewVote return a new Vote instance func NewVote( proposalID uint64, @@ -146,6 +155,22 @@ func NewVote( } } +func NewLegacyVote( + proposalID uint64, + voter string, + option legacyTypes.VoteOption, + timestamp time.Time, + height int64, +) LegacyVote { + return LegacyVote{ + ProposalID: proposalID, + Voter: voter, + Option: option, + Timestamp: timestamp, + Height: height, + } +} + type WeightedVoteOption struct { Option string Weight string @@ -178,6 +203,26 @@ func NewWeightedVote( return weightedvote } +func NewLegacyWeightedVote( + proposalID uint64, + voter string, + options []legacyTypes.WeightedVoteOption, + height int64, +) WeightedVote { + weightedvote := WeightedVote{ + ProposalID: proposalID, + Voter: voter, + Height: height, + } + for _, opt := range options { + weightedvote.Options = append(weightedvote.Options, WeightedVoteOption{ + Option: govtypesv1.VoteOption_name[int32(opt.Option)], + Weight: opt.Weight.String(), + }) + } + return weightedvote +} + // ------------------------------------------------------------------------------------------------------------------- // TallyResult contains the data about the final results of a proposal