From 24fbc45bf2f0685508fd98e0812d82325e99fbf5 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Fri, 28 Jan 2022 12:10:36 -0500 Subject: [PATCH 1/4] Allow synchronous 200 response for token pool creation Signed-off-by: Andrew Richardson --- internal/tokens/fftokens/fftokens.go | 29 +++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/internal/tokens/fftokens/fftokens.go b/internal/tokens/fftokens/fftokens.go index 0ee1242dcc..8f0a4499b4 100644 --- a/internal/tokens/fftokens/fftokens.go +++ b/internal/tokens/fftokens/fftokens.go @@ -177,11 +177,11 @@ func (ft *FFTokens) handleTokenPoolCreate(ctx context.Context, data fftypes.JSON eventProtocolID := data.GetString("id") tokenType := data.GetString("type") protocolID := data.GetString("poolId") - standard := data.GetString("standard") // this is optional operatorAddress := data.GetString("operator") - tx := data.GetObject("transaction") - txHash := tx.GetString("transactionHash") + standard := data.GetString("standard") // optional rawOutput := data.GetObject("rawOutput") // optional + tx := data.GetObject("transaction") + txHash := tx.GetString("transactionHash") // optional timestampStr := data.GetString("timestamp") timestamp, err := fftypes.ParseTimeString(timestampStr) @@ -191,8 +191,7 @@ func (ft *FFTokens) handleTokenPoolCreate(ctx context.Context, data fftypes.JSON if tokenType == "" || protocolID == "" || - operatorAddress == "" || - txHash == "" { + operatorAddress == "" { log.L(ctx).Errorf("TokenPool event is not valid - missing data: %+v", data) return nil // move on } @@ -392,6 +391,16 @@ func (ft *FFTokens) CreateTokenPool(ctx context.Context, opID *fftypes.UUID, poo if err != nil || !res.IsSuccess() { return restclient.WrapRestErr(ctx, res, err, i18n.MsgTokensRESTErr) } + if res.StatusCode() == 200 { + // Handle synchronous response (202 will be handled by later websocket listener) + var obj fftypes.JSONObject + if err := json.Unmarshal(res.Body(), &obj); err != nil { + return err + } + if err := ft.handleTokenPoolCreate(ctx, obj); err != nil { + return err + } + } return nil } @@ -406,6 +415,16 @@ func (ft *FFTokens) ActivateTokenPool(ctx context.Context, opID *fftypes.UUID, p if err != nil || !res.IsSuccess() { return restclient.WrapRestErr(ctx, res, err, i18n.MsgTokensRESTErr) } + if res.StatusCode() == 200 { + // Handle synchronous response (202 will be handled by later websocket listener) + var obj fftypes.JSONObject + if err := json.Unmarshal(res.Body(), &obj); err != nil { + return err + } + if err := ft.handleTokenPoolCreate(ctx, obj); err != nil { + return err + } + } return nil } From 41abb1b714538b3092f0df9822721748738d244d Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Fri, 28 Jan 2022 16:08:30 -0500 Subject: [PATCH 2/4] Add unit tests for synchronous token pool responses Signed-off-by: Andrew Richardson --- internal/tokens/fftokens/fftokens.go | 17 +- internal/tokens/fftokens/fftokens_test.go | 187 ++++++++++++++++++++++ 2 files changed, 193 insertions(+), 11 deletions(-) diff --git a/internal/tokens/fftokens/fftokens.go b/internal/tokens/fftokens/fftokens.go index 8f0a4499b4..5c44dae7f1 100644 --- a/internal/tokens/fftokens/fftokens.go +++ b/internal/tokens/fftokens/fftokens.go @@ -234,11 +234,11 @@ func (ft *FFTokens) handleTokenTransfer(ctx context.Context, t fftypes.TokenTran fromAddress := data.GetString("from") toAddress := data.GetString("to") value := data.GetString("amount") - tx := data.GetObject("transaction") - txHash := tx.GetString("transactionHash") tokenIndex := data.GetString("tokenIndex") // optional uri := data.GetString("uri") // optional rawOutput := data.GetObject("rawOutput") // optional + tx := data.GetObject("transaction") + txHash := tx.GetString("transactionHash") // optional timestampStr := data.GetString("timestamp") timestamp, err := fftypes.ParseTimeString(timestampStr) @@ -260,7 +260,6 @@ func (ft *FFTokens) handleTokenTransfer(ctx context.Context, t fftypes.TokenTran poolProtocolID == "" || operatorAddress == "" || value == "" || - txHash == "" || (t != fftypes.TokenTransferTypeMint && fromAddress == "") || (t != fftypes.TokenTransferTypeBurn && toAddress == "") { log.L(ctx).Errorf("%s event is not valid - missing data: %+v", eventName, data) @@ -395,11 +394,9 @@ func (ft *FFTokens) CreateTokenPool(ctx context.Context, opID *fftypes.UUID, poo // Handle synchronous response (202 will be handled by later websocket listener) var obj fftypes.JSONObject if err := json.Unmarshal(res.Body(), &obj); err != nil { - return err - } - if err := ft.handleTokenPoolCreate(ctx, obj); err != nil { - return err + return i18n.WrapError(ctx, err, i18n.MsgJSONObjectParseFailed, res.Body()) } + return ft.handleTokenPoolCreate(ctx, obj) } return nil } @@ -419,11 +416,9 @@ func (ft *FFTokens) ActivateTokenPool(ctx context.Context, opID *fftypes.UUID, p // Handle synchronous response (202 will be handled by later websocket listener) var obj fftypes.JSONObject if err := json.Unmarshal(res.Body(), &obj); err != nil { - return err - } - if err := ft.handleTokenPoolCreate(ctx, obj); err != nil { - return err + return i18n.WrapError(ctx, err, i18n.MsgJSONObjectParseFailed, res.Body()) } + return ft.handleTokenPoolCreate(ctx, obj) } return nil } diff --git a/internal/tokens/fftokens/fftokens_test.go b/internal/tokens/fftokens/fftokens_test.go index 4651fe3639..9620c3c52f 100644 --- a/internal/tokens/fftokens/fftokens_test.go +++ b/internal/tokens/fftokens/fftokens_test.go @@ -166,6 +166,99 @@ func TestCreateTokenPoolError(t *testing.T) { assert.Regexp(t, "FF10274", err) } +func TestCreateTokenPoolSynchronous(t *testing.T) { + h, _, _, httpURL, done := newTestFFTokens(t) + defer done() + + opID := fftypes.NewUUID() + pool := &fftypes.TokenPool{ + ID: fftypes.NewUUID(), + TX: fftypes.TransactionRef{ + ID: fftypes.NewUUID(), + Type: fftypes.TransactionTypeTokenPool, + }, + Namespace: "ns1", + Name: "new-pool", + Type: "fungible", + Key: "0x123", + Config: fftypes.JSONObject{ + "foo": "bar", + }, + Symbol: "symbol", + } + + httpmock.RegisterResponder("POST", fmt.Sprintf("%s/api/v1/createpool", httpURL), + func(req *http.Request) (*http.Response, error) { + body := make(fftypes.JSONObject) + err := json.NewDecoder(req.Body).Decode(&body) + assert.NoError(t, err) + + res := &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader([]byte(fftypes.JSONObject{ + "id": "000000000010/000020/000030/000040", + "type": "fungible", + "poolId": "F1", + "operator": "0x0", + "data": `{"tx":"` + pool.TX.ID.String() + `"}`, + }.String()))), + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + StatusCode: 200, + } + return res, nil + }) + + mcb := h.callbacks.(*tokenmocks.Callbacks) + mcb.On("TokenPoolCreated", h, mock.MatchedBy(func(p *tokens.TokenPool) bool { + return p.ProtocolID == "F1" && p.Type == fftypes.TokenTypeFungible && p.Key == "0x0" && *p.TransactionID == *pool.TX.ID && p.Event.ProtocolID == "000000000010/000020/000030/000040" + })).Return(nil) + + err := h.CreateTokenPool(context.Background(), opID, pool) + assert.NoError(t, err) +} + +func TestCreateTokenPoolSynchronousBadResponse(t *testing.T) { + h, _, _, httpURL, done := newTestFFTokens(t) + defer done() + + opID := fftypes.NewUUID() + pool := &fftypes.TokenPool{ + ID: fftypes.NewUUID(), + TX: fftypes.TransactionRef{ + ID: fftypes.NewUUID(), + Type: fftypes.TransactionTypeTokenPool, + }, + Namespace: "ns1", + Name: "new-pool", + Type: "fungible", + Key: "0x123", + Config: fftypes.JSONObject{ + "foo": "bar", + }, + Symbol: "symbol", + } + + httpmock.RegisterResponder("POST", fmt.Sprintf("%s/api/v1/createpool", httpURL), + func(req *http.Request) (*http.Response, error) { + body := make(fftypes.JSONObject) + err := json.NewDecoder(req.Body).Decode(&body) + assert.NoError(t, err) + + res := &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader([]byte("bad"))), + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + StatusCode: 200, + } + return res, nil + }) + + err := h.CreateTokenPool(context.Background(), opID, pool) + assert.Regexp(t, "FF10151", err) +} + func TestActivateTokenPool(t *testing.T) { h, _, _, httpURL, done := newTestFFTokens(t) defer done() @@ -226,6 +319,100 @@ func TestActivateTokenPoolError(t *testing.T) { assert.Regexp(t, "FF10274", err) } +func TestActivateTokenPoolSynchronous(t *testing.T) { + h, _, _, httpURL, done := newTestFFTokens(t) + defer done() + + opID := fftypes.NewUUID() + pool := &fftypes.TokenPool{ + ProtocolID: "N1", + } + txInfo := map[string]interface{}{ + "foo": "bar", + } + ev := &fftypes.BlockchainEvent{ + Info: txInfo, + } + + httpmock.RegisterResponder("POST", fmt.Sprintf("%s/api/v1/activatepool", httpURL), + func(req *http.Request) (*http.Response, error) { + body := make(fftypes.JSONObject) + err := json.NewDecoder(req.Body).Decode(&body) + assert.NoError(t, err) + assert.Equal(t, fftypes.JSONObject{ + "requestId": opID.String(), + "poolId": "N1", + "transaction": txInfo, + }, body) + + res := &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader([]byte(fftypes.JSONObject{ + "type": "fungible", + "poolId": "F1", + "operator": "0x0", + }.String()))), + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + StatusCode: 200, + } + return res, nil + }) + + mcb := h.callbacks.(*tokenmocks.Callbacks) + mcb.On("TokenPoolCreated", h, mock.MatchedBy(func(p *tokens.TokenPool) bool { + return p.ProtocolID == "F1" && p.Type == fftypes.TokenTypeFungible && p.Key == "0x0" && p.TransactionID == nil && p.Event.ProtocolID == "" + })).Return(nil) + + err := h.ActivateTokenPool(context.Background(), opID, pool, ev) + assert.NoError(t, err) +} + +func TestActivateTokenPoolSynchronousBadResponse(t *testing.T) { + h, _, _, httpURL, done := newTestFFTokens(t) + defer done() + + opID := fftypes.NewUUID() + pool := &fftypes.TokenPool{ + ProtocolID: "N1", + } + txInfo := map[string]interface{}{ + "foo": "bar", + } + ev := &fftypes.BlockchainEvent{ + Info: txInfo, + } + + httpmock.RegisterResponder("POST", fmt.Sprintf("%s/api/v1/activatepool", httpURL), + func(req *http.Request) (*http.Response, error) { + body := make(fftypes.JSONObject) + err := json.NewDecoder(req.Body).Decode(&body) + assert.NoError(t, err) + assert.Equal(t, fftypes.JSONObject{ + "requestId": opID.String(), + "poolId": "N1", + "transaction": txInfo, + }, body) + + res := &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader([]byte("bad"))), + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + StatusCode: 200, + } + return res, nil + }) + + mcb := h.callbacks.(*tokenmocks.Callbacks) + mcb.On("TokenPoolCreated", h, mock.MatchedBy(func(p *tokens.TokenPool) bool { + return p.ProtocolID == "F1" && p.Type == fftypes.TokenTypeFungible && p.Key == "0x0" && p.TransactionID == nil && p.Event.ProtocolID == "" + })).Return(nil) + + err := h.ActivateTokenPool(context.Background(), opID, pool, ev) + assert.Regexp(t, "FF10151", err) +} + func TestMintTokens(t *testing.T) { h, _, _, httpURL, done := newTestFFTokens(t) defer done() From 94db6cb4443b4bf5b20ac85a9aaa80864da9f638 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Fri, 28 Jan 2022 17:03:51 -0500 Subject: [PATCH 3/4] Remove "key" from token pool table Signed-off-by: Andrew Richardson --- .../postgres/000058_remove_tokenpool_key.down.sql | 4 ++++ .../postgres/000058_remove_tokenpool_key.up.sql | 3 +++ .../sqlite/000058_remove_tokenpool_key.down.sql | 2 ++ .../sqlite/000058_remove_tokenpool_key.up.sql | 1 + docs/swagger/swagger.yaml | 10 ---------- internal/database/sqlcommon/tokenpool_sql.go | 6 +----- internal/database/sqlcommon/tokenpool_sql_test.go | 3 +-- internal/events/token_pool_created.go | 5 ++--- internal/events/token_pool_created_test.go | 11 ----------- internal/tokens/fftokens/fftokens.go | 5 +---- internal/tokens/fftokens/fftokens_test.go | 10 +++++----- pkg/database/plugin.go | 1 - pkg/tokens/plugin.go | 3 --- 13 files changed, 20 insertions(+), 44 deletions(-) create mode 100644 db/migrations/postgres/000058_remove_tokenpool_key.down.sql create mode 100644 db/migrations/postgres/000058_remove_tokenpool_key.up.sql create mode 100644 db/migrations/sqlite/000058_remove_tokenpool_key.down.sql create mode 100644 db/migrations/sqlite/000058_remove_tokenpool_key.up.sql diff --git a/db/migrations/postgres/000058_remove_tokenpool_key.down.sql b/db/migrations/postgres/000058_remove_tokenpool_key.down.sql new file mode 100644 index 0000000000..5120119fd1 --- /dev/null +++ b/db/migrations/postgres/000058_remove_tokenpool_key.down.sql @@ -0,0 +1,4 @@ +BEGIN; +ALTER TABLE tokenpool ADD COLUMN "key" VARCHAR(1024); +UPDATE tokenpool SET "key" = ''; +COMMIT; diff --git a/db/migrations/postgres/000058_remove_tokenpool_key.up.sql b/db/migrations/postgres/000058_remove_tokenpool_key.up.sql new file mode 100644 index 0000000000..a85d58564b --- /dev/null +++ b/db/migrations/postgres/000058_remove_tokenpool_key.up.sql @@ -0,0 +1,3 @@ +BEGIN; +ALTER TABLE tokenpool DROP COLUMN key; +COMMIT; diff --git a/db/migrations/sqlite/000058_remove_tokenpool_key.down.sql b/db/migrations/sqlite/000058_remove_tokenpool_key.down.sql new file mode 100644 index 0000000000..eb2dfd9dd2 --- /dev/null +++ b/db/migrations/sqlite/000058_remove_tokenpool_key.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE tokenpool ADD COLUMN "key" VARCHAR(1024); +UPDATE tokenpool SET "key" = ''; diff --git a/db/migrations/sqlite/000058_remove_tokenpool_key.up.sql b/db/migrations/sqlite/000058_remove_tokenpool_key.up.sql new file mode 100644 index 0000000000..5953c370e2 --- /dev/null +++ b/db/migrations/sqlite/000058_remove_tokenpool_key.up.sql @@ -0,0 +1 @@ +ALTER TABLE tokenpool DROP COLUMN key; diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 5fcc64e0e2..c421dec364 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -6838,11 +6838,6 @@ paths: name: id schema: type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: key - schema: - type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query name: message @@ -9008,11 +9003,6 @@ paths: name: id schema: type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: key - schema: - type: string - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' in: query name: message diff --git a/internal/database/sqlcommon/tokenpool_sql.go b/internal/database/sqlcommon/tokenpool_sql.go index 7f1465374d..97bde384f2 100644 --- a/internal/database/sqlcommon/tokenpool_sql.go +++ b/internal/database/sqlcommon/tokenpool_sql.go @@ -1,4 +1,4 @@ -// Copyright © 2021 Kaleido, Inc. +// Copyright © 2022 Kaleido, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -42,7 +42,6 @@ var ( "created", "tx_type", "tx_id", - "key", } tokenPoolFilterFieldMap = map[string]string{ "protocolid": "protocol_id", @@ -94,7 +93,6 @@ func (s *SQLCommon) UpsertTokenPool(ctx context.Context, pool *fftypes.TokenPool Set("state", pool.State). Set("tx_type", pool.TX.Type). Set("tx_id", pool.TX.ID). - Set("key", pool.Key). Where(sq.Eq{"id": pool.ID}), func() { s.callbacks.UUIDCollectionNSEvent(database.CollectionTokenPools, fftypes.ChangeEventTypeUpdated, pool.Namespace, pool.ID) @@ -121,7 +119,6 @@ func (s *SQLCommon) UpsertTokenPool(ctx context.Context, pool *fftypes.TokenPool pool.Created, pool.TX.Type, pool.TX.ID, - pool.Key, ), func() { s.callbacks.UUIDCollectionNSEvent(database.CollectionTokenPools, fftypes.ChangeEventTypeCreated, pool.Namespace, pool.ID) @@ -150,7 +147,6 @@ func (s *SQLCommon) tokenPoolResult(ctx context.Context, row *sql.Rows) (*fftype &pool.Created, &pool.TX.Type, &pool.TX.ID, - &pool.Key, ) if err != nil { return nil, i18n.WrapError(ctx, err, i18n.MsgDBReadErr, "tokenpool") diff --git a/internal/database/sqlcommon/tokenpool_sql_test.go b/internal/database/sqlcommon/tokenpool_sql_test.go index eb8ee668c7..39644a4b69 100644 --- a/internal/database/sqlcommon/tokenpool_sql_test.go +++ b/internal/database/sqlcommon/tokenpool_sql_test.go @@ -1,4 +1,4 @@ -// Copyright © 2021 Kaleido, Inc. +// Copyright © 2022 Kaleido, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -52,7 +52,6 @@ func TestTokenPoolE2EWithDB(t *testing.T) { Type: fftypes.TransactionTypeTokenPool, ID: fftypes.NewUUID(), }, - Key: "0x12345", } s.callbacks.On("UUIDCollectionNSEvent", database.CollectionTokenPools, fftypes.ChangeEventTypeCreated, "ns1", poolID, mock.Anything). diff --git a/internal/events/token_pool_created.go b/internal/events/token_pool_created.go index 8e8dfa5501..b64632e054 100644 --- a/internal/events/token_pool_created.go +++ b/internal/events/token_pool_created.go @@ -30,7 +30,6 @@ import ( func addPoolDetailsFromPlugin(ffPool *fftypes.TokenPool, pluginPool *tokens.TokenPool) { ffPool.Type = pluginPool.Type ffPool.ProtocolID = pluginPool.ProtocolID - ffPool.Key = pluginPool.Key ffPool.Connector = pluginPool.Connector ffPool.Standard = pluginPool.Standard if pluginPool.TransactionID != nil { @@ -64,7 +63,7 @@ func (em *eventManager) confirmPool(ctx context.Context, pool *fftypes.TokenPool if err := em.database.UpsertTokenPool(ctx, pool); err != nil { return err } - log.L(ctx).Infof("Token pool confirmed id=%s author=%s", pool.ID, pool.Key) + log.L(ctx).Infof("Token pool confirmed, id=%s", pool.ID) event := fftypes.NewEvent(fftypes.EventTypePoolConfirmed, pool.Namespace, pool.ID) return em.database.InsertEvent(ctx, event) } @@ -186,7 +185,7 @@ func (em *eventManager) TokenPoolCreated(ti tokens.Plugin, pool *tokens.TokenPoo Pool: announcePool, Event: buildBlockchainEvent(announcePool.Namespace, nil, &pool.Event, &announcePool.TX), } - log.L(em.ctx).Infof("Announcing token pool id=%s author=%s", announcePool.ID, pool.Key) + log.L(em.ctx).Infof("Announcing token pool, id=%s", announcePool.ID) _, err = em.broadcast.BroadcastTokenPool(em.ctx, announcePool.Namespace, broadcast, false) } } diff --git a/internal/events/token_pool_created_test.go b/internal/events/token_pool_created_test.go index 895a9653d4..4d206848c8 100644 --- a/internal/events/token_pool_created_test.go +++ b/internal/events/token_pool_created_test.go @@ -43,7 +43,6 @@ func TestTokenPoolCreatedIgnore(t *testing.T) { pool := &tokens.TokenPool{ Type: fftypes.TokenTypeFungible, ProtocolID: "123", - Key: "0x0", TransactionID: txID, Connector: "erc1155", Event: blockchain.Event{ @@ -71,7 +70,6 @@ func TestTokenPoolCreatedIgnoreNoTX(t *testing.T) { pool := &tokens.TokenPool{ Type: fftypes.TokenTypeFungible, ProtocolID: "123", - Key: "0x0", TransactionID: nil, Connector: "erc1155", Event: blockchain.Event{ @@ -96,7 +94,6 @@ func TestTokenPoolCreatedConfirm(t *testing.T) { chainPool := &tokens.TokenPool{ Type: fftypes.TokenTypeFungible, ProtocolID: "123", - Key: "0x0", Connector: "erc1155", TransactionID: txID, Event: blockchain.Event{ @@ -109,7 +106,6 @@ func TestTokenPoolCreatedConfirm(t *testing.T) { storedPool := &fftypes.TokenPool{ Namespace: "ns1", ID: fftypes.NewUUID(), - Key: chainPool.Key, State: fftypes.TokenPoolStatePending, Message: fftypes.NewUUID(), TX: fftypes.TransactionRef{ @@ -156,7 +152,6 @@ func TestTokenPoolCreatedAlreadyConfirmed(t *testing.T) { chainPool := &tokens.TokenPool{ Type: fftypes.TokenTypeFungible, ProtocolID: "123", - Key: "0x0", Connector: "erc1155", TransactionID: txID, Event: blockchain.Event{ @@ -168,7 +163,6 @@ func TestTokenPoolCreatedAlreadyConfirmed(t *testing.T) { storedPool := &fftypes.TokenPool{ Namespace: "ns1", ID: fftypes.NewUUID(), - Key: chainPool.Key, State: fftypes.TokenPoolStateConfirmed, TX: fftypes.TransactionRef{ Type: fftypes.TransactionTypeTokenPool, @@ -196,7 +190,6 @@ func TestTokenPoolCreatedMigrate(t *testing.T) { chainPool := &tokens.TokenPool{ Type: fftypes.TokenTypeFungible, ProtocolID: "123", - Key: "0x0", Connector: "magic-tokens", TransactionID: txID, Event: blockchain.Event{ @@ -208,7 +201,6 @@ func TestTokenPoolCreatedMigrate(t *testing.T) { storedPool := &fftypes.TokenPool{ Namespace: "ns1", ID: fftypes.NewUUID(), - Key: chainPool.Key, State: fftypes.TokenPoolStateUnknown, TX: fftypes.TransactionRef{ Type: fftypes.TransactionTypeTokenPool, @@ -374,7 +366,6 @@ func TestTokenPoolCreatedAnnounce(t *testing.T) { pool := &tokens.TokenPool{ Type: fftypes.TokenTypeFungible, ProtocolID: "123", - Key: "0x0", TransactionID: txID, Connector: "erc1155", Event: blockchain.Event{ @@ -421,7 +412,6 @@ func TestTokenPoolCreatedAnnounceBadOpInputID(t *testing.T) { pool := &tokens.TokenPool{ Type: fftypes.TokenTypeFungible, ProtocolID: "123", - Key: "0x0", TransactionID: txID, Connector: "erc1155", Event: blockchain.Event{ @@ -460,7 +450,6 @@ func TestTokenPoolCreatedAnnounceBadOpInputNS(t *testing.T) { pool := &tokens.TokenPool{ Type: fftypes.TokenTypeFungible, ProtocolID: "123", - Key: "0x0", TransactionID: txID, Connector: "erc1155", Event: blockchain.Event{ diff --git a/internal/tokens/fftokens/fftokens.go b/internal/tokens/fftokens/fftokens.go index 5c44dae7f1..3b4b45d806 100644 --- a/internal/tokens/fftokens/fftokens.go +++ b/internal/tokens/fftokens/fftokens.go @@ -177,7 +177,6 @@ func (ft *FFTokens) handleTokenPoolCreate(ctx context.Context, data fftypes.JSON eventProtocolID := data.GetString("id") tokenType := data.GetString("type") protocolID := data.GetString("poolId") - operatorAddress := data.GetString("operator") standard := data.GetString("standard") // optional rawOutput := data.GetObject("rawOutput") // optional tx := data.GetObject("transaction") @@ -190,8 +189,7 @@ func (ft *FFTokens) handleTokenPoolCreate(ctx context.Context, data fftypes.JSON } if tokenType == "" || - protocolID == "" || - operatorAddress == "" { + protocolID == "" { log.L(ctx).Errorf("TokenPool event is not valid - missing data: %+v", data) return nil // move on } @@ -209,7 +207,6 @@ func (ft *FFTokens) handleTokenPoolCreate(ctx context.Context, data fftypes.JSON Type: fftypes.FFEnum(tokenType), ProtocolID: protocolID, TransactionID: poolData.TX, - Key: operatorAddress, Connector: ft.configuredName, Standard: standard, Event: blockchain.Event{ diff --git a/internal/tokens/fftokens/fftokens_test.go b/internal/tokens/fftokens/fftokens_test.go index 9620c3c52f..9b0b71624f 100644 --- a/internal/tokens/fftokens/fftokens_test.go +++ b/internal/tokens/fftokens/fftokens_test.go @@ -211,7 +211,7 @@ func TestCreateTokenPoolSynchronous(t *testing.T) { mcb := h.callbacks.(*tokenmocks.Callbacks) mcb.On("TokenPoolCreated", h, mock.MatchedBy(func(p *tokens.TokenPool) bool { - return p.ProtocolID == "F1" && p.Type == fftypes.TokenTypeFungible && p.Key == "0x0" && *p.TransactionID == *pool.TX.ID && p.Event.ProtocolID == "000000000010/000020/000030/000040" + return p.ProtocolID == "F1" && p.Type == fftypes.TokenTypeFungible && *p.TransactionID == *pool.TX.ID && p.Event.ProtocolID == "000000000010/000020/000030/000040" })).Return(nil) err := h.CreateTokenPool(context.Background(), opID, pool) @@ -361,7 +361,7 @@ func TestActivateTokenPoolSynchronous(t *testing.T) { mcb := h.callbacks.(*tokenmocks.Callbacks) mcb.On("TokenPoolCreated", h, mock.MatchedBy(func(p *tokens.TokenPool) bool { - return p.ProtocolID == "F1" && p.Type == fftypes.TokenTypeFungible && p.Key == "0x0" && p.TransactionID == nil && p.Event.ProtocolID == "" + return p.ProtocolID == "F1" && p.Type == fftypes.TokenTypeFungible && p.TransactionID == nil && p.Event.ProtocolID == "" })).Return(nil) err := h.ActivateTokenPool(context.Background(), opID, pool, ev) @@ -406,7 +406,7 @@ func TestActivateTokenPoolSynchronousBadResponse(t *testing.T) { mcb := h.callbacks.(*tokenmocks.Callbacks) mcb.On("TokenPoolCreated", h, mock.MatchedBy(func(p *tokens.TokenPool) bool { - return p.ProtocolID == "F1" && p.Type == fftypes.TokenTypeFungible && p.Key == "0x0" && p.TransactionID == nil && p.Event.ProtocolID == "" + return p.ProtocolID == "F1" && p.Type == fftypes.TokenTypeFungible && p.TransactionID == nil && p.Event.ProtocolID == "" })).Return(nil) err := h.ActivateTokenPool(context.Background(), opID, pool, ev) @@ -653,7 +653,7 @@ func TestEvents(t *testing.T) { // token-pool: invalid uuid (success) mcb.On("TokenPoolCreated", h, mock.MatchedBy(func(p *tokens.TokenPool) bool { - return p.ProtocolID == "F1" && p.Type == fftypes.TokenTypeFungible && p.Key == "0x0" && p.TransactionID == nil && p.Event.ProtocolID == "000000000010/000020/000030/000040" + return p.ProtocolID == "F1" && p.Type == fftypes.TokenTypeFungible && p.TransactionID == nil && p.Event.ProtocolID == "000000000010/000020/000030/000040" })).Return(nil).Once() fromServer <- fftypes.JSONObject{ "id": "7", @@ -674,7 +674,7 @@ func TestEvents(t *testing.T) { // token-pool: success mcb.On("TokenPoolCreated", h, mock.MatchedBy(func(p *tokens.TokenPool) bool { - return p.ProtocolID == "F1" && p.Type == fftypes.TokenTypeFungible && p.Key == "0x0" && txID.Equals(p.TransactionID) && p.Event.ProtocolID == "000000000010/000020/000030/000040" + return p.ProtocolID == "F1" && p.Type == fftypes.TokenTypeFungible && txID.Equals(p.TransactionID) && p.Event.ProtocolID == "000000000010/000020/000030/000040" })).Return(nil).Once() fromServer <- fftypes.JSONObject{ "id": "8", diff --git a/pkg/database/plugin.go b/pkg/database/plugin.go index b61f494eda..bb0ff62ee9 100644 --- a/pkg/database/plugin.go +++ b/pkg/database/plugin.go @@ -857,7 +857,6 @@ var TokenPoolQueryFactory = &queryFields{ "name": &StringField{}, "standard": &StringField{}, "protocolid": &StringField{}, - "key": &StringField{}, "symbol": &StringField{}, "message": &UUIDField{}, "state": &StringField{}, diff --git a/pkg/tokens/plugin.go b/pkg/tokens/plugin.go index 787f410dc2..3a23e73db7 100644 --- a/pkg/tokens/plugin.go +++ b/pkg/tokens/plugin.go @@ -101,9 +101,6 @@ type TokenPool struct { // Not guaranteed to be set for pool creation events triggered outside of FireFly TransactionID *fftypes.UUID - // Key is the chain-specific identifier for the user that created the pool - Key string - // Connector is the configured name of this connector Connector string From 4e6626f6d5b3dff002e1a17441d8514f1d8260db Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Fri, 28 Jan 2022 19:56:27 -0500 Subject: [PATCH 4/4] Allow secondary token-pool messages to omit transaction ID The transaction ID must be present in the response to /createpool, but it is optional in the response to /activatepool (because on that flow, the TokenPool has already been initialized by the definition broadcast handler). Signed-off-by: Andrew Richardson --- internal/events/token_pool_created.go | 16 +++++++++------- internal/events/token_pool_created_test.go | 3 +++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/internal/events/token_pool_created.go b/internal/events/token_pool_created.go index b64632e054..ec5b0d29ba 100644 --- a/internal/events/token_pool_created.go +++ b/internal/events/token_pool_created.go @@ -132,20 +132,17 @@ func (em *eventManager) shouldAnnounce(ctx context.Context, ti tokens.Plugin, po // It will be invoked on every node (including the submitter) after the pool is announced+activated, to trigger confirmation of the pool. // When received in any other scenario, it should be ignored. func (em *eventManager) TokenPoolCreated(ti tokens.Plugin, pool *tokens.TokenPool) (err error) { - if pool.TransactionID == nil { - log.L(em.ctx).Errorf("Invalid token pool transaction - ID is nil") - return nil // move on - } - var batchID *fftypes.UUID var announcePool *fftypes.TokenPool err = em.retry.Do(em.ctx, "persist token pool transaction", func(attempt int) (bool, error) { err := em.database.RunAsGroup(em.ctx, func(ctx context.Context) error { // See if this is a confirmation of an unconfirmed pool - if existingPool, err := em.shouldConfirm(ctx, pool); err != nil { + existingPool, err := em.shouldConfirm(ctx, pool) + if err != nil { return err - } else if existingPool != nil { + } + if existingPool != nil { if existingPool.State == fftypes.TokenPoolStateConfirmed { return nil // already confirmed } @@ -155,6 +152,11 @@ func (em *eventManager) TokenPoolCreated(ti tokens.Plugin, pool *tokens.TokenPoo batchID = msg.BatchID // trigger rewind after completion of database transaction } return em.confirmPool(ctx, existingPool, &pool.Event, pool.Event.BlockchainTXID) + } else if pool.TransactionID == nil { + // TransactionID is required if the pool doesn't exist yet + // (but it may be omitted when activating a pool that was received via definition broadcast) + log.L(em.ctx).Errorf("Invalid token pool transaction - ID is nil") + return nil // move on } // See if this pool was submitted locally and needs to be announced diff --git a/internal/events/token_pool_created_test.go b/internal/events/token_pool_created_test.go index 4d206848c8..cfe6b1a389 100644 --- a/internal/events/token_pool_created_test.go +++ b/internal/events/token_pool_created_test.go @@ -64,6 +64,7 @@ func TestTokenPoolCreatedIgnore(t *testing.T) { func TestTokenPoolCreatedIgnoreNoTX(t *testing.T) { em, cancel := newTestEventManager(t) defer cancel() + mdi := em.database.(*databasemocks.Plugin) mti := &tokenmocks.Plugin{} info := fftypes.JSONObject{"some": "info"} @@ -79,6 +80,8 @@ func TestTokenPoolCreatedIgnoreNoTX(t *testing.T) { }, } + mdi.On("GetTokenPoolByProtocolID", em.ctx, "erc1155", "123").Return(nil, nil, nil) + err := em.TokenPoolCreated(mti, pool) assert.NoError(t, err) }