-
Notifications
You must be signed in to change notification settings - Fork 251
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
fix: re-add support for gov v1beta1 messages #725
Changes from all commits
3b973cd
9a14591
e2670f5
0516d23
3936cc6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,20 +2,18 @@ package gov | |
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
"github.com/cosmos/cosmos-sdk/x/authz" | ||
|
||
"github.com/forbole/callisto/v4/types" | ||
"google.golang.org/grpc/codes" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/cosmos/cosmos-sdk/x/authz" | ||
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" | ||
govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" | ||
govtypesv1beta1 "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" | ||
) | ||
|
||
|
@@ -32,37 +30,35 @@ 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) | ||
return m.handleSubmitProposalEvent(tx, cosmosMsg.Proposer, tx.Logs[index].Events) | ||
case *govtypesv1beta1.MsgSubmitProposal: | ||
return m.handleSubmitProposalEvent(tx, cosmosMsg.Proposer, tx.Logs[index].Events) | ||
|
||
case *govtypesv1.MsgDeposit: | ||
return m.handleMsgDeposit(tx, cosmosMsg) | ||
return m.handleDepositEvent(tx, cosmosMsg.Depositor, tx.Logs[index].Events) | ||
case *govtypesv1beta1.MsgDeposit: | ||
return m.handleDepositEvent(tx, cosmosMsg.Depositor, tx.Logs[index].Events) | ||
|
||
case *govtypesv1.MsgVote: | ||
return m.handleMsgVote(tx, cosmosMsg) | ||
return m.handleVoteEvent(tx, cosmosMsg.Voter, tx.Logs[index].Events) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Voter event is supported by 0.47.5, we currently better to put Voter from message to make it backward compatible. |
||
case *govtypesv1beta1.MsgVote: | ||
return m.handleVoteEvent(tx, cosmosMsg.Voter, tx.Logs[index].Events) | ||
|
||
case *govtypesv1.MsgVoteWeighted: | ||
return m.handleMsgVoteWeighted(tx, cosmosMsg) | ||
return m.handleVoteEvent(tx, cosmosMsg.Voter, tx.Logs[index].Events) | ||
case *govtypesv1beta1.MsgVoteWeighted: | ||
return m.handleVoteEvent(tx, cosmosMsg.Voter, tx.Logs[index].Events) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// handleMsgSubmitProposal allows to properly handle a MsgSubmitProposal | ||
func (m *Module) handleMsgSubmitProposal(tx *juno.Tx, index int, msg *govtypesv1.MsgSubmitProposal) error { | ||
// handleSubmitProposalEvent allows to properly handle a handleSubmitProposalEvent | ||
func (m *Module) handleSubmitProposalEvent(tx *juno.Tx, proposer string, events sdk.StringEvents) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. V1beta1 and V1 messages are sharing the same event, so we can parse event rather than push message directly so that we don't support many version messages later. |
||
// 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) | ||
proposalID, err := ProposalIDFromEvents(events) | ||
if err != nil { | ||
return fmt.Errorf("error while parsing proposal id: %s", err) | ||
return fmt.Errorf("error while getting proposal id: %s", err) | ||
} | ||
|
||
// Get the proposal | ||
|
@@ -108,39 +104,45 @@ func (m *Module) handleMsgSubmitProposal(tx *juno.Tx, index int, msg *govtypesv1 | |
return fmt.Errorf("error while storing proposal recipient: %s", err) | ||
} | ||
|
||
// Unpack the proposal interfaces | ||
err = proposal.UnpackInterfaces(m.cdc) | ||
if err != nil { | ||
return fmt.Errorf("error while unpacking proposal interfaces: %s", err) | ||
} | ||
Comment on lines
+108
to
+111
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using codec to unpack Any type messages to the underlying structure, then we can get proposal message by proposal.Messages without error. |
||
|
||
// Store the proposal | ||
proposalObj := types.NewProposal( | ||
proposal.Id, | ||
proposal.Title, | ||
proposal.Summary, | ||
proposal.Metadata, | ||
msg.Messages, | ||
proposal.Messages, | ||
proposal.Status.String(), | ||
*proposal.SubmitTime, | ||
*proposal.DepositEndTime, | ||
proposal.VotingStartTime, | ||
proposal.VotingEndTime, | ||
msg.Proposer, | ||
proposer, | ||
) | ||
|
||
err = m.db.SaveProposals([]types.Proposal{proposalObj}) | ||
if err != nil { | ||
return err | ||
return fmt.Errorf("error while saving proposal: %s", err) | ||
} | ||
|
||
txTimestamp, err := time.Parse(time.RFC3339, tx.Timestamp) | ||
// Submit proposal must have a deposit event with depositor equal to the proposer | ||
return m.handleDepositEvent(tx, proposer, events) | ||
} | ||
|
||
// handleDepositEvent allows to properly handle a handleDepositEvent | ||
func (m *Module) handleDepositEvent(tx *juno.Tx, depositor string, events sdk.StringEvents) error { | ||
// Get the proposal id | ||
proposalID, err := ProposalIDFromEvents(events) | ||
if err != nil { | ||
return fmt.Errorf("error while parsing time: %s", err) | ||
return fmt.Errorf("error while getting proposal id: %s", err) | ||
} | ||
|
||
// Store the deposit | ||
deposit := types.NewDeposit(proposal.Id, msg.Proposer, msg.InitialDeposit, txTimestamp, tx.TxHash, tx.Height) | ||
return m.db.SaveDeposits([]types.Deposit{deposit}) | ||
} | ||
|
||
// handleMsgDeposit allows to properly handle a MsgDeposit | ||
func (m *Module) handleMsgDeposit(tx *juno.Tx, msg *govtypesv1.MsgDeposit) error { | ||
deposit, err := m.source.ProposalDeposit(tx.Height, msg.ProposalId, msg.Depositor) | ||
deposit, err := m.source.ProposalDeposit(tx.Height, proposalID, depositor) | ||
if err != nil { | ||
return fmt.Errorf("error while getting proposal deposit: %s", err) | ||
} | ||
|
@@ -150,43 +152,36 @@ func (m *Module) handleMsgDeposit(tx *juno.Tx, msg *govtypesv1.MsgDeposit) error | |
} | ||
|
||
return m.db.SaveDeposits([]types.Deposit{ | ||
types.NewDeposit(msg.ProposalId, msg.Depositor, deposit.Amount, txTimestamp, tx.TxHash, tx.Height), | ||
types.NewDeposit(proposalID, depositor, deposit.Amount, txTimestamp, tx.TxHash, tx.Height), | ||
}) | ||
} | ||
|
||
// handleMsgVote allows to properly handle a MsgVote | ||
func (m *Module) handleMsgVote(tx *juno.Tx, msg *govtypesv1.MsgVote) error { | ||
// handleVoteEvent allows to properly handle a handleVoteEvent | ||
func (m *Module) handleVoteEvent(tx *juno.Tx, voter string, events sdk.StringEvents) error { | ||
// Get the proposal id | ||
proposalID, err := ProposalIDFromEvents(events) | ||
if err != nil { | ||
return fmt.Errorf("error while getting proposal id: %s", err) | ||
} | ||
|
||
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, "1.0", txTimestamp, tx.Height) | ||
|
||
err = m.db.SaveVote(vote) | ||
// Get the vote option | ||
weightVoteOption, err := WeightVoteOptionFromEvents(events) | ||
if err != nil { | ||
return fmt.Errorf("error while saving vote: %s", err) | ||
return fmt.Errorf("error while getting vote option: %s", err) | ||
} | ||
|
||
// update tally result for given proposal | ||
return m.UpdateProposalTallyResult(msg.ProposalId, tx.Height) | ||
} | ||
vote := types.NewVote(proposalID, voter, weightVoteOption.Option, weightVoteOption.Weight, txTimestamp, tx.Height) | ||
|
||
// handleMsgVoteWeighted allows to properly handle a MsgVoteWeighted | ||
func (m *Module) handleMsgVoteWeighted(tx *juno.Tx, msg *govtypesv1.MsgVoteWeighted) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It shares the same vote event as MsgVote, so it can be removed safely. |
||
txTimestamp, err := time.Parse(time.RFC3339, tx.Timestamp) | ||
err = m.db.SaveVote(vote) | ||
if err != nil { | ||
return fmt.Errorf("error while parsing time: %s", err) | ||
} | ||
|
||
for _, option := range msg.Options { | ||
vote := types.NewVote(msg.ProposalId, msg.Voter, option.Option, option.Weight, txTimestamp, tx.Height) | ||
err = m.db.SaveVote(vote) | ||
if err != nil { | ||
return fmt.Errorf("error while saving weighted vote for address %s: %s", msg.Voter, err) | ||
} | ||
return fmt.Errorf("error while saving vote: %s", err) | ||
} | ||
|
||
// update tally result for given proposal | ||
return m.UpdateProposalTallyResult(msg.ProposalId, tx.Height) | ||
return m.UpdateProposalTallyResult(proposalID, tx.Height) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package gov | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" | ||
govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" | ||
eventsutil "github.com/forbole/callisto/v4/utils/events" | ||
) | ||
|
||
// ProposalIDFromEvent returns the proposal id from the given events | ||
func ProposalIDFromEvents(events sdk.StringEvents) (uint64, error) { | ||
for _, event := range events { | ||
attribute, ok := eventsutil.FindAttributeByKey(event, govtypes.AttributeKeyProposalID) | ||
if ok { | ||
return strconv.ParseUint(attribute.Value, 10, 64) | ||
} | ||
} | ||
|
||
return 0, fmt.Errorf("no proposal id found") | ||
} | ||
|
||
// WeightVoteOptionFromEvents returns the vote option from the given events | ||
func WeightVoteOptionFromEvents(events sdk.StringEvents) (govtypesv1.WeightedVoteOption, error) { | ||
for _, event := range events { | ||
attribute, ok := eventsutil.FindAttributeByKey(event, govtypes.AttributeKeyOption) | ||
if ok { | ||
return parseWeightVoteOption(attribute.Value) | ||
} | ||
} | ||
|
||
return govtypesv1.WeightedVoteOption{}, fmt.Errorf("no vote option found") | ||
} | ||
|
||
// parseWeightVoteOption returns the vote option from the given string | ||
// option value in string has 2 cases, for example: | ||
// 1. "{\"option\":1,\"weight\":\"1.000000000000000000\"}" | ||
// 2. "option:VOTE_OPTION_NO weight:\"1.000000000000000000\"" | ||
Comment on lines
+41
to
+42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. VoteOption inside event is represented in these two type format, v1 and v1beta1 currently. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am still trying to understand cosmos SDK. We are not able to use provided methods like: func (m *Vote) GetOptions() []*WeightedVoteOption {
if m != nil {
return m.Options
}
return nil
} |
||
func parseWeightVoteOption(optionValue string) (govtypesv1.WeightedVoteOption, error) { | ||
// try parse json option value | ||
var weightedVoteOption govtypesv1.WeightedVoteOption | ||
err := json.Unmarshal([]byte(optionValue), &weightedVoteOption) | ||
if err == nil { | ||
return weightedVoteOption, nil | ||
} | ||
|
||
// try parse string option value | ||
// option:VOTE_OPTION_NO weight:"1.000000000000000000" | ||
voteOptionParsed := strings.Split(optionValue, " ") | ||
if len(voteOptionParsed) != 2 { | ||
return govtypesv1.WeightedVoteOption{}, fmt.Errorf("failed to parse vote option %s", optionValue) | ||
} | ||
|
||
voteOption, err := govtypesv1.VoteOptionFromString(strings.ReplaceAll(voteOptionParsed[0], "option:", "")) | ||
if err != nil { | ||
return govtypesv1.WeightedVoteOption{}, fmt.Errorf("failed to parse vote option %s: %s", optionValue, err) | ||
} | ||
weight := strings.ReplaceAll(voteOptionParsed[1], "weight:", "") | ||
weight = strings.ReplaceAll(weight, "\"", "") | ||
|
||
return govtypesv1.WeightedVoteOption{Option: voteOption, Weight: weight}, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We still need put proposer from message since Cosmos-SDK does not support
proposer
attribute insidesubmit_proposal
event, it maybe better we post a request to Cosmos-SDK team or just remove this field in the feature. From my side, I would remove it as I would see depositors more than proposer, in addition, proposer must be one of depositors.