-
Notifications
You must be signed in to change notification settings - Fork 247
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 3 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) | ||
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. We still need put proposer from message since Cosmos-SDK does not support |
||
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 option value as json | ||
var weightedVoteOption govtypesv1.WeightedVoteOption | ||
err := json.Unmarshal([]byte(optionValue), &weightedVoteOption) | ||
if err == nil { | ||
return weightedVoteOption, nil | ||
} | ||
|
||
// try parse option value as string | ||
// 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 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package events | ||
|
||
import ( | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
) | ||
|
||
// FindEventByType returns the event with the given type | ||
func FindEventByType(events sdk.StringEvents, eventType string) (sdk.StringEvent, bool) { | ||
for _, event := range events { | ||
if event.Type == eventType { | ||
return event, true | ||
} | ||
} | ||
return sdk.StringEvent{}, false | ||
} | ||
|
||
// FindAttributeByKey returns the attribute with the given key | ||
func FindAttributeByKey(event sdk.StringEvent, key string) (sdk.Attribute, bool) { | ||
for _, attribute := range event.Attributes { | ||
if attribute.Key == key { | ||
return attribute, true | ||
} | ||
} | ||
return sdk.Attribute{}, false | ||
} |
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.
What about
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.
Great, it is cleaner, thanks! 3936cc6