From ae01eabc3bddb59ecd653301e5ad0ac1b85cb899 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Fri, 28 Jul 2023 13:07:42 +0300 Subject: [PATCH] api: Use EventRetriever when parsing events (#1603) * api: Use EventRetriever when parsing events * api: Register DecodedFields * deps: Update go-substrate-rpc-client to v4.1.0 * deps: Update chain-custom-types to v1.0.8 * test-client: Use EventRetriever * loans: Update CreatdLoan retrieval test * testworld: Fix investor test * api: Remove events from ExtrinsicInfo --- centchain/api.go | 195 ++++++--- centchain/api_integration_test.go | 8 +- centchain/api_test.go | 584 +++++++++++++++----------- centchain/bootstrapper.go | 11 +- centchain/events.go | 12 - centchain/test_client.go | 54 +-- go.mod | 4 +- go.sum | 8 +- pallets/loans/api_integration_test.go | 25 +- pallets/test_utils.go | 46 +- testworld/investor_test.go | 17 +- 11 files changed, 577 insertions(+), 387 deletions(-) delete mode 100644 centchain/events.go diff --git a/centchain/api.go b/centchain/api.go index 14ab3d070..a748361b0 100644 --- a/centchain/api.go +++ b/centchain/api.go @@ -10,6 +10,9 @@ import ( gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4" "github.com/centrifuge/go-substrate-rpc-client/v4/client" + "github.com/centrifuge/go-substrate-rpc-client/v4/registry" + "github.com/centrifuge/go-substrate-rpc-client/v4/registry/parser" + "github.com/centrifuge/go-substrate-rpc-client/v4/registry/retriever" "github.com/centrifuge/go-substrate-rpc-client/v4/signature" "github.com/centrifuge/go-substrate-rpc-client/v4/types" "github.com/centrifuge/go-substrate-rpc-client/v4/types/codec" @@ -50,15 +53,6 @@ type ExtrinsicInfo struct { Hash types.Hash BlockHash types.Hash Index uint // index number of extrinsic in a block - - // EventsRaw contains all the events in the given block - // if you want to filter events for an extrinsic, use the Index - EventsRaw types.EventRecordsRaw -} - -// Events returns all the events occurred in a given block -func (e ExtrinsicInfo) Events(meta *types.Metadata) (events Events, err error) { - return events, e.EventsRaw.DecodeEventRecords(meta, &events) } //go:generate mockery --name API --structname APIMock --filename api_mock.go --inpackage @@ -162,10 +156,11 @@ func (dsa *defaultSubstrateAPI) GetPendingExtrinsics() ([]types.Extrinsic, error } type api struct { - sapi substrateAPI - dispatcher jobs.Dispatcher - accounts map[string]uint32 - accMu sync.Mutex // accMu to protect accounts + sapi substrateAPI + dispatcher jobs.Dispatcher + accounts map[string]uint32 + accMu sync.Mutex + eventRetriever retriever.EventRetriever centChainMaxRetries int centChainRetryInterval time.Duration @@ -177,6 +172,7 @@ func NewAPI( dispatcher jobs.Dispatcher, centChainMaxRetries int, centChainRetryInterval time.Duration, + eventRetriever retriever.EventRetriever, ) API { return &api{ sapi: sapi, @@ -185,6 +181,7 @@ func NewAPI( accMu: sync.Mutex{}, centChainMaxRetries: centChainMaxRetries, centChainRetryInterval: centChainRetryInterval, + eventRetriever: eventRetriever, } } @@ -384,8 +381,7 @@ func (a *api) getDispatcherRunnerFunc( log.Debugf("Extrinsic %s found in block %d", txHash.Hex(), *blockNumber) - eventsRaw, err := a.checkExtrinsicEventSuccess(meta, bh, extIdx) - if err != nil { + if err := a.checkExtrinsicEventSuccess(meta, bh, extIdx); err != nil { log.Errorf("Couldn't check extrinsic event success in block %d: %s", *blockNumber, err) return nil, err @@ -395,7 +391,6 @@ func (a *api) getDispatcherRunnerFunc( Hash: txHash, BlockHash: bh, Index: uint(extIdx), - EventsRaw: eventsRaw, } return info, nil @@ -404,73 +399,157 @@ func (a *api) getDispatcherRunnerFunc( return fn } +const ( + ExtrinsicSuccessEventName = "System.ExtrinsicSuccess" + ExtrinsicFailedEventName = "System.ExtrinsicFailed" + DispatchErrorFieldName = "sp_runtime.DispatchError.dispatch_error" +) + func (a *api) checkExtrinsicEventSuccess( meta *types.Metadata, blockHash types.Hash, extrinsicIdx int, -) (eventsRaw types.EventRecordsRaw, err error) { - key, err := types.CreateStorageKey(meta, "System", "Events") +) error { + events, err := a.eventRetriever.GetEvents(blockHash) + if err != nil { - return nil, err + return fmt.Errorf("event retrieval error: %w", err) } - err = a.sapi.GetStorage(key, &eventsRaw, blockHash) + for _, event := range events { + switch { + case event.Name == ExtrinsicSuccessEventName && + event.Phase.IsApplyExtrinsic && + event.Phase.AsApplyExtrinsic == uint32(extrinsicIdx): + if err := checkSuccessfulProxyExecution(meta, events, extrinsicIdx); err != nil { + return fmt.Errorf("proxy call was not successful: %w", err) + } + + return nil + case event.Name == ExtrinsicFailedEventName && + event.Phase.IsApplyExtrinsic && + event.Phase.AsApplyExtrinsic == uint32(extrinsicIdx): + errorID, err := registry.ProcessDecodedFieldValue[*registry.ErrorID]( + event.Fields, + func(fieldIndex int, field *registry.DecodedField) bool { + return field.Name == DispatchErrorFieldName + }, + getErrorIDFromDispatchError, + ) + + if err != nil { + return fmt.Errorf("extrinsic with index %d failed", extrinsicIdx) + } + + return getMetaError(meta, errorID) + } + } + + return errors.New("should not have reached this step: %v", events) +} + +func getMetaError(meta *types.Metadata, errorID *registry.ErrorID) error { + metaErr, err := meta.FindError(errorID.ModuleIndex, errorID.ErrorIndex) + if err != nil { - return nil, err + return fmt.Errorf("extrinsic failed") + } + + return errors.New( + "extrinsic failed with '%s - %s'", + metaErr.Name, + metaErr.Value, + ) +} + +func getErrorIDFromDispatchError(value any) (*registry.ErrorID, error) { + dispatchErrorFields, ok := value.(registry.DecodedFields) + + if !ok { + return nil, fmt.Errorf("expected dispatch error field to be a slice of decoded fields") } - events := Events{} - err = eventsRaw.DecodeEventRecords(meta, &events) + if len(dispatchErrorFields) != 1 { + return nil, fmt.Errorf("expected dispatch error to have one field") + } + + moduleErrorFields, ok := dispatchErrorFields[0].Value.(registry.DecodedFields) + + if !ok { + return nil, fmt.Errorf("expected module error fields to be a slice of decoded fields") + } + + moduleIndex, err := registry.GetDecodedFieldAsType[types.U8]( + moduleErrorFields, + func(fieldIndex int, field *registry.DecodedField) bool { + return field.Name == "index" + }, + ) + if err != nil { - return nil, err + return nil, fmt.Errorf("module index retrieval: %w", err) } - // Check success events - for _, es := range events.System_ExtrinsicSuccess { - if es.Phase.IsApplyExtrinsic && es.Phase.AsApplyExtrinsic == uint32(extrinsicIdx) { - // Extra check for proxy calls. - if err := checkSuccessfulProxyExecution(events, meta, extrinsicIdx); err != nil { - return nil, errors.New("proxy call was not successful: %s", err) - } + errorIndex, err := registry.GetDecodedFieldAsSliceOfType[types.U8]( + moduleErrorFields, + func(fieldIndex int, field *registry.DecodedField) bool { + return field.Name == "error" + }, + ) - return eventsRaw, nil - } + if err != nil { + return nil, fmt.Errorf("error index retrieval: %w", err) } - // Otherwise, check failure events - for _, es := range events.System_ExtrinsicFailed { - if es.Phase.IsApplyExtrinsic && es.Phase.AsApplyExtrinsic == uint32(extrinsicIdx) { - return nil, handleDispatchError(meta, es.DispatchError, extrinsicIdx) - } + if len(errorIndex) != 4 { + return nil, fmt.Errorf("unexpected error index length") } - return nil, errors.New("should not have reached this step: %v", events) -} + var errorIndexArray [4]types.U8 -func handleDispatchError(meta *types.Metadata, dispatchError types.DispatchError, extrinsicIdx int) error { - if dispatchError.IsModule { - moduleErr := dispatchError.ModuleError - if metaErr, findErr := meta.FindError(moduleErr.Index, moduleErr.Error); findErr == nil { - return errors.New( - "extrinsic %d failed with '%s - %s'", - extrinsicIdx, - metaErr.Name, - metaErr.Value, - ) - } + for i, item := range errorIndex { + errorIndexArray[i] = item } - return errors.New("extrinsic %d failed: %v", extrinsicIdx, dispatchError) + return ®istry.ErrorID{ + ModuleIndex: moduleIndex, + ErrorIndex: errorIndexArray, + }, nil } -func checkSuccessfulProxyExecution(events Events, meta *types.Metadata, extrinsicIdx int) error { - for _, event := range events.Proxy_ProxyExecuted { - if event.Phase.IsApplyExtrinsic && event.Phase.AsApplyExtrinsic == uint32(extrinsicIdx) { - if !event.Result.Ok { - return handleDispatchError(meta, event.Result.Error, extrinsicIdx) +const ( + ProxyExecutedEventName = "Proxy.ProxyExecuted" + ResultFieldName = "Result.result" + ProxyExecutedExpectedLookupIndex = 40 +) + +func checkSuccessfulProxyExecution(meta *types.Metadata, events []*parser.Event, extrinsicIdx int) error { + for _, event := range events { + if event.Name == ProxyExecutedEventName && event.Phase.IsApplyExtrinsic && event.Phase.AsApplyExtrinsic == uint32(extrinsicIdx) { + res, err := registry.GetDecodedFieldAsType[registry.DecodedFields](event.Fields, func(fieldIndex int, field *registry.DecodedField) bool { + return field.Name == ResultFieldName + }) + + if err != nil { + return fmt.Errorf("result field retrieval: %w", err) } - return nil + if len(res) != 1 { + return errors.New("result field has unexpected size") + } + + if res[0].Value == nil && res[0].LookupIndex == ProxyExecutedExpectedLookupIndex { + // The DispatchResult is Ok(()). + return nil + } + + errorID, err := getErrorIDFromDispatchError(res[0].Value) + + if err != nil { + return errors.New("proxy execution was unsuccessful") + } + + return getMetaError(meta, errorID) } } diff --git a/centchain/api_integration_test.go b/centchain/api_integration_test.go index 78cbbfbd1..2080e14dd 100644 --- a/centchain/api_integration_test.go +++ b/centchain/api_integration_test.go @@ -112,7 +112,7 @@ func TestApi_GetBlockLatest(t *testing.T) { assert.NotNil(t, block) } -func TestApi_SubmitAndWatch(t *testing.T) { +func TestApi_SubmitAndWatch_ExtrinsicSuccess(t *testing.T) { meta, err := testAPI.GetMetadataLatest() assert.NoError(t, err) @@ -129,12 +129,8 @@ func TestApi_SubmitAndWatch(t *testing.T) { podOperator, err := cfgSrv.GetPodOperator() assert.NoError(t, err) - info, err := testAPI.SubmitAndWatch(ctx, meta, call, podOperator.ToKeyringPair()) + _, err = testAPI.SubmitAndWatch(ctx, meta, call, podOperator.ToKeyringPair()) assert.NoError(t, err) - - events, err := info.Events(meta) - assert.NoError(t, err) - assert.True(t, len(events.System_ExtrinsicSuccess) > 1) } func TestApi_GetPendingExtrinsics(t *testing.T) { diff --git a/centchain/api_test.go b/centchain/api_test.go index fd17955af..9003867da 100644 --- a/centchain/api_test.go +++ b/centchain/api_test.go @@ -3,14 +3,14 @@ package centchain import ( - "bytes" "context" - "math/big" "strings" "testing" "time" - "github.com/centrifuge/go-substrate-rpc-client/v4/scale" + "github.com/centrifuge/go-substrate-rpc-client/v4/registry" + "github.com/centrifuge/go-substrate-rpc-client/v4/registry/parser" + "github.com/centrifuge/go-substrate-rpc-client/v4/registry/retriever" "github.com/centrifuge/go-substrate-rpc-client/v4/types" "github.com/centrifuge/gocelery/v2" "github.com/centrifuge/pod/config" @@ -28,8 +28,9 @@ import ( func TestApi_Call(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - api := NewAPI(substrateAPIMock, dispatcherMock, 1, 5*time.Second) + api := NewAPI(substrateAPIMock, dispatcherMock, 1, 5*time.Second, eventRetrieverMock) result := types.AccountInfo{} method := "some_method" @@ -54,8 +55,9 @@ func TestApi_Call(t *testing.T) { func TestApi_GetMetadataLatest(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - api := NewAPI(substrateAPIMock, dispatcherMock, 1, 5*time.Second) + api := NewAPI(substrateAPIMock, dispatcherMock, 1, 5*time.Second, eventRetrieverMock) substrateAPIMock.On("GetMetadataLatest"). Return(types.NewMetadataV14(), nil). @@ -77,8 +79,9 @@ func TestApi_GetMetadataLatest(t *testing.T) { func TestApi_SubmitExtrinsic(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - api := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second) + api := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second, eventRetrieverMock) meta := metaDataWithCall("Anchor.commit") c, err := types.NewCall( @@ -167,8 +170,9 @@ func TestApi_SubmitExtrinsic(t *testing.T) { func TestApi_SubmitAndWatch(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - api := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second) + api := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second, eventRetrieverMock) meta := metaDataWithCall("Anchor.commit") c, err := types.NewCall( @@ -257,8 +261,9 @@ func TestApi_SubmitAndWatch(t *testing.T) { func TestApi_SubmitAndWatch_IdentityRetrievalError(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - api := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second) + api := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second, eventRetrieverMock) meta := metaDataWithCall("Anchor.commit") c, err := types.NewCall( @@ -285,8 +290,9 @@ func TestApi_SubmitAndWatch_IdentityRetrievalError(t *testing.T) { func TestApi_SubmitAndWatch_SubmitExtrinsicError(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - api := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second) + api := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second, eventRetrieverMock) meta := metaDataWithCall("Anchor.commit") c, err := types.NewCall( @@ -326,8 +332,9 @@ func TestApi_SubmitAndWatch_SubmitExtrinsicError(t *testing.T) { func TestApi_SubmitAndWatch_DispatcherError(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - api := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second) + api := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second, eventRetrieverMock) meta := metaDataWithCall("Anchor.commit") c, err := types.NewCall( @@ -411,8 +418,9 @@ func TestApi_SubmitAndWatch_DispatcherError(t *testing.T) { func TestApi_SubmitAndWatch_DispatcherResultError(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - api := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second) + api := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second, eventRetrieverMock) meta := metaDataWithCall("Anchor.commit") c, err := types.NewCall( @@ -501,8 +509,9 @@ func TestApi_SubmitAndWatch_DispatcherResultError(t *testing.T) { func TestApi_GetStorageLatest(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - api := NewAPI(substrateAPIMock, dispatcherMock, 1, 5*time.Second) + api := NewAPI(substrateAPIMock, dispatcherMock, 1, 5*time.Second, eventRetrieverMock) meta := types.NewMetadataV14() @@ -535,8 +544,9 @@ func TestApi_GetStorageLatest(t *testing.T) { func TestApi_GetBlockLatest(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - api := NewAPI(substrateAPIMock, dispatcherMock, 1, 5*time.Second) + api := NewAPI(substrateAPIMock, dispatcherMock, 1, 5*time.Second, eventRetrieverMock) testBlock := &types.SignedBlock{} @@ -562,8 +572,9 @@ func TestApi_GetBlockLatest(t *testing.T) { func TestApi_GetPendingExtrinsics(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - api := NewAPI(substrateAPIMock, dispatcherMock, 1, 5*time.Second) + api := NewAPI(substrateAPIMock, dispatcherMock, 1, 5*time.Second, eventRetrieverMock) pendingExtrinsics := []types.Extrinsic{ { @@ -598,8 +609,9 @@ func TestApi_GetPendingExtrinsics(t *testing.T) { func TestApi_dispatcherRunnerFunc(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - centApi := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second) + centApi := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second, eventRetrieverMock) a := centApi.(*api) meta, err := testingutils.GetTestMetadata() @@ -634,8 +646,28 @@ func TestApi_dispatcherRunnerFunc(t *testing.T) { substrateAPIMock.On("GetBlock", blockHash). Return(block, nil) - eventsStorageKey, err := types.CreateStorageKey(meta, "System", "Events") - assert.NoError(t, err) + events := []*parser.Event{ + { + Name: ExtrinsicSuccessEventName, + Fields: []*registry.DecodedField{ + { + Name: "", + Value: nil, + LookupIndex: 0, + }, + }, + EventID: types.EventID{0, 0}, + Phase: &types.Phase{ + IsApplyExtrinsic: true, + AsApplyExtrinsic: 0, + }, + Topics: nil, + }, + } + + eventRetrieverMock.On("GetEvents", blockHash). + Return(events, nil). + Once() extInfo := ExtrinsicInfo{ Hash: txHash, @@ -643,53 +675,6 @@ func TestApi_dispatcherRunnerFunc(t *testing.T) { Index: 0, // Index of the above signature. } - substrateAPIMock.On("GetStorage", eventsStorageKey, mock.IsType(new(types.EventRecordsRaw)), blockHash). - Run(func(args mock.Arguments) { - rawEvents := args.Get(1).(*types.EventRecordsRaw) - - var b []byte - buf := bytes.NewBuffer(b) - - enc := scale.NewEncoder(buf) - - // Push number of events - err = enc.EncodeUintCompact(*big.NewInt(1)) - assert.NoError(t, err) - - err = enc.Encode(types.Phase{ - IsApplyExtrinsic: true, - AsApplyExtrinsic: 0, // Index of the above signature. - }) - assert.NoError(t, err) - - // Extrinsic success event ID - - err = enc.Encode(types.EventID{0, 0}) - assert.NoError(t, err) - - err = enc.Encode(types.DispatchInfo{ - Weight: types.NewWeight(types.NewUCompactFromUInt(123), types.NewUCompactFromUInt(345)), - Class: types.DispatchClass{ - IsNormal: true, - }, - PaysFee: types.Pays{ - IsYes: true, - }, - }) - assert.NoError(t, err) - - err = enc.Encode([]types.Hash{ - types.NewHash(utils.RandomSlice(32)), - }) - assert.NoError(t, err) - - encodedEvents := buf.Bytes() - - *rawEvents = encodedEvents - extInfo.EventsRaw = encodedEvents - }). - Return(nil) - res, err := fn(nil, nil) assert.NoError(t, err) assert.Equal(t, extInfo, res) @@ -698,8 +683,9 @@ func TestApi_dispatcherRunnerFunc(t *testing.T) { func TestApi_dispatcherRunnerFunc_ed25519Signature(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - centApi := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second) + centApi := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second, eventRetrieverMock) a := centApi.(*api) meta, err := testingutils.GetTestMetadata() @@ -734,8 +720,28 @@ func TestApi_dispatcherRunnerFunc_ed25519Signature(t *testing.T) { substrateAPIMock.On("GetBlock", blockHash). Return(block, nil) - eventsStorageKey, err := types.CreateStorageKey(meta, "System", "Events") - assert.NoError(t, err) + events := []*parser.Event{ + { + Name: ExtrinsicSuccessEventName, + Fields: []*registry.DecodedField{ + { + Name: "", + Value: nil, + LookupIndex: 0, + }, + }, + EventID: types.EventID{0, 0}, + Phase: &types.Phase{ + IsApplyExtrinsic: true, + AsApplyExtrinsic: 0, + }, + Topics: nil, + }, + } + + eventRetrieverMock.On("GetEvents", blockHash). + Return(events, nil). + Once() extInfo := ExtrinsicInfo{ Hash: txHash, @@ -743,53 +749,6 @@ func TestApi_dispatcherRunnerFunc_ed25519Signature(t *testing.T) { Index: 0, // Index of the above signature. } - substrateAPIMock.On("GetStorage", eventsStorageKey, mock.IsType(new(types.EventRecordsRaw)), blockHash). - Run(func(args mock.Arguments) { - rawEvents := args.Get(1).(*types.EventRecordsRaw) - - var b []byte - buf := bytes.NewBuffer(b) - - enc := scale.NewEncoder(buf) - - // Push number of events - err = enc.EncodeUintCompact(*big.NewInt(1)) - assert.NoError(t, err) - - err = enc.Encode(types.Phase{ - IsApplyExtrinsic: true, - AsApplyExtrinsic: 0, // Index of the above signature. - }) - assert.NoError(t, err) - - // Extrinsic success event ID - - err = enc.Encode(types.EventID{0, 0}) - assert.NoError(t, err) - - err = enc.Encode(types.DispatchInfo{ - Weight: types.NewWeight(types.NewUCompactFromUInt(123), types.NewUCompactFromUInt(345)), - Class: types.DispatchClass{ - IsNormal: true, - }, - PaysFee: types.Pays{ - IsYes: true, - }, - }) - assert.NoError(t, err) - - err = enc.Encode([]types.Hash{ - types.NewHash(utils.RandomSlice(32)), - }) - assert.NoError(t, err) - - encodedEvents := buf.Bytes() - - *rawEvents = encodedEvents - extInfo.EventsRaw = encodedEvents - }). - Return(nil) - res, err := fn(nil, nil) assert.NoError(t, err) assert.Equal(t, extInfo, res) @@ -798,8 +757,9 @@ func TestApi_dispatcherRunnerFunc_ed25519Signature(t *testing.T) { func TestApi_dispatcherRunnerFunc_BlockHashError(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - centApi := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second) + centApi := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second, eventRetrieverMock) a := centApi.(*api) meta, err := testingutils.GetTestMetadata() @@ -822,8 +782,9 @@ func TestApi_dispatcherRunnerFunc_BlockHashError(t *testing.T) { func TestApi_dispatcherRunnerFunc_BlockError(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - centApi := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second) + centApi := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second, eventRetrieverMock) a := centApi.(*api) meta, err := testingutils.GetTestMetadata() @@ -851,8 +812,9 @@ func TestApi_dispatcherRunnerFunc_BlockError(t *testing.T) { func TestApi_dispatcherRunnerFunc_NoSignature(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - centApi := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second) + centApi := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second, eventRetrieverMock) a := centApi.(*api) meta, err := testingutils.GetTestMetadata() @@ -893,11 +855,12 @@ func TestApi_dispatcherRunnerFunc_NoSignature(t *testing.T) { assert.Nil(t, res) } -func TestApi_dispatcherRunnerFunc_EventStorageError(t *testing.T) { +func TestApi_dispatcherRunnerFunc_EventRetrieverError(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - centApi := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second) + centApi := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second, eventRetrieverMock) a := centApi.(*api) meta, err := testingutils.GetTestMetadata() @@ -932,22 +895,23 @@ func TestApi_dispatcherRunnerFunc_EventStorageError(t *testing.T) { substrateAPIMock.On("GetBlock", blockHash). Return(block, nil) - eventsStorageKey, err := types.CreateStorageKey(meta, "System", "Events") - assert.NoError(t, err) + eventRetrieverError := errors.New("error") - substrateAPIMock.On("GetStorage", eventsStorageKey, mock.IsType(new(types.EventRecordsRaw)), blockHash). - Return(errors.New("error")) + eventRetrieverMock.On("GetEvents", blockHash). + Return(nil, eventRetrieverError). + Once() res, err := fn(nil, nil) - assert.Error(t, err) + assert.ErrorIs(t, err, eventRetrieverError) assert.Nil(t, res) } -func TestApi_dispatcherRunnerFunc_EventDecodeError(t *testing.T) { +func TestApi_dispatcherRunnerFunc_FailedExtrinsic(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - centApi := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second) + centApi := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second, eventRetrieverMock) a := centApi.(*api) meta, err := testingutils.GetTestMetadata() @@ -982,66 +946,40 @@ func TestApi_dispatcherRunnerFunc_EventDecodeError(t *testing.T) { substrateAPIMock.On("GetBlock", blockHash). Return(block, nil) - eventsStorageKey, err := types.CreateStorageKey(meta, "System", "Events") - assert.NoError(t, err) - - substrateAPIMock.On("GetStorage", eventsStorageKey, mock.IsType(new(types.EventRecordsRaw)), blockHash). - Run(func(args mock.Arguments) { - rawEvents := args.Get(1).(*types.EventRecordsRaw) - - var b []byte - buf := bytes.NewBuffer(b) - - enc := scale.NewEncoder(buf) - - // Don't push number of events which will cause a decoding error - - //err = enc.EncodeUintCompact(*big.NewInt(1)) - //assert.NoError(t, err) - - err = enc.Encode(types.Phase{ - IsApplyExtrinsic: true, - AsApplyExtrinsic: 0, // Index of the above signature. - }) - assert.NoError(t, err) - - // Extrinsic success event ID - - err = enc.Encode(types.EventID{0, 0}) - assert.NoError(t, err) - - err = enc.Encode(types.DispatchInfo{ - Weight: types.NewWeight(types.NewUCompactFromUInt(123), types.NewUCompactFromUInt(345)), - Class: types.DispatchClass{ - IsNormal: true, - }, - PaysFee: types.Pays{ - IsYes: true, + events := []*parser.Event{ + { + Name: ExtrinsicFailedEventName, + Fields: []*registry.DecodedField{ + { + Name: "", + Value: nil, + LookupIndex: 0, }, - }) - assert.NoError(t, err) - - err = enc.Encode([]types.Hash{ - types.NewHash(utils.RandomSlice(32)), - }) - assert.NoError(t, err) - - encodedEvents := buf.Bytes() + }, + EventID: types.EventID{0, 1}, + Phase: &types.Phase{ + IsApplyExtrinsic: true, + AsApplyExtrinsic: 0, + }, + Topics: nil, + }, + } - *rawEvents = encodedEvents - }). - Return(nil) + eventRetrieverMock.On("GetEvents", blockHash). + Return(events, nil). + Once() res, err := fn(nil, nil) assert.Error(t, err) assert.Nil(t, res) } -func TestApi_dispatcherRunnerFunc_FailedExtrinsic(t *testing.T) { +func TestApi_dispatcherRunnerFunc_NoEvents(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - centApi := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second) + centApi := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second, eventRetrieverMock) a := centApi.(*api) meta, err := testingutils.GetTestMetadata() @@ -1076,129 +1014,263 @@ func TestApi_dispatcherRunnerFunc_FailedExtrinsic(t *testing.T) { substrateAPIMock.On("GetBlock", blockHash). Return(block, nil) - eventsStorageKey, err := types.CreateStorageKey(meta, "System", "Events") - assert.NoError(t, err) + eventRetrieverMock.On("GetEvents", blockHash). + Return(nil, nil). + Once() - substrateAPIMock.On("GetStorage", eventsStorageKey, mock.IsType(new(types.EventRecordsRaw)), blockHash). - Run(func(args mock.Arguments) { - rawEvents := args.Get(1).(*types.EventRecordsRaw) + res, err := fn(nil, nil) + assert.Error(t, err) + assert.Nil(t, res) +} + +func TestApi_checkExtrinsicEventSuccess_ExtrinsicSuccess_WithoutProxyEvent(t *testing.T) { + substrateAPIMock := NewSubstrateAPIMock(t) + dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - var b []byte - buf := bytes.NewBuffer(b) + centApi := NewAPI(substrateAPIMock, dispatcherMock, 1, 5*time.Second, eventRetrieverMock) - enc := scale.NewEncoder(buf) + testApi := centApi.(*api) - // Push number of events - err = enc.EncodeUintCompact(*big.NewInt(1)) - assert.NoError(t, err) + meta, err := testingutils.GetTestMetadata() + assert.NoError(t, err) + + blockHash := types.NewHash(utils.RandomSlice(32)) + + extrinsicIdx := 0 - err = enc.Encode(types.Phase{ + events := []*parser.Event{ + { + Name: ExtrinsicSuccessEventName, + Fields: []*registry.DecodedField{ + { + Name: "", + Value: nil, + LookupIndex: 0, + }, + }, + EventID: types.EventID{0, 0}, + Phase: &types.Phase{ IsApplyExtrinsic: true, - AsApplyExtrinsic: 0, // Index of the above signature. - }) - assert.NoError(t, err) + AsApplyExtrinsic: 0, + }, + Topics: nil, + }, + } - // Extrinsic failed event ID + eventRetrieverMock.On("GetEvents", blockHash). + Return(events, nil). + Once() - err = enc.Encode(types.EventID{0, 1}) - assert.NoError(t, err) + err = testApi.checkExtrinsicEventSuccess(meta, blockHash, extrinsicIdx) + assert.NoError(t, err) +} - err = enc.Encode(types.DispatchError{ - IsBadOrigin: true, - }) - assert.NoError(t, err) +func TestApi_checkExtrinsicEventSuccess_ExtrinsicSuccess_WithProxySuccess(t *testing.T) { + substrateAPIMock := NewSubstrateAPIMock(t) + dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - err = enc.Encode(types.DispatchInfo{ - Weight: types.NewWeight(types.NewUCompactFromUInt(123), types.NewUCompactFromUInt(345)), - Class: types.DispatchClass{ - IsNormal: true, - }, - PaysFee: types.Pays{ - IsYes: true, - }, - }) - assert.NoError(t, err) + centApi := NewAPI(substrateAPIMock, dispatcherMock, 1, 5*time.Second, eventRetrieverMock) - err = enc.Encode([]types.Hash{ - types.NewHash(utils.RandomSlice(32)), - }) - assert.NoError(t, err) + testApi := centApi.(*api) - encodedEvents := buf.Bytes() + meta, err := testingutils.GetTestMetadata() + assert.NoError(t, err) - *rawEvents = encodedEvents - }). - Return(nil) + blockHash := types.NewHash(utils.RandomSlice(32)) - res, err := fn(nil, nil) - assert.Error(t, err) - assert.Nil(t, res) + extrinsicIdx := 0 + + events := []*parser.Event{ + { + Name: ExtrinsicSuccessEventName, + Fields: []*registry.DecodedField{ + { + Name: "", + Value: nil, + LookupIndex: 0, + }, + }, + EventID: types.EventID{0, 0}, + Phase: &types.Phase{ + IsApplyExtrinsic: true, + AsApplyExtrinsic: 0, + }, + Topics: nil, + }, + { + Name: ProxyExecutedEventName, + Fields: []*registry.DecodedField{ + { + Name: ResultFieldName, + Value: registry.DecodedFields{ + { + Value: nil, + LookupIndex: ProxyExecutedExpectedLookupIndex, + }, + }, + LookupIndex: 0, + }, + }, + EventID: types.EventID{1, 0}, + Phase: &types.Phase{ + IsApplyExtrinsic: true, + AsApplyExtrinsic: 0, + }, + Topics: nil, + }, + } + + eventRetrieverMock.On("GetEvents", blockHash). + Return(events, nil). + Once() + + err = testApi.checkExtrinsicEventSuccess(meta, blockHash, extrinsicIdx) + assert.NoError(t, err) } -func TestApi_dispatcherRunnerFunc_NoEvents(t *testing.T) { +func TestApi_checkExtrinsicEventSuccess_ExtrinsicSuccess_WithProxyFailure(t *testing.T) { substrateAPIMock := NewSubstrateAPIMock(t) dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - centApi := NewAPI(substrateAPIMock, dispatcherMock, 3, 1*time.Second) - a := centApi.(*api) + centApi := NewAPI(substrateAPIMock, dispatcherMock, 1, 5*time.Second, eventRetrieverMock) + + testApi := centApi.(*api) meta, err := testingutils.GetTestMetadata() assert.NoError(t, err) - blockNumber := types.BlockNumber(11) - txHash := types.NewHash(utils.RandomSlice(32)) - sig := types.NewSignature(utils.RandomSlice(64)) - - fn := a.getDispatcherRunnerFunc(&blockNumber, txHash, sig, meta) - blockHash := types.NewHash(utils.RandomSlice(32)) - substrateAPIMock.On("GetBlockHash", uint64(blockNumber)). - Return(blockHash, nil) + extrinsicIdx := 0 - block := &types.SignedBlock{ - Block: types.Block{ - Extrinsics: []types.Extrinsic{ + events := []*parser.Event{ + { + Name: ExtrinsicSuccessEventName, + Fields: []*registry.DecodedField{ { - Signature: types.ExtrinsicSignatureV4{ - Signature: types.MultiSignature{ - IsSr25519: true, - AsSr25519: sig, + Name: "", + Value: nil, + LookupIndex: 0, + }, + }, + EventID: types.EventID{0, 0}, + Phase: &types.Phase{ + IsApplyExtrinsic: true, + AsApplyExtrinsic: 0, + }, + Topics: nil, + }, + { + Name: ProxyExecutedEventName, + Fields: []*registry.DecodedField{ + { + Name: ResultFieldName, + Value: registry.DecodedFields{ + { + Name: "dispatch_error", + Value: registry.DecodedFields{ + { + Name: "ModuleError", + Value: registry.DecodedFields{ + { + Name: "index", + Value: types.U8(0), + }, + { + Name: "error", + Value: []any{ + types.U8(1), + types.U8(0), + types.U8(0), + types.U8(0), + }, + }, + }, + }, + }, }, }, }, }, + EventID: types.EventID{1, 0}, + Phase: &types.Phase{ + IsApplyExtrinsic: true, + AsApplyExtrinsic: 0, + }, + Topics: nil, }, } - substrateAPIMock.On("GetBlock", blockHash). - Return(block, nil) + eventRetrieverMock.On("GetEvents", blockHash). + Return(events, nil). + Once() - eventsStorageKey, err := types.CreateStorageKey(meta, "System", "Events") - assert.NoError(t, err) + err = testApi.checkExtrinsicEventSuccess(meta, blockHash, extrinsicIdx) + assert.NotNil(t, err) +} - substrateAPIMock.On("GetStorage", eventsStorageKey, mock.IsType(new(types.EventRecordsRaw)), blockHash). - Run(func(args mock.Arguments) { - rawEvents := args.Get(1).(*types.EventRecordsRaw) +func TestApi_checkExtrinsicEventSuccess_ExtrinsicFailure(t *testing.T) { + substrateAPIMock := NewSubstrateAPIMock(t) + dispatcherMock := jobs.NewDispatcherMock(t) + eventRetrieverMock := retriever.NewEventRetrieverMock(t) - var b []byte - buf := bytes.NewBuffer(b) + centApi := NewAPI(substrateAPIMock, dispatcherMock, 1, 5*time.Second, eventRetrieverMock) - enc := scale.NewEncoder(buf) + testApi := centApi.(*api) - // Push number of events - err = enc.EncodeUintCompact(*big.NewInt(0)) - assert.NoError(t, err) + meta, err := testingutils.GetTestMetadata() + assert.NoError(t, err) - encodedEvents := buf.Bytes() + blockHash := types.NewHash(utils.RandomSlice(32)) - *rawEvents = encodedEvents - }). - Return(nil) + extrinsicIdx := 0 - res, err := fn(nil, nil) - assert.Error(t, err) - assert.Nil(t, res) + events := []*parser.Event{ + { + Name: ExtrinsicFailedEventName, + Fields: []*registry.DecodedField{ + { + Name: DispatchErrorFieldName, + Value: registry.DecodedFields{ + { + Name: "ModuleError", + Value: registry.DecodedFields{ + { + Name: "index", + Value: types.U8(0), + }, + { + Name: "error", + Value: []any{ + types.U8(1), + types.U8(0), + types.U8(0), + types.U8(0), + }, + }, + }, + }, + }, + }, + }, + EventID: types.EventID{1, 0}, + Phase: &types.Phase{ + IsApplyExtrinsic: true, + AsApplyExtrinsic: 0, + }, + Topics: nil, + }, + } + + eventRetrieverMock.On("GetEvents", blockHash). + Return(events, nil). + Once() + + err = testApi.checkExtrinsicEventSuccess(meta, blockHash, extrinsicIdx) + assert.NotNil(t, err) } func metaDataWithCall(call string) *types.Metadata { diff --git a/centchain/bootstrapper.go b/centchain/bootstrapper.go index e6b8a39bf..6d99317f2 100644 --- a/centchain/bootstrapper.go +++ b/centchain/bootstrapper.go @@ -2,6 +2,8 @@ package centchain import ( gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4" + "github.com/centrifuge/go-substrate-rpc-client/v4/registry/retriever" + "github.com/centrifuge/go-substrate-rpc-client/v4/registry/state" "github.com/centrifuge/pod/config" "github.com/centrifuge/pod/jobs" ) @@ -24,8 +26,15 @@ func (Bootstrapper) Bootstrap(context map[string]interface{}) error { if err != nil { return err } + + eventRetriever, err := retriever.NewDefaultEventRetriever(state.NewEventProvider(sapi.RPC.State), sapi.RPC.State) + + if err != nil { + return err + } + centSAPI := &defaultSubstrateAPI{sapi} - client := NewAPI(centSAPI, dispatcher, cfg.GetCentChainMaxRetries(), cfg.GetCentChainIntervalRetry()) + client := NewAPI(centSAPI, dispatcher, cfg.GetCentChainMaxRetries(), cfg.GetCentChainIntervalRetry(), eventRetriever) context[BootstrappedCentChainClient] = client return nil } diff --git a/centchain/events.go b/centchain/events.go deleted file mode 100644 index bec1e327e..000000000 --- a/centchain/events.go +++ /dev/null @@ -1,12 +0,0 @@ -package centchain - -import ( - centEvents "github.com/centrifuge/chain-custom-types/pkg/events" - "github.com/centrifuge/go-substrate-rpc-client/v4/types" -) - -// Events holds the default events and custom events for centrifuge chain -type Events struct { - types.EventRecords - centEvents.Events -} diff --git a/centchain/test_client.go b/centchain/test_client.go index d312db4ff..1bf04a7e1 100644 --- a/centchain/test_client.go +++ b/centchain/test_client.go @@ -7,6 +7,14 @@ import ( "fmt" "time" + "github.com/centrifuge/go-substrate-rpc-client/v4/registry" + + "github.com/centrifuge/go-substrate-rpc-client/v4/registry/parser" + + "github.com/centrifuge/go-substrate-rpc-client/v4/registry/state" + + "github.com/centrifuge/go-substrate-rpc-client/v4/registry/retriever" + gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4" "github.com/centrifuge/go-substrate-rpc-client/v4/signature" "github.com/centrifuge/go-substrate-rpc-client/v4/types" @@ -14,10 +22,11 @@ import ( ) type TestClient struct { - api *gsrpc.SubstrateAPI - meta *types.Metadata - rv *types.RuntimeVersion - genesisHash types.Hash + api *gsrpc.SubstrateAPI + meta *types.Metadata + rv *types.RuntimeVersion + genesisHash types.Hash + eventRetriever retriever.EventRetriever } func NewTestClient(centChainURL string) (*TestClient, error) { @@ -43,36 +52,29 @@ func NewTestClient(centChainURL string) (*TestClient, error) { return nil, fmt.Errorf("couldn't get genesis hash: %w", err) } + eventRetriever, err := retriever.NewDefaultEventRetriever( + state.NewEventProvider(api.RPC.State), + api.RPC.State, + registry.FieldOverride{ + FieldLookupIndex: 0, + FieldDecoder: ®istry.ValueDecoder[types.AccountID]{}, + }, + ) + if err != nil { + return nil, fmt.Errorf("couldn't create event retriever: %w", err) + } + return &TestClient{ api, meta, rv, genesisHash, + eventRetriever, }, nil } -func (f *TestClient) GetEvents(blockHash types.Hash) (*Events, error) { - key, err := types.CreateStorageKey(f.meta, "System", "Events") - - if err != nil { - return nil, err - } - - var eventsRaw types.EventRecordsRaw - - ok, err := f.api.RPC.State.GetStorage(key, &eventsRaw, blockHash) - - if err != nil || !ok { - return nil, errors.New("no events found in storage") - } - - var events Events - - if err = eventsRaw.DecodeEventRecords(f.meta, &events); err != nil { - return nil, err - } - - return &events, nil +func (f *TestClient) GetEvents(blockHash types.Hash) ([]*parser.Event, error) { + return f.eventRetriever.GetEvents(blockHash) } func (f *TestClient) Close() { diff --git a/go.mod b/go.mod index 230030bf6..c2f436a16 100644 --- a/go.mod +++ b/go.mod @@ -6,8 +6,8 @@ require ( github.com/ChainSafe/go-schnorrkel v1.0.0 github.com/Masterminds/semver v1.5.0 github.com/centrifuge/centrifuge-protobufs v1.0.0 - github.com/centrifuge/chain-custom-types v1.0.7 - github.com/centrifuge/go-substrate-rpc-client/v4 v4.0.14 + github.com/centrifuge/chain-custom-types v1.0.8 + github.com/centrifuge/go-substrate-rpc-client/v4 v4.1.0 github.com/centrifuge/gocelery/v2 v2.0.0-20221101190423-3b07af1b49a6 github.com/centrifuge/precise-proofs v1.0.0 github.com/common-nighthawk/go-figure v0.0.0-20200609044655-c4b36f998cf2 diff --git a/go.sum b/go.sum index a0aef2489..2ef5cd099 100644 --- a/go.sum +++ b/go.sum @@ -126,12 +126,12 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/centrifuge/centrifuge-protobufs v1.0.0 h1:ZPg0XpkTrGrjQu8scXjMGs7jjqsWPiXmOXdV/bz30ng= github.com/centrifuge/centrifuge-protobufs v1.0.0/go.mod h1:VL6mcnK6vTRiFljHP39J0WBI3Uu5BHQjhdFkCxY9/9I= -github.com/centrifuge/chain-custom-types v1.0.7 h1:YyNztKAVpfZkiEszK89RnylyTXUplr2eiUrQHLMO4VQ= -github.com/centrifuge/chain-custom-types v1.0.7/go.mod h1:kSUJ3O83vaLutJIiaEfqwn3lfTaisn/G/baS8WrycTg= +github.com/centrifuge/chain-custom-types v1.0.8 h1:JcXQNzjzs1y/xEBK23XlRJeD1OxLZByfnwstQkORuIg= +github.com/centrifuge/chain-custom-types v1.0.8/go.mod h1:kSUJ3O83vaLutJIiaEfqwn3lfTaisn/G/baS8WrycTg= github.com/centrifuge/go-merkle v0.0.0-20190727075423-0ac78bbbc01b h1:TPvvMcGAc3TVBVgQ4XYYEWTXxYls8YuylZ8JzrVxPzc= github.com/centrifuge/go-merkle v0.0.0-20190727075423-0ac78bbbc01b/go.mod h1:0voJY6Qzxvr2S0LeDSFQiCnJzGq5gORg2SwCmn8602I= -github.com/centrifuge/go-substrate-rpc-client/v4 v4.0.14 h1:eO3rscaPMsWTlB86mcIekJVyWrfJ4/PCvBcq+3xabD4= -github.com/centrifuge/go-substrate-rpc-client/v4 v4.0.14/go.mod h1:szA5wf9suAIcNg/1S3rGeFITHqrnqH5TC6b+O0SEQ94= +github.com/centrifuge/go-substrate-rpc-client/v4 v4.1.0 h1:GEvub7kU5YFAcn5A2uOo4AZSM1/cWZCOvfu7E3gQmK8= +github.com/centrifuge/go-substrate-rpc-client/v4 v4.1.0/go.mod h1:szA5wf9suAIcNg/1S3rGeFITHqrnqH5TC6b+O0SEQ94= github.com/centrifuge/gocelery/v2 v2.0.0-20221101190423-3b07af1b49a6 h1:0/y+LOu+sAnIlXNsvCYmxUY9n6OiCyhT/37KoYKEFSk= github.com/centrifuge/gocelery/v2 v2.0.0-20221101190423-3b07af1b49a6/go.mod h1:q6PvyLLCu1IQcE2dFv8advWprzY5b5GtZYRU/bH9nWE= github.com/centrifuge/precise-proofs v1.0.0 h1:hcXSK2d5aPEZUa09p+aoyw9ofKI6Twip+UMIx+sJKYc= diff --git a/pallets/loans/api_integration_test.go b/pallets/loans/api_integration_test.go index b16a4fe7c..fdc0f787e 100644 --- a/pallets/loans/api_integration_test.go +++ b/pallets/loans/api_integration_test.go @@ -45,13 +45,11 @@ var integrationTestBootstrappers = []bootstrap.TestBootstrapper{ var ( serviceCtx map[string]any - cfgService config.Service loansAPI loans.API ) func TestMain(m *testing.M) { serviceCtx = bootstrap.RunTestBootstrappers(integrationTestBootstrappers, nil) - cfgService = genericUtils.GetService[config.Service](serviceCtx) loansAPI = genericUtils.GetService[loans.API](serviceCtx) result := m.Run() @@ -141,7 +139,10 @@ func TestIntegration_CreatedLoanRetrieval(t *testing.T) { Maturity: loansTypes.Maturity{ IsFixed: true, // 1 Year maturity date. - AsFixed: types.U64(time.Now().Add(356 * 24 * time.Hour).Unix()), + AsFixed: loansTypes.FixedMaturity{ + Date: types.U64(time.Now().Add(356 * 24 * time.Hour).Unix()), + Extension: 0, + }, }, InterestPayments: loansTypes.InterestPayments{ IsNone: true, @@ -154,6 +155,15 @@ func TestIntegration_CreatedLoanRetrieval(t *testing.T) { CollectionID: nftCollectionID, ItemID: nftItemID, }, + InterestRate: loansTypes.InterestRate{ + IsFixed: true, + AsFixed: loansTypes.FixedInterestRate{ + RatePerYear: types.NewU128(*big.NewInt(0)), + Compounding: loansTypes.CompoundingSchedule{ + IsSecondly: true, + }, + }, + }, Pricing: loansTypes.Pricing{ IsInternal: true, AsInternal: loansTypes.InternalPricing{ @@ -161,8 +171,7 @@ func TestIntegration_CreatedLoanRetrieval(t *testing.T) { ValuationMethod: loansTypes.ValuationMethod{ IsOutstandingDebt: true, }, - InterestRate: types.NewU128(*big.NewInt(0)), - MaxBorrowAmount: loansTypes.MaxBorrowAmount{ + MaxBorrowAmount: loansTypes.InternalPricingMaxBorrowAmount{ IsUpToTotalBorrowed: true, AsUpToTotalBorrowed: loansTypes.AdvanceRate{ AdvanceRate: types.NewU128(*big.NewInt(11)), @@ -187,12 +196,6 @@ func TestIntegration_CreatedLoanRetrieval(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) defer cancel() - _ = nftCollectionCall - _ = nftMintCall - _ = registerPoolCall - _ = addBorrowerPermissionsCall - _ = loanCreateCall - err = pallets.ExecuteWithTestClient( ctx, serviceCtx, diff --git a/pallets/test_utils.go b/pallets/test_utils.go index cb802d848..c32050af9 100644 --- a/pallets/test_utils.go +++ b/pallets/test_utils.go @@ -13,6 +13,8 @@ import ( keystoreTypes "github.com/centrifuge/chain-custom-types/pkg/keystore" loansTypes "github.com/centrifuge/chain-custom-types/pkg/loans" proxyType "github.com/centrifuge/chain-custom-types/pkg/proxy" + "github.com/centrifuge/go-substrate-rpc-client/v4/registry" + "github.com/centrifuge/go-substrate-rpc-client/v4/registry/parser" "github.com/centrifuge/go-substrate-rpc-client/v4/scale" "github.com/centrifuge/go-substrate-rpc-client/v4/signature" "github.com/centrifuge/go-substrate-rpc-client/v4/types" @@ -87,21 +89,49 @@ func CreateAnonymousProxy( } } +const ( + ProxyPureCreatedEventName = "Proxy.PureCreated" + ProxyPureCreateWhoFieldName = "sp_core.crypto.AccountId32.who" + ProxyPureCreatePureFieldName = "sp_core.crypto.AccountId32.pure" +) + func getAnonymousProxyCreatedByAccount( originKrp signature.KeyringPair, - events *centchain.Events, + events []*parser.Event, ) (*types.AccountID, error) { - if len(events.Proxy_PureCreated) == 0 { - return nil, errors.New("no 'AnonymousCreated' events") - } + for _, event := range events { + if event.Name != ProxyPureCreatedEventName { + continue + } + + who, err := registry.GetDecodedFieldAsType[types.AccountID]( + event.Fields, + func(fieldIndex int, field *registry.DecodedField) bool { + return field.Name == ProxyPureCreateWhoFieldName + }, + ) + + if err != nil { + return nil, fmt.Errorf("cannot find proxy event field: %w", err) + } + + if bytes.Equal(who.ToBytes(), originKrp.PublicKey) { + proxyAccountID, err := registry.GetDecodedFieldAsType[types.AccountID]( + event.Fields, + func(fieldIndex int, field *registry.DecodedField) bool { + return field.Name == ProxyPureCreatePureFieldName + }, + ) + + if err != nil { + return nil, fmt.Errorf("couldn't get pure proxy: %w", err) + } - for _, event := range events.Proxy_PureCreated { - if bytes.Equal(event.Who.ToBytes(), originKrp.PublicKey) { - return &event.Pure, nil + return &proxyAccountID, nil } } - return nil, errors.New("anonymous proxy not found") + return nil, errors.New("pure proxy not found") } func ExecuteWithTestClient( diff --git a/testworld/investor_test.go b/testworld/investor_test.go index 412e024c0..49a130031 100644 --- a/testworld/investor_test.go +++ b/testworld/investor_test.go @@ -181,7 +181,10 @@ func TestInvestorAPI_GetAsset(t *testing.T) { Maturity: loansTypes.Maturity{ IsFixed: true, // 1 Year maturity date. - AsFixed: types.U64(time.Now().Add(356 * 24 * time.Hour).Unix()), + AsFixed: loansTypes.FixedMaturity{ + Date: types.U64(time.Now().Add(356 * 24 * time.Hour).Unix()), + Extension: 0, + }, }, InterestPayments: loansTypes.InterestPayments{ IsNone: true, @@ -194,6 +197,15 @@ func TestInvestorAPI_GetAsset(t *testing.T) { CollectionID: collectionID, ItemID: itemID, }, + InterestRate: loansTypes.InterestRate{ + IsFixed: true, + AsFixed: loansTypes.FixedInterestRate{ + RatePerYear: types.NewU128(*big.NewInt(0)), + Compounding: loansTypes.CompoundingSchedule{ + IsSecondly: true, + }, + }, + }, Pricing: loansTypes.Pricing{ IsInternal: true, AsInternal: loansTypes.InternalPricing{ @@ -201,8 +213,7 @@ func TestInvestorAPI_GetAsset(t *testing.T) { ValuationMethod: loansTypes.ValuationMethod{ IsOutstandingDebt: true, }, - InterestRate: types.NewU128(*big.NewInt(0)), - MaxBorrowAmount: loansTypes.MaxBorrowAmount{ + MaxBorrowAmount: loansTypes.InternalPricingMaxBorrowAmount{ IsUpToTotalBorrowed: true, AsUpToTotalBorrowed: loansTypes.AdvanceRate{ AdvanceRate: types.NewU128(*big.NewInt(11)),