Skip to content

Commit

Permalink
Merge pull request #143 from centrifuge/update-docker-image
Browse files Browse the repository at this point in the history
Update docker image and substrate event field handling
  • Loading branch information
cdamian authored Jul 29, 2024
2 parents fe74f01 + bae7913 commit c30dc0b
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 82 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright 2020 ChainSafe Systems
# SPDX-License-Identifier: LGPL-3.0-only

FROM golang:1.18-stretch AS builder
FROM golang:1.22 AS builder
ADD . /src
WORKDIR /src
RUN go mod download
Expand Down
17 changes: 12 additions & 5 deletions chains/substrate/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,18 @@ The current supported transfer types are Fungible, Nonfungible, and generic.
There are 3 major components: the connection, the listener, and the writer.
Connection
# Connection
The Connection handles connecting to the substrate client, and submitting transactions to the client.
It also handles state queries. The connection is shared by the writer and listener.
Listener
# Listener
The substrate listener polls blocks and parses the associated events for the three transfer types. It then forwards these into the router.
Writer
# Writer
As the writer receives messages from the router, it constructs proposals. If a proposal is still active, the writer will attempt to vote on it. Resource IDs are resolved to method name on-chain, which are then used in the proposals when constructing the resulting Call struct.
*/
package substrate

Expand All @@ -32,8 +31,10 @@ import (
"github.com/centrifuge/chainbridge-utils/keystore"
metrics "github.com/centrifuge/chainbridge-utils/metrics/types"
"github.com/centrifuge/chainbridge-utils/msg"
"github.com/centrifuge/go-substrate-rpc-client/v4/registry"
"github.com/centrifuge/go-substrate-rpc-client/v4/registry/retriever"
"github.com/centrifuge/go-substrate-rpc-client/v4/registry/state"
"github.com/centrifuge/go-substrate-rpc-client/v4/types"
)

var _ core.Chain = &Chain{}
Expand Down Expand Up @@ -105,7 +106,13 @@ func InitializeChain(cfg *core.ChainConfig, logger log15.Logger, sysErr chan<- e

ue := parseUseExtended(cfg)

eventRetriever, err := retriever.NewDefaultEventRetriever(state.NewEventProvider(conn.api.RPC.State), conn.api.RPC.State)
// u256 is represented as [u64;4]. We use this override to skip extra processing when decoding fields with this type.
u256FieldOverride := registry.FieldOverride{
FieldLookupIndex: 142,
FieldDecoder: &registry.ValueDecoder[types.U256]{},
}

eventRetriever, err := retriever.NewDefaultEventRetriever(state.NewEventProvider(conn.api.RPC.State), conn.api.RPC.State, u256FieldOverride)

if err != nil {
return nil, fmt.Errorf("event retriever creation: %w", err)
Expand Down
95 changes: 19 additions & 76 deletions chains/substrate/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,14 @@ package substrate
import (
"errors"
"fmt"
"math/big"

"github.com/ChainSafe/log15"
"github.com/centrifuge/chainbridge-utils/msg"
"github.com/centrifuge/go-substrate-rpc-client/v4/registry"
"github.com/centrifuge/go-substrate-rpc-client/v4/types"
"github.com/centrifuge/go-substrate-rpc-client/v4/types/codec"
)

type eventName string
type eventHandler func(map[string]any, log15.Logger) (msg.Message, error)
type eventHandler func(registry.DecodedFields, log15.Logger) (msg.Message, error)

const FungibleTransfer eventName = "ChainBridge.FungibleTransfer"
const NonFungibleTransfer eventName = "ChainBridge.NonFungibleTransfer"
Expand All @@ -30,7 +28,7 @@ var Subscriptions = []struct {
{GenericTransfer, genericTransferHandler},
}

func fungibleTransferHandler(eventFields map[string]any, log log15.Logger) (msg.Message, error) {
func fungibleTransferHandler(eventFields registry.DecodedFields, log log15.Logger) (msg.Message, error) {
chainID, err := getFieldValueAsType[types.U8]("ChainId", eventFields)
if err != nil {
return msg.Message{}, err
Expand All @@ -51,7 +49,7 @@ func fungibleTransferHandler(eventFields map[string]any, log log15.Logger) (msg.
return msg.Message{}, err
}

amount, err := getU256(eventFields)
amount, err := getFieldValueAsType[types.U256]("primitive_types.U256.U256", eventFields)
if err != nil {
return msg.Message{}, err
}
Expand All @@ -73,13 +71,13 @@ func fungibleTransferHandler(eventFields map[string]any, log log15.Logger) (msg.
), nil
}

func nonFungibleTransferHandler(_ map[string]any, log log15.Logger) (msg.Message, error) {
func nonFungibleTransferHandler(_ registry.DecodedFields, log log15.Logger) (msg.Message, error) {
log.Warn("Got non-fungible transfer event!")

return msg.Message{}, errors.New("non-fungible transfer not supported")
}

func genericTransferHandler(eventFields map[string]any, log log15.Logger) (msg.Message, error) {
func genericTransferHandler(eventFields registry.DecodedFields, log log15.Logger) (msg.Message, error) {
chainID, err := getFieldValueAsType[types.U8]("ChainId", eventFields)
if err != nil {
return msg.Message{}, err
Expand Down Expand Up @@ -130,26 +128,26 @@ func to32Bytes(array []types.U8) ([32]byte, error) {
return res, nil
}

func getFieldValueAsType[T any](fieldName string, eventFields map[string]any) (T, error) {
func getFieldValueAsType[T any](fieldName string, eventFields registry.DecodedFields) (T, error) {
var t T

for name, value := range eventFields {
if name == fieldName {
if v, ok := value.(T); ok {
for _, field := range eventFields {
if field.Name == fieldName {
if v, ok := field.Value.(T); ok {
return v, nil
}

return t, fmt.Errorf("field type mismatch, expected %T, got %T", t, value)
return t, fmt.Errorf("field type mismatch, expected %T, got %T", t, field.Value)
}
}

return t, fmt.Errorf("field with name '%s' not found", fieldName)
}

func getFieldValueAsSliceOfType[T any](fieldName string, eventFields map[string]any) ([]T, error) {
for name, value := range eventFields {
if name == fieldName {
value, ok := value.([]any)
func getFieldValueAsSliceOfType[T any](fieldName string, eventFields registry.DecodedFields) ([]T, error) {
for _, field := range eventFields {
if field.Name == fieldName {
value, ok := field.Value.([]any)

if !ok {
return nil, errors.New("field value not an array")
Expand All @@ -168,10 +166,10 @@ func getFieldValueAsSliceOfType[T any](fieldName string, eventFields map[string]
return nil, fmt.Errorf("field with name '%s' not found", fieldName)
}

func getFieldValueAsByteSlice(fieldName string, eventFields map[string]any) ([]byte, error) {
for name, value := range eventFields {
if name == fieldName {
value, ok := value.([]any)
func getFieldValueAsByteSlice(fieldName string, eventFields registry.DecodedFields) ([]byte, error) {
for _, field := range eventFields {
if field.Name == fieldName {
value, ok := field.Value.([]any)

if !ok {
return nil, errors.New("field value not an array")
Expand Down Expand Up @@ -222,58 +220,3 @@ func convertToByteSlice(array []types.U8) ([]byte, error) {

return res, nil
}

func getU256(eventFields map[string]any) (types.U256, error) {
for fieldName, fieldValue := range eventFields {
if fieldName != "primitive_types.U256.U256" {
continue
}

innerField, ok := fieldValue.(map[string]any)
if !ok {
return types.NewU256(*big.NewInt(0)), errors.New("unexpected amount field structure")
}

innerFieldVal, ok := innerField["[u64; 4]"]
if !ok {
return types.NewU256(*big.NewInt(0)), errors.New("amount field key not found")
}

slice, ok := innerFieldVal.([]any)
if !ok {
return types.NewU256(*big.NewInt(0)), errors.New("inner field value not a slice")
}

val, err := convertSliceToType[types.U64](slice)

if err != nil {
return types.NewU256(*big.NewInt(0)), err
}

if len(val) != 4 {
return types.NewU256(*big.NewInt(0)), errors.New("slice length mismatch")
}

var r [4]types.U64

for i, item := range val {
r[i] = item
}

encVal, err := codec.Encode(r)

if err != nil {
return types.NewU256(*big.NewInt(0)), errors.New("couldn't encode amount val")
}

var res types.U256

if err := codec.Decode(encVal, &res); err != nil {
return types.NewU256(*big.NewInt(0)), errors.New("couldn't decode amount")
}

return res, nil
}

return types.NewU256(*big.NewInt(0)), errors.New("amount field not found")
}

0 comments on commit c30dc0b

Please sign in to comment.