Skip to content

Commit

Permalink
feat: Add substrate message-handler (#65)
Browse files Browse the repository at this point in the history
Signed-off-by: tcar <[email protected]>
Co-authored-by: Matija Petrunić <[email protected]>
  • Loading branch information
tcar121293 and mpetrun5 authored Dec 15, 2022
1 parent 96a9b96 commit ec71361
Show file tree
Hide file tree
Showing 3 changed files with 262 additions and 0 deletions.
81 changes: 81 additions & 0 deletions chains/substrate/executor/message-handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package executor

import (
"errors"
"fmt"
"math/big"

"github.com/ChainSafe/chainbridge-core/relayer/message"
"github.com/ChainSafe/sygma-relayer/chains/substrate/executor/proposal"
"github.com/ethereum/go-ethereum/common"
"github.com/rs/zerolog/log"
)

type Handlers map[message.TransferType]MessageHandlerFunc
type MessageHandlerFunc func(m *message.Message) (*proposal.Proposal, error)

type SubstrateMessageHandler struct {
handlers Handlers
}

// NewSubstrateMessageHandler creates an instance of SubstrateMessageHandler that contains
// message handler functions for converting deposit message into a chain specific
// proposal
func NewSubstrateMessageHandler() *SubstrateMessageHandler {
return &SubstrateMessageHandler{
handlers: make(map[message.TransferType]MessageHandlerFunc),
}
}

func (mh *SubstrateMessageHandler) HandleMessage(m *message.Message) (*proposal.Proposal, error) {
// Based on handler that was registered on BridgeContract
handleMessage, err := mh.matchTransferTypeHandlerFunc(m.Type)
if err != nil {
return nil, err
}
log.Info().Str("type", string(m.Type)).Uint8("src", m.Source).Uint8("dst", m.Destination).Uint64("nonce", m.DepositNonce).Str("resourceID", fmt.Sprintf("%x", m.ResourceId)).Msg("Handling new message")
prop, err := handleMessage(m)
if err != nil {
return nil, err
}
return prop, nil
}

func (mh *SubstrateMessageHandler) matchTransferTypeHandlerFunc(transferType message.TransferType) (MessageHandlerFunc, error) {
h, ok := mh.handlers[transferType]
if !ok {
return nil, fmt.Errorf("no corresponding message handler for this transfer type %s exists", transferType)
}
return h, nil
}

// RegisterEventHandler registers an message handler by associating a handler function to a specified transfer type
func (mh *SubstrateMessageHandler) RegisterMessageHandler(transferType message.TransferType, handler MessageHandlerFunc) {
if transferType == "" {
return
}

log.Info().Msgf("Registered message handler for transfer type %s", transferType)

mh.handlers[transferType] = handler
}

func FungibleTransferMessageHandler(m *message.Message) (*proposal.Proposal, error) {
if len(m.Payload) != 2 {
return nil, errors.New("malformed payload. Len of payload should be 2")
}
amount, ok := m.Payload[0].([]byte)
if !ok {
return nil, errors.New("wrong payload amount format")
}
recipient, ok := m.Payload[1].([]byte)
if !ok {
return nil, errors.New("wrong payload recipient format")
}
var data []byte
data = append(data, common.LeftPadBytes(amount, 32)...) // amount (uint256)
recipientLen := big.NewInt(int64(len(recipient))).Bytes()
data = append(data, common.LeftPadBytes(recipientLen, 32)...) // length of recipient (uint256)
data = append(data, recipient...) // recipient ([]byte)
return proposal.NewProposal(m.Source, m.Destination, m.DepositNonce, m.ResourceId, data), nil
}
155 changes: 155 additions & 0 deletions chains/substrate/executor/message-handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package executor_test

import (
"errors"
"github.com/ChainSafe/chainbridge-core/relayer/message"
"github.com/ChainSafe/sygma-relayer/chains/substrate/executor"
"github.com/stretchr/testify/suite"
"testing"
)

var errIncorrectFungibleTransferPayloadLen = errors.New("malformed payload. Len of payload should be 2")
var errIncorrectAmount = errors.New("wrong payload amount format")
var errIncorrectRecipient = errors.New("wrong payload recipient format")

type FungibleTransferHandlerTestSuite struct {
suite.Suite
}

func TestRunFungibleTransferHandlerTestSuite(t *testing.T) {
suite.Run(t, new(FungibleTransferHandlerTestSuite))
}

func (s *FungibleTransferHandlerTestSuite) TestFungibleTransferHandleMessage() {
message := &message.Message{
Source: 1,
Destination: 0,
DepositNonce: 1,
ResourceId: [32]byte{0},
Type: message.FungibleTransfer,
Payload: []interface{}{
[]byte{2}, // amount
[]byte{0x8e, 0xaf, 0x4, 0x15, 0x16, 0x87, 0x73, 0x63, 0x26, 0xc9, 0xfe, 0xa1, 0x7e, 0x25, 0xfc, 0x52, 0x87, 0x61, 0x36, 0x93, 0xc9, 0x12, 0x90, 0x9c, 0xb2, 0x26, 0xaa, 0x47, 0x94, 0xf2, 0x6a, 0x48}, // recipientAddress
},
Metadata: message.Metadata{
Priority: uint8(1),
},
}

prop, err := executor.FungibleTransferMessageHandler(message)

s.Nil(err)
s.NotNil(prop)
}

func (s *FungibleTransferHandlerTestSuite) TestFungibleTransferHandleMessageIncorrectDataLen() {
message := &message.Message{
Source: 1,
Destination: 0,
DepositNonce: 1,
ResourceId: [32]byte{0},
Type: message.FungibleTransfer,
Payload: []interface{}{
[]byte{2}, // amount
},
Metadata: message.Metadata{
Priority: uint8(1),
},
}

prop, err := executor.FungibleTransferMessageHandler(message)

s.Nil(prop)
s.NotNil(err)
s.EqualError(err, errIncorrectFungibleTransferPayloadLen.Error())
}

func (s *FungibleTransferHandlerTestSuite) TestFungibleTransferHandleMessageIncorrectAmount() {
message := &message.Message{
Source: 1,
Destination: 0,
DepositNonce: 1,
ResourceId: [32]byte{0},
Type: message.FungibleTransfer,
Payload: []interface{}{
"incorrectAmount", // amount
[]byte{0x8e, 0xaf, 0x4, 0x15, 0x16, 0x87, 0x73, 0x63, 0x26, 0xc9, 0xfe, 0xa1, 0x7e, 0x25, 0xfc, 0x52, 0x87, 0x61, 0x36, 0x93, 0xc9, 0x12, 0x90, 0x9c, 0xb2, 0x26, 0xaa, 0x47, 0x94, 0xf2, 0x6a, 0x48}, // recipientAddress
},
Metadata: message.Metadata{
Priority: uint8(1),
},
}

prop, err := executor.FungibleTransferMessageHandler(message)

s.Nil(prop)
s.NotNil(err)
s.EqualError(err, errIncorrectAmount.Error())
}

func (s *FungibleTransferHandlerTestSuite) TestFungibleTransferHandleMessageIncorrectRecipient() {
message := &message.Message{
Source: 1,
Destination: 0,
DepositNonce: 1,
ResourceId: [32]byte{0},
Type: message.FungibleTransfer,
Payload: []interface{}{
[]byte{2}, // amount
"incorrectRecipient", // recipientAddress
},
Metadata: message.Metadata{
Priority: uint8(1),
},
}

prop, err := executor.FungibleTransferMessageHandler(message)

s.Nil(prop)
s.NotNil(err)
s.EqualError(err, errIncorrectRecipient.Error())
}

func (s *FungibleTransferHandlerTestSuite) TestSuccesfullyRegisterFungibleTransferMessageHandler() {
messageData := &message.Message{
Source: 1,
Destination: 0,
DepositNonce: 1,
ResourceId: [32]byte{0},
Type: message.FungibleTransfer,
Payload: []interface{}{
[]byte{2}, // amount
[]byte{0x8e, 0xaf, 0x4, 0x15, 0x16, 0x87, 0x73, 0x63, 0x26, 0xc9, 0xfe, 0xa1, 0x7e, 0x25, 0xfc, 0x52, 0x87, 0x61, 0x36, 0x93, 0xc9, 0x12, 0x90, 0x9c, 0xb2, 0x26, 0xaa, 0x47, 0x94, 0xf2, 0x6a, 0x48}, // recipientAddress
},
Metadata: message.Metadata{
Priority: uint8(1),
},
}

invalidMessageData := &message.Message{
Source: 1,
Destination: 0,
DepositNonce: 1,
ResourceId: [32]byte{0},
Type: message.NonFungibleTransfer,
Payload: []interface{}{
[]byte{2}, // amount
[]byte{0x8e, 0xaf, 0x4, 0x15, 0x16, 0x87, 0x73, 0x63, 0x26, 0xc9, 0xfe, 0xa1, 0x7e, 0x25, 0xfc, 0x52, 0x87, 0x61, 0x36, 0x93, 0xc9, 0x12, 0x90, 0x9c, 0xb2, 0x26, 0xaa, 0x47, 0x94, 0xf2, 0x6a, 0x48}, // recipientAddress
},
Metadata: message.Metadata{
Priority: uint8(1),
},
}

depositMessageHandler := executor.NewSubstrateMessageHandler()
// Register FungibleTransferMessageHandler function
depositMessageHandler.RegisterMessageHandler(message.FungibleTransfer, executor.FungibleTransferMessageHandler)
prop1, err1 := depositMessageHandler.HandleMessage(messageData)
s.Nil(err1)
s.NotNil(prop1)

// Use unregistered transfer type
prop2, err2 := depositMessageHandler.HandleMessage(invalidMessageData)
s.Nil(prop2)
s.NotNil(err2)
}
26 changes: 26 additions & 0 deletions chains/substrate/executor/proposal/proposal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package proposal

import (
"github.com/ChainSafe/chainbridge-core/relayer/message"
"github.com/ChainSafe/chainbridge-core/types"
)

func NewProposal(source, destination uint8, depositNonce uint64, resourceId types.ResourceID, data []byte) *Proposal {

return &Proposal{
Source: source,
Destination: destination,
DepositNonce: depositNonce,
ResourceId: resourceId,
Data: data,
}
}

type Proposal struct {
Source uint8 // Source domainID where message was initiated
Destination uint8 // Destination domainID where message is to be sent
DepositNonce uint64 // Nonce for the deposit
ResourceId types.ResourceID
Metadata message.Metadata
Data []byte
}

0 comments on commit ec71361

Please sign in to comment.