From 16ea79c2da1bae8d7be201621334dc0df8e26481 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Mon, 29 Jul 2024 12:31:02 +0300 Subject: [PATCH 1/2] docker: Use golang-1.22 image --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d4453a270..1e8cccab1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 From bae7913e4b380a59329d4577e59ad32acab26bcf Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Mon, 29 Jul 2024 13:10:58 +0300 Subject: [PATCH 2/2] events: Update field parsing to use the latest field format --- chains/substrate/chain.go | 17 +++++-- chains/substrate/events.go | 95 ++++++++------------------------------ 2 files changed, 31 insertions(+), 81 deletions(-) diff --git a/chains/substrate/chain.go b/chains/substrate/chain.go index f72c561d6..ceaf4dd22 100644 --- a/chains/substrate/chain.go +++ b/chains/substrate/chain.go @@ -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 @@ -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{} @@ -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: ®istry.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) diff --git a/chains/substrate/events.go b/chains/substrate/events.go index 49875b45d..cebd2fa96 100644 --- a/chains/substrate/events.go +++ b/chains/substrate/events.go @@ -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" @@ -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 @@ -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 } @@ -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 @@ -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") @@ -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") @@ -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") -}