Skip to content
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

feature/ implement substrate event parser #923

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.18

require (
github.com/99designs/keyring v1.2.1
github.com/ComposableFi/go-substrate-rpc-client/v4 v4.0.1-0.20220820010439-71c9d526f2f5
github.com/ComposableFi/go-substrate-rpc-client/v4 v4.0.1-0.20220819133021-62ed9987ea7c
github.com/avast/retry-go/v4 v4.1.0
github.com/cosmos/cosmos-sdk v0.46.0
github.com/cosmos/go-bip39 v1.0.0
Expand Down Expand Up @@ -39,7 +39,7 @@ require (
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/ChainSafe/go-schnorrkel v1.0.0 // indirect
github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect
github.com/ComposableFi/go-subkey/v2 v2.0.0-tm03420 // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
Expand Down Expand Up @@ -68,6 +68,7 @@ require (
github.com/cosmos/ledger-go v0.9.2 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/base58 v1.0.4 // indirect
github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
Expand All @@ -88,6 +89,7 @@ require (
github.com/go-kit/kit v0.12.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gogo/gateway v1.1.0 // indirect
github.com/golang/glog v1.0.0 // indirect
Expand Down Expand Up @@ -140,6 +142,7 @@ require (
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.2 // indirect
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
github.com/pierrec/xxHash v0.1.5 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.34.0 // indirect
Expand Down Expand Up @@ -181,11 +184,10 @@ require (
google.golang.org/grpc v1.48.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/ini.v1 v1.66.6 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
nhooyr.io/websocket v1.8.6 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1

replace github.com/ChainSafe/go-schnorrkel v1.0.0 => github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d
8 changes: 6 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQ
github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4=
github.com/ComposableFi/go-subkey/v2 v2.0.0-tm03420 h1:oknQF/iIhf5lVjbwjsVDzDByupRhga8nhA3NAmwyHDA=
github.com/ComposableFi/go-subkey/v2 v2.0.0-tm03420/go.mod h1:KYkiMX5AbOlXXYfxkrYPrRPV6EbVUALTQh5ptUOJzu8=
github.com/ComposableFi/go-substrate-rpc-client/v4 v4.0.1-0.20220820010439-71c9d526f2f5 h1:OXSENjIo4rEYYn8GapFPEc3dpP8SMayxyHSOwOiXHg4=
github.com/ComposableFi/go-substrate-rpc-client/v4 v4.0.1-0.20220820010439-71c9d526f2f5/go.mod h1:swRgltPLuxQuM1AnrlRRXkbtkcHN0BjlMvGC0iEkNjk=
github.com/ComposableFi/go-substrate-rpc-client/v4 v4.0.1-0.20220819133021-62ed9987ea7c h1:m8C9WQpI5BMaB3nGFIFBFyAwzktCeacVl+FH3dbfCyQ=
github.com/ComposableFi/go-substrate-rpc-client/v4 v4.0.1-0.20220819133021-62ed9987ea7c/go.mod h1:swRgltPLuxQuM1AnrlRRXkbtkcHN0BjlMvGC0iEkNjk=
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
Expand Down Expand Up @@ -343,6 +343,7 @@ github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4=
github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
github.com/decred/base58 v1.0.4 h1:QJC6B0E0rXOPA8U/kw2rP+qiRJsUaE2Er+pYb3siUeA=
github.com/decred/base58 v1.0.4/go.mod h1:jJswKPEdvpFpvf7dsDvFZyLT22xZ9lWqEByX38oGd9E=
Expand Down Expand Up @@ -500,6 +501,7 @@ github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfC
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ=
Expand Down Expand Up @@ -1140,6 +1142,7 @@ github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/xxHash v0.1.5 h1:n/jBpwTHiER4xYvK3/CdPVnLDPchj8eTJFFLUb4QHBo=
github.com/pierrec/xxHash v0.1.5/go.mod h1:w2waW5Zoa/Wc4Yqe0wgrIYAGKqRMf7czn2HNKXmuL+I=
github.com/pierrre/gotestcover v0.0.0-20160517101806-924dca7d15f0/go.mod h1:4xpMLz7RBWyB+ElzHu8Llua96TRCB3YwX+l5EP1wmHk=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
Expand Down Expand Up @@ -2197,6 +2200,7 @@ gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
Expand Down
221 changes: 221 additions & 0 deletions relayer/chains/substrate/event_parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
package substrate

import (
"encoding/json"
"strconv"

rpcclienttypes "github.com/ComposableFi/go-substrate-rpc-client/v4/types"
clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types"
"github.com/cosmos/relayer/v2/relayer/processor"
"github.com/cosmos/relayer/v2/relayer/provider"
"go.uber.org/zap/zapcore"
)

// ibcMessage is the type used for parsing all possible properties of IBC messages
type ibcMessage struct {
eventType string
info ibcMessageInfo
}

type ibcMessageInfo interface {
MarshalLogObject(enc zapcore.ObjectEncoder) error
}

// ibcMessagesFromTransaction parses all events within a transaction to find IBC messages
func (scp *SubstrateChainProcessor) handleIBCMessagesFromEvents(ibcEvents rpcclienttypes.IBCEventsQueryResult, height uint64, c processor.IBCMessagesCache) error {
for i := 0; i < len(ibcEvents); i++ {
for eType, data := range ibcEvents[i] {
var info ibcMessageInfo
var eventType string

marshalled, _ := json.Marshal(data)

switch eType {

case "CreateClient", "UpgradeClient", "ClientMisbehaviour":
ce := clientInfo{}
json.Unmarshal(marshalled, &ce)
info = &ce
eventType = eType

case "UpdateClient":
ce := clientUpdateInfo{}
json.Unmarshal(marshalled, &ce)
info = &ce
eventType = eType
jackzampolin marked this conversation as resolved.
Show resolved Hide resolved

case "OpenInitConnection", "OpenTryConnection", "OpenAckConnection", "OpenConfirmConnection":
ce := connectionEvent{}
json.Unmarshal(marshalled, &ce)
info = &connectionInfo{
Height: height,
ConnID: ce.connectionID,
ClientID: ce.clientID,
CounterpartyConnID: ce.counterpartyConnectionID,
CounterpartyClientID: ce.counterpartyClientID,
}
eventType = eType

case "OpenInitChannel", "OpenTryChannel", "OpenAckChannel", "OpenConfirmChannel", "CloseInitChannel", "CloseConfirmChannel":
ce := channelEvent{}
json.Unmarshal(marshalled, &ce)
info = &channelInfo{
Height: height,
PortID: ce.portID,
ChannelID: strconv.FormatUint(ce.channelID, 10),
CounterpartyPortID: strconv.FormatUint(ce.counterpartyPortID, 10),
CounterpartyChannelID: ce.counterpartyChannelID,
ConnID: ce.connectionID,
CounterpartyConnID: ce.counterpartyChannelID,
// TODO: how to populate order
// Order: ,
// TODO: how to populate version
// Version: ,
}
eventType = eType

case "SendPacket", "ReceivePacket", "WriteAcknowledgement", "AcknowledgePacket", "TimeoutPacket", "TimeoutOnClosePacket":
ce := packetEvent{}
json.Unmarshal(marshalled, &ce)
info = &packetInfo{
Height: height,
Sequence: ce.sequence,
SourcePort: ce.sourcePort,
SourceChannel: strconv.FormatUint(ce.sourceCannel, 10),
DestPort: ce.destinationPort,
DestChannel: strconv.FormatUint(ce.destinationChannel, 10),
// TODO: how to populate channel order
// ChannelOrder: ,
Data: ce.data,
TimeoutHeight: ce.timeoutHeight,
TimeoutTimestamp: ce.timeoutTimestamp,
// TODO: how to populate Ack
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Ack bytes come from the WriteAcknowledgement event, while the rest of the params come from the ReceivePacket event. We use packetAccumulator for combining the info from both events in the cosmos event parser.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it mean

info = &packetInfo{Height: height}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In cosmos, both the WriteAcknowledgement and ReceivePacket event will be included in a single IBC message. The packetInfo should be constructed with the Height property, as you have shown, if info is nil. If info is not nil, it should be casted to packetInfo. The attributes should be parsed into the resulting packetInfo. This will "accumulate" the properties from multiple events into a single packetInfo. The case of the WriteAcknowledgement/ReceivePacket events in the same message is the only need for the accumulator, the rest of the message types do not need an accumulator.

if msg.info == nil {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this context, where is msg?
Given that the function signature is

func (scp *SubstrateChainProcessor) handleIBCMessagesFromEvents(ibcEvents rpcclienttypes.IBCEventsQueryResult, height uint64, c processor.IBCMessagesCache) error {

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, Please check the implementation.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@agouin can you confirm, please?

// Ack: ,

}
eventType = eType
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PathProcessor depends on the eventType being in the format of ibc-go. For example, instead of SendPacket, it should be chantypes.EventTypeSendPacket (which is send_packet). A helper might be nice to translate from the substrate ibc event type to the ibc-go event type.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@agouin can you point me to a place to lookup for the mappings? I've started here already 39d09b5

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's a consolidated place to find them in the cosmos event parser


default:
panic("event not recognized")
}

if info == nil {
// Not an IBC message, don't need to log here
continue
}

scp.handleMessage(ibcMessage{
eventType: eventType,
info: info,
}, c)

}
}

return nil
}

// client info attributes and methods
type clientInfo struct {
height clienttypes.Height `json:"height"`
clientID string `json:"client_id"`
clientType uint32 `json:"client_type"`
consensusHeight clienttypes.Height `json:"consensus_height"`
}

func (c clientInfo) ClientState() provider.ClientState {
return provider.ClientState{
ClientID: c.clientID,
ConsensusHeight: c.consensusHeight,
}
}

func (res *clientInfo) MarshalLogObject(enc zapcore.ObjectEncoder) error {
enc.AddString("client_id", res.clientID)
enc.AddUint64("consensus_height", res.consensusHeight.RevisionHeight)
enc.AddUint64("consensus_height_revision", res.consensusHeight.RevisionNumber)
return nil
}

// client update info attributes and methods
type clientUpdateInfo struct {
common clientInfo `json:"common"`
header BeefyHeader `json:"header"`
}

// TODO: to be replaced with ibc beefy header type
type BeefyHeader struct{}

func (res *clientUpdateInfo) MarshalLogObject(enc zapcore.ObjectEncoder) error {
enc.AddString("client_id", res.common.clientID)
enc.AddUint64("consensus_height", res.common.consensusHeight.RevisionHeight)
enc.AddUint64("consensus_height_revision", res.common.consensusHeight.RevisionNumber)
// TODO: include header if
return nil
}

// packet attributes
type packetEvent struct {
height clienttypes.Height `json:"height"`
sequence uint64 `json:"sequence"`
sourcePort string `json:"source_port"`
sourceCannel uint64 `json:"source_channel"`
destinationPort string `json:"destination_port"`
destinationChannel uint64 `json:"destination_channel"`
data []byte `json:"data"`
timeoutHeight clienttypes.Height `json:"timeout_height"`
timeoutTimestamp uint64 `json:"timeout_timestamp"`
}

// alias type to the provider types, used for adding parser methods
type packetInfo provider.PacketInfo

func (res *packetInfo) MarshalLogObject(enc zapcore.ObjectEncoder) error {
enc.AddUint64("sequence", res.Sequence)
enc.AddString("src_channel", res.SourceChannel)
enc.AddString("src_port", res.SourcePort)
enc.AddString("dst_channel", res.DestChannel)
enc.AddString("dst_port", res.DestPort)
return nil
}

// channel attributes
type channelEvent struct {
height clienttypes.Height `json:"height"`
channelID uint64 `json:"channel_id"`
portID string `json:"port_id"`
connectionID string `json:"connection_id"`
counterpartyPortID uint64 `json:"counterparty_port_id"`
counterpartyChannelID string `json:"counterparty_channel_id"`
}

// alias type to the provider types, used for adding parser methods
type channelInfo provider.ChannelInfo

func (res *channelInfo) MarshalLogObject(enc zapcore.ObjectEncoder) error {
enc.AddString("channel_id", res.ChannelID)
enc.AddString("port_id", res.PortID)
enc.AddString("counterparty_channel_id", res.CounterpartyChannelID)
enc.AddString("counterparty_port_id", res.CounterpartyPortID)
return nil
}

// connection attributes
type connectionEvent struct {
height clienttypes.Height `json:"height"`
connectionID string `json:"connection_id"`
clientID string `json:"client_id"`
counterpartyConnectionID string `json:"counterparty_connection_id"`
counterpartyClientID string `json:"counterparty_client_id"`
}

// alias type to the provider types, used for adding parser methods
type connectionInfo provider.ConnectionInfo

func (res *connectionInfo) MarshalLogObject(enc zapcore.ObjectEncoder) error {
enc.AddString("connection_id", res.ConnID)
enc.AddString("client_id", res.ClientID)
enc.AddString("counterparty_connection_id", res.CounterpartyConnID)
enc.AddString("counterparty_client_id", res.CounterpartyClientID)
return nil
}
10 changes: 10 additions & 0 deletions relayer/chains/substrate/message_handlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package substrate

import (
"github.com/cosmos/relayer/v2/relayer/processor"
)

func (ccp *SubstrateChainProcessor) handleMessage(m ibcMessage, c processor.IBCMessagesCache) {
//TODO implement me
panic("implement me")
}
30 changes: 26 additions & 4 deletions relayer/chains/substrate/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"path"
"time"

rpcclient "github.com/ComposableFi/go-substrate-rpc-client/v4"
sdk "github.com/cosmos/cosmos-sdk/types"
transfertypes "github.com/cosmos/ibc-go/v5/modules/apps/transfer/types"
clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types"
Expand Down Expand Up @@ -84,10 +85,31 @@ func (sp *SubstrateProvider) Init() error {
}

type SubstrateProvider struct {
log *zap.Logger
Keybase keystore.Keyring
PCfg SubstrateProviderConfig
Input io.Reader
log *zap.Logger
Keybase keystore.Keyring
RPCClient *rpcclient.SubstrateAPI
PCfg SubstrateProviderConfig
Input io.Reader
}

type SubstrateIBCHeader struct{}

// noop to implement processor.IBCHeader
func (h SubstrateIBCHeader) IBCHeaderIndicator() {
//TODO implement me
panic("implement me")
}

func (h SubstrateIBCHeader) Height() uint64 {
//TODO implement me
panic("implement me")
return 0
}

func (h SubstrateIBCHeader) ConsensusState() ibcexported.ConsensusState {
//TODO implement me
panic("implement me")
return nil
}

func (sp *SubstrateProvider) BlockTime(ctx context.Context, height int64) (time.Time, error) {
Expand Down
Loading