From 8da46295d5c044e93afdd7c4954920d1d571aef3 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Fri, 15 Dec 2023 12:44:15 +0600 Subject: [PATCH 01/32] Add `pallet-ddc-clusters` events type definitions --- blockchain/pallets/ddcclusters.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/blockchain/pallets/ddcclusters.go b/blockchain/pallets/ddcclusters.go index 346a2ac..6d522b7 100644 --- a/blockchain/pallets/ddcclusters.go +++ b/blockchain/pallets/ddcclusters.go @@ -21,6 +21,31 @@ type ClusterProps struct { NodeProviderAuthContract types.AccountID } +// Events +type ( + ClusterCreated struct { + ClusterId ClusterId + } + + ClusterNodeAdded struct { + ClusterId ClusterId + NodePubKey NodePubKey + } + + ClusterNodeRemoved struct { + ClusterId ClusterId + NodePubKey NodePubKey + } + + ClusterParamsSet struct { + ClusterId ClusterId + } + + ClusterGovParamsSet struct { + ClusterId ClusterId + } +) + type DdcClustersApi interface { GetClustersNodes(clusterId ClusterId) ([]NodePubKey, error) } From 91aef79a2bab128f6e939f85885d627456aea4d6 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Fri, 15 Dec 2023 18:37:15 +0600 Subject: [PATCH 02/32] Add event retriever to the client --- blockchain/client.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/blockchain/client.go b/blockchain/client.go index ccc2c4d..65763e3 100644 --- a/blockchain/client.go +++ b/blockchain/client.go @@ -2,12 +2,15 @@ package blockchain 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/cerebellum-network/cere-ddc-sdk-go/blockchain/pallets" ) type Client struct { *gsrpc.SubstrateAPI + eventRetriever retriever.EventRetriever DdcClusters pallets.DdcClustersApi DdcCustomers pallets.DdcCustomersApi @@ -24,12 +27,17 @@ func NewClient(url string) (*Client, error) { if err != nil { return nil, err } + eventRetriever, _ := retriever.NewDefaultEventRetriever( + state.NewEventProvider(substrateApi.RPC.State), + substrateApi.RPC.State, + ) return &Client{ - SubstrateAPI: substrateApi, - DdcClusters: pallets.NewDdcClustersApi(substrateApi), - DdcCustomers: pallets.NewDdcCustomersApi(substrateApi, meta), - DdcNodes: pallets.NewDdcNodesApi(substrateApi, meta), - DdcPayouts: pallets.NewDdcPayoutsApi(substrateApi, meta), + SubstrateAPI: substrateApi, + eventRetriever: eventRetriever, + DdcClusters: pallets.NewDdcClustersApi(substrateApi), + DdcCustomers: pallets.NewDdcCustomersApi(substrateApi, meta), + DdcNodes: pallets.NewDdcNodesApi(substrateApi, meta), + DdcPayouts: pallets.NewDdcPayoutsApi(substrateApi, meta), }, nil } From c9bd637be105b6b10c2dac02c1bc18dae6707a95 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Fri, 15 Dec 2023 18:39:54 +0600 Subject: [PATCH 03/32] Store pallets' subscription to events in client --- blockchain/client.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/blockchain/client.go b/blockchain/client.go index 65763e3..b46a7ae 100644 --- a/blockchain/client.go +++ b/blockchain/client.go @@ -2,6 +2,7 @@ package blockchain import ( gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4" + "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/registry/state" @@ -11,6 +12,7 @@ import ( type Client struct { *gsrpc.SubstrateAPI eventRetriever retriever.EventRetriever + subs map[string]chan []*parser.Event DdcClusters pallets.DdcClustersApi DdcCustomers pallets.DdcCustomersApi @@ -32,9 +34,12 @@ func NewClient(url string) (*Client, error) { substrateApi.RPC.State, ) + subs := make(map[string]chan []*parser.Event) + return &Client{ SubstrateAPI: substrateApi, eventRetriever: eventRetriever, + subs: subs, DdcClusters: pallets.NewDdcClustersApi(substrateApi), DdcCustomers: pallets.NewDdcCustomersApi(substrateApi, meta), DdcNodes: pallets.NewDdcNodesApi(substrateApi, meta), From 8212a4f8e1e73469a87b147b6e8b863d1184134a Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Fri, 15 Dec 2023 18:41:49 +0600 Subject: [PATCH 04/32] New client method to start listening to events --- blockchain/client.go | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/blockchain/client.go b/blockchain/client.go index b46a7ae..2f3c982 100644 --- a/blockchain/client.go +++ b/blockchain/client.go @@ -1,6 +1,8 @@ package blockchain import ( + "sync" + gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4" "github.com/centrifuge/go-substrate-rpc-client/v4/registry/parser" "github.com/centrifuge/go-substrate-rpc-client/v4/registry/retriever" @@ -46,3 +48,46 @@ func NewClient(url string) (*Client, error) { DdcPayouts: pallets.NewDdcPayoutsApi(substrateApi, meta), }, nil } + +func (c *Client) StartEventsListening() (func(), <-chan error, error) { + sub, err := c.RPC.Chain.SubscribeNewHeads() + if err != nil { + return nil, nil, err + } + + done := make(chan struct{}) + errCh := make(chan error) + + go func() { + for { + select { + case <-done: + return + case header := <-sub.Chan(): + blockHash, err := c.RPC.Chain.GetBlockHash(uint64(header.Number)) + if err != nil { + errCh <- err + return + } + + events, err := c.eventRetriever.GetEvents(blockHash) + if err != nil { + errCh <- err + return + } + + for _, ch := range c.subs { + ch <- events + } + } + } + }() + + once := sync.Once{} + + return func() { + once.Do(func() { + done <- struct{}{} + }) + }, nil, nil +} From 796555fd7f30024b34012418c8b5919b53627673 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Fri, 15 Dec 2023 18:44:28 +0600 Subject: [PATCH 05/32] New generic events subscription type --- blockchain/pallets/events.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 blockchain/pallets/events.go diff --git a/blockchain/pallets/events.go b/blockchain/pallets/events.go new file mode 100644 index 0000000..b875155 --- /dev/null +++ b/blockchain/pallets/events.go @@ -0,0 +1,20 @@ +package pallets + +import "sync" + +type NewEventSubscription[T any] struct { + ch chan T + done chan struct{} + o sync.Once +} + +func (s *NewEventSubscription[T]) Unsubscribe() { + s.o.Do(func() { + s.done <- struct{}{} + close(s.ch) + }) +} + +func (s *NewEventSubscription[T]) Chan() <-chan T { + return s.ch +} From d9b9d144415adf5f45891d33128ce96440879e21 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Fri, 15 Dec 2023 18:48:42 +0600 Subject: [PATCH 06/32] New events subscriber type --- blockchain/pallets/events.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/blockchain/pallets/events.go b/blockchain/pallets/events.go index b875155..b4c85c7 100644 --- a/blockchain/pallets/events.go +++ b/blockchain/pallets/events.go @@ -1,6 +1,10 @@ package pallets -import "sync" +import ( + "sync" + + "github.com/centrifuge/go-substrate-rpc-client/v4/registry/parser" +) type NewEventSubscription[T any] struct { ch chan T @@ -18,3 +22,8 @@ func (s *NewEventSubscription[T]) Unsubscribe() { func (s *NewEventSubscription[T]) Chan() <-chan T { return s.ch } + +type subscriber struct { + ch chan *parser.Event + done chan struct{} +} From 4a6ef91a49ff4e82b8a1f9af7083880a4626d5d9 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Fri, 15 Dec 2023 18:49:42 +0600 Subject: [PATCH 07/32] New events publisher interface --- blockchain/pallets/events.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/blockchain/pallets/events.go b/blockchain/pallets/events.go index b4c85c7..e9a6315 100644 --- a/blockchain/pallets/events.go +++ b/blockchain/pallets/events.go @@ -27,3 +27,8 @@ type subscriber struct { ch chan *parser.Event done chan struct{} } + +type Publisher interface { + Subs() map[string]map[int]subscriber + Mu() *sync.Mutex +} From 1501773b71483976b46d5a9ec6ff25c73baccf61 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Fri, 15 Dec 2023 18:50:01 +0600 Subject: [PATCH 08/32] A func to add buffered subscription to Publisher --- blockchain/pallets/events.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/blockchain/pallets/events.go b/blockchain/pallets/events.go index e9a6315..39651b1 100644 --- a/blockchain/pallets/events.go +++ b/blockchain/pallets/events.go @@ -32,3 +32,21 @@ type Publisher interface { Subs() map[string]map[int]subscriber Mu() *sync.Mutex } + +func AddSubscriber(pub Publisher, eventName string) int { + pub.Mu().Lock() + defer pub.Mu().Unlock() + + if pub.Subs()[eventName] == nil { + pub.Subs()[eventName] = make(map[int]subscriber) + } + + key := len(pub.Subs()[eventName]) + + pub.Subs()[eventName][key] = subscriber{ + ch: make(chan *parser.Event, 256), + done: make(chan struct{}), + } + + return key +} From 0bbdfe233db94e6cacdd416699a953236c01e7e6 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Fri, 15 Dec 2023 18:53:21 +0600 Subject: [PATCH 09/32] Impl Publisher interface on ddcClustersApi --- blockchain/pallets/ddcclusters.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/blockchain/pallets/ddcclusters.go b/blockchain/pallets/ddcclusters.go index 6d522b7..e9ebe64 100644 --- a/blockchain/pallets/ddcclusters.go +++ b/blockchain/pallets/ddcclusters.go @@ -54,6 +54,9 @@ type ddcClustersApi struct { substrateApi *gsrpc.SubstrateAPI clustersNodesKey []byte + + subs map[string]map[int]subscriber + mu sync.Mutex } func NewDdcClustersApi(substrateApi *gsrpc.SubstrateAPI) DdcClustersApi { @@ -62,9 +65,13 @@ func NewDdcClustersApi(substrateApi *gsrpc.SubstrateAPI) DdcClustersApi { xxhash.New128([]byte("ClustersNodes")).Sum(nil)..., ) - return &ddcClustersApi{ + subs := make(map[string]map[int]subscriber) + + api := &ddcClustersApi{ substrateApi: substrateApi, clustersNodesKey: clustersNodesKey, + subs: subs, + mu: sync.Mutex{}, } } @@ -109,3 +116,11 @@ func (api *ddcClustersApi) GetClustersNodes(clusterId ClusterId) ([]NodePubKey, return nodesKeys, nil } + +func (api *ddcClustersApi) Subs() map[string]map[int]subscriber { + return api.subs +} + +func (api *ddcClustersApi) Mu() *sync.Mutex { + return &api.mu +} From f53d0cfa8f7bf47311def2a680f237a706eea305 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Fri, 15 Dec 2023 18:58:10 +0600 Subject: [PATCH 10/32] Subscribe ddcClustersApi to block events --- blockchain/client.go | 13 ++++++++---- blockchain/pallets/ddcclusters.go | 34 ++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/blockchain/client.go b/blockchain/client.go index 2f3c982..fb90bd4 100644 --- a/blockchain/client.go +++ b/blockchain/client.go @@ -37,15 +37,20 @@ func NewClient(url string) (*Client, error) { ) subs := make(map[string]chan []*parser.Event) + subs["DdcClusters"] = make(chan []*parser.Event) return &Client{ SubstrateAPI: substrateApi, eventRetriever: eventRetriever, subs: subs, - DdcClusters: pallets.NewDdcClustersApi(substrateApi), - DdcCustomers: pallets.NewDdcCustomersApi(substrateApi, meta), - DdcNodes: pallets.NewDdcNodesApi(substrateApi, meta), - DdcPayouts: pallets.NewDdcPayoutsApi(substrateApi, meta), + DdcClusters: pallets.NewDdcClustersApi( + substrateApi, + eventRetriever, + subs["DdcClusters"], + ), + DdcCustomers: pallets.NewDdcCustomersApi(substrateApi, meta), + DdcNodes: pallets.NewDdcNodesApi(substrateApi, meta), + DdcPayouts: pallets.NewDdcPayoutsApi(substrateApi, meta), }, nil } diff --git a/blockchain/pallets/ddcclusters.go b/blockchain/pallets/ddcclusters.go index e9ebe64..6bdafbf 100644 --- a/blockchain/pallets/ddcclusters.go +++ b/blockchain/pallets/ddcclusters.go @@ -1,8 +1,12 @@ package pallets import ( + "sync" + gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4" "github.com/centrifuge/go-substrate-rpc-client/v4/hash" + "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/go-substrate-rpc-client/v4/types/codec" "github.com/centrifuge/go-substrate-rpc-client/v4/xxhash" @@ -59,7 +63,11 @@ type ddcClustersApi struct { mu sync.Mutex } -func NewDdcClustersApi(substrateApi *gsrpc.SubstrateAPI) DdcClustersApi { +func NewDdcClustersApi( + substrateApi *gsrpc.SubstrateAPI, + eventRetriever retriever.EventRetriever, + blockEventsCh <-chan []*parser.Event, +) DdcClustersApi { clustersNodesKey := append( xxhash.New128([]byte("DdcClusters")).Sum(nil), xxhash.New128([]byte("ClustersNodes")).Sum(nil)..., @@ -73,6 +81,30 @@ func NewDdcClustersApi(substrateApi *gsrpc.SubstrateAPI) DdcClustersApi { subs: subs, mu: sync.Mutex{}, } + + go func() { + for blockEvents := range blockEventsCh { + for _, event := range blockEvents { + api.mu.Lock() + subs, ok := api.subs[event.Name] + if ok { + for subId, sub := range subs { + select { + case <-sub.done: + close(sub.ch) + delete(api.subs[event.Name], subId) + case sub.ch <- event: + default: + panic("buffer exhausted") + } + } + } + api.mu.Unlock() + } + } + }() + + return api } func (api *ddcClustersApi) GetClustersNodes(clusterId ClusterId) ([]NodePubKey, error) { From 7b9cd800e67ca27ffa159eb180e6cd1c24e71da1 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Fri, 15 Dec 2023 19:01:07 +0600 Subject: [PATCH 11/32] Event DdcClusters.ClusterNodeAdded subscription --- blockchain/pallets/ddcclusters.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/blockchain/pallets/ddcclusters.go b/blockchain/pallets/ddcclusters.go index 6bdafbf..9f0d351 100644 --- a/blockchain/pallets/ddcclusters.go +++ b/blockchain/pallets/ddcclusters.go @@ -52,6 +52,7 @@ type ( type DdcClustersApi interface { GetClustersNodes(clusterId ClusterId) ([]NodePubKey, error) + SubscribeNewClusterNodeAdded() *NewEventSubscription[ClusterNodeAdded] } type ddcClustersApi struct { @@ -149,6 +150,28 @@ func (api *ddcClustersApi) GetClustersNodes(clusterId ClusterId) ([]NodePubKey, return nodesKeys, nil } +func (api *ddcClustersApi) SubscribeNewClusterNodeAdded() *NewEventSubscription[ClusterNodeAdded] { + subId := AddSubscriber(api, "DdcClusters.ClusterNodeAdded") + + sub := &NewEventSubscription[ClusterNodeAdded]{ + ch: make(chan ClusterNodeAdded), + } + + go func() { + for { + select { + case <-sub.done: + api.subs["DdcClusters.ClusterNodeAdded"][subId].done <- struct{}{} + return + case <-api.subs["DdcClusters.ClusterNodeAdded"][subId].ch: + sub.ch <- ClusterNodeAdded{} // TODO: parse incoming event + } + } + }() + + return sub +} + func (api *ddcClustersApi) Subs() map[string]map[int]subscriber { return api.subs } From caa807b15a4afc5cd0a52ca3c9158987caa48756 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Tue, 2 Jan 2024 17:53:33 +0600 Subject: [PATCH 12/32] Reshape events to remove events retriever --- blockchain/pallets/ddcclusters.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/blockchain/pallets/ddcclusters.go b/blockchain/pallets/ddcclusters.go index 9f0d351..3e7ad72 100644 --- a/blockchain/pallets/ddcclusters.go +++ b/blockchain/pallets/ddcclusters.go @@ -27,26 +27,36 @@ type ClusterProps struct { // Events type ( - ClusterCreated struct { + EventDdcClustersClusterCreated struct { + Phase types.Phase ClusterId ClusterId + Topics []types.Hash } - ClusterNodeAdded struct { + EventDdcClustersClusterNodeAdded struct { + Phase types.Phase ClusterId ClusterId NodePubKey NodePubKey + Topics []types.Hash } - ClusterNodeRemoved struct { + EventDdcClustersClusterNodeRemoved struct { + Phase types.Phase ClusterId ClusterId NodePubKey NodePubKey + Topics []types.Hash } - ClusterParamsSet struct { + EventDdcClustersClusterParamsSet struct { + Phase types.Phase ClusterId ClusterId + Topics []types.Hash } - ClusterGovParamsSet struct { + EventDdcClustersClusterGovParamsSet struct { + Phase types.Phase ClusterId ClusterId + Topics []types.Hash } ) From d2fa6dcb75522f3aba0d9fd2b41f4a4e90d7fe5d Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Tue, 2 Jan 2024 17:57:33 +0600 Subject: [PATCH 13/32] Create chain custom event records type --- blockchain/pallets/events.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/blockchain/pallets/events.go b/blockchain/pallets/events.go index 39651b1..ddd22a5 100644 --- a/blockchain/pallets/events.go +++ b/blockchain/pallets/events.go @@ -4,8 +4,19 @@ import ( "sync" "github.com/centrifuge/go-substrate-rpc-client/v4/registry/parser" + "github.com/centrifuge/go-substrate-rpc-client/v4/types" ) +type Events struct { + types.EventRecords + + DdcClusters_ClusterCreated []EventDdcClustersClusterCreated //nolint:stylecheck,golint + DdcClusters_ClusterNodeAdded []EventDdcClustersClusterNodeAdded //nolint:stylecheck,golint + DdcClusters_ClusterNodeRemoved []EventDdcClustersClusterNodeRemoved //nolint:stylecheck,golint + DdcClusters_ClusterParamsSet []EventDdcClustersClusterParamsSet //nolint:stylecheck,golint + DdcClusters_ClusterGovParamsSet []EventDdcClustersClusterGovParamsSet //nolint:stylecheck,golint +} + type NewEventSubscription[T any] struct { ch chan T done chan struct{} From 75bdbb19e689c30aa18975045bd80ba71ae3e312 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Tue, 2 Jan 2024 18:03:12 +0600 Subject: [PATCH 14/32] Add event unsubscription callback --- blockchain/pallets/events.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/blockchain/pallets/events.go b/blockchain/pallets/events.go index ddd22a5..9488533 100644 --- a/blockchain/pallets/events.go +++ b/blockchain/pallets/events.go @@ -18,15 +18,17 @@ type Events struct { } type NewEventSubscription[T any] struct { - ch chan T - done chan struct{} - o sync.Once + ch chan T + done chan struct{} + onDone func() + o sync.Once } func (s *NewEventSubscription[T]) Unsubscribe() { s.o.Do(func() { s.done <- struct{}{} close(s.ch) + s.onDone() }) } From 1cc6353617ace0ebeb0d249899967354ad0b20fb Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Tue, 2 Jan 2024 18:07:34 +0600 Subject: [PATCH 15/32] Remove Publisher interface --- blockchain/pallets/ddcclusters.go | 8 -------- blockchain/pallets/events.go | 23 ----------------------- 2 files changed, 31 deletions(-) diff --git a/blockchain/pallets/ddcclusters.go b/blockchain/pallets/ddcclusters.go index 3e7ad72..a24bf52 100644 --- a/blockchain/pallets/ddcclusters.go +++ b/blockchain/pallets/ddcclusters.go @@ -181,11 +181,3 @@ func (api *ddcClustersApi) SubscribeNewClusterNodeAdded() *NewEventSubscription[ return sub } - -func (api *ddcClustersApi) Subs() map[string]map[int]subscriber { - return api.subs -} - -func (api *ddcClustersApi) Mu() *sync.Mutex { - return &api.mu -} diff --git a/blockchain/pallets/events.go b/blockchain/pallets/events.go index 9488533..bccb19f 100644 --- a/blockchain/pallets/events.go +++ b/blockchain/pallets/events.go @@ -40,26 +40,3 @@ type subscriber struct { ch chan *parser.Event done chan struct{} } - -type Publisher interface { - Subs() map[string]map[int]subscriber - Mu() *sync.Mutex -} - -func AddSubscriber(pub Publisher, eventName string) int { - pub.Mu().Lock() - defer pub.Mu().Unlock() - - if pub.Subs()[eventName] == nil { - pub.Subs()[eventName] = make(map[int]subscriber) - } - - key := len(pub.Subs()[eventName]) - - pub.Subs()[eventName][key] = subscriber{ - ch: make(chan *parser.Event, 256), - done: make(chan struct{}), - } - - return key -} From 9a29fccffd6874a14157082074f933a4e3151928 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Tue, 2 Jan 2024 18:08:01 +0600 Subject: [PATCH 16/32] Generic events subscriber --- blockchain/pallets/events.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/blockchain/pallets/events.go b/blockchain/pallets/events.go index bccb19f..5ad0452 100644 --- a/blockchain/pallets/events.go +++ b/blockchain/pallets/events.go @@ -3,7 +3,6 @@ package pallets import ( "sync" - "github.com/centrifuge/go-substrate-rpc-client/v4/registry/parser" "github.com/centrifuge/go-substrate-rpc-client/v4/types" ) @@ -36,7 +35,7 @@ func (s *NewEventSubscription[T]) Chan() <-chan T { return s.ch } -type subscriber struct { - ch chan *parser.Event +type subscriber[T any] struct { + ch chan T done chan struct{} } From a6460673fa54f30d564d7413c92930e240f156ed Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Tue, 2 Jan 2024 18:09:13 +0600 Subject: [PATCH 17/32] Filter specific block events for subscribers --- blockchain/pallets/ddcclusters.go | 104 ++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 35 deletions(-) diff --git a/blockchain/pallets/ddcclusters.go b/blockchain/pallets/ddcclusters.go index a24bf52..fed639a 100644 --- a/blockchain/pallets/ddcclusters.go +++ b/blockchain/pallets/ddcclusters.go @@ -1,12 +1,12 @@ package pallets import ( + "fmt" + "math" "sync" gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4" "github.com/centrifuge/go-substrate-rpc-client/v4/hash" - "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/go-substrate-rpc-client/v4/types/codec" "github.com/centrifuge/go-substrate-rpc-client/v4/xxhash" @@ -62,7 +62,15 @@ type ( type DdcClustersApi interface { GetClustersNodes(clusterId ClusterId) ([]NodePubKey, error) - SubscribeNewClusterNodeAdded() *NewEventSubscription[ClusterNodeAdded] + SubscribeNewClusterNodeAdded() (*NewEventSubscription[EventDdcClustersClusterNodeAdded], error) +} + +type ddcClustersEventsSubs struct { + clusterCreated map[int]subscriber[EventDdcClustersClusterCreated] + clusterNodeAdded map[int]subscriber[EventDdcClustersClusterNodeAdded] + clusterNodeRemoved map[int]subscriber[EventDdcClustersClusterNodeRemoved] + clusterParamsSet map[int]subscriber[EventDdcClustersClusterParamsSet] + clusterGovParamsSet map[int]subscriber[EventDdcClustersClusterGovParamsSet] } type ddcClustersApi struct { @@ -70,21 +78,26 @@ type ddcClustersApi struct { clustersNodesKey []byte - subs map[string]map[int]subscriber + subs *ddcClustersEventsSubs mu sync.Mutex } func NewDdcClustersApi( substrateApi *gsrpc.SubstrateAPI, - eventRetriever retriever.EventRetriever, - blockEventsCh <-chan []*parser.Event, + events <-chan *Events, ) DdcClustersApi { clustersNodesKey := append( xxhash.New128([]byte("DdcClusters")).Sum(nil), xxhash.New128([]byte("ClustersNodes")).Sum(nil)..., ) - subs := make(map[string]map[int]subscriber) + subs := &ddcClustersEventsSubs{ + clusterCreated: make(map[int]subscriber[EventDdcClustersClusterCreated]), + clusterNodeAdded: make(map[int]subscriber[EventDdcClustersClusterNodeAdded]), + clusterNodeRemoved: make(map[int]subscriber[EventDdcClustersClusterNodeRemoved]), + clusterParamsSet: make(map[int]subscriber[EventDdcClustersClusterParamsSet]), + clusterGovParamsSet: make(map[int]subscriber[EventDdcClustersClusterGovParamsSet]), + } api := &ddcClustersApi{ substrateApi: substrateApi, @@ -94,20 +107,26 @@ func NewDdcClustersApi( } go func() { - for blockEvents := range blockEventsCh { - for _, event := range blockEvents { + for blockEvents := range events { + for _, e := range blockEvents.DdcClusters_ClusterCreated { + api.mu.Lock() + for i, sub := range api.subs.clusterCreated { + select { + case <-sub.done: + delete(api.subs.clusterCreated, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcClusters_ClusterNodeAdded { api.mu.Lock() - subs, ok := api.subs[event.Name] - if ok { - for subId, sub := range subs { - select { - case <-sub.done: - close(sub.ch) - delete(api.subs[event.Name], subId) - case sub.ch <- event: - default: - panic("buffer exhausted") - } + for i, sub := range api.subs.clusterNodeAdded { + select { + case <-sub.done: + delete(api.subs.clusterNodeAdded, i) + case sub.ch <- e: } } api.mu.Unlock() @@ -160,24 +179,39 @@ func (api *ddcClustersApi) GetClustersNodes(clusterId ClusterId) ([]NodePubKey, return nodesKeys, nil } -func (api *ddcClustersApi) SubscribeNewClusterNodeAdded() *NewEventSubscription[ClusterNodeAdded] { - subId := AddSubscriber(api, "DdcClusters.ClusterNodeAdded") +func (api *ddcClustersApi) SubscribeNewClusterNodeAdded() (*NewEventSubscription[EventDdcClustersClusterNodeAdded], error) { + api.mu.Lock() + defer api.mu.Unlock() - sub := &NewEventSubscription[ClusterNodeAdded]{ - ch: make(chan ClusterNodeAdded), + if api.subs.clusterNodeAdded == nil { + api.subs.clusterNodeAdded = make(map[int]subscriber[EventDdcClustersClusterNodeAdded]) } - go func() { - for { - select { - case <-sub.done: - api.subs["DdcClusters.ClusterNodeAdded"][subId].done <- struct{}{} - return - case <-api.subs["DdcClusters.ClusterNodeAdded"][subId].ch: - sub.ch <- ClusterNodeAdded{} // TODO: parse incoming event - } + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.clusterNodeAdded[i]; !ok { + idx = i + break } - }() + if i == math.MaxInt { + return nil, fmt.Errorf("can't create %d+1 subscriber", len(api.subs.clusterNodeAdded)) + } + } + + sub := subscriber[EventDdcClustersClusterNodeAdded]{ + ch: make(chan EventDdcClustersClusterNodeAdded), + done: make(chan struct{}), + } - return sub + api.subs.clusterNodeAdded[idx] = sub + + return &NewEventSubscription[EventDdcClustersClusterNodeAdded]{ + ch: sub.ch, + done: sub.done, + onDone: func() { + api.mu.Lock() + delete(api.subs.clusterNodeAdded, idx) + api.mu.Unlock() + }, + }, nil } From d1158d0feb8cc12eaf49e46c7f30399c1bae58f8 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Tue, 2 Jan 2024 18:13:07 +0600 Subject: [PATCH 18/32] Remove events retriever, listen to storage changes --- blockchain/client.go | 67 +++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/blockchain/client.go b/blockchain/client.go index fb90bd4..14b287c 100644 --- a/blockchain/client.go +++ b/blockchain/client.go @@ -1,20 +1,19 @@ package blockchain import ( + "fmt" "sync" gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4" - "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/registry/state" + "github.com/centrifuge/go-substrate-rpc-client/v4/types" + "github.com/centrifuge/go-substrate-rpc-client/v4/types/codec" "github.com/cerebellum-network/cere-ddc-sdk-go/blockchain/pallets" ) type Client struct { *gsrpc.SubstrateAPI - eventRetriever retriever.EventRetriever - subs map[string]chan []*parser.Event + subs map[string]chan *pallets.Events DdcClusters pallets.DdcClustersApi DdcCustomers pallets.DdcCustomersApi @@ -31,21 +30,15 @@ func NewClient(url string) (*Client, error) { if err != nil { return nil, err } - eventRetriever, _ := retriever.NewDefaultEventRetriever( - state.NewEventProvider(substrateApi.RPC.State), - substrateApi.RPC.State, - ) - subs := make(map[string]chan []*parser.Event) - subs["DdcClusters"] = make(chan []*parser.Event) + subs := make(map[string]chan *pallets.Events) + subs["DdcClusters"] = make(chan *pallets.Events) return &Client{ - SubstrateAPI: substrateApi, - eventRetriever: eventRetriever, - subs: subs, + SubstrateAPI: substrateApi, + subs: subs, DdcClusters: pallets.NewDdcClustersApi( substrateApi, - eventRetriever, subs["DdcClusters"], ), DdcCustomers: pallets.NewDdcCustomersApi(substrateApi, meta), @@ -55,7 +48,15 @@ func NewClient(url string) (*Client, error) { } func (c *Client) StartEventsListening() (func(), <-chan error, error) { - sub, err := c.RPC.Chain.SubscribeNewHeads() + meta, err := c.RPC.State.GetMetadataLatest() + if err != nil { + return nil, nil, err + } + key, err := types.CreateStorageKey(meta, "System", "Events", nil) + if err != nil { + return nil, nil, err + } + sub, err := c.RPC.State.SubscribeStorageRaw([]types.StorageKey{key}) if err != nil { return nil, nil, err } @@ -68,31 +69,33 @@ func (c *Client) StartEventsListening() (func(), <-chan error, error) { select { case <-done: return - case header := <-sub.Chan(): - blockHash, err := c.RPC.Chain.GetBlockHash(uint64(header.Number)) - if err != nil { - errCh <- err - return - } + case set := <-sub.Chan(): + for _, change := range set.Changes { + if !codec.Eq(change.StorageKey, key) || !change.HasStorageData { + continue + } - events, err := c.eventRetriever.GetEvents(blockHash) - if err != nil { - errCh <- err - return - } + events := &pallets.Events{} + err = types.EventRecordsRaw(change.StorageData).DecodeEventRecords(meta, events) + if err != nil { + errCh <- fmt.Errorf("events listener: %w", err) + } - for _, ch := range c.subs { - ch <- events + for _, module := range c.subs { + module <- events + } } } } }() once := sync.Once{} - - return func() { + stop := func() { once.Do(func() { done <- struct{}{} + sub.Unsubscribe() }) - }, nil, nil + } + + return stop, errCh, nil } From ee5d94902944879223846bb6321120a049fdf243 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Tue, 2 Jan 2024 18:14:45 +0600 Subject: [PATCH 19/32] Upgrade `go-substrate-rpc-client` to `v4.2.1` --- blockchain/go.mod | 4 ++-- blockchain/go.sum | 9 ++++----- go.work.sum | 11 +++++++++++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/blockchain/go.mod b/blockchain/go.mod index bc1726d..e6a6d70 100644 --- a/blockchain/go.mod +++ b/blockchain/go.mod @@ -2,7 +2,7 @@ module github.com/cerebellum-network/cere-ddc-sdk-go/blockchain go 1.18 -require github.com/centrifuge/go-substrate-rpc-client/v4 v4.0.8 +require github.com/centrifuge/go-substrate-rpc-client/v4 v4.2.1 require ( github.com/ChainSafe/go-schnorrkel v1.0.0 // indirect @@ -18,7 +18,7 @@ require ( github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b // indirect github.com/pierrec/xxHash v0.1.5 // indirect github.com/rs/cors v1.8.2 // indirect - github.com/vedhavyas/go-subkey v1.0.3 // indirect + github.com/vedhavyas/go-subkey/v2 v2.0.0 // indirect golang.org/x/crypto v0.7.0 // indirect golang.org/x/sys v0.6.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect diff --git a/blockchain/go.sum b/blockchain/go.sum index 612d59e..1d46f81 100644 --- a/blockchain/go.sum +++ b/blockchain/go.sum @@ -1,11 +1,10 @@ github.com/ChainSafe/go-schnorrkel v1.0.0 h1:3aDA67lAykLaG1y3AOjs88dMxC88PgUuHRrLeDnvGIM= github.com/ChainSafe/go-schnorrkel v1.0.0/go.mod h1:dpzHYVxLZcp8pjlV+O+UR8K0Hp/z7vcchBSbMBEhCw4= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= -github.com/btcsuite/btcd v0.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo= github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= -github.com/centrifuge/go-substrate-rpc-client/v4 v4.0.8 h1:gHLD5S81As9u5DbefLahw1enVO6OdBSS8gBI2R6KNEQ= -github.com/centrifuge/go-substrate-rpc-client/v4 v4.0.8/go.mod h1:5g1oM4Zu3BOaLpsKQ+O8PAv2kNuq+kPcA1VzFbsSqxE= +github.com/centrifuge/go-substrate-rpc-client/v4 v4.2.1 h1:io49TJ8IOIlzipioJc9pJlrjgdJvqktpUWYxVY5AUjE= +github.com/centrifuge/go-substrate-rpc-client/v4 v4.2.1/go.mod h1:k61SBXqYmnZO4frAJyH3iuqjolYrYsq79r8EstmklDY= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= @@ -47,8 +46,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= -github.com/vedhavyas/go-subkey v1.0.3 h1:iKR33BB/akKmcR2PMlXPBeeODjWLM90EL98OrOGs8CA= -github.com/vedhavyas/go-subkey v1.0.3/go.mod h1:CloUaFQSSTdWnINfBRFjVMkWXZANW+nd8+TI5jYcl6Y= +github.com/vedhavyas/go-subkey/v2 v2.0.0 h1:LemDIsrVtRSOkp0FA8HxP6ynfKjeOj3BY2U9UNfeDMA= +github.com/vedhavyas/go-subkey/v2 v2.0.0/go.mod h1:95aZ+XDCWAUUynjlmi7BtPExjXgXxByE0WfBwbmIRH4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= diff --git a/go.work.sum b/go.work.sum index 5d0eb11..3b8edee 100644 --- a/go.work.sum +++ b/go.work.sum @@ -226,6 +226,8 @@ github.com/c-bata/go-prompt v0.2.2 h1:uyKRz6Z6DUyj49QVijyM339UJV9yhbr70gESwbNU3e github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= +github.com/centrifuge/go-substrate-rpc-client/v4 v4.2.1 h1:io49TJ8IOIlzipioJc9pJlrjgdJvqktpUWYxVY5AUjE= +github.com/centrifuge/go-substrate-rpc-client/v4 v4.2.1/go.mod h1:k61SBXqYmnZO4frAJyH3iuqjolYrYsq79r8EstmklDY= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/checkpoint-restore/go-criu/v5 v5.3.0 h1:wpFFOoomK3389ue2lAb0Boag6XPht5QYpipxmSNL4d8= @@ -287,6 +289,8 @@ github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= github.com/dave/jennifer v1.2.0 h1:S15ZkFMRoJ36mGAQgWL1tnr0NQJh9rZ8qatseX/VbBc= +github.com/decred/base58 v1.0.4 h1:QJC6B0E0rXOPA8U/kw2rP+qiRJsUaE2Er+pYb3siUeA= +github.com/decred/base58 v1.0.4/go.mod h1:jJswKPEdvpFpvf7dsDvFZyLT22xZ9lWqEByX38oGd9E= github.com/decred/dcrd/lru v1.0.0 h1:Kbsb1SFDsIlaupWPwsPp+dkxiBY1frcS07PCPgotKz8= github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU= github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73 h1:OGNva6WhsKst5OZf7eZOklDztV3hwtTHovdrLHV+MsA= @@ -469,6 +473,8 @@ github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/Qd github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104 h1:d8RFOZ2IiFtFWBcKEHAFYJcPTf0wY5q0exFNJZVWa1U= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b h1:QrHweqAtyJ9EwCaGHBu1fghwxIPiopAHV06JlXrMHjk= +github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b/go.mod h1:xxLb2ip6sSUts3g1irPVHyk/DGslwQsNOo9I7smJfNU= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible h1:aKW/4cBs+yK6gpqU3K/oIwk9Q/XICqd3zOX/UFuvqmk= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= @@ -577,6 +583,8 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME= github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= +github.com/vedhavyas/go-subkey/v2 v2.0.0 h1:LemDIsrVtRSOkp0FA8HxP6ynfKjeOj3BY2U9UNfeDMA= +github.com/vedhavyas/go-subkey/v2 v2.0.0/go.mod h1:95aZ+XDCWAUUynjlmi7BtPExjXgXxByE0WfBwbmIRH4= github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 h1:+UB2BJA852UkGH42H+Oee69djmxS3ANzl2b/JtT1YiA= github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= @@ -613,6 +621,8 @@ go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= @@ -631,6 +641,7 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= From 67a3abc8bcc44ff09169af00967b537ca950d10e Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Tue, 2 Jan 2024 18:30:34 +0600 Subject: [PATCH 20/32] Add `DdcClusters_ClusterCreated` events subscriber --- blockchain/pallets/ddcclusters.go | 38 +++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/blockchain/pallets/ddcclusters.go b/blockchain/pallets/ddcclusters.go index fed639a..23160b5 100644 --- a/blockchain/pallets/ddcclusters.go +++ b/blockchain/pallets/ddcclusters.go @@ -62,6 +62,7 @@ type ( type DdcClustersApi interface { GetClustersNodes(clusterId ClusterId) ([]NodePubKey, error) + SubscribeNewClusterCreated() (*NewEventSubscription[EventDdcClustersClusterCreated], error) SubscribeNewClusterNodeAdded() (*NewEventSubscription[EventDdcClustersClusterNodeAdded], error) } @@ -179,6 +180,43 @@ func (api *ddcClustersApi) GetClustersNodes(clusterId ClusterId) ([]NodePubKey, return nodesKeys, nil } +func (api *ddcClustersApi) SubscribeNewClusterCreated() (*NewEventSubscription[EventDdcClustersClusterCreated], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.clusterCreated == nil { + api.subs.clusterCreated = make(map[int]subscriber[EventDdcClustersClusterCreated]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.clusterCreated[i]; !ok { + idx = i + break + } + if i == math.MaxInt { + return nil, fmt.Errorf("can't create %d+1 subscriber", len(api.subs.clusterCreated)) + } + } + + sub := subscriber[EventDdcClustersClusterCreated]{ + ch: make(chan EventDdcClustersClusterCreated), + done: make(chan struct{}), + } + + api.subs.clusterCreated[idx] = sub + + return &NewEventSubscription[EventDdcClustersClusterCreated]{ + ch: sub.ch, + done: sub.done, + onDone: func() { + api.mu.Lock() + delete(api.subs.clusterCreated, idx) + api.mu.Unlock() + }, + }, nil +} + func (api *ddcClustersApi) SubscribeNewClusterNodeAdded() (*NewEventSubscription[EventDdcClustersClusterNodeAdded], error) { api.mu.Lock() defer api.mu.Unlock() From c344094a5533b54560c89c05cd8bd6e855a0796c Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Wed, 3 Jan 2024 17:46:55 +0600 Subject: [PATCH 21/32] Add `pallet-ddc-customers` event types --- blockchain/pallets/ddccustomers.go | 38 ++++++++++++++++++++++++++++++ blockchain/pallets/events.go | 7 ++++++ 2 files changed, 45 insertions(+) diff --git a/blockchain/pallets/ddccustomers.go b/blockchain/pallets/ddccustomers.go index be4c75d..a8f0685 100644 --- a/blockchain/pallets/ddccustomers.go +++ b/blockchain/pallets/ddccustomers.go @@ -25,6 +25,44 @@ type UnlockChunk struct { Block types.BlockNumber } +// Events +type ( + EventDdcCustomersDeposited struct { + Phase types.Phase + Owner types.AccountID + Amount types.U128 + Topics []types.Hash + } + EventDdcCustomersInitialDepositUnlock struct { + Phase types.Phase + Owner types.AccountID + Amount types.U128 + Topics []types.Hash + } + EventDdcCustomersWithdrawn struct { + Phase types.Phase + Owner types.AccountID + Amount types.U128 + Topics []types.Hash + } + EventDdcCustomersCharged struct { + Phase types.Phase + Owner types.AccountID + Amount types.U128 + Topics []types.Hash + } + EventDdcCustomersBucketCreated struct { + Phase types.Phase + BucketId BucketId + Topics []types.Hash + } + EventDdcCustomersBucketUpdated struct { + Phase types.Phase + BucketId BucketId + Topics []types.Hash + } +) + type DdcCustomersApi interface { GetBuckets(bucketId BucketId) (types.Option[Bucket], error) GetBucketsCount() (types.U64, error) diff --git a/blockchain/pallets/events.go b/blockchain/pallets/events.go index 5ad0452..d665785 100644 --- a/blockchain/pallets/events.go +++ b/blockchain/pallets/events.go @@ -14,6 +14,13 @@ type Events struct { DdcClusters_ClusterNodeRemoved []EventDdcClustersClusterNodeRemoved //nolint:stylecheck,golint DdcClusters_ClusterParamsSet []EventDdcClustersClusterParamsSet //nolint:stylecheck,golint DdcClusters_ClusterGovParamsSet []EventDdcClustersClusterGovParamsSet //nolint:stylecheck,golint + + DdcCustomers_Deposited []EventDdcCustomersDeposited //nolint:stylecheck,golint + DdcCustomers_InitialDepositUnlock []EventDdcCustomersInitialDepositUnlock //nolint:stylecheck,golint + DdcCustomers_Withdrawn []EventDdcCustomersWithdrawn //nolint:stylecheck,golint + DdcCustomers_Charged []EventDdcCustomersCharged //nolint:stylecheck,golint + DdcCustomers_BucketCreated []EventDdcCustomersBucketCreated //nolint:stylecheck,golint + DdcCustomers_BucketUpdated []EventDdcCustomersBucketUpdated //nolint:stylecheck,golint } type NewEventSubscription[T any] struct { From d3bcb3a6076a2deb6657ca1b81d967d05b6a0087 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Wed, 3 Jan 2024 18:14:09 +0600 Subject: [PATCH 22/32] Track `ddc-customers` events subscribers --- blockchain/pallets/ddccustomers.go | 113 +++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 5 deletions(-) diff --git a/blockchain/pallets/ddccustomers.go b/blockchain/pallets/ddccustomers.go index a8f0685..ff57a8e 100644 --- a/blockchain/pallets/ddccustomers.go +++ b/blockchain/pallets/ddccustomers.go @@ -1,6 +1,8 @@ package pallets import ( + "sync" + gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4" "github.com/centrifuge/go-substrate-rpc-client/v4/types" "github.com/centrifuge/go-substrate-rpc-client/v4/types/codec" @@ -69,16 +71,117 @@ type DdcCustomersApi interface { GetLedger(owner types.AccountID) (types.Option[AccountsLedger], error) } +type ddcCustomersEventsSubs struct { + deposited map[int]subscriber[EventDdcCustomersDeposited] + initialDepositUnlock map[int]subscriber[EventDdcCustomersInitialDepositUnlock] + withdrawn map[int]subscriber[EventDdcCustomersWithdrawn] + charged map[int]subscriber[EventDdcCustomersCharged] + bucketCreated map[int]subscriber[EventDdcCustomersBucketCreated] + bucketUpdated map[int]subscriber[EventDdcCustomersBucketUpdated] +} + type ddcCustomersApi struct { substrateApi *gsrpc.SubstrateAPI meta *types.Metadata + + subs *ddcCustomersEventsSubs + mu sync.Mutex } -func NewDdcCustomersApi(substrateAPI *gsrpc.SubstrateAPI, meta *types.Metadata) DdcCustomersApi { - return &ddcCustomersApi{ - substrateAPI, - meta, - } +func NewDdcCustomersApi(substrateAPI *gsrpc.SubstrateAPI, meta *types.Metadata, events <-chan *Events) DdcCustomersApi { + subs := &ddcCustomersEventsSubs{ + deposited: make(map[int]subscriber[EventDdcCustomersDeposited]), + initialDepositUnlock: make(map[int]subscriber[EventDdcCustomersInitialDepositUnlock]), + withdrawn: make(map[int]subscriber[EventDdcCustomersWithdrawn]), + charged: make(map[int]subscriber[EventDdcCustomersCharged]), + bucketCreated: make(map[int]subscriber[EventDdcCustomersBucketCreated]), + bucketUpdated: make(map[int]subscriber[EventDdcCustomersBucketUpdated]), + } + + api := &ddcCustomersApi{ + substrateApi: substrateAPI, + meta: meta, + subs: subs, + mu: sync.Mutex{}, + } + + go func() { + for blockEvents := range events { + for _, e := range blockEvents.DdcCustomers_Deposited { + api.mu.Lock() + for i, sub := range api.subs.deposited { + select { + case <-sub.done: + delete(api.subs.deposited, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcCustomers_InitialDepositUnlock { + api.mu.Lock() + for i, sub := range api.subs.initialDepositUnlock { + select { + case <-sub.done: + delete(api.subs.initialDepositUnlock, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcCustomers_Withdrawn { + api.mu.Lock() + for i, sub := range api.subs.withdrawn { + select { + case <-sub.done: + delete(api.subs.withdrawn, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcCustomers_Charged { + api.mu.Lock() + for i, sub := range api.subs.charged { + select { + case <-sub.done: + delete(api.subs.charged, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcCustomers_BucketCreated { + api.mu.Lock() + for i, sub := range api.subs.bucketCreated { + select { + case <-sub.done: + delete(api.subs.bucketCreated, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcCustomers_BucketUpdated { + api.mu.Lock() + for i, sub := range api.subs.bucketUpdated { + select { + case <-sub.done: + delete(api.subs.bucketUpdated, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + } + }() + + return api } func (api *ddcCustomersApi) GetBuckets(bucketId BucketId) (types.Option[Bucket], error) { From 0214d43aca335fb85cafdda4dbb344f9c5ddf796 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Wed, 3 Jan 2024 18:17:17 +0600 Subject: [PATCH 23/32] Add `ddc-customers` events subscription --- blockchain/pallets/ddccustomers.go | 187 +++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) diff --git a/blockchain/pallets/ddccustomers.go b/blockchain/pallets/ddccustomers.go index ff57a8e..8b2c2fe 100644 --- a/blockchain/pallets/ddccustomers.go +++ b/blockchain/pallets/ddccustomers.go @@ -1,6 +1,7 @@ package pallets import ( + "math" "sync" gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4" @@ -249,3 +250,189 @@ func (api *ddcCustomersApi) GetLedger(owner types.AccountID) (types.Option[Accou return maybeLedger, nil } + +func (api *ddcCustomersApi) SubscribeNewDeposited() (*NewEventSubscription[EventDdcCustomersDeposited], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.deposited == nil { + api.subs.deposited = make(map[int]subscriber[EventDdcCustomersDeposited]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.deposited[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcCustomersDeposited) + done := make(chan struct{}) + api.subs.deposited[idx] = subscriber[EventDdcCustomersDeposited]{ch, done} + + return &NewEventSubscription[EventDdcCustomersDeposited]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.deposited, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcCustomersApi) SubscribeNewInitialDepositUnlock() (*NewEventSubscription[EventDdcCustomersInitialDepositUnlock], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.initialDepositUnlock == nil { + api.subs.initialDepositUnlock = make(map[int]subscriber[EventDdcCustomersInitialDepositUnlock]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.initialDepositUnlock[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcCustomersInitialDepositUnlock) + done := make(chan struct{}) + api.subs.initialDepositUnlock[idx] = subscriber[EventDdcCustomersInitialDepositUnlock]{ch, done} + + return &NewEventSubscription[EventDdcCustomersInitialDepositUnlock]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.initialDepositUnlock, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcCustomersApi) SubscribeNewWithdrawn() (*NewEventSubscription[EventDdcCustomersWithdrawn], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.withdrawn == nil { + api.subs.withdrawn = make(map[int]subscriber[EventDdcCustomersWithdrawn]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.withdrawn[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcCustomersWithdrawn) + done := make(chan struct{}) + api.subs.withdrawn[idx] = subscriber[EventDdcCustomersWithdrawn]{ch, done} + + return &NewEventSubscription[EventDdcCustomersWithdrawn]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.withdrawn, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcCustomersApi) SubscribeNewCharged() (*NewEventSubscription[EventDdcCustomersCharged], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.charged == nil { + api.subs.charged = make(map[int]subscriber[EventDdcCustomersCharged]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.charged[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcCustomersCharged) + done := make(chan struct{}) + api.subs.charged[idx] = subscriber[EventDdcCustomersCharged]{ch, done} + + return &NewEventSubscription[EventDdcCustomersCharged]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.charged, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcCustomersApi) SubscribeNewBucketCreated() (*NewEventSubscription[EventDdcCustomersBucketCreated], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.bucketCreated == nil { + api.subs.bucketCreated = make(map[int]subscriber[EventDdcCustomersBucketCreated]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.bucketCreated[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcCustomersBucketCreated) + done := make(chan struct{}) + api.subs.bucketCreated[idx] = subscriber[EventDdcCustomersBucketCreated]{ch, done} + + return &NewEventSubscription[EventDdcCustomersBucketCreated]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.bucketCreated, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcCustomersApi) SubscribeNewBucketUpdated() (*NewEventSubscription[EventDdcCustomersBucketUpdated], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.bucketUpdated == nil { + api.subs.bucketUpdated = make(map[int]subscriber[EventDdcCustomersBucketUpdated]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.bucketUpdated[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcCustomersBucketUpdated) + done := make(chan struct{}) + api.subs.bucketUpdated[idx] = subscriber[EventDdcCustomersBucketUpdated]{ch, done} + + return &NewEventSubscription[EventDdcCustomersBucketUpdated]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.bucketUpdated, idx) + api.mu.Unlock() + }, + }, nil +} From daae22b09c18e8c772e0a73f9161094c9be7120b Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Wed, 3 Jan 2024 18:20:00 +0600 Subject: [PATCH 24/32] Pass block events to `ddc-customers` subscribers --- blockchain/client.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/blockchain/client.go b/blockchain/client.go index 14b287c..4881fe7 100644 --- a/blockchain/client.go +++ b/blockchain/client.go @@ -33,6 +33,7 @@ func NewClient(url string) (*Client, error) { subs := make(map[string]chan *pallets.Events) subs["DdcClusters"] = make(chan *pallets.Events) + subs["DdcCustomers"] = make(chan *pallets.Events) return &Client{ SubstrateAPI: substrateApi, @@ -41,7 +42,7 @@ func NewClient(url string) (*Client, error) { substrateApi, subs["DdcClusters"], ), - DdcCustomers: pallets.NewDdcCustomersApi(substrateApi, meta), + DdcCustomers: pallets.NewDdcCustomersApi(substrateApi, meta, subs["DdcCustomers"]), DdcNodes: pallets.NewDdcNodesApi(substrateApi, meta), DdcPayouts: pallets.NewDdcPayoutsApi(substrateApi, meta), }, nil From ccc8ddcf4109d9d59f485d942988775cb323357b Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Wed, 3 Jan 2024 18:59:59 +0600 Subject: [PATCH 25/32] Add `pallet-ddc-payouts` event types --- blockchain/pallets/ddcpayouts.go | 118 +++++++++++++++++++++++++++++++ blockchain/pallets/events.go | 15 ++++ 2 files changed, 133 insertions(+) diff --git a/blockchain/pallets/ddcpayouts.go b/blockchain/pallets/ddcpayouts.go index 637b132..287b442 100644 --- a/blockchain/pallets/ddcpayouts.go +++ b/blockchain/pallets/ddcpayouts.go @@ -90,6 +90,124 @@ func (m State) Encode(encoder scale.Encoder) error { return nil } +// Events +type ( + EventDdcPayoutsBillingReportInitialized struct { + Phase types.Phase + ClusterId ClusterId + Topics []types.Hash + } + + EventDdcPayoutsChargingStarted struct { + Phase types.Phase + ClusterId ClusterId + Era DdcEra + Topics []types.Hash + } + + EventDdcPayoutsCharged struct { + Phase types.Phase + ClusterId ClusterId + Era DdcEra + BatchIndex BatchIndex + CustomerId types.AccountID + Amount types.U128 + Topics []types.Hash + } + + EventDdcPayoutsChargeFailed struct { + Phase types.Phase + ClusterId ClusterId + Era DdcEra + BatchIndex BatchIndex + CustomerId types.AccountID + Amount types.U128 + Topics []types.Hash + } + + EventDdcPayoutsIndebted struct { + Phase types.Phase + ClusterId ClusterId + Era DdcEra + BatchIndex BatchIndex + CustomerId types.AccountID + Amount types.U128 + Topics []types.Hash + } + + EventDdcPayoutsChargingFinished struct { + Phase types.Phase + ClusterId ClusterId + Era DdcEra + Topics []types.Hash + } + + EventDdcPayoutsTreasuryFeesCollected struct { + Phase types.Phase + ClusterId ClusterId + Era DdcEra + Topics []types.Hash + } + + EventDdcPayoutsClusterReserveFeesCollected struct { + Phase types.Phase + ClusterId ClusterId + Era DdcEra + Amount types.U128 + Topics []types.Hash + } + + EventDdcPayoutsValidatorFeesCollected struct { + Phase types.Phase + ClusterId ClusterId + Era DdcEra + Amount types.U128 + Topics []types.Hash + } + + EventDdcPayoutsRewardingStarted struct { + Phase types.Phase + ClusterId ClusterId + Era DdcEra + Topics []types.Hash + } + + EventDdcPayouts struct { + Phase types.Phase + ClusterId ClusterId + Topics []types.Hash + } + + EventDdcPayoutsRewarded struct { + Phase types.Phase + ClusterId ClusterId + Era DdcEra + NodeProviderId types.AccountID + Amount types.U128 + Topics []types.Hash + } + + EventDdcPayoutsRewardingFinished struct { + Phase types.Phase + ClusterId ClusterId + Era DdcEra + Topics []types.Hash + } + + EventDdcPayoutsBillingReportFinalized struct { + Phase types.Phase + ClusterId ClusterId + Era DdcEra + Topics []types.Hash + } + + EventDdcPayoutsAuthorisedCaller struct { + Phase types.Phase + AuthorisedCaller types.AccountID + Topics []types.Hash + } +) + type DdcPayoutsApi interface { GetActiveBillingReports(cluster ClusterId, era DdcEra) (types.Option[BillingReport], error) GetAuthorisedCaller() (types.Option[types.AccountID], error) diff --git a/blockchain/pallets/events.go b/blockchain/pallets/events.go index d665785..193c958 100644 --- a/blockchain/pallets/events.go +++ b/blockchain/pallets/events.go @@ -21,6 +21,21 @@ type Events struct { DdcCustomers_Charged []EventDdcCustomersCharged //nolint:stylecheck,golint DdcCustomers_BucketCreated []EventDdcCustomersBucketCreated //nolint:stylecheck,golint DdcCustomers_BucketUpdated []EventDdcCustomersBucketUpdated //nolint:stylecheck,golint + + DdcPayouts_BillingReportInitialized []EventDdcPayoutsBillingReportInitialized //nolint:stylecheck,golint + DdcPayouts_ChargingStarted []EventDdcPayoutsChargingStarted //nolint:stylecheck,golint + DdcPayouts_Charged []EventDdcPayoutsCharged //nolint:stylecheck,golint + DdcPayouts_ChargeFailed []EventDdcPayoutsChargeFailed //nolint:stylecheck,golint + DdcPayouts_Indebted []EventDdcPayoutsIndebted //nolint:stylecheck,golint + DdcPayouts_ChargingFinished []EventDdcPayoutsChargingFinished //nolint:stylecheck,golint + DdcPayouts_TreasuryFeesCollected []EventDdcPayoutsTreasuryFeesCollected //nolint:stylecheck,golint + DdcPayouts_ClusterReserveFeesCollected []EventDdcPayoutsClusterReserveFeesCollected //nolint:stylecheck,golint + DdcPayouts_ValidatorFeesCollected []EventDdcPayoutsValidatorFeesCollected //nolint:stylecheck,golint + DdcPayouts_RewardingStarted []EventDdcPayoutsRewardingStarted //nolint:stylecheck,golint + DdcPayouts_Rewarded []EventDdcPayoutsRewarded //nolint:stylecheck,golint + DdcPayouts_RewardingFinished []EventDdcPayoutsRewardingFinished //nolint:stylecheck,golint + DdcPayouts_BillingReportFinalized []EventDdcPayoutsBillingReportFinalized //nolint:stylecheck,golint + DdcPayouts_AuthorisedCaller []EventDdcPayoutsAuthorisedCaller //nolint:stylecheck,golint } type NewEventSubscription[T any] struct { From edda19824108f451eb99f012db9ea50a85f57b59 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Thu, 4 Jan 2024 11:31:37 +0600 Subject: [PATCH 26/32] Add `ddc-payouts` events subscription --- blockchain/pallets/ddcpayouts.go | 657 ++++++++++++++++++++++++++++++- 1 file changed, 653 insertions(+), 4 deletions(-) diff --git a/blockchain/pallets/ddcpayouts.go b/blockchain/pallets/ddcpayouts.go index 287b442..2a07730 100644 --- a/blockchain/pallets/ddcpayouts.go +++ b/blockchain/pallets/ddcpayouts.go @@ -1,7 +1,9 @@ package pallets import ( + "math" "reflect" + "sync" gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4" "github.com/centrifuge/go-substrate-rpc-client/v4/scale" @@ -214,16 +216,229 @@ type DdcPayoutsApi interface { GetDebtorCustomers(cluster ClusterId, account types.AccountID) (types.Option[types.U128], error) } +type ddcPayoutsEventsSubs struct { + billingReportInitialized map[int]subscriber[EventDdcPayoutsBillingReportInitialized] + chargingStarted map[int]subscriber[EventDdcPayoutsChargingStarted] + charged map[int]subscriber[EventDdcPayoutsCharged] + chargeFailed map[int]subscriber[EventDdcPayoutsChargeFailed] + indebted map[int]subscriber[EventDdcPayoutsIndebted] + chargingFinished map[int]subscriber[EventDdcPayoutsChargingFinished] + treasuryFeesCollected map[int]subscriber[EventDdcPayoutsTreasuryFeesCollected] + clusterReserveFeesCollected map[int]subscriber[EventDdcPayoutsClusterReserveFeesCollected] + validatorFeesCollected map[int]subscriber[EventDdcPayoutsValidatorFeesCollected] + rewardingStarted map[int]subscriber[EventDdcPayoutsRewardingStarted] + rewarded map[int]subscriber[EventDdcPayoutsRewarded] + rewardingFinished map[int]subscriber[EventDdcPayoutsRewardingFinished] + billingReportFinalized map[int]subscriber[EventDdcPayoutsBillingReportFinalized] + authorisedCaller map[int]subscriber[EventDdcPayoutsAuthorisedCaller] +} + type ddcPayoutsApi struct { substrateApi *gsrpc.SubstrateAPI meta *types.Metadata + + subs *ddcPayoutsEventsSubs + mu sync.Mutex } -func NewDdcPayoutsApi(substrateAPI *gsrpc.SubstrateAPI, meta *types.Metadata) DdcPayoutsApi { - return &ddcPayoutsApi{ - substrateAPI, - meta, +func NewDdcPayoutsApi(substrateAPI *gsrpc.SubstrateAPI, meta *types.Metadata, events <-chan *Events) DdcPayoutsApi { + subs := &ddcPayoutsEventsSubs{ + billingReportInitialized: make(map[int]subscriber[EventDdcPayoutsBillingReportInitialized]), + chargingStarted: make(map[int]subscriber[EventDdcPayoutsChargingStarted]), + charged: make(map[int]subscriber[EventDdcPayoutsCharged]), + chargeFailed: make(map[int]subscriber[EventDdcPayoutsChargeFailed]), + indebted: make(map[int]subscriber[EventDdcPayoutsIndebted]), + chargingFinished: make(map[int]subscriber[EventDdcPayoutsChargingFinished]), + treasuryFeesCollected: make(map[int]subscriber[EventDdcPayoutsTreasuryFeesCollected]), + clusterReserveFeesCollected: make(map[int]subscriber[EventDdcPayoutsClusterReserveFeesCollected]), + validatorFeesCollected: make(map[int]subscriber[EventDdcPayoutsValidatorFeesCollected]), + rewardingStarted: make(map[int]subscriber[EventDdcPayoutsRewardingStarted]), + rewarded: make(map[int]subscriber[EventDdcPayoutsRewarded]), + rewardingFinished: make(map[int]subscriber[EventDdcPayoutsRewardingFinished]), + billingReportFinalized: make(map[int]subscriber[EventDdcPayoutsBillingReportFinalized]), + authorisedCaller: make(map[int]subscriber[EventDdcPayoutsAuthorisedCaller]), + } + + api := &ddcPayoutsApi{ + substrateApi: substrateAPI, + meta: meta, + subs: subs, + mu: sync.Mutex{}, } + + go func() { + for blockEvents := range events { + for _, e := range blockEvents.DdcPayouts_BillingReportInitialized { + api.mu.Lock() + for i, sub := range api.subs.billingReportInitialized { + select { + case <-sub.done: + delete(api.subs.billingReportInitialized, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcPayouts_ChargingStarted { + api.mu.Lock() + for i, sub := range api.subs.chargingStarted { + select { + case <-sub.done: + delete(api.subs.chargingStarted, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcPayouts_Charged { + api.mu.Lock() + for i, sub := range api.subs.charged { + select { + case <-sub.done: + delete(api.subs.charged, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcPayouts_ChargeFailed { + api.mu.Lock() + for i, sub := range api.subs.chargeFailed { + select { + case <-sub.done: + delete(api.subs.chargeFailed, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcPayouts_Indebted { + api.mu.Lock() + for i, sub := range api.subs.indebted { + select { + case <-sub.done: + delete(api.subs.indebted, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcPayouts_ChargingFinished { + api.mu.Lock() + for i, sub := range api.subs.chargingFinished { + select { + case <-sub.done: + delete(api.subs.chargingFinished, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcPayouts_TreasuryFeesCollected { + api.mu.Lock() + for i, sub := range api.subs.treasuryFeesCollected { + select { + case <-sub.done: + delete(api.subs.treasuryFeesCollected, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcPayouts_ClusterReserveFeesCollected { + api.mu.Lock() + for i, sub := range api.subs.clusterReserveFeesCollected { + select { + case <-sub.done: + delete(api.subs.clusterReserveFeesCollected, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcPayouts_ValidatorFeesCollected { + api.mu.Lock() + for i, sub := range api.subs.validatorFeesCollected { + select { + case <-sub.done: + delete(api.subs.validatorFeesCollected, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcPayouts_RewardingStarted { + api.mu.Lock() + for i, sub := range api.subs.rewardingStarted { + select { + case <-sub.done: + delete(api.subs.rewardingStarted, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcPayouts_Rewarded { + api.mu.Lock() + for i, sub := range api.subs.rewarded { + select { + case <-sub.done: + delete(api.subs.rewarded, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcPayouts_RewardingFinished { + api.mu.Lock() + for i, sub := range api.subs.rewardingFinished { + select { + case <-sub.done: + delete(api.subs.rewardingFinished, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcPayouts_BillingReportFinalized { + api.mu.Lock() + for i, sub := range api.subs.billingReportFinalized { + select { + case <-sub.done: + delete(api.subs.billingReportFinalized, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcPayouts_AuthorisedCaller { + api.mu.Lock() + for i, sub := range api.subs.authorisedCaller { + select { + case <-sub.done: + delete(api.subs.authorisedCaller, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + } + }() + + return api } func (api *ddcPayoutsApi) GetActiveBillingReports(cluster ClusterId, era DdcEra) (types.Option[BillingReport], error) { @@ -302,3 +517,437 @@ func (api *ddcPayoutsApi) GetDebtorCustomers(cluster ClusterId, account types.Ac return maybeV, nil } + +func (api *ddcPayoutsApi) SubscribeNewBillingReportInitialized() (*NewEventSubscription[EventDdcPayoutsBillingReportInitialized], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.billingReportInitialized == nil { + api.subs.billingReportInitialized = make(map[int]subscriber[EventDdcPayoutsBillingReportInitialized]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.billingReportInitialized[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcPayoutsBillingReportInitialized) + done := make(chan struct{}) + api.subs.billingReportInitialized[idx] = subscriber[EventDdcPayoutsBillingReportInitialized]{ch, done} + + return &NewEventSubscription[EventDdcPayoutsBillingReportInitialized]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.billingReportInitialized, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcPayoutsApi) SubscribeNewChargingStarted() (*NewEventSubscription[EventDdcPayoutsChargingStarted], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.chargingStarted == nil { + api.subs.chargingStarted = make(map[int]subscriber[EventDdcPayoutsChargingStarted]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.chargingStarted[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcPayoutsChargingStarted) + done := make(chan struct{}) + api.subs.chargingStarted[idx] = subscriber[EventDdcPayoutsChargingStarted]{ch, done} + + return &NewEventSubscription[EventDdcPayoutsChargingStarted]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.chargingStarted, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcPayoutsApi) SubscribeNewCharged() (*NewEventSubscription[EventDdcPayoutsCharged], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.charged == nil { + api.subs.charged = make(map[int]subscriber[EventDdcPayoutsCharged]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.charged[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcPayoutsCharged) + done := make(chan struct{}) + api.subs.charged[idx] = subscriber[EventDdcPayoutsCharged]{ch, done} + + return &NewEventSubscription[EventDdcPayoutsCharged]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.charged, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcPayoutsApi) SubscribeNewChargeFailed() (*NewEventSubscription[EventDdcPayoutsChargeFailed], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.chargeFailed == nil { + api.subs.chargeFailed = make(map[int]subscriber[EventDdcPayoutsChargeFailed]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.chargeFailed[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcPayoutsChargeFailed) + done := make(chan struct{}) + api.subs.chargeFailed[idx] = subscriber[EventDdcPayoutsChargeFailed]{ch, done} + + return &NewEventSubscription[EventDdcPayoutsChargeFailed]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.chargeFailed, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcPayoutsApi) SubscribeNewIndebted() (*NewEventSubscription[EventDdcPayoutsIndebted], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.indebted == nil { + api.subs.indebted = make(map[int]subscriber[EventDdcPayoutsIndebted]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.indebted[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcPayoutsIndebted) + done := make(chan struct{}) + api.subs.indebted[idx] = subscriber[EventDdcPayoutsIndebted]{ch, done} + + return &NewEventSubscription[EventDdcPayoutsIndebted]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.indebted, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcPayoutsApi) SubscribeNewChargingFinished() (*NewEventSubscription[EventDdcPayoutsChargingFinished], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.chargingFinished == nil { + api.subs.chargingFinished = make(map[int]subscriber[EventDdcPayoutsChargingFinished]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.chargingFinished[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcPayoutsChargingFinished) + done := make(chan struct{}) + api.subs.chargingFinished[idx] = subscriber[EventDdcPayoutsChargingFinished]{ch, done} + + return &NewEventSubscription[EventDdcPayoutsChargingFinished]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.chargingFinished, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcPayoutsApi) SubscribeNewTreasuryFeesCollected() (*NewEventSubscription[EventDdcPayoutsTreasuryFeesCollected], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.treasuryFeesCollected == nil { + api.subs.treasuryFeesCollected = make(map[int]subscriber[EventDdcPayoutsTreasuryFeesCollected]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.treasuryFeesCollected[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcPayoutsTreasuryFeesCollected) + done := make(chan struct{}) + api.subs.treasuryFeesCollected[idx] = subscriber[EventDdcPayoutsTreasuryFeesCollected]{ch, done} + + return &NewEventSubscription[EventDdcPayoutsTreasuryFeesCollected]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.treasuryFeesCollected, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcPayoutsApi) SubscribeNewClusterReserveFeesCollected() (*NewEventSubscription[EventDdcPayoutsClusterReserveFeesCollected], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.clusterReserveFeesCollected == nil { + api.subs.clusterReserveFeesCollected = make(map[int]subscriber[EventDdcPayoutsClusterReserveFeesCollected]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.clusterReserveFeesCollected[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcPayoutsClusterReserveFeesCollected) + done := make(chan struct{}) + api.subs.clusterReserveFeesCollected[idx] = subscriber[EventDdcPayoutsClusterReserveFeesCollected]{ch, done} + + return &NewEventSubscription[EventDdcPayoutsClusterReserveFeesCollected]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.clusterReserveFeesCollected, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcPayoutsApi) SubscribeNewValidatorFeesCollected() (*NewEventSubscription[EventDdcPayoutsValidatorFeesCollected], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.validatorFeesCollected == nil { + api.subs.validatorFeesCollected = make(map[int]subscriber[EventDdcPayoutsValidatorFeesCollected]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.validatorFeesCollected[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcPayoutsValidatorFeesCollected) + done := make(chan struct{}) + api.subs.validatorFeesCollected[idx] = subscriber[EventDdcPayoutsValidatorFeesCollected]{ch, done} + + return &NewEventSubscription[EventDdcPayoutsValidatorFeesCollected]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.validatorFeesCollected, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcPayoutsApi) SubscribeNewRewardingStarted() (*NewEventSubscription[EventDdcPayoutsRewardingStarted], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.rewardingStarted == nil { + api.subs.rewardingStarted = make(map[int]subscriber[EventDdcPayoutsRewardingStarted]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.rewardingStarted[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcPayoutsRewardingStarted) + done := make(chan struct{}) + api.subs.rewardingStarted[idx] = subscriber[EventDdcPayoutsRewardingStarted]{ch, done} + + return &NewEventSubscription[EventDdcPayoutsRewardingStarted]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.rewardingStarted, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcPayoutsApi) SubscribeNewRewarded() (*NewEventSubscription[EventDdcPayoutsRewarded], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.rewarded == nil { + api.subs.rewarded = make(map[int]subscriber[EventDdcPayoutsRewarded]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.rewarded[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcPayoutsRewarded) + done := make(chan struct{}) + api.subs.rewarded[idx] = subscriber[EventDdcPayoutsRewarded]{ch, done} + + return &NewEventSubscription[EventDdcPayoutsRewarded]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.rewarded, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcPayoutsApi) SubscribeNewRewardingFinished() (*NewEventSubscription[EventDdcPayoutsRewardingFinished], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.rewardingFinished == nil { + api.subs.rewardingFinished = make(map[int]subscriber[EventDdcPayoutsRewardingFinished]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.rewardingFinished[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcPayoutsRewardingFinished) + done := make(chan struct{}) + api.subs.rewardingFinished[idx] = subscriber[EventDdcPayoutsRewardingFinished]{ch, done} + + return &NewEventSubscription[EventDdcPayoutsRewardingFinished]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.rewardingFinished, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcPayoutsApi) SubscribeNewBillingReportFinalized() (*NewEventSubscription[EventDdcPayoutsBillingReportFinalized], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.billingReportFinalized == nil { + api.subs.billingReportFinalized = make(map[int]subscriber[EventDdcPayoutsBillingReportFinalized]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.billingReportFinalized[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcPayoutsBillingReportFinalized) + done := make(chan struct{}) + api.subs.billingReportFinalized[idx] = subscriber[EventDdcPayoutsBillingReportFinalized]{ch, done} + + return &NewEventSubscription[EventDdcPayoutsBillingReportFinalized]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.billingReportFinalized, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcPayoutsApi) SubscribeNewAuthorisedCaller() (*NewEventSubscription[EventDdcPayoutsAuthorisedCaller], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.authorisedCaller == nil { + api.subs.authorisedCaller = make(map[int]subscriber[EventDdcPayoutsAuthorisedCaller]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.authorisedCaller[i]; !ok { + idx = i + break + } + } + + ch := make(chan EventDdcPayoutsAuthorisedCaller) + done := make(chan struct{}) + api.subs.authorisedCaller[idx] = subscriber[EventDdcPayoutsAuthorisedCaller]{ch, done} + + return &NewEventSubscription[EventDdcPayoutsAuthorisedCaller]{ + ch: ch, + done: done, + onDone: func() { + api.mu.Lock() + delete(api.subs.authorisedCaller, idx) + api.mu.Unlock() + }, + }, nil +} From 4d6a0453b7f16d00249d01a8e8a8fb1a0772bb0b Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Thu, 4 Jan 2024 11:32:00 +0600 Subject: [PATCH 27/32] Pass block events to `ddc-payouts` subscribers --- blockchain/client.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/blockchain/client.go b/blockchain/client.go index 4881fe7..fae69dd 100644 --- a/blockchain/client.go +++ b/blockchain/client.go @@ -34,6 +34,7 @@ func NewClient(url string) (*Client, error) { subs := make(map[string]chan *pallets.Events) subs["DdcClusters"] = make(chan *pallets.Events) subs["DdcCustomers"] = make(chan *pallets.Events) + subs["DdcPayouts"] = make(chan *pallets.Events) return &Client{ SubstrateAPI: substrateApi, @@ -44,7 +45,7 @@ func NewClient(url string) (*Client, error) { ), DdcCustomers: pallets.NewDdcCustomersApi(substrateApi, meta, subs["DdcCustomers"]), DdcNodes: pallets.NewDdcNodesApi(substrateApi, meta), - DdcPayouts: pallets.NewDdcPayoutsApi(substrateApi, meta), + DdcPayouts: pallets.NewDdcPayoutsApi(substrateApi, meta, subs["DdcPayouts"]), }, nil } From 40ca238a6fd312cb5e85100142ed2a0ac232926a Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Thu, 4 Jan 2024 11:34:23 +0600 Subject: [PATCH 28/32] Unify parameter naming --- blockchain/pallets/ddccustomers.go | 4 ++-- blockchain/pallets/ddcnodes.go | 4 ++-- blockchain/pallets/ddcpayouts.go | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/blockchain/pallets/ddccustomers.go b/blockchain/pallets/ddccustomers.go index 8b2c2fe..6577343 100644 --- a/blockchain/pallets/ddccustomers.go +++ b/blockchain/pallets/ddccustomers.go @@ -89,7 +89,7 @@ type ddcCustomersApi struct { mu sync.Mutex } -func NewDdcCustomersApi(substrateAPI *gsrpc.SubstrateAPI, meta *types.Metadata, events <-chan *Events) DdcCustomersApi { +func NewDdcCustomersApi(substrateApi *gsrpc.SubstrateAPI, meta *types.Metadata, events <-chan *Events) DdcCustomersApi { subs := &ddcCustomersEventsSubs{ deposited: make(map[int]subscriber[EventDdcCustomersDeposited]), initialDepositUnlock: make(map[int]subscriber[EventDdcCustomersInitialDepositUnlock]), @@ -100,7 +100,7 @@ func NewDdcCustomersApi(substrateAPI *gsrpc.SubstrateAPI, meta *types.Metadata, } api := &ddcCustomersApi{ - substrateApi: substrateAPI, + substrateApi: substrateApi, meta: meta, subs: subs, mu: sync.Mutex{}, diff --git a/blockchain/pallets/ddcnodes.go b/blockchain/pallets/ddcnodes.go index 481865b..be73372 100644 --- a/blockchain/pallets/ddcnodes.go +++ b/blockchain/pallets/ddcnodes.go @@ -40,9 +40,9 @@ type ddcNodesApi struct { meta *types.Metadata } -func NewDdcNodesApi(substrateAPI *gsrpc.SubstrateAPI, meta *types.Metadata) DdcNodesApi { +func NewDdcNodesApi(substrateApi *gsrpc.SubstrateAPI, meta *types.Metadata) DdcNodesApi { return &ddcNodesApi{ - substrateAPI, + substrateApi, meta, } } diff --git a/blockchain/pallets/ddcpayouts.go b/blockchain/pallets/ddcpayouts.go index 2a07730..ed273c1 100644 --- a/blockchain/pallets/ddcpayouts.go +++ b/blockchain/pallets/ddcpayouts.go @@ -241,7 +241,7 @@ type ddcPayoutsApi struct { mu sync.Mutex } -func NewDdcPayoutsApi(substrateAPI *gsrpc.SubstrateAPI, meta *types.Metadata, events <-chan *Events) DdcPayoutsApi { +func NewDdcPayoutsApi(substrateApi *gsrpc.SubstrateAPI, meta *types.Metadata, events <-chan *Events) DdcPayoutsApi { subs := &ddcPayoutsEventsSubs{ billingReportInitialized: make(map[int]subscriber[EventDdcPayoutsBillingReportInitialized]), chargingStarted: make(map[int]subscriber[EventDdcPayoutsChargingStarted]), @@ -260,7 +260,7 @@ func NewDdcPayoutsApi(substrateAPI *gsrpc.SubstrateAPI, meta *types.Metadata, ev } api := &ddcPayoutsApi{ - substrateApi: substrateAPI, + substrateApi: substrateApi, meta: meta, subs: subs, mu: sync.Mutex{}, From c0f64b73476b44e627c7464ce10c7b9a87c8df16 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Thu, 4 Jan 2024 11:36:20 +0600 Subject: [PATCH 29/32] Implement remaining events subs for `ddc-clusters` --- blockchain/pallets/ddcclusters.go | 147 ++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/blockchain/pallets/ddcclusters.go b/blockchain/pallets/ddcclusters.go index 23160b5..fe8fbcc 100644 --- a/blockchain/pallets/ddcclusters.go +++ b/blockchain/pallets/ddcclusters.go @@ -132,6 +132,42 @@ func NewDdcClustersApi( } api.mu.Unlock() } + + for _, e := range blockEvents.DdcClusters_ClusterNodeRemoved { + api.mu.Lock() + for i, sub := range api.subs.clusterNodeRemoved { + select { + case <-sub.done: + delete(api.subs.clusterNodeRemoved, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcClusters_ClusterParamsSet { + api.mu.Lock() + for i, sub := range api.subs.clusterParamsSet { + select { + case <-sub.done: + delete(api.subs.clusterParamsSet, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } + + for _, e := range blockEvents.DdcClusters_ClusterGovParamsSet { + api.mu.Lock() + for i, sub := range api.subs.clusterGovParamsSet { + select { + case <-sub.done: + delete(api.subs.clusterGovParamsSet, i) + case sub.ch <- e: + } + } + api.mu.Unlock() + } } }() @@ -253,3 +289,114 @@ func (api *ddcClustersApi) SubscribeNewClusterNodeAdded() (*NewEventSubscription }, }, nil } + +func (api *ddcClustersApi) SubscribeNewClusterNodeRemoved() (*NewEventSubscription[EventDdcClustersClusterNodeRemoved], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.clusterNodeRemoved == nil { + api.subs.clusterNodeRemoved = make(map[int]subscriber[EventDdcClustersClusterNodeRemoved]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.clusterNodeRemoved[i]; !ok { + idx = i + break + } + if i == math.MaxInt { + return nil, fmt.Errorf("can't create %d+1 subscriber", len(api.subs.clusterNodeRemoved)) + } + } + + sub := subscriber[EventDdcClustersClusterNodeRemoved]{ + ch: make(chan EventDdcClustersClusterNodeRemoved), + done: make(chan struct{}), + } + + api.subs.clusterNodeRemoved[idx] = sub + + return &NewEventSubscription[EventDdcClustersClusterNodeRemoved]{ + ch: sub.ch, + done: sub.done, + onDone: func() { + api.mu.Lock() + delete(api.subs.clusterNodeRemoved, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcClustersApi) SubscribeNewClusterParamsSet() (*NewEventSubscription[EventDdcClustersClusterParamsSet], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.clusterParamsSet == nil { + api.subs.clusterParamsSet = make(map[int]subscriber[EventDdcClustersClusterParamsSet]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.clusterParamsSet[i]; !ok { + idx = i + break + } + if i == math.MaxInt { + return nil, fmt.Errorf("can't create %d+1 subscriber", len(api.subs.clusterParamsSet)) + } + } + + sub := subscriber[EventDdcClustersClusterParamsSet]{ + ch: make(chan EventDdcClustersClusterParamsSet), + done: make(chan struct{}), + } + + api.subs.clusterParamsSet[idx] = sub + + return &NewEventSubscription[EventDdcClustersClusterParamsSet]{ + ch: sub.ch, + done: sub.done, + onDone: func() { + api.mu.Lock() + delete(api.subs.clusterParamsSet, idx) + api.mu.Unlock() + }, + }, nil +} + +func (api *ddcClustersApi) SubscribeNewClusterGovParamsSet() (*NewEventSubscription[EventDdcClustersClusterGovParamsSet], error) { + api.mu.Lock() + defer api.mu.Unlock() + + if api.subs.clusterGovParamsSet == nil { + api.subs.clusterGovParamsSet = make(map[int]subscriber[EventDdcClustersClusterGovParamsSet]) + } + + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := api.subs.clusterGovParamsSet[i]; !ok { + idx = i + break + } + if i == math.MaxInt { + return nil, fmt.Errorf("can't create %d+1 subscriber", len(api.subs.clusterGovParamsSet)) + } + } + + sub := subscriber[EventDdcClustersClusterGovParamsSet]{ + ch: make(chan EventDdcClustersClusterGovParamsSet), + done: make(chan struct{}), + } + + api.subs.clusterGovParamsSet[idx] = sub + + return &NewEventSubscription[EventDdcClustersClusterGovParamsSet]{ + ch: sub.ch, + done: sub.done, + onDone: func() { + api.mu.Lock() + delete(api.subs.clusterGovParamsSet, idx) + api.mu.Unlock() + }, + }, nil +} From 3abdee1ba89389d8cba0ba4e24e0e356367266aa Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Fri, 5 Jan 2024 12:53:12 +0600 Subject: [PATCH 30/32] Callbacks based blockchain events listener --- blockchain/client.go | 46 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/blockchain/client.go b/blockchain/client.go index fae69dd..5fc121d 100644 --- a/blockchain/client.go +++ b/blockchain/client.go @@ -2,6 +2,7 @@ package blockchain import ( "fmt" + "math" "sync" gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4" @@ -11,9 +12,13 @@ import ( "github.com/cerebellum-network/cere-ddc-sdk-go/blockchain/pallets" ) +type EventsListener func(*pallets.Events) + type Client struct { *gsrpc.SubstrateAPI - subs map[string]chan *pallets.Events + subs map[string]chan *pallets.Events + eventsListeners map[int]EventsListener + mu sync.Mutex DdcClusters pallets.DdcClustersApi DdcCustomers pallets.DdcCustomersApi @@ -37,8 +42,9 @@ func NewClient(url string) (*Client, error) { subs["DdcPayouts"] = make(chan *pallets.Events) return &Client{ - SubstrateAPI: substrateApi, - subs: subs, + SubstrateAPI: substrateApi, + subs: subs, + eventsListeners: make(map[int]EventsListener), DdcClusters: pallets.NewDdcClustersApi( substrateApi, subs["DdcClusters"], @@ -80,11 +86,11 @@ func (c *Client) StartEventsListening() (func(), <-chan error, error) { events := &pallets.Events{} err = types.EventRecordsRaw(change.StorageData).DecodeEventRecords(meta, events) if err != nil { - errCh <- fmt.Errorf("events listener: %w", err) + errCh <- fmt.Errorf("events decoder: %w", err) } - for _, module := range c.subs { - module <- events + for _, callback := range c.eventsListeners { + go callback(events) } } } @@ -101,3 +107,31 @@ func (c *Client) StartEventsListening() (func(), <-chan error, error) { return stop, errCh, nil } + +func (c *Client) RegisterEventsListener(callback EventsListener) (func(), error) { + var idx int + for i := 0; i <= math.MaxInt; i++ { + if _, ok := c.eventsListeners[i]; !ok { + idx = i + break + } + if i == math.MaxInt { + return nil, fmt.Errorf("too many events listeners") + } + } + + c.mu.Lock() + c.eventsListeners[idx] = callback + c.mu.Unlock() + + once := sync.Once{} + stop := func() { + once.Do(func() { + c.mu.Lock() + delete(c.eventsListeners, idx) + c.mu.Unlock() + }) + } + + return stop, nil +} From 2966920f92e4e668dd3be0eb89be679518386de9 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Fri, 5 Jan 2024 13:09:32 +0600 Subject: [PATCH 31/32] Revert multiple commits with older events sub impl --- blockchain/client.go | 18 +- blockchain/pallets/ddcclusters.go | 285 +------------ blockchain/pallets/ddccustomers.go | 298 +------------ blockchain/pallets/ddcpayouts.go | 657 +---------------------------- blockchain/pallets/events.go | 26 -- 5 files changed, 14 insertions(+), 1270 deletions(-) diff --git a/blockchain/client.go b/blockchain/client.go index 5fc121d..a369500 100644 --- a/blockchain/client.go +++ b/blockchain/client.go @@ -16,7 +16,6 @@ type EventsListener func(*pallets.Events) type Client struct { *gsrpc.SubstrateAPI - subs map[string]chan *pallets.Events eventsListeners map[int]EventsListener mu sync.Mutex @@ -36,22 +35,13 @@ func NewClient(url string) (*Client, error) { return nil, err } - subs := make(map[string]chan *pallets.Events) - subs["DdcClusters"] = make(chan *pallets.Events) - subs["DdcCustomers"] = make(chan *pallets.Events) - subs["DdcPayouts"] = make(chan *pallets.Events) - return &Client{ SubstrateAPI: substrateApi, - subs: subs, eventsListeners: make(map[int]EventsListener), - DdcClusters: pallets.NewDdcClustersApi( - substrateApi, - subs["DdcClusters"], - ), - DdcCustomers: pallets.NewDdcCustomersApi(substrateApi, meta, subs["DdcCustomers"]), - DdcNodes: pallets.NewDdcNodesApi(substrateApi, meta), - DdcPayouts: pallets.NewDdcPayoutsApi(substrateApi, meta, subs["DdcPayouts"]), + DdcClusters: pallets.NewDdcClustersApi(substrateApi), + DdcCustomers: pallets.NewDdcCustomersApi(substrateApi, meta), + DdcNodes: pallets.NewDdcNodesApi(substrateApi, meta), + DdcPayouts: pallets.NewDdcPayoutsApi(substrateApi, meta), }, nil } diff --git a/blockchain/pallets/ddcclusters.go b/blockchain/pallets/ddcclusters.go index fe8fbcc..03dbe5c 100644 --- a/blockchain/pallets/ddcclusters.go +++ b/blockchain/pallets/ddcclusters.go @@ -1,10 +1,6 @@ package pallets import ( - "fmt" - "math" - "sync" - gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4" "github.com/centrifuge/go-substrate-rpc-client/v4/hash" "github.com/centrifuge/go-substrate-rpc-client/v4/types" @@ -62,116 +58,24 @@ type ( type DdcClustersApi interface { GetClustersNodes(clusterId ClusterId) ([]NodePubKey, error) - SubscribeNewClusterCreated() (*NewEventSubscription[EventDdcClustersClusterCreated], error) - SubscribeNewClusterNodeAdded() (*NewEventSubscription[EventDdcClustersClusterNodeAdded], error) -} - -type ddcClustersEventsSubs struct { - clusterCreated map[int]subscriber[EventDdcClustersClusterCreated] - clusterNodeAdded map[int]subscriber[EventDdcClustersClusterNodeAdded] - clusterNodeRemoved map[int]subscriber[EventDdcClustersClusterNodeRemoved] - clusterParamsSet map[int]subscriber[EventDdcClustersClusterParamsSet] - clusterGovParamsSet map[int]subscriber[EventDdcClustersClusterGovParamsSet] } type ddcClustersApi struct { substrateApi *gsrpc.SubstrateAPI clustersNodesKey []byte - - subs *ddcClustersEventsSubs - mu sync.Mutex } -func NewDdcClustersApi( - substrateApi *gsrpc.SubstrateAPI, - events <-chan *Events, -) DdcClustersApi { +func NewDdcClustersApi(substrateApi *gsrpc.SubstrateAPI) DdcClustersApi { clustersNodesKey := append( xxhash.New128([]byte("DdcClusters")).Sum(nil), xxhash.New128([]byte("ClustersNodes")).Sum(nil)..., ) - subs := &ddcClustersEventsSubs{ - clusterCreated: make(map[int]subscriber[EventDdcClustersClusterCreated]), - clusterNodeAdded: make(map[int]subscriber[EventDdcClustersClusterNodeAdded]), - clusterNodeRemoved: make(map[int]subscriber[EventDdcClustersClusterNodeRemoved]), - clusterParamsSet: make(map[int]subscriber[EventDdcClustersClusterParamsSet]), - clusterGovParamsSet: make(map[int]subscriber[EventDdcClustersClusterGovParamsSet]), - } - - api := &ddcClustersApi{ + return &ddcClustersApi{ substrateApi: substrateApi, clustersNodesKey: clustersNodesKey, - subs: subs, - mu: sync.Mutex{}, } - - go func() { - for blockEvents := range events { - for _, e := range blockEvents.DdcClusters_ClusterCreated { - api.mu.Lock() - for i, sub := range api.subs.clusterCreated { - select { - case <-sub.done: - delete(api.subs.clusterCreated, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcClusters_ClusterNodeAdded { - api.mu.Lock() - for i, sub := range api.subs.clusterNodeAdded { - select { - case <-sub.done: - delete(api.subs.clusterNodeAdded, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcClusters_ClusterNodeRemoved { - api.mu.Lock() - for i, sub := range api.subs.clusterNodeRemoved { - select { - case <-sub.done: - delete(api.subs.clusterNodeRemoved, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcClusters_ClusterParamsSet { - api.mu.Lock() - for i, sub := range api.subs.clusterParamsSet { - select { - case <-sub.done: - delete(api.subs.clusterParamsSet, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcClusters_ClusterGovParamsSet { - api.mu.Lock() - for i, sub := range api.subs.clusterGovParamsSet { - select { - case <-sub.done: - delete(api.subs.clusterGovParamsSet, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - } - }() - - return api } func (api *ddcClustersApi) GetClustersNodes(clusterId ClusterId) ([]NodePubKey, error) { @@ -215,188 +119,3 @@ func (api *ddcClustersApi) GetClustersNodes(clusterId ClusterId) ([]NodePubKey, return nodesKeys, nil } - -func (api *ddcClustersApi) SubscribeNewClusterCreated() (*NewEventSubscription[EventDdcClustersClusterCreated], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.clusterCreated == nil { - api.subs.clusterCreated = make(map[int]subscriber[EventDdcClustersClusterCreated]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.clusterCreated[i]; !ok { - idx = i - break - } - if i == math.MaxInt { - return nil, fmt.Errorf("can't create %d+1 subscriber", len(api.subs.clusterCreated)) - } - } - - sub := subscriber[EventDdcClustersClusterCreated]{ - ch: make(chan EventDdcClustersClusterCreated), - done: make(chan struct{}), - } - - api.subs.clusterCreated[idx] = sub - - return &NewEventSubscription[EventDdcClustersClusterCreated]{ - ch: sub.ch, - done: sub.done, - onDone: func() { - api.mu.Lock() - delete(api.subs.clusterCreated, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcClustersApi) SubscribeNewClusterNodeAdded() (*NewEventSubscription[EventDdcClustersClusterNodeAdded], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.clusterNodeAdded == nil { - api.subs.clusterNodeAdded = make(map[int]subscriber[EventDdcClustersClusterNodeAdded]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.clusterNodeAdded[i]; !ok { - idx = i - break - } - if i == math.MaxInt { - return nil, fmt.Errorf("can't create %d+1 subscriber", len(api.subs.clusterNodeAdded)) - } - } - - sub := subscriber[EventDdcClustersClusterNodeAdded]{ - ch: make(chan EventDdcClustersClusterNodeAdded), - done: make(chan struct{}), - } - - api.subs.clusterNodeAdded[idx] = sub - - return &NewEventSubscription[EventDdcClustersClusterNodeAdded]{ - ch: sub.ch, - done: sub.done, - onDone: func() { - api.mu.Lock() - delete(api.subs.clusterNodeAdded, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcClustersApi) SubscribeNewClusterNodeRemoved() (*NewEventSubscription[EventDdcClustersClusterNodeRemoved], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.clusterNodeRemoved == nil { - api.subs.clusterNodeRemoved = make(map[int]subscriber[EventDdcClustersClusterNodeRemoved]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.clusterNodeRemoved[i]; !ok { - idx = i - break - } - if i == math.MaxInt { - return nil, fmt.Errorf("can't create %d+1 subscriber", len(api.subs.clusterNodeRemoved)) - } - } - - sub := subscriber[EventDdcClustersClusterNodeRemoved]{ - ch: make(chan EventDdcClustersClusterNodeRemoved), - done: make(chan struct{}), - } - - api.subs.clusterNodeRemoved[idx] = sub - - return &NewEventSubscription[EventDdcClustersClusterNodeRemoved]{ - ch: sub.ch, - done: sub.done, - onDone: func() { - api.mu.Lock() - delete(api.subs.clusterNodeRemoved, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcClustersApi) SubscribeNewClusterParamsSet() (*NewEventSubscription[EventDdcClustersClusterParamsSet], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.clusterParamsSet == nil { - api.subs.clusterParamsSet = make(map[int]subscriber[EventDdcClustersClusterParamsSet]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.clusterParamsSet[i]; !ok { - idx = i - break - } - if i == math.MaxInt { - return nil, fmt.Errorf("can't create %d+1 subscriber", len(api.subs.clusterParamsSet)) - } - } - - sub := subscriber[EventDdcClustersClusterParamsSet]{ - ch: make(chan EventDdcClustersClusterParamsSet), - done: make(chan struct{}), - } - - api.subs.clusterParamsSet[idx] = sub - - return &NewEventSubscription[EventDdcClustersClusterParamsSet]{ - ch: sub.ch, - done: sub.done, - onDone: func() { - api.mu.Lock() - delete(api.subs.clusterParamsSet, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcClustersApi) SubscribeNewClusterGovParamsSet() (*NewEventSubscription[EventDdcClustersClusterGovParamsSet], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.clusterGovParamsSet == nil { - api.subs.clusterGovParamsSet = make(map[int]subscriber[EventDdcClustersClusterGovParamsSet]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.clusterGovParamsSet[i]; !ok { - idx = i - break - } - if i == math.MaxInt { - return nil, fmt.Errorf("can't create %d+1 subscriber", len(api.subs.clusterGovParamsSet)) - } - } - - sub := subscriber[EventDdcClustersClusterGovParamsSet]{ - ch: make(chan EventDdcClustersClusterGovParamsSet), - done: make(chan struct{}), - } - - api.subs.clusterGovParamsSet[idx] = sub - - return &NewEventSubscription[EventDdcClustersClusterGovParamsSet]{ - ch: sub.ch, - done: sub.done, - onDone: func() { - api.mu.Lock() - delete(api.subs.clusterGovParamsSet, idx) - api.mu.Unlock() - }, - }, nil -} diff --git a/blockchain/pallets/ddccustomers.go b/blockchain/pallets/ddccustomers.go index 6577343..8af576d 100644 --- a/blockchain/pallets/ddccustomers.go +++ b/blockchain/pallets/ddccustomers.go @@ -1,9 +1,6 @@ package pallets import ( - "math" - "sync" - gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4" "github.com/centrifuge/go-substrate-rpc-client/v4/types" "github.com/centrifuge/go-substrate-rpc-client/v4/types/codec" @@ -72,117 +69,16 @@ type DdcCustomersApi interface { GetLedger(owner types.AccountID) (types.Option[AccountsLedger], error) } -type ddcCustomersEventsSubs struct { - deposited map[int]subscriber[EventDdcCustomersDeposited] - initialDepositUnlock map[int]subscriber[EventDdcCustomersInitialDepositUnlock] - withdrawn map[int]subscriber[EventDdcCustomersWithdrawn] - charged map[int]subscriber[EventDdcCustomersCharged] - bucketCreated map[int]subscriber[EventDdcCustomersBucketCreated] - bucketUpdated map[int]subscriber[EventDdcCustomersBucketUpdated] -} - type ddcCustomersApi struct { substrateApi *gsrpc.SubstrateAPI meta *types.Metadata - - subs *ddcCustomersEventsSubs - mu sync.Mutex } -func NewDdcCustomersApi(substrateApi *gsrpc.SubstrateAPI, meta *types.Metadata, events <-chan *Events) DdcCustomersApi { - subs := &ddcCustomersEventsSubs{ - deposited: make(map[int]subscriber[EventDdcCustomersDeposited]), - initialDepositUnlock: make(map[int]subscriber[EventDdcCustomersInitialDepositUnlock]), - withdrawn: make(map[int]subscriber[EventDdcCustomersWithdrawn]), - charged: make(map[int]subscriber[EventDdcCustomersCharged]), - bucketCreated: make(map[int]subscriber[EventDdcCustomersBucketCreated]), - bucketUpdated: make(map[int]subscriber[EventDdcCustomersBucketUpdated]), +func NewDdcCustomersApi(substrateApi *gsrpc.SubstrateAPI, meta *types.Metadata) DdcCustomersApi { + return &ddcCustomersApi{ + substrateApi, + meta, } - - api := &ddcCustomersApi{ - substrateApi: substrateApi, - meta: meta, - subs: subs, - mu: sync.Mutex{}, - } - - go func() { - for blockEvents := range events { - for _, e := range blockEvents.DdcCustomers_Deposited { - api.mu.Lock() - for i, sub := range api.subs.deposited { - select { - case <-sub.done: - delete(api.subs.deposited, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcCustomers_InitialDepositUnlock { - api.mu.Lock() - for i, sub := range api.subs.initialDepositUnlock { - select { - case <-sub.done: - delete(api.subs.initialDepositUnlock, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcCustomers_Withdrawn { - api.mu.Lock() - for i, sub := range api.subs.withdrawn { - select { - case <-sub.done: - delete(api.subs.withdrawn, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcCustomers_Charged { - api.mu.Lock() - for i, sub := range api.subs.charged { - select { - case <-sub.done: - delete(api.subs.charged, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcCustomers_BucketCreated { - api.mu.Lock() - for i, sub := range api.subs.bucketCreated { - select { - case <-sub.done: - delete(api.subs.bucketCreated, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcCustomers_BucketUpdated { - api.mu.Lock() - for i, sub := range api.subs.bucketUpdated { - select { - case <-sub.done: - delete(api.subs.bucketUpdated, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - } - }() - - return api } func (api *ddcCustomersApi) GetBuckets(bucketId BucketId) (types.Option[Bucket], error) { @@ -250,189 +146,3 @@ func (api *ddcCustomersApi) GetLedger(owner types.AccountID) (types.Option[Accou return maybeLedger, nil } - -func (api *ddcCustomersApi) SubscribeNewDeposited() (*NewEventSubscription[EventDdcCustomersDeposited], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.deposited == nil { - api.subs.deposited = make(map[int]subscriber[EventDdcCustomersDeposited]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.deposited[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcCustomersDeposited) - done := make(chan struct{}) - api.subs.deposited[idx] = subscriber[EventDdcCustomersDeposited]{ch, done} - - return &NewEventSubscription[EventDdcCustomersDeposited]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.deposited, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcCustomersApi) SubscribeNewInitialDepositUnlock() (*NewEventSubscription[EventDdcCustomersInitialDepositUnlock], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.initialDepositUnlock == nil { - api.subs.initialDepositUnlock = make(map[int]subscriber[EventDdcCustomersInitialDepositUnlock]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.initialDepositUnlock[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcCustomersInitialDepositUnlock) - done := make(chan struct{}) - api.subs.initialDepositUnlock[idx] = subscriber[EventDdcCustomersInitialDepositUnlock]{ch, done} - - return &NewEventSubscription[EventDdcCustomersInitialDepositUnlock]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.initialDepositUnlock, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcCustomersApi) SubscribeNewWithdrawn() (*NewEventSubscription[EventDdcCustomersWithdrawn], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.withdrawn == nil { - api.subs.withdrawn = make(map[int]subscriber[EventDdcCustomersWithdrawn]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.withdrawn[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcCustomersWithdrawn) - done := make(chan struct{}) - api.subs.withdrawn[idx] = subscriber[EventDdcCustomersWithdrawn]{ch, done} - - return &NewEventSubscription[EventDdcCustomersWithdrawn]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.withdrawn, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcCustomersApi) SubscribeNewCharged() (*NewEventSubscription[EventDdcCustomersCharged], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.charged == nil { - api.subs.charged = make(map[int]subscriber[EventDdcCustomersCharged]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.charged[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcCustomersCharged) - done := make(chan struct{}) - api.subs.charged[idx] = subscriber[EventDdcCustomersCharged]{ch, done} - - return &NewEventSubscription[EventDdcCustomersCharged]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.charged, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcCustomersApi) SubscribeNewBucketCreated() (*NewEventSubscription[EventDdcCustomersBucketCreated], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.bucketCreated == nil { - api.subs.bucketCreated = make(map[int]subscriber[EventDdcCustomersBucketCreated]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.bucketCreated[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcCustomersBucketCreated) - done := make(chan struct{}) - api.subs.bucketCreated[idx] = subscriber[EventDdcCustomersBucketCreated]{ch, done} - - return &NewEventSubscription[EventDdcCustomersBucketCreated]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.bucketCreated, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcCustomersApi) SubscribeNewBucketUpdated() (*NewEventSubscription[EventDdcCustomersBucketUpdated], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.bucketUpdated == nil { - api.subs.bucketUpdated = make(map[int]subscriber[EventDdcCustomersBucketUpdated]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.bucketUpdated[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcCustomersBucketUpdated) - done := make(chan struct{}) - api.subs.bucketUpdated[idx] = subscriber[EventDdcCustomersBucketUpdated]{ch, done} - - return &NewEventSubscription[EventDdcCustomersBucketUpdated]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.bucketUpdated, idx) - api.mu.Unlock() - }, - }, nil -} diff --git a/blockchain/pallets/ddcpayouts.go b/blockchain/pallets/ddcpayouts.go index ed273c1..21e9ec9 100644 --- a/blockchain/pallets/ddcpayouts.go +++ b/blockchain/pallets/ddcpayouts.go @@ -1,9 +1,7 @@ package pallets import ( - "math" "reflect" - "sync" gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4" "github.com/centrifuge/go-substrate-rpc-client/v4/scale" @@ -216,229 +214,16 @@ type DdcPayoutsApi interface { GetDebtorCustomers(cluster ClusterId, account types.AccountID) (types.Option[types.U128], error) } -type ddcPayoutsEventsSubs struct { - billingReportInitialized map[int]subscriber[EventDdcPayoutsBillingReportInitialized] - chargingStarted map[int]subscriber[EventDdcPayoutsChargingStarted] - charged map[int]subscriber[EventDdcPayoutsCharged] - chargeFailed map[int]subscriber[EventDdcPayoutsChargeFailed] - indebted map[int]subscriber[EventDdcPayoutsIndebted] - chargingFinished map[int]subscriber[EventDdcPayoutsChargingFinished] - treasuryFeesCollected map[int]subscriber[EventDdcPayoutsTreasuryFeesCollected] - clusterReserveFeesCollected map[int]subscriber[EventDdcPayoutsClusterReserveFeesCollected] - validatorFeesCollected map[int]subscriber[EventDdcPayoutsValidatorFeesCollected] - rewardingStarted map[int]subscriber[EventDdcPayoutsRewardingStarted] - rewarded map[int]subscriber[EventDdcPayoutsRewarded] - rewardingFinished map[int]subscriber[EventDdcPayoutsRewardingFinished] - billingReportFinalized map[int]subscriber[EventDdcPayoutsBillingReportFinalized] - authorisedCaller map[int]subscriber[EventDdcPayoutsAuthorisedCaller] -} - type ddcPayoutsApi struct { substrateApi *gsrpc.SubstrateAPI meta *types.Metadata - - subs *ddcPayoutsEventsSubs - mu sync.Mutex } -func NewDdcPayoutsApi(substrateApi *gsrpc.SubstrateAPI, meta *types.Metadata, events <-chan *Events) DdcPayoutsApi { - subs := &ddcPayoutsEventsSubs{ - billingReportInitialized: make(map[int]subscriber[EventDdcPayoutsBillingReportInitialized]), - chargingStarted: make(map[int]subscriber[EventDdcPayoutsChargingStarted]), - charged: make(map[int]subscriber[EventDdcPayoutsCharged]), - chargeFailed: make(map[int]subscriber[EventDdcPayoutsChargeFailed]), - indebted: make(map[int]subscriber[EventDdcPayoutsIndebted]), - chargingFinished: make(map[int]subscriber[EventDdcPayoutsChargingFinished]), - treasuryFeesCollected: make(map[int]subscriber[EventDdcPayoutsTreasuryFeesCollected]), - clusterReserveFeesCollected: make(map[int]subscriber[EventDdcPayoutsClusterReserveFeesCollected]), - validatorFeesCollected: make(map[int]subscriber[EventDdcPayoutsValidatorFeesCollected]), - rewardingStarted: make(map[int]subscriber[EventDdcPayoutsRewardingStarted]), - rewarded: make(map[int]subscriber[EventDdcPayoutsRewarded]), - rewardingFinished: make(map[int]subscriber[EventDdcPayoutsRewardingFinished]), - billingReportFinalized: make(map[int]subscriber[EventDdcPayoutsBillingReportFinalized]), - authorisedCaller: make(map[int]subscriber[EventDdcPayoutsAuthorisedCaller]), - } - - api := &ddcPayoutsApi{ - substrateApi: substrateApi, - meta: meta, - subs: subs, - mu: sync.Mutex{}, +func NewDdcPayoutsApi(substrateApi *gsrpc.SubstrateAPI, meta *types.Metadata) DdcPayoutsApi { + return &ddcPayoutsApi{ + substrateApi, + meta, } - - go func() { - for blockEvents := range events { - for _, e := range blockEvents.DdcPayouts_BillingReportInitialized { - api.mu.Lock() - for i, sub := range api.subs.billingReportInitialized { - select { - case <-sub.done: - delete(api.subs.billingReportInitialized, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcPayouts_ChargingStarted { - api.mu.Lock() - for i, sub := range api.subs.chargingStarted { - select { - case <-sub.done: - delete(api.subs.chargingStarted, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcPayouts_Charged { - api.mu.Lock() - for i, sub := range api.subs.charged { - select { - case <-sub.done: - delete(api.subs.charged, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcPayouts_ChargeFailed { - api.mu.Lock() - for i, sub := range api.subs.chargeFailed { - select { - case <-sub.done: - delete(api.subs.chargeFailed, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcPayouts_Indebted { - api.mu.Lock() - for i, sub := range api.subs.indebted { - select { - case <-sub.done: - delete(api.subs.indebted, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcPayouts_ChargingFinished { - api.mu.Lock() - for i, sub := range api.subs.chargingFinished { - select { - case <-sub.done: - delete(api.subs.chargingFinished, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcPayouts_TreasuryFeesCollected { - api.mu.Lock() - for i, sub := range api.subs.treasuryFeesCollected { - select { - case <-sub.done: - delete(api.subs.treasuryFeesCollected, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcPayouts_ClusterReserveFeesCollected { - api.mu.Lock() - for i, sub := range api.subs.clusterReserveFeesCollected { - select { - case <-sub.done: - delete(api.subs.clusterReserveFeesCollected, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcPayouts_ValidatorFeesCollected { - api.mu.Lock() - for i, sub := range api.subs.validatorFeesCollected { - select { - case <-sub.done: - delete(api.subs.validatorFeesCollected, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcPayouts_RewardingStarted { - api.mu.Lock() - for i, sub := range api.subs.rewardingStarted { - select { - case <-sub.done: - delete(api.subs.rewardingStarted, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcPayouts_Rewarded { - api.mu.Lock() - for i, sub := range api.subs.rewarded { - select { - case <-sub.done: - delete(api.subs.rewarded, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcPayouts_RewardingFinished { - api.mu.Lock() - for i, sub := range api.subs.rewardingFinished { - select { - case <-sub.done: - delete(api.subs.rewardingFinished, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcPayouts_BillingReportFinalized { - api.mu.Lock() - for i, sub := range api.subs.billingReportFinalized { - select { - case <-sub.done: - delete(api.subs.billingReportFinalized, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - - for _, e := range blockEvents.DdcPayouts_AuthorisedCaller { - api.mu.Lock() - for i, sub := range api.subs.authorisedCaller { - select { - case <-sub.done: - delete(api.subs.authorisedCaller, i) - case sub.ch <- e: - } - } - api.mu.Unlock() - } - } - }() - - return api } func (api *ddcPayoutsApi) GetActiveBillingReports(cluster ClusterId, era DdcEra) (types.Option[BillingReport], error) { @@ -517,437 +302,3 @@ func (api *ddcPayoutsApi) GetDebtorCustomers(cluster ClusterId, account types.Ac return maybeV, nil } - -func (api *ddcPayoutsApi) SubscribeNewBillingReportInitialized() (*NewEventSubscription[EventDdcPayoutsBillingReportInitialized], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.billingReportInitialized == nil { - api.subs.billingReportInitialized = make(map[int]subscriber[EventDdcPayoutsBillingReportInitialized]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.billingReportInitialized[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcPayoutsBillingReportInitialized) - done := make(chan struct{}) - api.subs.billingReportInitialized[idx] = subscriber[EventDdcPayoutsBillingReportInitialized]{ch, done} - - return &NewEventSubscription[EventDdcPayoutsBillingReportInitialized]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.billingReportInitialized, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcPayoutsApi) SubscribeNewChargingStarted() (*NewEventSubscription[EventDdcPayoutsChargingStarted], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.chargingStarted == nil { - api.subs.chargingStarted = make(map[int]subscriber[EventDdcPayoutsChargingStarted]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.chargingStarted[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcPayoutsChargingStarted) - done := make(chan struct{}) - api.subs.chargingStarted[idx] = subscriber[EventDdcPayoutsChargingStarted]{ch, done} - - return &NewEventSubscription[EventDdcPayoutsChargingStarted]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.chargingStarted, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcPayoutsApi) SubscribeNewCharged() (*NewEventSubscription[EventDdcPayoutsCharged], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.charged == nil { - api.subs.charged = make(map[int]subscriber[EventDdcPayoutsCharged]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.charged[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcPayoutsCharged) - done := make(chan struct{}) - api.subs.charged[idx] = subscriber[EventDdcPayoutsCharged]{ch, done} - - return &NewEventSubscription[EventDdcPayoutsCharged]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.charged, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcPayoutsApi) SubscribeNewChargeFailed() (*NewEventSubscription[EventDdcPayoutsChargeFailed], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.chargeFailed == nil { - api.subs.chargeFailed = make(map[int]subscriber[EventDdcPayoutsChargeFailed]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.chargeFailed[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcPayoutsChargeFailed) - done := make(chan struct{}) - api.subs.chargeFailed[idx] = subscriber[EventDdcPayoutsChargeFailed]{ch, done} - - return &NewEventSubscription[EventDdcPayoutsChargeFailed]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.chargeFailed, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcPayoutsApi) SubscribeNewIndebted() (*NewEventSubscription[EventDdcPayoutsIndebted], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.indebted == nil { - api.subs.indebted = make(map[int]subscriber[EventDdcPayoutsIndebted]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.indebted[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcPayoutsIndebted) - done := make(chan struct{}) - api.subs.indebted[idx] = subscriber[EventDdcPayoutsIndebted]{ch, done} - - return &NewEventSubscription[EventDdcPayoutsIndebted]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.indebted, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcPayoutsApi) SubscribeNewChargingFinished() (*NewEventSubscription[EventDdcPayoutsChargingFinished], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.chargingFinished == nil { - api.subs.chargingFinished = make(map[int]subscriber[EventDdcPayoutsChargingFinished]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.chargingFinished[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcPayoutsChargingFinished) - done := make(chan struct{}) - api.subs.chargingFinished[idx] = subscriber[EventDdcPayoutsChargingFinished]{ch, done} - - return &NewEventSubscription[EventDdcPayoutsChargingFinished]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.chargingFinished, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcPayoutsApi) SubscribeNewTreasuryFeesCollected() (*NewEventSubscription[EventDdcPayoutsTreasuryFeesCollected], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.treasuryFeesCollected == nil { - api.subs.treasuryFeesCollected = make(map[int]subscriber[EventDdcPayoutsTreasuryFeesCollected]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.treasuryFeesCollected[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcPayoutsTreasuryFeesCollected) - done := make(chan struct{}) - api.subs.treasuryFeesCollected[idx] = subscriber[EventDdcPayoutsTreasuryFeesCollected]{ch, done} - - return &NewEventSubscription[EventDdcPayoutsTreasuryFeesCollected]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.treasuryFeesCollected, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcPayoutsApi) SubscribeNewClusterReserveFeesCollected() (*NewEventSubscription[EventDdcPayoutsClusterReserveFeesCollected], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.clusterReserveFeesCollected == nil { - api.subs.clusterReserveFeesCollected = make(map[int]subscriber[EventDdcPayoutsClusterReserveFeesCollected]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.clusterReserveFeesCollected[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcPayoutsClusterReserveFeesCollected) - done := make(chan struct{}) - api.subs.clusterReserveFeesCollected[idx] = subscriber[EventDdcPayoutsClusterReserveFeesCollected]{ch, done} - - return &NewEventSubscription[EventDdcPayoutsClusterReserveFeesCollected]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.clusterReserveFeesCollected, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcPayoutsApi) SubscribeNewValidatorFeesCollected() (*NewEventSubscription[EventDdcPayoutsValidatorFeesCollected], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.validatorFeesCollected == nil { - api.subs.validatorFeesCollected = make(map[int]subscriber[EventDdcPayoutsValidatorFeesCollected]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.validatorFeesCollected[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcPayoutsValidatorFeesCollected) - done := make(chan struct{}) - api.subs.validatorFeesCollected[idx] = subscriber[EventDdcPayoutsValidatorFeesCollected]{ch, done} - - return &NewEventSubscription[EventDdcPayoutsValidatorFeesCollected]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.validatorFeesCollected, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcPayoutsApi) SubscribeNewRewardingStarted() (*NewEventSubscription[EventDdcPayoutsRewardingStarted], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.rewardingStarted == nil { - api.subs.rewardingStarted = make(map[int]subscriber[EventDdcPayoutsRewardingStarted]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.rewardingStarted[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcPayoutsRewardingStarted) - done := make(chan struct{}) - api.subs.rewardingStarted[idx] = subscriber[EventDdcPayoutsRewardingStarted]{ch, done} - - return &NewEventSubscription[EventDdcPayoutsRewardingStarted]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.rewardingStarted, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcPayoutsApi) SubscribeNewRewarded() (*NewEventSubscription[EventDdcPayoutsRewarded], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.rewarded == nil { - api.subs.rewarded = make(map[int]subscriber[EventDdcPayoutsRewarded]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.rewarded[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcPayoutsRewarded) - done := make(chan struct{}) - api.subs.rewarded[idx] = subscriber[EventDdcPayoutsRewarded]{ch, done} - - return &NewEventSubscription[EventDdcPayoutsRewarded]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.rewarded, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcPayoutsApi) SubscribeNewRewardingFinished() (*NewEventSubscription[EventDdcPayoutsRewardingFinished], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.rewardingFinished == nil { - api.subs.rewardingFinished = make(map[int]subscriber[EventDdcPayoutsRewardingFinished]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.rewardingFinished[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcPayoutsRewardingFinished) - done := make(chan struct{}) - api.subs.rewardingFinished[idx] = subscriber[EventDdcPayoutsRewardingFinished]{ch, done} - - return &NewEventSubscription[EventDdcPayoutsRewardingFinished]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.rewardingFinished, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcPayoutsApi) SubscribeNewBillingReportFinalized() (*NewEventSubscription[EventDdcPayoutsBillingReportFinalized], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.billingReportFinalized == nil { - api.subs.billingReportFinalized = make(map[int]subscriber[EventDdcPayoutsBillingReportFinalized]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.billingReportFinalized[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcPayoutsBillingReportFinalized) - done := make(chan struct{}) - api.subs.billingReportFinalized[idx] = subscriber[EventDdcPayoutsBillingReportFinalized]{ch, done} - - return &NewEventSubscription[EventDdcPayoutsBillingReportFinalized]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.billingReportFinalized, idx) - api.mu.Unlock() - }, - }, nil -} - -func (api *ddcPayoutsApi) SubscribeNewAuthorisedCaller() (*NewEventSubscription[EventDdcPayoutsAuthorisedCaller], error) { - api.mu.Lock() - defer api.mu.Unlock() - - if api.subs.authorisedCaller == nil { - api.subs.authorisedCaller = make(map[int]subscriber[EventDdcPayoutsAuthorisedCaller]) - } - - var idx int - for i := 0; i <= math.MaxInt; i++ { - if _, ok := api.subs.authorisedCaller[i]; !ok { - idx = i - break - } - } - - ch := make(chan EventDdcPayoutsAuthorisedCaller) - done := make(chan struct{}) - api.subs.authorisedCaller[idx] = subscriber[EventDdcPayoutsAuthorisedCaller]{ch, done} - - return &NewEventSubscription[EventDdcPayoutsAuthorisedCaller]{ - ch: ch, - done: done, - onDone: func() { - api.mu.Lock() - delete(api.subs.authorisedCaller, idx) - api.mu.Unlock() - }, - }, nil -} diff --git a/blockchain/pallets/events.go b/blockchain/pallets/events.go index 193c958..4f666e9 100644 --- a/blockchain/pallets/events.go +++ b/blockchain/pallets/events.go @@ -1,8 +1,6 @@ package pallets import ( - "sync" - "github.com/centrifuge/go-substrate-rpc-client/v4/types" ) @@ -37,27 +35,3 @@ type Events struct { DdcPayouts_BillingReportFinalized []EventDdcPayoutsBillingReportFinalized //nolint:stylecheck,golint DdcPayouts_AuthorisedCaller []EventDdcPayoutsAuthorisedCaller //nolint:stylecheck,golint } - -type NewEventSubscription[T any] struct { - ch chan T - done chan struct{} - onDone func() - o sync.Once -} - -func (s *NewEventSubscription[T]) Unsubscribe() { - s.o.Do(func() { - s.done <- struct{}{} - close(s.ch) - s.onDone() - }) -} - -func (s *NewEventSubscription[T]) Chan() <-chan T { - return s.ch -} - -type subscriber[T any] struct { - ch chan T - done chan struct{} -} From 19c6706629af3ab450da0cbbd05be464e7d4b4b4 Mon Sep 17 00:00:00 2001 From: "Alisher A. Khassanov" Date: Fri, 5 Jan 2024 19:03:17 +0600 Subject: [PATCH 32/32] Ignore duplicate attempt to start event listening --- blockchain/client.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/blockchain/client.go b/blockchain/client.go index a369500..013262b 100644 --- a/blockchain/client.go +++ b/blockchain/client.go @@ -4,6 +4,7 @@ import ( "fmt" "math" "sync" + "sync/atomic" gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4" "github.com/centrifuge/go-substrate-rpc-client/v4/types" @@ -16,8 +17,12 @@ type EventsListener func(*pallets.Events) type Client struct { *gsrpc.SubstrateAPI + eventsListeners map[int]EventsListener mu sync.Mutex + isListening uint32 + stopListening func() + errsListening chan error DdcClusters pallets.DdcClustersApi DdcCustomers pallets.DdcCustomersApi @@ -46,6 +51,10 @@ func NewClient(url string) (*Client, error) { } func (c *Client) StartEventsListening() (func(), <-chan error, error) { + if !atomic.CompareAndSwapUint32(&c.isListening, 0, 1) { + return c.stopListening, c.errsListening, nil + } + meta, err := c.RPC.State.GetMetadataLatest() if err != nil { return nil, nil, err @@ -60,7 +69,7 @@ func (c *Client) StartEventsListening() (func(), <-chan error, error) { } done := make(chan struct{}) - errCh := make(chan error) + c.errsListening = make(chan error) go func() { for { @@ -76,7 +85,7 @@ func (c *Client) StartEventsListening() (func(), <-chan error, error) { events := &pallets.Events{} err = types.EventRecordsRaw(change.StorageData).DecodeEventRecords(meta, events) if err != nil { - errCh <- fmt.Errorf("events decoder: %w", err) + c.errsListening <- fmt.Errorf("events decoder: %w", err) } for _, callback := range c.eventsListeners { @@ -88,14 +97,15 @@ func (c *Client) StartEventsListening() (func(), <-chan error, error) { }() once := sync.Once{} - stop := func() { + c.stopListening = func() { once.Do(func() { done <- struct{}{} sub.Unsubscribe() + c.isListening = 0 }) } - return stop, errCh, nil + return c.stopListening, c.errsListening, nil } func (c *Client) RegisterEventsListener(callback EventsListener) (func(), error) {