diff --git a/cylinder/workers/de/de.go b/cylinder/workers/de/de.go index b1fab2388..91a9c88e6 100644 --- a/cylinder/workers/de/de.go +++ b/cylinder/workers/de/de.go @@ -27,6 +27,7 @@ type DE struct { client *client.Client assignEventCh <-chan ctypes.ResultEvent useEventCh <-chan ctypes.ResultEvent + deleteEventCh <-chan ctypes.ResultEvent cntUsed uint64 } @@ -66,23 +67,34 @@ func (de *DE) subscribe() (err error) { de.context.Config.Granter, ) de.useEventCh, err = de.client.Subscribe("DE-submitted", subscriptionQuery, 1000) + if err != nil { + return + } + + subscriptionQuery = fmt.Sprintf( + "tm.event = 'Tx' AND %s.%s = '%s'", + types.EventTypeDEDeleted, + types.AttributeKeyAddress, + de.context.Config.Granter, + ) + de.deleteEventCh, err = de.client.Subscribe("DE-deleted", subscriptionQuery, 1000) return } -// handleABCIEvents signs the specific signingID if the given events contain a request_signature event. -func (de *DE) handleABCIEvents(abciEvents []abci.Event) { +// deleteDEFromABCIEvents signs the specific signingID if the given events contain a request_signature event. +func (de *DE) deleteDEFromABCIEvents(abciEvents []abci.Event) { events := sdk.StringifyEvents(abciEvents) for _, ev := range events { - if ev.Type == types.EventTypeSubmitSignature { - events, err := ParseSubmitSignEvents(sdk.StringEvents{ev}) + if ev.Type == types.EventTypeSubmitSignature || ev.Type == types.EventTypeDEDeleted { + pubDEs, err := ParsePubDEFromEvents(sdk.StringEvents{ev}, ev.Type) if err != nil { de.logger.Error(":cold_sweat: Failed to parse event with error: %s", err) return } - for _, event := range events { - go de.deleteDE(event.PubDE) + for _, pubDE := range pubDEs { + go de.deleteDE(pubDE.PubDE) } } } @@ -115,6 +127,18 @@ func (de *DE) getDECount() (uint64, error) { // updateDE updates DE if the remaining DE is too low. func (de *DE) updateDE(numNewDE uint64) { + canUpdate, err := de.canUpdateDE() + if err != nil { + de.logger.Error(":cold_sweat: Cannot update DE: %s", err) + return + } + if !canUpdate { + de.logger.Debug( + ":cold_sweat: Cannot update DE: the granter is not a member of the current or incoming group and gas price isn't set in the config", + ) + return + } + de.logger.Info(":delivery_truck: Updating DE") // Generate new DE pairs @@ -143,6 +167,34 @@ func (de *DE) updateDE(numNewDE uint64) { de.context.MsgCh <- types.NewMsgSubmitDEs(pubDEs, de.context.Config.Granter) } +// canUpdateDE checks if the system allows to update DEs into the system and chain. +func (de *DE) canUpdateDE() (bool, error) { + gasPrices, err := sdk.ParseDecCoins(de.context.Config.GasPrices) + if err != nil { + de.logger.Debug(":cold_sweat: Failed to parse gas prices from config: %s", err) + } + + // If the gas price is non-zero, it indicates that the user is willing to pay + // a transaction fee for submitting DEs to the chain. + if gasPrices != nil && !gasPrices.IsZero() { + return true, nil + } + + // If the address is a member of the current group, the system can submit DEs to the chain + // without paying gas. + resp, err := de.client.QueryMember(de.context.Config.Granter) + if err != nil { + return false, fmt.Errorf("failed to query member information: %w", err) + } + + if resp.CurrentGroupMember.Address == de.context.Config.Granter || + resp.IncomingGroupMember.Address == de.context.Config.Granter { + return true, nil + } + + return false, nil +} + // intervalUpdateDE updates DE on the chain so that the remaining DE is // always above the minimum threshold. func (de *DE) intervalUpdateDE() error { @@ -176,10 +228,15 @@ func (de *DE) Start() { return } - // Remove DE if there is used DE event. + // Remove DE if there is used DE or deleted DE event. go func() { - for ev := range de.useEventCh { - go de.handleABCIEvents(ev.Data.(tmtypes.EventDataTx).TxResult.Result.Events) + for { + select { + case ev := <-de.useEventCh: + go de.deleteDEFromABCIEvents(ev.Data.(tmtypes.EventDataTx).TxResult.Result.Events) + case ev := <-de.deleteEventCh: + go de.deleteDEFromABCIEvents(ev.Data.(tmtypes.EventDataTx).TxResult.Result.Events) + } } }() diff --git a/cylinder/workers/de/event.go b/cylinder/workers/de/event.go index f056471a7..0de4e275e 100644 --- a/cylinder/workers/de/event.go +++ b/cylinder/workers/de/event.go @@ -9,20 +9,20 @@ import ( "github.com/bandprotocol/chain/v3/x/tss/types" ) -// Event represents the data structure for submit_sign events. -type Event struct { +// PubDE represents the data structure for public D,E being retrieved from events. +type PubDE struct { PubDE types.DE } -// ParseSubmitSignEvents parses the submit_sign events from the given events. +// ParsePubDEFromEvents parses the events into PubDE struct from the given events and event type. // It extracts the public D and E from the log and returns the parsed Events or an error if parsing fails. -func ParseSubmitSignEvents(events sdk.StringEvents) ([]Event, error) { - pubDs, err := event.GetEventValuesBytes(events, types.EventTypeSubmitSignature, types.AttributeKeyPubD) +func ParsePubDEFromEvents(events sdk.StringEvents, eventType string) ([]PubDE, error) { + pubDs, err := event.GetEventValuesBytes(events, eventType, types.AttributeKeyPubD) if err != nil { return nil, err } - pubEs, err := event.GetEventValuesBytes(events, types.EventTypeSubmitSignature, types.AttributeKeyPubE) + pubEs, err := event.GetEventValuesBytes(events, eventType, types.AttributeKeyPubE) if err != nil { return nil, err } @@ -31,9 +31,9 @@ func ParseSubmitSignEvents(events sdk.StringEvents) ([]Event, error) { return nil, errors.New("length of public D and e are not equal") } - var eves []Event + var pubDEs []PubDE for i, pubD := range pubDs { - eves = append(eves, Event{ + pubDEs = append(pubDEs, PubDE{ PubDE: types.DE{ PubD: pubD, PubE: pubEs[i], @@ -41,5 +41,5 @@ func ParseSubmitSignEvents(events sdk.StringEvents) ([]Event, error) { }) } - return eves, nil + return pubDEs, nil } diff --git a/cylinder/workers/de/event_test.go b/cylinder/workers/de/event_test.go index 3975ce1bf..af3d88de8 100644 --- a/cylinder/workers/de/event_test.go +++ b/cylinder/workers/de/event_test.go @@ -16,10 +16,11 @@ import ( func TestParseSubmitSignEvents(t *testing.T) { tests := []struct { - name string - events sdk.StringEvents - expEvent []de.Event - expError string + name string + events sdk.StringEvents + eventType string + expEvent []de.PubDE + expError string }{ { "success", @@ -35,7 +36,8 @@ func TestParseSubmitSignEvents(t *testing.T) { sdk.NewAttribute(types.AttributeKeySignature, hex.EncodeToString([]byte("signature"))), )), }), - []de.Event{ + types.EventTypeSubmitSignature, + []de.PubDE{ { PubDE: types.DE{ PubD: []byte("pubD"), @@ -69,7 +71,8 @@ func TestParseSubmitSignEvents(t *testing.T) { sdk.NewAttribute(types.AttributeKeySignature, hex.EncodeToString([]byte("signature"))), )), }), - []de.Event{ + types.EventTypeSubmitSignature, + []de.PubDE{ { PubDE: types.DE{ PubD: []byte("pubD 1"), @@ -106,7 +109,8 @@ func TestParseSubmitSignEvents(t *testing.T) { sdk.NewAttribute(types.AttributeKeySignature, hex.EncodeToString([]byte("signature"))), )), }), - []de.Event{ + types.EventTypeSubmitSignature, + []de.PubDE{ { PubDE: types.DE{ PubD: []byte("pubD 1"), @@ -125,6 +129,7 @@ func TestParseSubmitSignEvents(t *testing.T) { { "no event", sdk.StringifyEvents([]abci.Event{}), + types.EventTypeSubmitSignature, nil, "", }, @@ -142,14 +147,48 @@ func TestParseSubmitSignEvents(t *testing.T) { sdk.NewAttribute(types.AttributeKeySignature, hex.EncodeToString([]byte("signature"))), )), }), + types.EventTypeSubmitSignature, nil, "encoding/hex: invalid byte", }, + { + "success - de_deleted", + sdk.StringifyEvents([]abci.Event{ + abci.Event(sdk.NewEvent( + types.EventTypeDEDeleted, + sdk.NewAttribute(types.AttributeKeyAddress, "member 1"), + sdk.NewAttribute(types.AttributeKeyPubD, hex.EncodeToString([]byte("pubD 1"))), + sdk.NewAttribute(types.AttributeKeyPubE, hex.EncodeToString([]byte("pubE 1"))), + )), + abci.Event(sdk.NewEvent( + types.EventTypeDEDeleted, + sdk.NewAttribute(types.AttributeKeyAddress, "member 1"), + sdk.NewAttribute(types.AttributeKeyPubD, hex.EncodeToString([]byte("pubD 2"))), + sdk.NewAttribute(types.AttributeKeyPubE, hex.EncodeToString([]byte("pubE 2"))), + )), + }), + types.EventTypeDEDeleted, + []de.PubDE{ + { + PubDE: types.DE{ + PubD: []byte("pubD 1"), + PubE: []byte("pubE 1"), + }, + }, + { + PubDE: types.DE{ + PubD: []byte("pubD 2"), + PubE: []byte("pubE 2"), + }, + }, + }, + "", + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - events, err := de.ParseSubmitSignEvents(test.events) + events, err := de.ParsePubDEFromEvents(test.events, test.eventType) assert.Equal(t, test.expEvent, events) if test.expError != "" { assert.ErrorContains(t, err, test.expError)