-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add substrate message-handler (#65)
Signed-off-by: tcar <[email protected]> Co-authored-by: Matija Petrunić <[email protected]>
- Loading branch information
1 parent
96a9b96
commit ec71361
Showing
3 changed files
with
262 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |