Skip to content

Commit

Permalink
Custom message Handle
Browse files Browse the repository at this point in the history
  • Loading branch information
devcantuaria committed May 17, 2024
1 parent 2a92873 commit 352eb46
Show file tree
Hide file tree
Showing 4 changed files with 435 additions and 0 deletions.
322 changes: 322 additions & 0 deletions modules/messages/account_parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,322 @@
package messages

import (
"fmt"
"strings"

"github.com/gogo/protobuf/proto"

crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types"
evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types"
channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
authztypes "github.com/cosmos/cosmos-sdk/x/authz"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)

// MessageNotSupported returns an error telling that the given message is not supported
func MessageNotSupported(msg sdk.Msg) error {
return fmt.Errorf("message type not supported: %s", proto.MessageName(msg))
}

// MessageAddressesParser represents a function that extracts all the
// involved addresses from a provided message (both accounts and validators)
type MessageAddressesParser = func(cdc codec.Codec, msg sdk.Msg) ([]string, error)

// JoinMessageParsers joins together all the given parsers, calling them in order
func JoinMessageParsers(parsers ...MessageAddressesParser) MessageAddressesParser {
return func(cdc codec.Codec, msg sdk.Msg) ([]string, error) {
for _, parser := range parsers {
// Try getting the addresses
addresses, _ := parser(cdc, msg)

// If some addresses are found, return them
if len(addresses) > 0 {
return addresses, nil
}
}
return nil, MessageNotSupported(msg)
}
}

// CosmosMessageAddressesParser represents a MessageAddressesParser that parses a
// Chain message and returns all the involved addresses (both accounts and validators)
var CosmosMessageAddressesParser = JoinMessageParsers(
BankMessagesParser,
CrisisMessagesParser,
DistributionMessagesParser,
EvidenceMessagesParser,
GovMessagesParser,
IBCTransferMessagesParser,
SlashingMessagesParser,
StakingMessagesParser,
AuthzMessageParser,
DefaultMessagesParser,
)

// DefaultMessagesParser represents the default messages parser that simply returns the list
// of all the signers of a message
func DefaultMessagesParser(_ codec.Codec, cosmosMsg sdk.Msg) ([]string, error) {
var signers = make([]string, len(cosmosMsg.GetSigners()))
for index, signer := range cosmosMsg.GetSigners() {
signers[index] = signer.String()
}
return signers, nil
}

// BankMessagesParser returns the list of all the accounts involved in the given
// message if it's related to the x/bank module
func BankMessagesParser(_ codec.Codec, cosmosMsg sdk.Msg) ([]string, error) {
switch msg := cosmosMsg.(type) {
case *banktypes.MsgSend:
return []string{msg.ToAddress, msg.FromAddress}, nil

case *banktypes.MsgMultiSend:
var addresses []string
for _, i := range msg.Inputs {
addresses = append(addresses, i.Address)
}
for _, o := range msg.Outputs {
addresses = append(addresses, o.Address)
}
return addresses, nil
}

return nil, MessageNotSupported(cosmosMsg)
}

// CrisisMessagesParser returns the list of all the accounts involved in the given
// message if it's related to the x/crisis module
func CrisisMessagesParser(_ codec.Codec, cosmosMsg sdk.Msg) ([]string, error) {
switch msg := cosmosMsg.(type) {

case *crisistypes.MsgVerifyInvariant:
return []string{msg.Sender}, nil

}

return nil, MessageNotSupported(cosmosMsg)
}

// DistributionMessagesParser returns the list of all the accounts involved in the given
// message if it's related to the x/distribution module
func DistributionMessagesParser(_ codec.Codec, cosmosMsg sdk.Msg) ([]string, error) {
switch msg := cosmosMsg.(type) {

case *distrtypes.MsgSetWithdrawAddress:
return []string{msg.DelegatorAddress, msg.WithdrawAddress}, nil

case *distrtypes.MsgWithdrawDelegatorReward:
return []string{msg.DelegatorAddress, msg.ValidatorAddress}, nil

case *distrtypes.MsgWithdrawValidatorCommission:
return []string{msg.ValidatorAddress}, nil

case *distrtypes.MsgFundCommunityPool:
return []string{msg.Depositor}, nil

}

return nil, MessageNotSupported(cosmosMsg)
}

// EvidenceMessagesParser returns the list of all the accounts involved in the given
// message if it's related to the x/evidence module
func EvidenceMessagesParser(_ codec.Codec, cosmosMsg sdk.Msg) ([]string, error) {
switch msg := cosmosMsg.(type) {

case *evidencetypes.MsgSubmitEvidence:
return []string{msg.Submitter}, nil

}

return nil, MessageNotSupported(cosmosMsg)
}

// GovMessagesParser returns the list of all the accounts involved in the given
// message if it's related to the x/gov module
func GovMessagesParser(cdc codec.Codec, cosmosMsg sdk.Msg) ([]string, error) {
switch msg := cosmosMsg.(type) {

case *govtypes.MsgSubmitProposal:
addresses := []string{msg.Proposer}

var content govtypes.Content
err := cdc.UnpackAny(msg.Content, &content)
if err != nil {
return nil, err
}

// Get addresses from contents
switch content := content.(type) {
//nolint:staticcheck // Let's keep this for the time being
case *distrtypes.CommunityPoolSpendProposal:
addresses = append(addresses, content.Recipient)
}

return addresses, nil

case *govtypes.MsgDeposit:
return []string{msg.Depositor}, nil

case *govtypes.MsgVote:
return []string{msg.Voter}, nil

}

return nil, MessageNotSupported(cosmosMsg)
}

// IBCTransferMessagesParser returns the list of all the accounts involved in the given
// message if it's related to the x/iBCTransfer module
func IBCTransferMessagesParser(_ codec.Codec, cosmosMsg sdk.Msg) ([]string, error) {
switch msg := cosmosMsg.(type) {

case *ibctransfertypes.MsgTransfer:
return []string{msg.Sender, msg.Receiver}, nil

case *channeltypes.MsgRecvPacket:
var data ibctransfertypes.FungibleTokenPacketData
if err := ibctransfertypes.ModuleCdc.UnmarshalJSON(msg.Packet.Data, &data); err != nil {
// The packet data is not a FungibleTokenPacketData, so nothing to update
return nil, nil
}

// We are receiving some IBC tokens, so we need to update the receiver balance
// as well as the message signer (the relayer)
return []string{data.Receiver, msg.Signer}, nil
}

return nil, MessageNotSupported(cosmosMsg)
}

// SlashingMessagesParser returns the list of all the accounts involved in the given
// message if it's related to the x/slashing module
func SlashingMessagesParser(_ codec.Codec, cosmosMsg sdk.Msg) ([]string, error) {
switch msg := cosmosMsg.(type) {

case *slashingtypes.MsgUnjail:
return []string{msg.ValidatorAddr}, nil

}

return nil, MessageNotSupported(cosmosMsg)
}

// StakingMessagesParser returns the list of all the accounts involved in the given
// message if it's related to the x/staking module
func StakingMessagesParser(_ codec.Codec, cosmosMsg sdk.Msg) ([]string, error) {
switch msg := cosmosMsg.(type) {

case *stakingtypes.MsgCreateValidator:
return []string{msg.ValidatorAddress, msg.DelegatorAddress}, nil

case *stakingtypes.MsgEditValidator:
return []string{msg.ValidatorAddress}, nil

case *stakingtypes.MsgDelegate:
return []string{msg.DelegatorAddress, msg.ValidatorAddress}, nil

case *stakingtypes.MsgBeginRedelegate:
return []string{msg.DelegatorAddress, msg.ValidatorSrcAddress, msg.ValidatorDstAddress}, nil

case *stakingtypes.MsgUndelegate:
return []string{msg.DelegatorAddress, msg.ValidatorAddress}, nil

}

return nil, MessageNotSupported(cosmosMsg)
}

// AuthzMessageParser returns the list of all the accounts involved in the given
// message if it's related to the x/authz module
func AuthzMessageParser(c codec.Codec, cosmosMsg sdk.Msg) ([]string, error) {
switch msg := cosmosMsg.(type) {
case *authztypes.MsgGrant:
return []string{msg.Grantee, msg.Granter}, nil
case *authztypes.MsgRevoke:
return []string{msg.Grantee, msg.Granter}, nil
case *authztypes.MsgExec:
for _, index := range msg.Msgs {
var executedMsg sdk.Msg
if err := c.UnpackAny(index, &executedMsg); err != nil {
return nil, fmt.Errorf("error while unpacking message from authz: %s", err)
}

switch {
case strings.Contains(index.TypeUrl, "bank"):
addresses, err := BankMessagesParser(c, executedMsg)
if err != nil {
return nil, MessageNotSupported(executedMsg)
}
addresses = append(addresses, msg.Grantee)
return addresses, nil
case strings.Contains(index.TypeUrl, "crisis"):
addresses, err := CrisisMessagesParser(c, executedMsg)
if err != nil {
return nil, MessageNotSupported(executedMsg)
}
addresses = append(addresses, msg.Grantee)
return addresses, nil
case strings.Contains(index.TypeUrl, "distribution"):
addresses, err := DistributionMessagesParser(c, executedMsg)
if err != nil {
return nil, MessageNotSupported(executedMsg)
}
addresses = append(addresses, msg.Grantee)
return addresses, nil
case strings.Contains(index.TypeUrl, "evidence"):
addresses, err := EvidenceMessagesParser(c, executedMsg)
if err != nil {
return nil, MessageNotSupported(executedMsg)
}
addresses = append(addresses, msg.Grantee)
return addresses, nil
case strings.Contains(index.TypeUrl, "gov"):
addresses, err := GovMessagesParser(c, executedMsg)
if err != nil {
return nil, MessageNotSupported(executedMsg)
}
addresses = append(addresses, msg.Grantee)
return addresses, nil
case strings.Contains(index.TypeUrl, "ibc"):
addresses, err := IBCTransferMessagesParser(c, executedMsg)
if err != nil {
return nil, MessageNotSupported(executedMsg)
}
addresses = append(addresses, msg.Grantee)
return addresses, nil
case strings.Contains(index.TypeUrl, "slashing"):
addresses, err := SlashingMessagesParser(c, executedMsg)
if err != nil {
return nil, MessageNotSupported(executedMsg)
}
addresses = append(addresses, msg.Grantee)
return addresses, nil
case strings.Contains(index.TypeUrl, "staking"):
addresses, err := StakingMessagesParser(c, executedMsg)
if err != nil {
return nil, MessageNotSupported(executedMsg)
}
addresses = append(addresses, msg.Grantee)
return addresses, nil
default:
addresses, err := DefaultMessagesParser(c, executedMsg)
if err != nil {
return nil, MessageNotSupported(executedMsg)
}
addresses = append(addresses, msg.Grantee)
return addresses, nil
}
}
}

return nil, MessageNotSupported(cosmosMsg)
}
64 changes: 64 additions & 0 deletions modules/messages/message_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package messages

import (
"fmt"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"
"github.com/gogo/protobuf/proto"

"github.com/forbole/bdjuno/v4/database"
"github.com/forbole/bdjuno/v4/modules/utils"
msgtypes "github.com/forbole/bdjuno/v4/types"
"github.com/forbole/juno/v5/types"
)

// HandleMsg represents a message handler that stores the given message inside the proper database table
func HandleMsg(
index int, msg sdk.Msg, tx *types.Tx,
parseAddresses MessageAddressesParser, cdc codec.Codec, db *database.Db,
) error {

// Get the involved addresses
addresses, err := parseAddresses(cdc, msg)
if err != nil {
return err
}

// Marshal the value properly
bz, err := cdc.MarshalJSON(msg)
if err != nil {
return err
}

// Save message type
db.SaveMessageType(msgtypes.NewMessageType(
proto.MessageName(msg),
utils.GetModuleNameFromTypeURL(proto.MessageName(msg)),
utils.GetMsgFromTypeURL(proto.MessageName(msg)),
tx.Height))

// Handle MsgRecvPacket data object
if msgIBC, ok := msg.(*channeltypes.MsgRecvPacket); ok {
trimMessageString := TrimLastChar(string(bz))
trimDataString := string(msgIBC.Packet.Data)[1:]
return db.SaveMessage(types.NewMessage(
tx.TxHash,
index,
proto.MessageName(msg),
fmt.Sprintf("%s,%s", trimMessageString, trimDataString),
addresses,
tx.Height,
))
}

return db.SaveMessage(types.NewMessage(
tx.TxHash,
index,
proto.MessageName(msg),
string(bz),
addresses,
tx.Height,
))
}
Loading

0 comments on commit 352eb46

Please sign in to comment.