diff --git a/.golangci.yml b/.golangci.yml index 00d61e57b6..b983567a5b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -33,7 +33,6 @@ linters: disable: - structcheck enable: - - deadcode - depguard - dogsled - errcheck @@ -56,4 +55,3 @@ linters: - typecheck - unconvert - unused - - varcheck diff --git a/docs/reference/config.md b/docs/reference/config.md index c28874a3b5..1000d191ba 100644 --- a/docs/reference/config.md +++ b/docs/reference/config.md @@ -81,6 +81,7 @@ nav_order: 2 |Key|Description|Type|Default Value| |---|-----------|----|-------------| +|alwaysResolve|Causes the address resolver to be invoked on every API call that submits a signing key, regardless of whether the input string conforms to an 0x address. Also disables any result caching|`boolean`|`` |bodyTemplate|The body go template string to use when making HTTP requests|[Go Template](https://pkg.go.dev/text/template) `string`|`` |connectionTimeout|The maximum amount of time that a connection is allowed to remain with no data transmitted|[`time.Duration`](https://pkg.go.dev/time#Duration)|`30s` |expectContinueTimeout|See [ExpectContinueTimeout in the Go docs](https://pkg.go.dev/net/http#Transport)|[`time.Duration`](https://pkg.go.dev/time#Duration)|`1s` @@ -339,13 +340,6 @@ nav_order: 2 |limit|Max number of cached items for operations|`int`|`` |ttl|Time to live of cached items for operations|`string`|`` -## cache.signingkey - -|Key|Description|Type|Default Value| -|---|-----------|----|-------------| -|limit|Max number of cached signing keys for identity manager|`int`|`` -|ttl|Time to live of cached signing keys for identity manager|`string`|`` - ## cache.transaction |Key|Description|Type|Default Value| @@ -819,6 +813,7 @@ nav_order: 2 |Key|Description|Type|Default Value| |---|-----------|----|-------------| +|alwaysResolve|Causes the address resolver to be invoked on every API call that submits a signing key, regardless of whether the input string conforms to an 0x address. Also disables any result caching|`boolean`|`` |bodyTemplate|The body go template string to use when making HTTP requests|[Go Template](https://pkg.go.dev/text/template) `string`|`` |connectionTimeout|The maximum amount of time that a connection is allowed to remain with no data transmitted|[`time.Duration`](https://pkg.go.dev/time#Duration)|`30s` |expectContinueTimeout|See [ExpectContinueTimeout in the Go docs](https://pkg.go.dev/net/http#Transport)|[`time.Duration`](https://pkg.go.dev/time#Duration)|`1s` diff --git a/internal/apiserver/route_post_verifiers_resolve.go b/internal/apiserver/route_post_verifiers_resolve.go index 29091d06cf..a7c107847e 100644 --- a/internal/apiserver/route_post_verifiers_resolve.go +++ b/internal/apiserver/route_post_verifiers_resolve.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Kaleido, Inc. +// Copyright © 2023 Kaleido, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -36,7 +36,7 @@ var postVerifiersResolve = &ffapi.Route{ JSONOutputCodes: []int{http.StatusOK}, Extensions: &coreExtensions{ CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) { - return cr.or.Identity().ResolveInputSigningKey(cr.ctx, r.Input.(*core.VerifierRef)) + return cr.or.Identity().ResolveInputVerifierRef(cr.ctx, r.Input.(*core.VerifierRef)) }, }, } diff --git a/internal/apiserver/route_post_verifiers_resolve_test.go b/internal/apiserver/route_post_verifiers_resolve_test.go index 9565713508..e080f1c4ff 100644 --- a/internal/apiserver/route_post_verifiers_resolve_test.go +++ b/internal/apiserver/route_post_verifiers_resolve_test.go @@ -40,7 +40,7 @@ func TestPostVerifiersResolve(t *testing.T) { req.Header.Set("Content-Type", "application/json; charset=utf-8") res := httptest.NewRecorder() - im.On("ResolveInputSigningKey", mock.Anything, mock.AnythingOfType("*core.VerifierRef")). + im.On("ResolveInputVerifierRef", mock.Anything, mock.AnythingOfType("*core.VerifierRef")). Return(&core.VerifierRef{}, nil) r.ServeHTTP(res, req) diff --git a/internal/assets/token_approval.go b/internal/assets/token_approval.go index 28ec45d73e..435e630e11 100644 --- a/internal/assets/token_approval.go +++ b/internal/assets/token_approval.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Kaleido, Inc. +// Copyright © 2023 Kaleido, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -189,7 +189,7 @@ func (am *assetManager) validateApproval(ctx context.Context, approval *core.Tok if pool.State != core.TokenPoolStateConfirmed { return nil, i18n.NewError(ctx, coremsgs.MsgTokenPoolNotConfirmed) } - approval.Key, err = am.identity.NormalizeSigningKey(ctx, approval.Key, am.keyNormalization) + approval.Key, err = am.identity.ResolveInputSigningKey(ctx, approval.Key, am.keyNormalization) return pool, err } diff --git a/internal/assets/token_approval_test.go b/internal/assets/token_approval_test.go index 0e7768c3f7..cc81d85db3 100644 --- a/internal/assets/token_approval_test.go +++ b/internal/assets/token_approval_test.go @@ -71,7 +71,7 @@ func TestTokenApprovalSuccess(t *testing.T) { mim := am.identity.(*identitymanagermocks.Manager) mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenApproval, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) @@ -111,7 +111,7 @@ func TestTokenApprovalSuccessUnknownIdentity(t *testing.T) { mim := am.identity.(*identitymanagermocks.Manager) mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenApproval, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) @@ -149,7 +149,7 @@ func TestApprovalBadConnector(t *testing.T) { mdi := am.database.(*databasemocks.Plugin) mim := am.identity.(*identitymanagermocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) _, err := am.TokenApproval(context.Background(), approval, false) @@ -191,7 +191,7 @@ func TestApprovalDefaultPoolSuccess(t *testing.T) { filterResult := &ffapi.FilterResult{ TotalCount: &totalCount, } - mim.On("NormalizeSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPools", context.Background(), "ns1", mock.MatchedBy((func(f ffapi.AndFilter) bool { info, _ := f.Finalize() return info.Count && info.Limit == 1 @@ -257,7 +257,7 @@ func TestApprovalBadPool(t *testing.T) { mdi := am.database.(*databasemocks.Plugin) mim := am.identity.(*identitymanagermocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(nil, fmt.Errorf("pop")) _, err := am.TokenApproval(context.Background(), approval, false) @@ -309,7 +309,7 @@ func TestApprovalIdentityFail(t *testing.T) { mdi := am.database.(*databasemocks.Plugin) mim := am.identity.(*identitymanagermocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) _, err := am.TokenApproval(context.Background(), approval, false) @@ -342,7 +342,7 @@ func TestApprovalFail(t *testing.T) { mim := am.identity.(*identitymanagermocks.Manager) mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenApproval, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) @@ -381,7 +381,7 @@ func TestApprovalTransactionFail(t *testing.T) { mdi := am.database.(*databasemocks.Plugin) mim := am.identity.(*identitymanagermocks.Manager) mth := am.txHelper.(*txcommonmocks.Helper) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenApproval, core.IdempotencyKey("idem1")).Return(nil, fmt.Errorf("pop")) @@ -430,7 +430,7 @@ func TestApprovalWithBroadcastMessage(t *testing.T) { mms := &syncasyncmocks.Sender{} mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenApproval, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) @@ -526,7 +526,7 @@ func TestApprovalWithBroadcastMessageSendFail(t *testing.T) { mms := &syncasyncmocks.Sender{} mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenApproval, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) @@ -617,7 +617,7 @@ func TestApprovalWithPrivateMessage(t *testing.T) { mms := &syncasyncmocks.Sender{} mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenApproval, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) @@ -727,7 +727,7 @@ func TestApprovalOperationsFail(t *testing.T) { mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenApproval, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(fmt.Errorf("pop")) @@ -765,7 +765,7 @@ func TestTokenApprovalConfirm(t *testing.T) { msa := am.syncasync.(*syncasyncmocks.Bridge) mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenApproval, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) @@ -831,7 +831,7 @@ func TestApprovalWithBroadcastConfirm(t *testing.T) { msa := am.syncasync.(*syncasyncmocks.Bridge) mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenApproval, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) @@ -890,7 +890,7 @@ func TestApprovalPrepare(t *testing.T) { mdi := am.database.(*databasemocks.Plugin) mim := am.identity.(*identitymanagermocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) err := sender.Prepare(context.Background()) diff --git a/internal/assets/token_pool.go b/internal/assets/token_pool.go index 93644430cc..87fd56e998 100644 --- a/internal/assets/token_pool.go +++ b/internal/assets/token_pool.go @@ -56,7 +56,7 @@ func (am *assetManager) CreateTokenPool(ctx context.Context, pool *core.TokenPoo } var err error - pool.Key, err = am.identity.NormalizeSigningKey(ctx, pool.Key, am.keyNormalization) + pool.Key, err = am.identity.ResolveInputSigningKey(ctx, pool.Key, am.keyNormalization) if err != nil { return nil, err } diff --git a/internal/assets/token_pool_test.go b/internal/assets/token_pool_test.go index 7c2ace87ed..e44d84d797 100644 --- a/internal/assets/token_pool_test.go +++ b/internal/assets/token_pool_test.go @@ -100,7 +100,7 @@ func TestCreateTokenPoolDefaultConnectorSuccess(t *testing.T) { mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) mdi.On("GetTokenPool", context.Background(), "ns1", "testpool").Return(nil, nil) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("resolved-key", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("resolved-key", nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenPool, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) mom.On("RunOperation", context.Background(), mock.MatchedBy(func(op *core.PreparedOperation) bool { @@ -193,7 +193,7 @@ func TestCreateTokenPoolIdentityFail(t *testing.T) { mdi := am.database.(*databasemocks.Plugin) mim := am.identity.(*identitymanagermocks.Manager) mdi.On("GetTokenPool", context.Background(), "ns1", "testpool").Return(nil, nil) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) _, err := am.CreateTokenPool(context.Background(), pool, false) assert.EqualError(t, err, "pop") @@ -216,7 +216,7 @@ func TestCreateTokenPoolWrongConnector(t *testing.T) { mdi := am.database.(*databasemocks.Plugin) mim := am.identity.(*identitymanagermocks.Manager) mdi.On("GetTokenPool", context.Background(), "ns1", "testpool").Return(nil, nil) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) _, err := am.CreateTokenPool(context.Background(), pool, false) assert.Regexp(t, "FF10272", err) @@ -242,7 +242,7 @@ func TestCreateTokenPoolFail(t *testing.T) { mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) mdi.On("GetTokenPool", context.Background(), "ns1", "testpool").Return(nil, nil) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenPool, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) mom.On("RunOperation", context.Background(), mock.MatchedBy(func(op *core.PreparedOperation) bool { @@ -275,7 +275,7 @@ func TestCreateTokenPoolTransactionFail(t *testing.T) { mim := am.identity.(*identitymanagermocks.Manager) mth := am.txHelper.(*txcommonmocks.Helper) mdi.On("GetTokenPool", context.Background(), "ns1", "testpool").Return(nil, nil) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenPool, core.IdempotencyKey("idem1")).Return(nil, fmt.Errorf("pop")) _, err := am.CreateTokenPool(context.Background(), pool, false) @@ -303,7 +303,7 @@ func TestCreateTokenPoolOpInsertFail(t *testing.T) { mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) mdi.On("GetTokenPool", context.Background(), "ns1", "testpool").Return(nil, nil) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenPool, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(fmt.Errorf("pop")) @@ -360,7 +360,7 @@ func TestCreateTokenPoolSyncSuccess(t *testing.T) { mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) mdi.On("GetTokenPool", context.Background(), "ns1", "testpool").Return(nil, nil) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenPool, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) mom.On("RunOperation", context.Background(), mock.MatchedBy(func(op *core.PreparedOperation) bool { @@ -394,7 +394,7 @@ func TestCreateTokenPoolAsyncSuccess(t *testing.T) { mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) mdi.On("GetTokenPool", context.Background(), "ns1", "testpool").Return(nil, nil) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenPool, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) mom.On("RunOperation", context.Background(), mock.MatchedBy(func(op *core.PreparedOperation) bool { @@ -429,7 +429,7 @@ func TestCreateTokenPoolConfirm(t *testing.T) { mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) mdi.On("GetTokenPool", context.Background(), "ns1", "testpool").Return(nil, nil) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenPool, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) msa.On("WaitForTokenPool", context.Background(), mock.Anything, mock.Anything). diff --git a/internal/assets/token_transfer.go b/internal/assets/token_transfer.go index 29be876792..86cc2e7a69 100644 --- a/internal/assets/token_transfer.go +++ b/internal/assets/token_transfer.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Kaleido, Inc. +// Copyright © 2023 Kaleido, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -103,7 +103,7 @@ func (am *assetManager) validateTransfer(ctx context.Context, transfer *core.Tok if pool.State != core.TokenPoolStateConfirmed { return nil, i18n.NewError(ctx, coremsgs.MsgTokenPoolNotConfirmed) } - if transfer.Key, err = am.identity.NormalizeSigningKey(ctx, transfer.Key, am.keyNormalization); err != nil { + if transfer.Key, err = am.identity.ResolveInputSigningKey(ctx, transfer.Key, am.keyNormalization); err != nil { return nil, err } if transfer.From == "" { diff --git a/internal/assets/token_transfer_test.go b/internal/assets/token_transfer_test.go index 83a591719b..d020788148 100644 --- a/internal/assets/token_transfer_test.go +++ b/internal/assets/token_transfer_test.go @@ -91,7 +91,7 @@ func TestMintTokensSuccess(t *testing.T) { mim := am.identity.(*identitymanagermocks.Manager) mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenTransfer, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) @@ -126,7 +126,7 @@ func TestMintTokensBadConnector(t *testing.T) { mdi := am.database.(*databasemocks.Plugin) mim := am.identity.(*identitymanagermocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) _, err := am.MintTokens(context.Background(), mint, false) @@ -165,7 +165,7 @@ func TestMintTokenDefaultPoolSuccess(t *testing.T) { filterResult := &ffapi.FilterResult{ TotalCount: &totalCount, } - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPools", context.Background(), "ns1", mock.MatchedBy((func(f ffapi.AndFilter) bool { info, _ := f.Finalize() return info.Count && info.Limit == 1 @@ -309,7 +309,7 @@ func TestMintTokensIdentityFail(t *testing.T) { mdi := am.database.(*databasemocks.Plugin) mim := am.identity.(*identitymanagermocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) _, err := am.MintTokens(context.Background(), mint, false) @@ -339,7 +339,7 @@ func TestMintTokensFail(t *testing.T) { mim := am.identity.(*identitymanagermocks.Manager) mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenTransfer, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) @@ -378,7 +378,7 @@ func TestMintTokensOperationFail(t *testing.T) { mim := am.identity.(*identitymanagermocks.Manager) mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenTransfer, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(fmt.Errorf("pop")) @@ -413,7 +413,7 @@ func TestMintTokensConfirm(t *testing.T) { mim := am.identity.(*identitymanagermocks.Manager) mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenTransfer, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) @@ -456,7 +456,7 @@ func TestBurnTokensSuccess(t *testing.T) { mim := am.identity.(*identitymanagermocks.Manager) mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenTransfer, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) @@ -491,7 +491,7 @@ func TestBurnTokensIdentityFail(t *testing.T) { mdi := am.database.(*databasemocks.Plugin) mim := am.identity.(*identitymanagermocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) _, err := am.BurnTokens(context.Background(), burn, false) @@ -522,7 +522,7 @@ func TestBurnTokensConfirm(t *testing.T) { mim := am.identity.(*identitymanagermocks.Manager) mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenTransfer, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) @@ -568,7 +568,7 @@ func TestTransferTokensSuccess(t *testing.T) { mim := am.identity.(*identitymanagermocks.Manager) mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenTransfer, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) @@ -632,7 +632,7 @@ func TestTransferTokensIdentityFail(t *testing.T) { mdi := am.database.(*databasemocks.Plugin) mim := am.identity.(*identitymanagermocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) _, err := am.TransferTokens(context.Background(), transfer, false) @@ -656,7 +656,7 @@ func TestTransferTokensNoFromOrTo(t *testing.T) { mdi := am.database.(*databasemocks.Plugin) mim := am.identity.(*identitymanagermocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) _, err := am.TransferTokens(context.Background(), transfer, false) @@ -688,7 +688,7 @@ func TestTransferTokensTransactionFail(t *testing.T) { mdi := am.database.(*databasemocks.Plugin) mim := am.identity.(*identitymanagermocks.Manager) mth := am.txHelper.(*txcommonmocks.Helper) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenTransfer, core.IdempotencyKey("idem1")).Return(nil, fmt.Errorf("pop")) @@ -739,7 +739,7 @@ func TestTransferTokensWithBroadcastMessage(t *testing.T) { mms := &syncasyncmocks.Sender{} mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenTransfer, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) @@ -836,7 +836,7 @@ func TestTransferTokensWithBroadcastMessageSendFail(t *testing.T) { mms := &syncasyncmocks.Sender{} mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenTransfer, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) @@ -929,7 +929,7 @@ func TestTransferTokensWithPrivateMessage(t *testing.T) { mms := &syncasyncmocks.Sender{} mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenTransfer, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) @@ -1040,7 +1040,7 @@ func TestTransferTokensConfirm(t *testing.T) { mim := am.identity.(*identitymanagermocks.Manager) mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenTransfer, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) @@ -1105,7 +1105,7 @@ func TestTransferTokensWithBroadcastConfirm(t *testing.T) { msa := am.syncasync.(*syncasyncmocks.Bridge) mth := am.txHelper.(*txcommonmocks.Helper) mom := am.operations.(*operationmocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) mom.On("AddOrReuseOperation", context.Background(), mock.Anything).Return(nil) mth.On("SubmitNewTransaction", context.Background(), core.TransactionTypeTokenTransfer, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) @@ -1186,7 +1186,7 @@ func TestTransferPrepare(t *testing.T) { mdi := am.database.(*databasemocks.Plugin) mim := am.identity.(*identitymanagermocks.Manager) - mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) + mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil) mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil) err := sender.Prepare(context.Background()) diff --git a/internal/blockchain/ethereum/address_resolver.go b/internal/blockchain/ethereum/address_resolver.go index c1346e5d5b..abe61b4e5e 100644 --- a/internal/blockchain/ethereum/address_resolver.go +++ b/internal/blockchain/ethereum/address_resolver.go @@ -52,24 +52,25 @@ type addressResolverInserts struct { Key string } -func newAddressResolver(ctx context.Context, localConfig config.Section, cacheManager cache.Manager) (ar *addressResolver, err error) { - cache, err := cacheManager.GetCache( - cache.NewCacheConfig( - ctx, - coreconfig.CacheAddressResolverLimit, - coreconfig.CacheAddressResolverTTL, - "", - ), - ) - if err != nil { - return nil, err - } +func newAddressResolver(ctx context.Context, localConfig config.Section, cacheManager cache.Manager, enableCache bool) (ar *addressResolver, err error) { ar = &addressResolver{ retainOriginal: localConfig.GetBool(AddressResolverRetainOriginal), method: localConfig.GetString(AddressResolverMethod), responseField: localConfig.GetString(AddressResolverResponseField), client: ffresty.New(ctx, localConfig), - cache: cache, + } + if enableCache { + ar.cache, err = cacheManager.GetCache( + cache.NewCacheConfig( + ctx, + coreconfig.CacheAddressResolverLimit, + coreconfig.CacheAddressResolverTTL, + "", + ), + ) + if err != nil { + return nil, err + } } urlTemplateString := localConfig.GetString(AddressResolverURLTemplate) @@ -89,10 +90,12 @@ func newAddressResolver(ctx context.Context, localConfig config.Section, cacheMa return ar, nil } -func (ar *addressResolver) NormalizeSigningKey(ctx context.Context, keyDescriptor string) (string, error) { +func (ar *addressResolver) ResolveInputSigningKey(ctx context.Context, keyDescriptor string) (string, error) { - if cached := ar.cache.GetString(keyDescriptor); cached != "" { - return cached, nil + if ar.cache != nil { + if cached := ar.cache.GetString(keyDescriptor); cached != "" { + return cached, nil + } } inserts := &addressResolverInserts{ @@ -126,11 +129,13 @@ func (ar *addressResolver) NormalizeSigningKey(ctx context.Context, keyDescripto return "", i18n.NewError(ctx, coremsgs.MsgAddressResolveBadStatus, keyDescriptor, res.StatusCode(), jsonRes.String()) } - address, err := validateEthAddress(ctx, jsonRes.GetString(ar.responseField)) + address, err := formatEthAddress(ctx, jsonRes.GetString(ar.responseField)) if err != nil { return "", i18n.NewError(ctx, coremsgs.MsgAddressResolveBadResData, keyDescriptor, jsonRes.String(), err) } - ar.cache.SetString(keyDescriptor, address) + if ar.cache != nil { + ar.cache.SetString(keyDescriptor, address) + } return address, nil } diff --git a/internal/blockchain/ethereum/address_resolver_test.go b/internal/blockchain/ethereum/address_resolver_test.go index e89746ece8..bdca0cee72 100644 --- a/internal/blockchain/ethereum/address_resolver_test.go +++ b/internal/blockchain/ethereum/address_resolver_test.go @@ -50,10 +50,21 @@ func TestCacheInitFail(t *testing.T) { cmi := &cachemocks.Manager{} cmi.On("GetCache", mock.Anything).Return(nil, cacheInitError) - _, err := newAddressResolver(ctx, config, cmi) + _, err := newAddressResolver(ctx, config, cmi, true) assert.Equal(t, cacheInitError, err) } +func newAddressResolverTestEth(t *testing.T, config config.Section) (context.Context, *Ethereum, context.CancelFunc) { + ctx, cancel := context.WithCancel(context.Background()) + cmi := &cachemocks.Manager{} + cmi.On("GetCache", mock.Anything).Return(cache.NewUmanagedCache(ctx, 100, 5*time.Minute), nil) + e := &Ethereum{ctx: ctx} + var err error + e.addressResolver, err = newAddressResolver(ctx, config, cmi, true) + assert.NoError(t, err) + return ctx, e, cancel +} + func TestAddressResolverInEthereumOKCached(t *testing.T) { count := 0 @@ -72,26 +83,57 @@ func TestAddressResolverInEthereumOKCached(t *testing.T) { config := utAddresResolverConfig() config.Set(AddressResolverURLTemplate, fmt.Sprintf("%s/resolve/{{.Key}}", server.URL)) - ctx, cancel := context.WithCancel(context.Background()) - cmi := &cachemocks.Manager{} - cmi.On("GetCache", mock.Anything).Return(cache.NewUmanagedCache(ctx, 100, 5*time.Minute), nil) + ctx, e, cancel := newAddressResolverTestEth(t, config) defer cancel() - ar, err := newAddressResolver(ctx, config, cmi) + resolved, err := e.ResolveInputSigningKey(ctx, "testkeystring") + assert.NoError(t, err) + assert.Equal(t, strings.ToLower(addr), resolved) + + resolved, err = e.ResolveInputSigningKey(ctx, "testkeystring") // cached assert.NoError(t, err) + assert.Equal(t, strings.ToLower(addr), resolved) +} + +func TestAddressResolverForceNoCacheAlwaysInvoke(t *testing.T) { + + count := 0 + addr1 := "0xf1A9dB812D6710040185e9d981A0AB25003878ce" + addr2 := "0xffffffffffffffffffffffffffffffffffffffff" + server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.Header().Set("Content-Type", "application/json") + assert.Equal(t, "GET", r.Method) + assert.Equal(t, fmt.Sprintf("/resolve/%s", addr1), r.URL.Path) + rw.WriteHeader(200) + // arbitrarily map addr1 to addr2 + rw.Write([]byte(fmt.Sprintf(`{"address":"%s"}`, addr2))) + count++ + })) + defer server.Close() + + config := utAddresResolverConfig() + config.Set(AddressResolverURLTemplate, fmt.Sprintf("%s/resolve/{{.Key}}", server.URL)) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() e := &Ethereum{ - ctx: ctx, - addressResolver: ar, + ctx: ctx, + addressResolveAlways: true, } + var err error + e.addressResolver, err = newAddressResolver(ctx, config, nil, false) + assert.NoError(t, err) - resolved, err := e.NormalizeSigningKey(ctx, "testkeystring") + resolved, err := e.ResolveInputSigningKey(ctx, addr1) assert.NoError(t, err) - assert.Equal(t, strings.ToLower(addr), resolved) + assert.Equal(t, strings.ToLower(addr2), resolved) - resolved, err = e.NormalizeSigningKey(ctx, "testkeystring") // cached + resolved, err = e.ResolveInputSigningKey(ctx, addr1) assert.NoError(t, err) - assert.Equal(t, strings.ToLower(addr), resolved) + assert.Equal(t, strings.ToLower(addr2), resolved) + + assert.Equal(t, count, 2) } func TestAddressResolverPOSTOk(t *testing.T) { @@ -114,14 +156,10 @@ func TestAddressResolverPOSTOk(t *testing.T) { config.Set(AddressResolverBodyTemplate, `{"key":"{{.Key}}"}`) config.Set(AddressResolverResponseField, "Addr") - ctx, cancel := context.WithCancel(context.Background()) + ctx, e, cancel := newAddressResolverTestEth(t, config) defer cancel() - cmi := &cachemocks.Manager{} - cmi.On("GetCache", mock.Anything).Return(cache.NewUmanagedCache(ctx, 100, 5*time.Minute), nil) - ar, err := newAddressResolver(ctx, config, cmi) - assert.NoError(t, err) - resolved, err := ar.NormalizeSigningKey(ctx, "testkeystring") + resolved, err := e.addressResolver.ResolveInputSigningKey(ctx, "testkeystring") assert.NoError(t, err) assert.Equal(t, strings.ToLower(addr), resolved) @@ -142,14 +180,10 @@ func TestAddressResolverPOSTBadKey(t *testing.T) { config.Set(AddressResolverURLTemplate, fmt.Sprintf("%s/resolve", server.URL)) config.Set(AddressResolverBodyTemplate, `{"key":"{{.Key}}"}`) - ctx, cancel := context.WithCancel(context.Background()) + ctx, e, cancel := newAddressResolverTestEth(t, config) defer cancel() - cmi := &cachemocks.Manager{} - cmi.On("GetCache", mock.Anything).Return(cache.NewUmanagedCache(ctx, 100, 5*time.Minute), nil) - ar, err := newAddressResolver(ctx, config, cmi) - assert.NoError(t, err) - _, err = ar.NormalizeSigningKey(ctx, "testkeystring") + _, err := e.addressResolver.ResolveInputSigningKey(ctx, "testkeystring") assert.Regexp(t, "FF10341", err) } @@ -166,14 +200,10 @@ func TestAddressResolverPOSTResponse(t *testing.T) { config.Set(AddressResolverURLTemplate, fmt.Sprintf("%s/resolve", server.URL)) config.Set(AddressResolverBodyTemplate, `{"key":"{{.Key}}"}`) - ctx, cancel := context.WithCancel(context.Background()) + ctx, e, cancel := newAddressResolverTestEth(t, config) defer cancel() - cmi := &cachemocks.Manager{} - cmi.On("GetCache", mock.Anything).Return(cache.NewUmanagedCache(ctx, 100, 5*time.Minute), nil) - ar, err := newAddressResolver(ctx, config, cmi) - assert.NoError(t, err) - _, err = ar.NormalizeSigningKey(ctx, "testkeystring") + _, err := e.addressResolver.ResolveInputSigningKey(ctx, "testkeystring") assert.Regexp(t, "FF10341", err) } @@ -188,14 +218,10 @@ func TestAddressResolverFailureResponse(t *testing.T) { config := utAddresResolverConfig() config.Set(AddressResolverURLTemplate, fmt.Sprintf("%s/resolve/{{.Key}}", server.URL)) - ctx, cancel := context.WithCancel(context.Background()) + ctx, e, cancel := newAddressResolverTestEth(t, config) defer cancel() - cmi := &cachemocks.Manager{} - cmi.On("GetCache", mock.Anything).Return(cache.NewUmanagedCache(ctx, 100, 5*time.Minute), nil) - ar, err := newAddressResolver(ctx, config, cmi) - assert.NoError(t, err) - _, err = ar.NormalizeSigningKey(ctx, "testkeystring") + _, err := e.addressResolver.ResolveInputSigningKey(ctx, "testkeystring") assert.Regexp(t, "FF10340", err) } @@ -210,14 +236,10 @@ func TestAddressResolverErrorResponse(t *testing.T) { config := utAddresResolverConfig() config.Set(AddressResolverURLTemplate, fmt.Sprintf("%s/resolve/{{.Key}}", server.URL)) - ctx, cancel := context.WithCancel(context.Background()) + ctx, e, cancel := newAddressResolverTestEth(t, config) defer cancel() - cmi := &cachemocks.Manager{} - cmi.On("GetCache", mock.Anything).Return(cache.NewUmanagedCache(ctx, 100, 5*time.Minute), nil) - ar, err := newAddressResolver(ctx, config, cmi) - assert.NoError(t, err) - _, err = ar.NormalizeSigningKey(ctx, "testkeystring") + _, err := e.addressResolver.ResolveInputSigningKey(ctx, "testkeystring") assert.Regexp(t, "FF10339", err) } @@ -232,7 +254,7 @@ func TestAddressResolverBadBodyTemplate(t *testing.T) { defer cancel() cmi := &cachemocks.Manager{} cmi.On("GetCache", mock.Anything).Return(cache.NewUmanagedCache(ctx, 100, 5*time.Minute), nil) - _, err := newAddressResolver(ctx, config, cmi) + _, err := newAddressResolver(ctx, config, cmi, true) assert.Regexp(t, "FF10337.*bodyTemplate", err) } @@ -242,14 +264,10 @@ func TestAddressResolverErrorURLTemplate(t *testing.T) { config := utAddresResolverConfig() config.Set(AddressResolverURLTemplate, "http://ff.example/resolve/{{.Wrong}}") - ctx, cancel := context.WithCancel(context.Background()) + ctx, e, cancel := newAddressResolverTestEth(t, config) defer cancel() - cmi := &cachemocks.Manager{} - cmi.On("GetCache", mock.Anything).Return(cache.NewUmanagedCache(ctx, 100, 5*time.Minute), nil) - ar, err := newAddressResolver(ctx, config, cmi) - assert.NoError(t, err) - _, err = ar.NormalizeSigningKey(ctx, "testkeystring") + _, err := e.addressResolver.ResolveInputSigningKey(ctx, "testkeystring") assert.Regexp(t, "FF10338.*urlTemplate", err) } @@ -264,7 +282,7 @@ func TestAddressResolverErrorBodyTemplate(t *testing.T) { defer cancel() cmi := &cachemocks.Manager{} cmi.On("GetCache", mock.Anything).Return(cache.NewUmanagedCache(ctx, 100, 5*time.Minute), nil) - ar, err := newAddressResolver(ctx, config, cmi) + ar, err := newAddressResolver(ctx, config, cmi, true) cmi.AssertCalled(t, "GetCache", cache.NewCacheConfig( ctx, coreconfig.CacheAddressResolverLimit, @@ -273,7 +291,7 @@ func TestAddressResolverErrorBodyTemplate(t *testing.T) { )) assert.NoError(t, err) - _, err = ar.NormalizeSigningKey(ctx, "testkeystring") + _, err = ar.ResolveInputSigningKey(ctx, "testkeystring") assert.Regexp(t, "FF10338.*bodyTemplate", err) } diff --git a/internal/blockchain/ethereum/config.go b/internal/blockchain/ethereum/config.go index f250004fcc..875dc9bb52 100644 --- a/internal/blockchain/ethereum/config.go +++ b/internal/blockchain/ethereum/config.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Kaleido, Inc. +// Copyright © 2023 Kaleido, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -54,6 +54,8 @@ const ( // AddressResolverConfigKey is a sub-key in the config to contain an address resolver config. AddressResolverConfigKey = "addressResolver" + // AddressResolverAlwaysResolve causes the address resolve to be invoked on every API call that resolves an address, regardless of whether the input conforms to an 0x address, and disables any caching + AddressResolverAlwaysResolve = "alwaysResolve" // AddressResolverRetainOriginal when true the original pre-resolved string is retained after the lookup, and passed down to Ethconnect as the from address AddressResolverRetainOriginal = "retainOriginal" // AddressResolverMethod the HTTP method to use to call the address resolver (default GET) @@ -85,6 +87,7 @@ func (e *Ethereum) InitConfig(config config.Section) { addressResolverConf := config.SubSection(AddressResolverConfigKey) ffresty.InitConfig(addressResolverConf) + addressResolverConf.AddKnownKey(AddressResolverAlwaysResolve) addressResolverConf.AddKnownKey(AddressResolverRetainOriginal) addressResolverConf.AddKnownKey(AddressResolverMethod, defaultAddressResolverMethod) addressResolverConf.AddKnownKey(AddressResolverURLTemplate) diff --git a/internal/blockchain/ethereum/ethereum.go b/internal/blockchain/ethereum/ethereum.go index 38cc391f6e..ed348f903e 100644 --- a/internal/blockchain/ethereum/ethereum.go +++ b/internal/blockchain/ethereum/ethereum.go @@ -57,23 +57,24 @@ const ( ) type Ethereum struct { - ctx context.Context - cancelCtx context.CancelFunc - topic string - prefixShort string - prefixLong string - capabilities *blockchain.Capabilities - callbacks common.BlockchainCallbacks - client *resty.Client - streams *streamManager - streamID string - wsconn wsclient.WSClient - closed chan struct{} - addressResolver *addressResolver - metrics metrics.Manager - ethconnectConf config.Section - subs common.FireflySubscriptions - cache cache.CInterface + ctx context.Context + cancelCtx context.CancelFunc + topic string + prefixShort string + prefixLong string + capabilities *blockchain.Capabilities + callbacks common.BlockchainCallbacks + client *resty.Client + streams *streamManager + streamID string + wsconn wsclient.WSClient + closed chan struct{} + addressResolveAlways bool + addressResolver *addressResolver + metrics metrics.Manager + ethconnectConf config.Section + subs common.FireflySubscriptions + cache cache.CInterface } type eventStreamWebsocket struct { @@ -149,7 +150,9 @@ func (e *Ethereum) Init(ctx context.Context, cancelCtx context.CancelFunc, conf e.subs = common.NewFireflySubscriptions() if addressResolverConf.GetString(AddressResolverURLTemplate) != "" { - if e.addressResolver, err = newAddressResolver(ctx, addressResolverConf, cacheManager); err != nil { + // Check if we need to invoke the address resolver (without caching) on every call + e.addressResolveAlways = addressResolverConf.GetBool(AddressResolverAlwaysResolve) + if e.addressResolver, err = newAddressResolver(ctx, addressResolverConf, cacheManager, !e.addressResolveAlways); err != nil { return err } } @@ -221,7 +224,7 @@ func (e *Ethereum) Capabilities() *blockchain.Capabilities { } func (e *Ethereum) AddFireflySubscription(ctx context.Context, namespace *core.Namespace, location *fftypes.JSONAny, firstEvent string) (string, error) { - ethLocation, err := parseContractLocation(ctx, location) + ethLocation, err := e.parseContractLocation(ctx, location) if err != nil { return "", err } @@ -324,7 +327,9 @@ func (e *Ethereum) handleBatchPinEvent(ctx context.Context, location *fftypes.JS Contexts: event.Output.GetStringArray("contexts"), } - authorAddress, err = e.NormalizeSigningKey(ctx, authorAddress) + // Validate the ethereum address - it must already be a valid address, we do not + // engage the address resolve on this blockchain-driven path. + authorAddress, err = formatEthAddress(ctx, authorAddress) if err != nil { log.L(ctx).Errorf("BatchPin event is not valid - bad from address (%s): %+v", err, msgJSON) return nil // move on @@ -377,7 +382,7 @@ func (e *Ethereum) handleMessageBatch(ctx context.Context, messages []interface{ // Matches one of the active FireFly BatchPin subscriptions if subInfo := e.subs.GetSubscription(sub); subInfo != nil { - location, err := encodeContractLocation(ctx, &Location{ + location, err := e.encodeContractLocation(ctx, &Location{ Address: msgJSON.GetString("address"), }) if err != nil { @@ -484,7 +489,7 @@ func (e *Ethereum) eventLoop() { } } -func validateEthAddress(ctx context.Context, key string) (string, error) { +func formatEthAddress(ctx context.Context, key string) (string, error) { keyLower := strings.ToLower(key) keyNoHexPrefix := strings.TrimPrefix(keyLower, "0x") if addressVerify.MatchString(keyNoHexPrefix) { @@ -493,14 +498,20 @@ func validateEthAddress(ctx context.Context, key string) (string, error) { return "", i18n.NewError(ctx, coremsgs.MsgInvalidEthAddress) } -func (e *Ethereum) NormalizeSigningKey(ctx context.Context, key string) (string, error) { - resolved, err := validateEthAddress(ctx, key) - if err != nil && e.addressResolver != nil { - resolved, err := e.addressResolver.NormalizeSigningKey(ctx, key) +func (e *Ethereum) ResolveInputSigningKey(ctx context.Context, key string) (resolved string, err error) { + if !e.addressResolveAlways { + // If there's no address resolver plugin, or addressResolveAlways is false, + // we check if it's already an ethereum address - in which case we can just return it. + resolved, err = formatEthAddress(ctx, key) + } + if e.addressResolveAlways || (err != nil && e.addressResolver != nil) { + // Either it's not a valid ethereum address, + // or we've been configured to invoke the address resolver on every call + resolved, err = e.addressResolver.ResolveInputSigningKey(ctx, key) if err == nil { log.L(ctx).Infof("Key '%s' resolved to '%s'", key, resolved) + return resolved, nil } - return resolved, err } return resolved, err } @@ -589,7 +600,7 @@ func (e *Ethereum) queryContractMethod(ctx context.Context, address string, abi } func (e *Ethereum) SubmitBatchPin(ctx context.Context, nsOpID, networkNamespace, signingKey string, batch *blockchain.BatchPin, location *fftypes.JSONAny) error { - ethLocation, err := parseContractLocation(ctx, location) + ethLocation, err := e.parseContractLocation(ctx, location) if err != nil { return err } @@ -633,7 +644,7 @@ func (e *Ethereum) SubmitBatchPin(ctx context.Context, nsOpID, networkNamespace, } func (e *Ethereum) SubmitNetworkAction(ctx context.Context, nsOpID string, signingKey string, action core.NetworkActionType, location *fftypes.JSONAny) error { - ethLocation, err := parseContractLocation(ctx, location) + ethLocation, err := e.parseContractLocation(ctx, location) if err != nil { return err } @@ -707,7 +718,7 @@ func (e *Ethereum) DeployContract(ctx context.Context, nsOpID, signingKey string } func (e *Ethereum) InvokeContract(ctx context.Context, nsOpID string, signingKey string, location *fftypes.JSONAny, method *fftypes.FFIMethod, input map[string]interface{}, errors []*fftypes.FFIError, options map[string]interface{}) error { - ethereumLocation, err := parseContractLocation(ctx, location) + ethereumLocation, err := e.parseContractLocation(ctx, location) if err != nil { return err } @@ -719,7 +730,7 @@ func (e *Ethereum) InvokeContract(ctx context.Context, nsOpID string, signingKey } func (e *Ethereum) QueryContract(ctx context.Context, location *fftypes.JSONAny, method *fftypes.FFIMethod, input map[string]interface{}, errors []*fftypes.FFIError, options map[string]interface{}) (interface{}, error) { - ethereumLocation, err := parseContractLocation(ctx, location) + ethereumLocation, err := e.parseContractLocation(ctx, location) if err != nil { return nil, err } @@ -739,14 +750,14 @@ func (e *Ethereum) QueryContract(ctx context.Context, location *fftypes.JSONAny, } func (e *Ethereum) NormalizeContractLocation(ctx context.Context, location *fftypes.JSONAny) (result *fftypes.JSONAny, err error) { - parsed, err := parseContractLocation(ctx, location) + parsed, err := e.parseContractLocation(ctx, location) if err != nil { return nil, err } - return encodeContractLocation(ctx, parsed) + return e.encodeContractLocation(ctx, parsed) } -func parseContractLocation(ctx context.Context, location *fftypes.JSONAny) (*Location, error) { +func (e *Ethereum) parseContractLocation(ctx context.Context, location *fftypes.JSONAny) (*Location, error) { ethLocation := Location{} if err := json.Unmarshal(location.Bytes(), ðLocation); err != nil { return nil, i18n.NewError(ctx, coremsgs.MsgContractLocationInvalid, err) @@ -757,8 +768,8 @@ func parseContractLocation(ctx context.Context, location *fftypes.JSONAny) (*Loc return ðLocation, nil } -func encodeContractLocation(ctx context.Context, location *Location) (result *fftypes.JSONAny, err error) { - location.Address, err = validateEthAddress(ctx, location.Address) +func (e *Ethereum) encodeContractLocation(ctx context.Context, location *Location) (result *fftypes.JSONAny, err error) { + location.Address, err = formatEthAddress(ctx, location.Address) if err != nil { return nil, err } @@ -772,7 +783,7 @@ func encodeContractLocation(ctx context.Context, location *Location) (result *ff func (e *Ethereum) AddContractListener(ctx context.Context, listener *core.ContractListenerInput) (err error) { var location *Location if listener.Location != nil { - location, err = parseContractLocation(ctx, listener.Location) + location, err = e.parseContractLocation(ctx, listener.Location) if err != nil { return err } @@ -886,7 +897,7 @@ func (e *Ethereum) GenerateFFI(ctx context.Context, generationRequest *fftypes.F } func (e *Ethereum) GetNetworkVersion(ctx context.Context, location *fftypes.JSONAny) (version int, err error) { - ethLocation, err := parseContractLocation(ctx, location) + ethLocation, err := e.parseContractLocation(ctx, location) if err != nil { return 0, err } @@ -953,7 +964,7 @@ func (e *Ethereum) GetAndConvertDeprecatedContractConfig(ctx context.Context) (l address = strings.Replace(address, "/instances/", "", 1) } - location, err = encodeContractLocation(ctx, &Location{ + location, err = e.encodeContractLocation(ctx, &Location{ Address: address, }) return location, fromBlock, err diff --git a/internal/blockchain/ethereum/ethereum_test.go b/internal/blockchain/ethereum/ethereum_test.go index 0ea79022ac..d98ebb053f 100644 --- a/internal/blockchain/ethereum/ethereum_test.go +++ b/internal/blockchain/ethereum/ethereum_test.go @@ -1113,10 +1113,10 @@ func TestVerifyEthAddress(t *testing.T) { e, cancel := newTestEthereum() defer cancel() - _, err := e.NormalizeSigningKey(context.Background(), "0x12345") + _, err := e.ResolveInputSigningKey(context.Background(), "0x12345") assert.Regexp(t, "FF10141", err) - key, err := e.NormalizeSigningKey(context.Background(), "0x2a7c9D5248681CE6c393117E641aD037F5C079F6") + key, err := e.ResolveInputSigningKey(context.Background(), "0x2a7c9D5248681CE6c393117E641aD037F5C079F6") assert.NoError(t, err) assert.Equal(t, "0x2a7c9d5248681ce6c393117e641ad037f5c079f6", key) @@ -3282,7 +3282,7 @@ func TestConvertDeprecatedContractConfig(t *testing.T) { assert.Equal(t, "0", fromBlock) assert.NoError(t, err) - location, err := parseContractLocation(e.ctx, locationBytes) + location, err := e.parseContractLocation(e.ctx, locationBytes) assert.NoError(t, err) assert.Equal(t, "0x71c7656ec7ab88b098defb751b7401b5f6d8976f", location.Address) @@ -3329,7 +3329,7 @@ func TestConvertDeprecatedContractConfigContractURL(t *testing.T) { assert.NoError(t, err) assert.Equal(t, "0", fromBlock) - location, err := parseContractLocation(e.ctx, locationBytes) + location, err := e.parseContractLocation(e.ctx, locationBytes) assert.NoError(t, err) assert.Equal(t, "0x71c7656ec7ab88b098defb751b7401b5f6d8976f", location.Address) diff --git a/internal/blockchain/fabric/fabric.go b/internal/blockchain/fabric/fabric.go index 1c699d262c..9ec1549467 100644 --- a/internal/blockchain/fabric/fabric.go +++ b/internal/blockchain/fabric/fabric.go @@ -499,7 +499,7 @@ func (f *Fabric) eventLoop() { } } -func (f *Fabric) NormalizeSigningKey(ctx context.Context, signingKeyInput string) (string, error) { +func (f *Fabric) ResolveInputSigningKey(ctx context.Context, signingKeyInput string) (string, error) { // we expand the short user name into the fully qualified onchain identity: // mspid::x509::{ecert DN}::{CA DN} return signingKeyInput, nil if !fullIdentityPattern.MatchString(signingKeyInput) { diff --git a/internal/blockchain/fabric/fabric_test.go b/internal/blockchain/fabric/fabric_test.go index 53d4b3dba1..783fdc3441 100644 --- a/internal/blockchain/fabric/fabric_test.go +++ b/internal/blockchain/fabric/fabric_test.go @@ -959,7 +959,7 @@ func TestResolveFullIDSigner(t *testing.T) { defer cancel() id := "org1MSP::x509::CN=admin,OU=client::CN=fabric-ca-server" - signKey, err := e.NormalizeSigningKey(context.Background(), id) + signKey, err := e.ResolveInputSigningKey(context.Background(), id) assert.NoError(t, err) assert.Equal(t, "org1MSP::x509::CN=admin,OU=client::CN=fabric-ca-server", signKey) @@ -979,7 +979,7 @@ func TestResolveSigner(t *testing.T) { responder, _ := httpmock.NewJsonResponder(200, res) httpmock.RegisterResponder("GET", `http://localhost:12345/identities/signer001`, responder) - resolved, err := e.NormalizeSigningKey(context.Background(), "signer001") + resolved, err := e.ResolveInputSigningKey(context.Background(), "signer001") assert.NoError(t, err) assert.Equal(t, "org1MSP::x509::CN=admin,OU=client::CN=fabric-ca-server", resolved) } @@ -994,7 +994,7 @@ func TestResolveSignerFailedFabricCARequest(t *testing.T) { responder, _ := httpmock.NewJsonResponder(503, res) httpmock.RegisterResponder("GET", `http://localhost:12345/identities/signer001`, responder) - _, err := e.NormalizeSigningKey(context.Background(), "signer001") + _, err := e.ResolveInputSigningKey(context.Background(), "signer001") assert.EqualError(t, err, "FF10284: Error from fabconnect: %!!(MISSING)s()") } @@ -1012,7 +1012,7 @@ func TestResolveSignerBadECertReturned(t *testing.T) { responder, _ := httpmock.NewJsonResponder(200, res) httpmock.RegisterResponder("GET", `http://localhost:12345/identities/signer001`, responder) - _, err := e.NormalizeSigningKey(context.Background(), "signer001") + _, err := e.ResolveInputSigningKey(context.Background(), "signer001") assert.Contains(t, err.Error(), "FF10286: Failed to decode certificate:") } @@ -1030,7 +1030,7 @@ func TestResolveSignerBadCACertReturned(t *testing.T) { responder, _ := httpmock.NewJsonResponder(200, res) httpmock.RegisterResponder("GET", `http://localhost:12345/identities/signer001`, responder) - _, err := e.NormalizeSigningKey(context.Background(), "signer001") + _, err := e.ResolveInputSigningKey(context.Background(), "signer001") assert.Contains(t, err.Error(), "FF10286: Failed to decode certificate:") } diff --git a/internal/contracts/manager.go b/internal/contracts/manager.go index 21e46df4d2..75e93f979b 100644 --- a/internal/contracts/manager.go +++ b/internal/contracts/manager.go @@ -231,7 +231,7 @@ func (cm *contractManager) writeDeployTransaction(ctx context.Context, req *core } func (cm *contractManager) DeployContract(ctx context.Context, req *core.ContractDeployRequest, waitConfirm bool) (res interface{}, err error) { - req.Key, err = cm.identity.NormalizeSigningKey(ctx, req.Key, identity.KeyNormalizationBlockchainPlugin) + req.Key, err = cm.identity.ResolveInputSigningKey(ctx, req.Key, identity.KeyNormalizationBlockchainPlugin) if err != nil { return nil, err } @@ -260,7 +260,7 @@ func (cm *contractManager) DeployContract(ctx context.Context, req *core.Contrac } func (cm *contractManager) InvokeContract(ctx context.Context, req *core.ContractCallRequest, waitConfirm bool) (res interface{}, err error) { - req.Key, err = cm.identity.NormalizeSigningKey(ctx, req.Key, identity.KeyNormalizationBlockchainPlugin) + req.Key, err = cm.identity.ResolveInputSigningKey(ctx, req.Key, identity.KeyNormalizationBlockchainPlugin) if err != nil { return nil, err } diff --git a/internal/contracts/manager_test.go b/internal/contracts/manager_test.go index 897433528b..fcf5d80ff1 100644 --- a/internal/contracts/manager_test.go +++ b/internal/contracts/manager_test.go @@ -1445,7 +1445,7 @@ func TestDeployContract(t *testing.T) { } mth.On("SubmitNewTransaction", mock.Anything, core.TransactionTypeContractDeploy, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) - mim.On("NormalizeSigningKey", mock.Anything, signingKey, identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) + mim.On("ResolveInputSigningKey", mock.Anything, signingKey, identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) mom.On("AddOrReuseOperation", mock.Anything, mock.MatchedBy(func(op *core.Operation) bool { return op.Namespace == "ns1" && op.Type == core.OpTypeBlockchainContractDeploy && op.Plugin == "mockblockchain" })).Return(nil) @@ -1481,7 +1481,7 @@ func TestDeployContractSync(t *testing.T) { } mth.On("SubmitNewTransaction", mock.Anything, core.TransactionTypeContractDeploy, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) - mim.On("NormalizeSigningKey", mock.Anything, signingKey, identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) + mim.On("ResolveInputSigningKey", mock.Anything, signingKey, identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) mom.On("AddOrReuseOperation", mock.Anything, mock.MatchedBy(func(op *core.Operation) bool { return op.Namespace == "ns1" && op.Type == core.OpTypeBlockchainContractDeploy && op.Plugin == "mockblockchain" })).Return(nil) @@ -1498,7 +1498,7 @@ func TestDeployContractSync(t *testing.T) { mom.AssertExpectations(t) } -func TestDeployContractNormalizeSigningKeyFail(t *testing.T) { +func TestDeployContractResolveInputSigningKeyFail(t *testing.T) { cm := newTestContractManager() mim := cm.identity.(*identitymanagermocks.Manager) mdi := cm.database.(*databasemocks.Plugin) @@ -1512,7 +1512,7 @@ func TestDeployContractNormalizeSigningKeyFail(t *testing.T) { Input: []interface{}{"one", "two", "three"}, } - mim.On("NormalizeSigningKey", mock.Anything, signingKey, identity.KeyNormalizationBlockchainPlugin).Return("", errors.New("pop")) + mim.On("ResolveInputSigningKey", mock.Anything, signingKey, identity.KeyNormalizationBlockchainPlugin).Return("", errors.New("pop")) _, err := cm.DeployContract(context.Background(), req, false) assert.Regexp(t, "pop", err) @@ -1539,7 +1539,7 @@ func TestDeployContractSubmitNewTransactionFail(t *testing.T) { } mth.On("SubmitNewTransaction", mock.Anything, core.TransactionTypeContractDeploy, core.IdempotencyKey("idem1")).Return(nil, errors.New("pop")) - mim.On("NormalizeSigningKey", mock.Anything, signingKey, identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) + mim.On("ResolveInputSigningKey", mock.Anything, signingKey, identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) _, err := cm.DeployContract(context.Background(), req, false) @@ -1572,7 +1572,7 @@ func TestInvokeContract(t *testing.T) { } mth.On("SubmitNewTransaction", mock.Anything, core.TransactionTypeContractInvoke, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) - mim.On("NormalizeSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) + mim.On("ResolveInputSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) mom.On("AddOrReuseOperation", mock.Anything, mock.MatchedBy(func(op *core.Operation) bool { return op.Namespace == "ns1" && op.Type == core.OpTypeBlockchainInvoke && op.Plugin == "mockblockchain" })).Return(nil) @@ -1613,7 +1613,7 @@ func TestInvokeContractConfirm(t *testing.T) { } mth.On("SubmitNewTransaction", mock.Anything, core.TransactionTypeContractInvoke, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) - mim.On("NormalizeSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) + mim.On("ResolveInputSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) mom.On("AddOrReuseOperation", mock.Anything, mock.MatchedBy(func(op *core.Operation) bool { return op.Namespace == "ns1" && op.Type == core.OpTypeBlockchainInvoke && op.Plugin == "mockblockchain" })).Return(nil) @@ -1660,7 +1660,7 @@ func TestInvokeContractFail(t *testing.T) { } mth.On("SubmitNewTransaction", mock.Anything, core.TransactionTypeContractInvoke, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) - mim.On("NormalizeSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) + mim.On("ResolveInputSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) mom.On("AddOrReuseOperation", mock.Anything, mock.MatchedBy(func(op *core.Operation) bool { return op.Namespace == "ns1" && op.Type == core.OpTypeBlockchainInvoke && op.Plugin == "mockblockchain" })).Return(nil) @@ -1679,7 +1679,7 @@ func TestInvokeContractFail(t *testing.T) { mom.AssertExpectations(t) } -func TestInvokeContractFailNormalizeSigningKey(t *testing.T) { +func TestInvokeContractFailResolveInputSigningKey(t *testing.T) { cm := newTestContractManager() mim := cm.identity.(*identitymanagermocks.Manager) @@ -1689,7 +1689,7 @@ func TestInvokeContractFailNormalizeSigningKey(t *testing.T) { Location: fftypes.JSONAnyPtr(""), } - mim.On("NormalizeSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) + mim.On("ResolveInputSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) _, err := cm.InvokeContract(context.Background(), req, false) @@ -1707,7 +1707,7 @@ func TestInvokeContractFailResolve(t *testing.T) { Location: fftypes.JSONAnyPtr(""), } - mim.On("NormalizeSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) + mim.On("ResolveInputSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) mbi.On("InvokeContract", mock.Anything, mock.AnythingOfType("*fftypes.UUID"), "key-resolved", req.Location, req.Method, req.Input, req.Errors).Return(nil) _, err := cm.InvokeContract(context.Background(), req, false) @@ -1733,7 +1733,7 @@ func TestInvokeContractTXFail(t *testing.T) { IdempotencyKey: "idem1", } - mim.On("NormalizeSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) + mim.On("ResolveInputSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) mth.On("SubmitNewTransaction", mock.Anything, core.TransactionTypeContractInvoke, core.IdempotencyKey("idem1")).Return(nil, fmt.Errorf("pop")) _, err := cm.InvokeContract(context.Background(), req, false) @@ -1753,7 +1753,7 @@ func TestInvokeContractMethodNotFound(t *testing.T) { MethodPath: "set", } - mim.On("NormalizeSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) + mim.On("ResolveInputSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) mdb.On("GetFFIMethod", mock.Anything, "ns1", req.Interface, req.MethodPath).Return(nil, fmt.Errorf("pop")) _, err := cm.InvokeContract(context.Background(), req, false) @@ -1773,7 +1773,7 @@ func TestInvokeContractErrorsFail(t *testing.T) { MethodPath: "set", } - mim.On("NormalizeSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) + mim.On("ResolveInputSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) mdb.On("GetFFIMethod", mock.Anything, "ns1", req.Interface, req.MethodPath).Return(&fftypes.FFIMethod{Name: "set"}, nil) mdb.On("GetFFIErrors", mock.Anything, "ns1", mock.Anything).Return(nil, nil, fmt.Errorf("pop")) @@ -1811,7 +1811,7 @@ func TestInvokeContractMethodBadInput(t *testing.T) { }, }, } - mim.On("NormalizeSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) + mim.On("ResolveInputSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) _, err := cm.InvokeContract(context.Background(), req, false) assert.Regexp(t, "FF10304", err) @@ -1837,7 +1837,7 @@ func TestQueryContract(t *testing.T) { IdempotencyKey: "idem1", } - mim.On("NormalizeSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) + mim.On("ResolveInputSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) mth.On("SubmitNewTransaction", mock.Anything, core.TransactionTypeContractInvoke, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", mock.Anything, mock.MatchedBy(func(op *core.Operation) bool { return op.Namespace == "ns1" && op.Type == core.OpTypeBlockchainInvoke && op.Plugin == "mockblockchain" @@ -1867,7 +1867,7 @@ func TestCallContractInvalidType(t *testing.T) { IdempotencyKey: "idem1", } - mim.On("NormalizeSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) + mim.On("ResolveInputSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) mth.On("SubmitNewTransaction", mock.Anything, core.TransactionTypeContractInvoke, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", mock.Anything, mock.MatchedBy(func(op *core.Operation) bool { return op.Namespace == "ns1" && op.Type == core.OpTypeBlockchainInvoke && op.Plugin == "mockblockchain" @@ -2148,7 +2148,7 @@ func TestInvokeContractAPI(t *testing.T) { Location: fftypes.JSONAnyPtr(""), } - mim.On("NormalizeSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) + mim.On("ResolveInputSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) mdb.On("GetContractAPIByName", mock.Anything, "ns1", "banana").Return(api, nil) mth.On("SubmitNewTransaction", mock.Anything, core.TransactionTypeContractInvoke, core.IdempotencyKey("idem1")).Return(fftypes.NewUUID(), nil) mom.On("AddOrReuseOperation", mock.Anything, mock.MatchedBy(func(op *core.Operation) bool { @@ -2183,7 +2183,7 @@ func TestInvokeContractAPIFailContractLookup(t *testing.T) { }, } - mim.On("NormalizeSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) + mim.On("ResolveInputSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) mdb.On("GetContractAPIByName", mock.Anything, "ns1", "banana").Return(nil, fmt.Errorf("pop")) _, err := cm.InvokeContractAPI(context.Background(), "banana", "peel", req, false) @@ -2204,7 +2204,7 @@ func TestInvokeContractAPIContractNotFound(t *testing.T) { }, } - mim.On("NormalizeSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) + mim.On("ResolveInputSigningKey", mock.Anything, "", identity.KeyNormalizationBlockchainPlugin).Return("key-resolved", nil) mdb.On("GetContractAPIByName", mock.Anything, "ns1", "banana").Return(nil, nil) _, err := cm.InvokeContractAPI(context.Background(), "banana", "peel", req, false) diff --git a/internal/coreconfig/coreconfig.go b/internal/coreconfig/coreconfig.go index b3ba1c9fa9..e65f7826d3 100644 --- a/internal/coreconfig/coreconfig.go +++ b/internal/coreconfig/coreconfig.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Kaleido, Inc. +// Copyright © 2023 Kaleido, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -146,10 +146,6 @@ var ( CacheIdentityLimit = ffc("cache.identity.limit") CacheIdentityTTL = ffc("cache.identity.ttl") - // IdentityManager signing key cache config - CacheSigningKeyLimit = ffc("cache.signingkey.limit") - CacheSigningKeyTTL = ffc("cache.signingkey.ttl") - // DataManager Message cache config CacheMessageSize = ffc("cache.message.size") CacheMessageTTL = ffc("cache.message.ttl") @@ -428,8 +424,6 @@ func setDefaults() { viper.SetDefault(string(CacheValidatorTTL), "1h") viper.SetDefault(string(CacheIdentityLimit), 100) viper.SetDefault(string(CacheIdentityTTL), "1h") - viper.SetDefault(string(CacheSigningKeyLimit), 100) - viper.SetDefault(string(CacheSigningKeyTTL), "1h") } func Reset() { diff --git a/internal/coremsgs/en_config_descriptions.go b/internal/coremsgs/en_config_descriptions.go index 393e911d67..c81d59d00a 100644 --- a/internal/coremsgs/en_config_descriptions.go +++ b/internal/coremsgs/en_config_descriptions.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Kaleido, Inc. +// Copyright © 2023 Kaleido, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -56,6 +56,7 @@ var ( ConfigBlockchainType = ffc("config.blockchain.type", "A string defining which type of blockchain plugin to use. This tells FireFly which type of configuration to load for the rest of the `blockchain` section", i18n.StringType) + ConfigBlockchainEthereumAddressResolverAlwaysResolve = ffc("config.blockchain.ethereum.addressResolver.alwaysResolve", "Causes the address resolver to be invoked on every API call that submits a signing key, regardless of whether the input string conforms to an 0x address. Also disables any result caching", i18n.BooleanType) ConfigBlockchainEthereumAddressResolverBodyTemplate = ffc("config.blockchain.ethereum.addressResolver.bodyTemplate", "The body go template string to use when making HTTP requests", i18n.GoTemplateType) ConfigBlockchainEthereumAddressResolverCustomClient = ffc("config.blockchain.ethereum.addressResolver.customClient", "Used for testing purposes only", i18n.IgnoredType) ConfigBlockchainEthereumAddressResolverExpectContinueTimeout = ffc("config.blockchain.ethereum.addressResolver.expectContinueTimeout", "See [ExpectContinueTimeout in the Go docs](https://pkg.go.dev/net/http#Transport)", i18n.TimeDurationType) @@ -141,6 +142,7 @@ var ( ConfigPluginBlockchainName = ffc("config.plugins.blockchain[].name", "The name of the configured Blockchain plugin", i18n.StringType) ConfigPluginBlockchainType = ffc("config.plugins.blockchain[].type", "The type of the configured Blockchain Connector plugin", i18n.StringType) + ConfigPluginBlockchainEthereumAddressResolverAlwaysResolve = ffc("config.plugins.blockchain[].ethereum.addressResolver.alwaysResolve", "Causes the address resolver to be invoked on every API call that submits a signing key, regardless of whether the input string conforms to an 0x address. Also disables any result caching", i18n.BooleanType) ConfigPluginBlockchainEthereumAddressResolverBodyTemplate = ffc("config.plugins.blockchain[].ethereum.addressResolver.bodyTemplate", "The body go template string to use when making HTTP requests", i18n.GoTemplateType) ConfigPluginBlockchainEthereumAddressResolverCustomClient = ffc("config.plugins.blockchain[].ethereum.addressResolver.customClient", "Used for testing purposes only", i18n.IgnoredType) ConfigPluginBlockchainEthereumAddressResolverExpectContinueTimeout = ffc("config.plugins.blockchain[].ethereum.addressResolver.expectContinueTimeout", "See [ExpectContinueTimeout in the Go docs](https://pkg.go.dev/net/http#Transport)", i18n.TimeDurationType) diff --git a/internal/definitions/sender_identity.go b/internal/definitions/sender_identity.go index 5a4abd5c52..04bee92a70 100644 --- a/internal/definitions/sender_identity.go +++ b/internal/definitions/sender_identity.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Kaleido, Inc. +// Copyright © 2023 Kaleido, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -28,7 +28,7 @@ import ( func (bm *definitionSender) ClaimIdentity(ctx context.Context, claim *core.IdentityClaim, signingIdentity *core.SignerRef, parentSigner *core.SignerRef, waitConfirm bool) error { if bm.multiparty { var err error - signingIdentity.Key, err = bm.identity.NormalizeSigningKey(ctx, signingIdentity.Key, identity.KeyNormalizationBlockchainPlugin) + signingIdentity.Key, err = bm.identity.ResolveInputSigningKey(ctx, signingIdentity.Key, identity.KeyNormalizationBlockchainPlugin) if err != nil { return err } diff --git a/internal/definitions/sender_identity_test.go b/internal/definitions/sender_identity_test.go index 1f32ff4afe..4e035ee300 100644 --- a/internal/definitions/sender_identity_test.go +++ b/internal/definitions/sender_identity_test.go @@ -37,7 +37,7 @@ func TestClaimIdentity(t *testing.T) { mbm := ds.broadcast.(*broadcastmocks.Manager) mms := &syncasyncmocks.Sender{} - mim.On("NormalizeSigningKey", mock.Anything, "0x1234", identity.KeyNormalizationBlockchainPlugin).Return("", nil) + mim.On("ResolveInputSigningKey", mock.Anything, "0x1234", identity.KeyNormalizationBlockchainPlugin).Return("", nil) mbm.On("NewBroadcast", mock.Anything).Return(mms) mms.On("SendAndWait", mock.Anything).Return(nil) @@ -63,7 +63,7 @@ func TestClaimIdentityFail(t *testing.T) { mbm := ds.broadcast.(*broadcastmocks.Manager) mms := &syncasyncmocks.Sender{} - mim.On("NormalizeSigningKey", mock.Anything, "0x1234", identity.KeyNormalizationBlockchainPlugin).Return("", nil) + mim.On("ResolveInputSigningKey", mock.Anything, "0x1234", identity.KeyNormalizationBlockchainPlugin).Return("", nil) mbm.On("NewBroadcast", mock.Anything).Return(mms) mms.On("SendAndWait", mock.Anything).Return(fmt.Errorf("pop")) @@ -87,7 +87,7 @@ func TestClaimIdentityFailKey(t *testing.T) { mim := ds.identity.(*identitymanagermocks.Manager) - mim.On("NormalizeSigningKey", mock.Anything, "0x1234", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) + mim.On("ResolveInputSigningKey", mock.Anything, "0x1234", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) ds.multiparty = true @@ -110,7 +110,7 @@ func TestClaimIdentityChild(t *testing.T) { mms1 := &syncasyncmocks.Sender{} mms2 := &syncasyncmocks.Sender{} - mim.On("NormalizeSigningKey", mock.Anything, "0x1234", identity.KeyNormalizationBlockchainPlugin).Return("", nil) + mim.On("ResolveInputSigningKey", mock.Anything, "0x1234", identity.KeyNormalizationBlockchainPlugin).Return("", nil) mbm.On("NewBroadcast", mock.Anything).Return(mms1).Once() mbm.On("NewBroadcast", mock.Anything).Return(mms2).Once() mms1.On("SendAndWait", mock.Anything).Return(nil) @@ -144,7 +144,7 @@ func TestClaimIdentityChildFail(t *testing.T) { mms1 := &syncasyncmocks.Sender{} mms2 := &syncasyncmocks.Sender{} - mim.On("NormalizeSigningKey", mock.Anything, "0x1234", identity.KeyNormalizationBlockchainPlugin).Return("", nil) + mim.On("ResolveInputSigningKey", mock.Anything, "0x1234", identity.KeyNormalizationBlockchainPlugin).Return("", nil) mbm.On("NewBroadcast", mock.Anything).Return(mms1).Once() mbm.On("NewBroadcast", mock.Anything).Return(mms2).Once() mms1.On("SendAndWait", mock.Anything).Return(nil) diff --git a/internal/events/webhooks/webhooks.go b/internal/events/webhooks/webhooks.go index 4e534f97e7..1d9facbb2a 100644 --- a/internal/events/webhooks/webhooks.go +++ b/internal/events/webhooks/webhooks.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Kaleido, Inc. +// Copyright © 2023 Kaleido, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -271,7 +271,7 @@ func (wh *WebHooks) attemptRequest(sub *core.Subscription, event *core.EventDeli return req, res, nil } -func (wh *WebHooks) doDelivery(connID string, reply bool, sub *core.Subscription, event *core.EventDelivery, data core.DataArray, fastAck bool) error { +func (wh *WebHooks) doDelivery(connID string, reply bool, sub *core.Subscription, event *core.EventDelivery, data core.DataArray, fastAck bool) { req, res, gwErr := wh.attemptRequest(sub, event, data) if gwErr != nil { // Generate a bad-gateway error response - we always want to send something back, @@ -329,7 +329,6 @@ func (wh *WebHooks) doDelivery(connID string, reply bool, sub *core.Subscription }) } } - return nil } func (wh *WebHooks) DeliveryRequest(connID string, sub *core.Subscription, event *core.EventDelivery, data core.DataArray) error { @@ -365,12 +364,10 @@ func (wh *WebHooks) DeliveryRequest(connID string, sub *core.Subscription, event Subscription: event.Subscription, }) } - go func() { - err := wh.doDelivery(connID, reply, sub, event, data, true) - log.L(wh.ctx).Warnf("Webhook delivery failed in fastack mode for event '%s': %s", event.ID, err) - }() + go wh.doDelivery(connID, reply, sub, event, data, true) return nil } - return wh.doDelivery(connID, reply, sub, event, data, false) + wh.doDelivery(connID, reply, sub, event, data, false) + return nil } diff --git a/internal/events/webhooks/webhooks_test.go b/internal/events/webhooks/webhooks_test.go index 690beda474..aab2cb572b 100644 --- a/internal/events/webhooks/webhooks_test.go +++ b/internal/events/webhooks/webhooks_test.go @@ -682,19 +682,31 @@ func TestWebhookFailFastAsk(t *testing.T) { }, } + count := 0 waiter := make(chan struct{}) mcb := wh.callbacks["ns1"].(*eventsmocks.Callbacks) mcb.On("DeliveryResponse", mock.Anything, mock.Anything). Return(nil). Run(func(a mock.Arguments) { - close(waiter) + count++ + if count == 2 { + close(waiter) + } }) + // Drive two deliveries, waiting for them both to ack (noting both will fail) err := wh.DeliveryRequest(mock.Anything, sub, event, core.DataArray{ {ID: fftypes.NewUUID(), Value: fftypes.JSONAnyPtr(`"value1"`)}, {ID: fftypes.NewUUID(), Value: fftypes.JSONAnyPtr(`"value2"`)}, }) assert.NoError(t, err) + + err = wh.DeliveryRequest(mock.Anything, sub, event, core.DataArray{ + {ID: fftypes.NewUUID(), Value: fftypes.JSONAnyPtr(`"value1"`)}, + {ID: fftypes.NewUUID(), Value: fftypes.JSONAnyPtr(`"value2"`)}, + }) + assert.NoError(t, err) + <-waiter mcb.AssertExpectations(t) diff --git a/internal/identity/identitymanager.go b/internal/identity/identitymanager.go index 1902f9bec3..9ff0e3705c 100644 --- a/internal/identity/identitymanager.go +++ b/internal/identity/identitymanager.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Kaleido, Inc. +// Copyright © 2023 Kaleido, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -40,10 +40,11 @@ const ( type Manager interface { ResolveInputSigningIdentity(ctx context.Context, signerRef *core.SignerRef) (err error) - ResolveInputSigningKey(ctx context.Context, inputKey *core.VerifierRef) (*core.VerifierRef, error) - NormalizeSigningKey(ctx context.Context, inputKey string, keyNormalizationMode int) (signingKey string, err error) - FindIdentityForVerifier(ctx context.Context, iTypes []core.IdentityType, verifier *core.VerifierRef) (identity *core.Identity, err error) + ResolveInputVerifierRef(ctx context.Context, inputKey *core.VerifierRef) (*core.VerifierRef, error) + ResolveInputSigningKey(ctx context.Context, inputKey string, keyNormalizationMode int) (signingKey string, err error) ResolveIdentitySigner(ctx context.Context, identity *core.Identity) (parentSigner *core.SignerRef, err error) + + FindIdentityForVerifier(ctx context.Context, iTypes []core.IdentityType, verifier *core.VerifierRef) (identity *core.Identity, err error) CachedIdentityLookupByID(ctx context.Context, id *fftypes.UUID) (identity *core.Identity, err error) CachedIdentityLookupMustExist(ctx context.Context, did string) (identity *core.Identity, retryable bool, err error) CachedIdentityLookupNilOK(ctx context.Context, did string) (identity *core.Identity, retryable bool, err error) @@ -62,7 +63,6 @@ type identityManager struct { defaultKey string multipartyRootVerifier *core.VerifierRef identityCache cache.CInterface - signingKeyCache cache.CInterface } func NewIdentityManager(ctx context.Context, ns, defaultKey string, di database.Plugin, bi blockchain.Plugin, mp multiparty.Manager, cacheManager cache.Manager) (Manager, error) { @@ -90,21 +90,6 @@ func NewIdentityManager(ctx context.Context, ns, defaultKey string, di database. } im.identityCache = identityCache - signingKeyCache, err := cacheManager.GetCache( - cache.NewCacheConfig( - ctx, - coreconfig.CacheSigningKeyLimit, - coreconfig.CacheSigningKeyTTL, - ns, - ), - ) - if err != nil { - return nil, err - } - - // For the identity and signingkey caches, we just treat them all equally sized and the max items - im.signingKeyCache = signingKeyCache - return im, nil } @@ -124,10 +109,10 @@ func (im *identityManager) GetLocalNode(ctx context.Context) (node *core.Identit return node, err } -// NormalizeSigningKey takes in only a "key" (which may be empty to use the default) to be normalized and returned. +// ResolveInputSigningKey takes in only a "key" (which may be empty to use the default) to be resolved and returned. // This is for cases where keys are used directly without an "author" field alongside them (custom contracts, tokens), // or when the author is known by the caller and should not / cannot be confirmed prior to sending (identity claims) -func (im *identityManager) NormalizeSigningKey(ctx context.Context, inputKey string, keyNormalizationMode int) (signingKey string, err error) { +func (im *identityManager) ResolveInputSigningKey(ctx context.Context, inputKey string, keyNormalizationMode int) (signingKey string, err error) { if inputKey == "" { if im.blockchain == nil { if im.defaultKey == "" { @@ -149,14 +134,14 @@ func (im *identityManager) NormalizeSigningKey(ctx context.Context, inputKey str if keyNormalizationMode != KeyNormalizationBlockchainPlugin { return inputKey, nil } - signer, err := im.normalizeKeyViaBlockchainPlugin(ctx, inputKey) + signer, err := im.resolveInputKeyViaBlockchainPlugin(ctx, inputKey) if err != nil { return "", err } return signer.Value, nil } -func (im *identityManager) ResolveInputSigningKey(ctx context.Context, inputKey *core.VerifierRef) (*core.VerifierRef, error) { +func (im *identityManager) ResolveInputVerifierRef(ctx context.Context, inputKey *core.VerifierRef) (*core.VerifierRef, error) { log.L(ctx).Debugf("Resolving input signing key: type='%s' value='%s'", inputKey.Type, inputKey.Value) if im.blockchain == nil { @@ -173,7 +158,7 @@ func (im *identityManager) ResolveInputSigningKey(ctx context.Context, inputKey return nil, i18n.NewError(ctx, coremsgs.MsgUnknownVerifierType) } - signingKey, err := im.blockchain.NormalizeSigningKey(ctx, inputKey.Value) + signingKey, err := im.blockchain.ResolveInputSigningKey(ctx, inputKey.Value) if err != nil { return nil, err } @@ -204,7 +189,7 @@ func (im *identityManager) ResolveInputSigningIdentity(ctx context.Context, sign case signerRef.Key != "": // Key specified: normalize it, then check it against author (if specified) - if verifier, err = im.normalizeKeyViaBlockchainPlugin(ctx, signerRef.Key); err != nil { + if verifier, err = im.resolveInputKeyViaBlockchainPlugin(ctx, signerRef.Key); err != nil { return err } signerRef.Key = verifier.Value @@ -290,7 +275,7 @@ func (im *identityManager) resolveDefaultSigningIdentity(ctx context.Context, si // getDefaultVerifier gets the default blockchain verifier via the configuration func (im *identityManager) getDefaultVerifier(ctx context.Context) (verifier *core.VerifierRef, err error) { if im.defaultKey != "" { - return im.normalizeKeyViaBlockchainPlugin(ctx, im.defaultKey) + return im.resolveInputKeyViaBlockchainPlugin(ctx, im.defaultKey) } if im.multiparty != nil { return im.GetMultipartyRootVerifier(ctx) @@ -298,7 +283,8 @@ func (im *identityManager) getDefaultVerifier(ctx context.Context) (verifier *co return nil, i18n.NewError(ctx, coremsgs.MsgNodeMissingBlockchainKey) } -// GetMultipartyRootVerifier gets the blockchain verifier of the root org via the configuration +// GetMultipartyRootVerifier gets the blockchain verifier of the root org via the configuration, +// resolving it for use as a signing key for the purpose of signing a child identity func (im *identityManager) GetMultipartyRootVerifier(ctx context.Context) (*core.VerifierRef, error) { if im.multipartyRootVerifier != nil { return im.multipartyRootVerifier, nil @@ -309,7 +295,7 @@ func (im *identityManager) GetMultipartyRootVerifier(ctx context.Context) (*core return nil, i18n.NewError(ctx, coremsgs.MsgNodeMissingBlockchainKey) } - verifier, err := im.normalizeKeyViaBlockchainPlugin(ctx, orgKey) + verifier, err := im.resolveInputKeyViaBlockchainPlugin(ctx, orgKey) if err != nil { return nil, err } @@ -317,20 +303,18 @@ func (im *identityManager) GetMultipartyRootVerifier(ctx context.Context) (*core return verifier, nil } -// normalizeKeyViaBlockchainPlugin does a cached lookup of the fully qualified key, associated with a key reference string -func (im *identityManager) normalizeKeyViaBlockchainPlugin(ctx context.Context, inputKey string) (verifier *core.VerifierRef, err error) { - if inputKey == "" { - return nil, i18n.NewError(ctx, coremsgs.MsgBlockchainKeyNotSet) - } +// resolveInputKeyViaBlockchainPlugin calls the blockchain plugin to resolve an input key string, to the +// blockchain native representation of that key. Which might involve sophisticated processing. +// See ResolveInputSigningKey on the blockchain connector +// +// Note: Caching is deferred down to the blockchain plugin (prior to v1.2 it was performed in the identity manager) +func (im *identityManager) resolveInputKeyViaBlockchainPlugin(ctx context.Context, inputKey string) (verifier *core.VerifierRef, err error) { if im.blockchain == nil { return nil, i18n.NewError(ctx, coremsgs.MsgBlockchainNotConfigured) } - if cachedValue := im.signingKeyCache.Get(inputKey); cachedValue != nil { - return cachedValue.(*core.VerifierRef), nil - } - keyString, err := im.blockchain.NormalizeSigningKey(ctx, inputKey) + keyString, err := im.blockchain.ResolveInputSigningKey(ctx, inputKey) if err != nil { return nil, err } @@ -338,7 +322,6 @@ func (im *identityManager) normalizeKeyViaBlockchainPlugin(ctx context.Context, Type: im.blockchain.VerifierType(), Value: keyString, } - im.signingKeyCache.Set(inputKey, verifier) return verifier, nil } diff --git a/internal/identity/identitymanager_test.go b/internal/identity/identitymanager_test.go index b17a4d47cd..5e522d58b8 100644 --- a/internal/identity/identitymanager_test.go +++ b/internal/identity/identitymanager_test.go @@ -55,12 +55,6 @@ func newTestIdentityManager(t *testing.T) (context.Context, *identityManager) { coreconfig.CacheIdentityTTL, ns, )) - cmi.AssertCalled(t, "GetCache", cache.NewCacheConfig( - ctx, - coreconfig.CacheSigningKeyLimit, - coreconfig.CacheSigningKeyTTL, - ns, - )) return ctx, im.(*identityManager) } @@ -93,25 +87,9 @@ func TestCacheInitFail(t *testing.T) { _, err := NewIdentityManager(ctx, ns, "", mdi, mbi, mmp, iErrcmi) assert.Equal(t, cacheInitError, err) - sErrcmi := &cachemocks.Manager{} - sErrcmi.On("GetCache", cache.NewCacheConfig( - ctx, - coreconfig.CacheIdentityLimit, - coreconfig.CacheIdentityTTL, - ns, - )).Return(cache.NewUmanagedCache(ctx, 100, 5*time.Minute), nil).Once() - sErrcmi.On("GetCache", cache.NewCacheConfig( - ctx, - coreconfig.CacheSigningKeyLimit, - coreconfig.CacheSigningKeyTTL, - ns, - )).Return(nil, cacheInitError).Once() - defer sErrcmi.AssertExpectations(t) - _, err = NewIdentityManager(ctx, ns, "", mdi, mbi, mmp, sErrcmi) - assert.Equal(t, cacheInitError, err) } -func TestResolveInputSigningKeyMissingBlockchain(t *testing.T) { +func TestResolveInputVerifierRefMissingBlockchain(t *testing.T) { ctx, im := newTestIdentityManager(t) im.blockchain = nil @@ -120,11 +98,11 @@ func TestResolveInputSigningKeyMissingBlockchain(t *testing.T) { Value: "testValue", } - _, err := im.ResolveInputSigningKey(ctx, inputKey) + _, err := im.ResolveInputVerifierRef(ctx, inputKey) assert.Regexp(t, "FF10417", err) } -func TestResolveInputSigningKeyUnknownVerifier(t *testing.T) { +func TestResolveInputVerifierRefUnknownVerifier(t *testing.T) { ctx, im := newTestIdentityManager(t) mbi := im.blockchain.(*blockchainmocks.Plugin) @@ -135,24 +113,24 @@ func TestResolveInputSigningKeyUnknownVerifier(t *testing.T) { Value: "testValue", } - _, err := im.ResolveInputSigningKey(ctx, inputKey) + _, err := im.ResolveInputVerifierRef(ctx, inputKey) assert.Regexp(t, "FF10428", err) mbi.AssertExpectations(t) } -func TestResolveInputSigningKeyNoVerifierOK(t *testing.T) { +func TestResolveInputVerifierRefNoVerifierOK(t *testing.T) { ctx, im := newTestIdentityManager(t) mbi := im.blockchain.(*blockchainmocks.Plugin) mbi.On("VerifierType").Return(core.VerifierTypeEthAddress, nil) - mbi.On("NormalizeSigningKey", ctx, "testValue").Return("fullkey123", nil) + mbi.On("ResolveInputSigningKey", ctx, "testValue").Return("fullkey123", nil) inputKey := &core.VerifierRef{ Value: "testValue", } - res, err := im.ResolveInputSigningKey(ctx, inputKey) + res, err := im.ResolveInputVerifierRef(ctx, inputKey) assert.NoError(t, err) assert.Equal(t, core.VerifierTypeEthAddress, res.Type) @@ -160,37 +138,37 @@ func TestResolveInputSigningKeyNoVerifierOK(t *testing.T) { mbi.AssertExpectations(t) } -func TestResolveInputSigningKeyErrorNormalizingKey(t *testing.T) { +func TestResolveInputVerifierRefErrorNormalizingKey(t *testing.T) { ctx, im := newTestIdentityManager(t) mbi := im.blockchain.(*blockchainmocks.Plugin) mbi.On("VerifierType").Return(core.VerifierTypeEthAddress, nil) - mbi.On("NormalizeSigningKey", ctx, "testValue").Return("", fmt.Errorf("pop")) + mbi.On("ResolveInputSigningKey", ctx, "testValue").Return("", fmt.Errorf("pop")) inputKey := &core.VerifierRef{ Type: core.VerifierTypeEthAddress, Value: "testValue", } - _, err := im.ResolveInputSigningKey(ctx, inputKey) + _, err := im.ResolveInputVerifierRef(ctx, inputKey) assert.Regexp(t, "pop", err) mbi.AssertExpectations(t) } -func TestResolveInputSigningKeySuccess(t *testing.T) { +func TestResolveInputVerifierRefSuccess(t *testing.T) { ctx, im := newTestIdentityManager(t) mbi := im.blockchain.(*blockchainmocks.Plugin) mbi.On("VerifierType").Return(core.VerifierTypeEthAddress, nil) - mbi.On("NormalizeSigningKey", ctx, "testValue").Return("fullkey123", nil) + mbi.On("ResolveInputSigningKey", ctx, "testValue").Return("fullkey123", nil) inputKey := &core.VerifierRef{ Type: core.VerifierTypeEthAddress, Value: "testValue", } - res, err := im.ResolveInputSigningKey(ctx, inputKey) + res, err := im.ResolveInputVerifierRef(ctx, inputKey) assert.NoError(t, err) assert.Equal(t, core.VerifierTypeEthAddress, res.Type) @@ -221,7 +199,7 @@ func TestResolveInputSigningIdentityOrgFallbackOk(t *testing.T) { mmp.On("RootOrg").Return(multiparty.RootOrg{Name: "org1", Key: "key123"}) mbi := im.blockchain.(*blockchainmocks.Plugin) - mbi.On("NormalizeSigningKey", ctx, "key123").Return("fullkey123", nil) + mbi.On("ResolveInputSigningKey", ctx, "key123").Return("fullkey123", nil) orgID := fftypes.NewUUID() @@ -274,7 +252,7 @@ func TestResolveInputSigningIdentityByKeyOk(t *testing.T) { ctx, im := newTestIdentityManager(t) mbi := im.blockchain.(*blockchainmocks.Plugin) - mbi.On("NormalizeSigningKey", ctx, "mykey123").Return("fullkey123", nil) + mbi.On("ResolveInputSigningKey", ctx, "mykey123").Return("fullkey123", nil) idID := fftypes.NewUUID() @@ -318,7 +296,7 @@ func TestResolveInputSigningIdentityAnonymousKeyWithAuthorOk(t *testing.T) { mbi := im.blockchain.(*blockchainmocks.Plugin) mmp := im.multiparty.(*multipartymocks.Manager) - mbi.On("NormalizeSigningKey", ctx, "mykey123").Return("fullkey123", nil) + mbi.On("ResolveInputSigningKey", ctx, "mykey123").Return("fullkey123", nil) mmp.On("GetNetworkVersion").Return(1) idID := fftypes.NewUUID() @@ -359,7 +337,7 @@ func TestResolveInputSigningIdentityKeyWithNoAuthorFail(t *testing.T) { mbi := im.blockchain.(*blockchainmocks.Plugin) mmp := im.multiparty.(*multipartymocks.Manager) - mbi.On("NormalizeSigningKey", ctx, "mykey123").Return("fullkey123", nil) + mbi.On("ResolveInputSigningKey", ctx, "mykey123").Return("fullkey123", nil) mmp.On("GetNetworkVersion").Return(1) mdi := im.database.(*databasemocks.Plugin) @@ -383,7 +361,7 @@ func TestResolveInputSigningIdentityByKeyDIDMismatch(t *testing.T) { ctx, im := newTestIdentityManager(t) mbi := im.blockchain.(*blockchainmocks.Plugin) - mbi.On("NormalizeSigningKey", ctx, "mykey123").Return("fullkey123", nil) + mbi.On("ResolveInputSigningKey", ctx, "mykey123").Return("fullkey123", nil) idID := fftypes.NewUUID() @@ -426,7 +404,7 @@ func TestResolveInputSigningIdentityByKeyNotFound(t *testing.T) { mbi := im.blockchain.(*blockchainmocks.Plugin) mmp := im.multiparty.(*multipartymocks.Manager) - mbi.On("NormalizeSigningKey", ctx, "mykey123").Return("fullkey123", nil) + mbi.On("ResolveInputSigningKey", ctx, "mykey123").Return("fullkey123", nil) mmp.On("GetNetworkVersion").Return(1) mdi := im.database.(*databasemocks.Plugin) @@ -459,7 +437,7 @@ func TestResolveInputSigningIdentityByKeyFail(t *testing.T) { ctx, im := newTestIdentityManager(t) mbi := im.blockchain.(*blockchainmocks.Plugin) - mbi.On("NormalizeSigningKey", ctx, "mykey123").Return("fullkey123", nil) + mbi.On("ResolveInputSigningKey", ctx, "mykey123").Return("fullkey123", nil) mdi := im.database.(*databasemocks.Plugin) mdi.On("GetVerifierByValue", ctx, core.VerifierTypeEthAddress, "ns1", "fullkey123"). @@ -481,7 +459,7 @@ func TestResolveInputSigningIdentityByKeyResolveFail(t *testing.T) { ctx, im := newTestIdentityManager(t) mbi := im.blockchain.(*blockchainmocks.Plugin) - mbi.On("NormalizeSigningKey", ctx, "mykey123").Return("", fmt.Errorf("pop")) + mbi.On("ResolveInputSigningKey", ctx, "mykey123").Return("", fmt.Errorf("pop")) msgIdentity := &core.SignerRef{ Key: "mykey123", @@ -601,13 +579,13 @@ func TestResolveInputSigningIdentityByOrgVerifierFail(t *testing.T) { } -func TestNormalizeSigningKeyDefault(t *testing.T) { +func TestResolveInputSigningKeyDefault(t *testing.T) { ctx, im := newTestIdentityManager(t) im.blockchain = nil im.defaultKey = "key123" - resolvedKey, err := im.NormalizeSigningKey(ctx, "", KeyNormalizationBlockchainPlugin) + resolvedKey, err := im.ResolveInputSigningKey(ctx, "", KeyNormalizationBlockchainPlugin) assert.NoError(t, err) assert.Equal(t, "key123", resolvedKey) } @@ -622,37 +600,37 @@ func TestGetDefaultVerifierNoBlockchain(t *testing.T) { assert.Nil(t, verifier) } -func TestNormalizeSigningKeyNoDefaultNoBlockchain(t *testing.T) { +func TestResolveInputSigningKeyNoDefaultNoBlockchain(t *testing.T) { ctx, im := newTestIdentityManager(t) im.blockchain = nil - resolvedKey, err := im.NormalizeSigningKey(ctx, "", KeyNormalizationBlockchainPlugin) + resolvedKey, err := im.ResolveInputSigningKey(ctx, "", KeyNormalizationBlockchainPlugin) assert.Regexp(t, "FF10354", err) assert.Equal(t, "", resolvedKey) } -func TestNormalizeSigningKeyDefaultNoBlockchainInputFallback(t *testing.T) { +func TestResolveInputSigningKeyDefaultNoBlockchainInputFallback(t *testing.T) { ctx, im := newTestIdentityManager(t) im.blockchain = nil im.defaultKey = "key123" - resolvedKey, err := im.NormalizeSigningKey(ctx, "testKey", KeyNormalizationBlockchainPlugin) + resolvedKey, err := im.ResolveInputSigningKey(ctx, "testKey", KeyNormalizationBlockchainPlugin) assert.Regexp(t, "FF10417", err) assert.Equal(t, "", resolvedKey) } -func TestNormalizeSigningKeyDefaultNoBlockchainDefaultKeyFallback(t *testing.T) { +func TestResolveInputSigningKeyDefaultNoBlockchainDefaultKeyFallback(t *testing.T) { ctx, im := newTestIdentityManager(t) im.blockchain = nil im.defaultKey = "key123" - resolvedKey, err := im.NormalizeSigningKey(ctx, "", KeyNormalizationBlockchainPlugin) + resolvedKey, err := im.ResolveInputSigningKey(ctx, "", KeyNormalizationBlockchainPlugin) assert.NoError(t, err) assert.Equal(t, "key123", resolvedKey) } -func TestNormalizeSigningKeyOrgFallbackOk(t *testing.T) { +func TestResolveInputSigningKeyOrgFallbackOk(t *testing.T) { ctx, im := newTestIdentityManager(t) @@ -660,9 +638,9 @@ func TestNormalizeSigningKeyOrgFallbackOk(t *testing.T) { mmp.On("RootOrg").Return(multiparty.RootOrg{Key: "key123"}) mbi := im.blockchain.(*blockchainmocks.Plugin) - mbi.On("NormalizeSigningKey", ctx, "key123").Return("fullkey123", nil) + mbi.On("ResolveInputSigningKey", ctx, "key123").Return("fullkey123", nil) // just a format, not a lookup as we get it from the root org that's registered - resolvedKey, err := im.NormalizeSigningKey(ctx, "", KeyNormalizationBlockchainPlugin) + resolvedKey, err := im.ResolveInputSigningKey(ctx, "", KeyNormalizationBlockchainPlugin) assert.NoError(t, err) assert.Equal(t, "fullkey123", resolvedKey) @@ -671,7 +649,7 @@ func TestNormalizeSigningKeyOrgFallbackOk(t *testing.T) { } -func TestNormalizeSigningKeyOrgFallbackErr(t *testing.T) { +func TestResolveInputSigningKeyOrgFallbackErr(t *testing.T) { ctx, im := newTestIdentityManager(t) @@ -679,9 +657,9 @@ func TestNormalizeSigningKeyOrgFallbackErr(t *testing.T) { mmp.On("RootOrg").Return(multiparty.RootOrg{Key: "key123"}) mbi := im.blockchain.(*blockchainmocks.Plugin) - mbi.On("NormalizeSigningKey", ctx, "key123").Return("fullkey123", fmt.Errorf("pop")) + mbi.On("ResolveInputSigningKey", ctx, "key123").Return("fullkey123", fmt.Errorf("pop")) - _, err := im.NormalizeSigningKey(ctx, "", KeyNormalizationBlockchainPlugin) + _, err := im.ResolveInputSigningKey(ctx, "", KeyNormalizationBlockchainPlugin) assert.Regexp(t, "pop", err) mbi.AssertExpectations(t) @@ -689,12 +667,12 @@ func TestNormalizeSigningKeyOrgFallbackErr(t *testing.T) { } -func TestNormalizeSigningKeyNoDefault(t *testing.T) { +func TestResolveInputSigningKeyNoDefault(t *testing.T) { ctx, im := newTestIdentityManager(t) im.multiparty = nil - _, err := im.NormalizeSigningKey(ctx, "", KeyNormalizationBlockchainPlugin) + _, err := im.ResolveInputSigningKey(ctx, "", KeyNormalizationBlockchainPlugin) assert.Regexp(t, "FF10354", err) } @@ -704,9 +682,9 @@ func TestResolveInputSigningKeyOk(t *testing.T) { ctx, im := newTestIdentityManager(t) mbi := im.blockchain.(*blockchainmocks.Plugin) - mbi.On("NormalizeSigningKey", ctx, "key123").Return("fullkey123", nil) + mbi.On("ResolveInputSigningKey", ctx, "key123").Return("fullkey123", nil) - resolvedKey, err := im.NormalizeSigningKey(ctx, "key123", KeyNormalizationBlockchainPlugin) + resolvedKey, err := im.ResolveInputSigningKey(ctx, "key123", KeyNormalizationBlockchainPlugin) assert.NoError(t, err) assert.Equal(t, "fullkey123", resolvedKey) @@ -718,9 +696,9 @@ func TestResolveInputSigningKeyFail(t *testing.T) { ctx, im := newTestIdentityManager(t) mbi := im.blockchain.(*blockchainmocks.Plugin) - mbi.On("NormalizeSigningKey", ctx, "key123").Return("", fmt.Errorf("pop")) + mbi.On("ResolveInputSigningKey", ctx, "key123").Return("", fmt.Errorf("pop")) - _, err := im.NormalizeSigningKey(ctx, "key123", KeyNormalizationBlockchainPlugin) + _, err := im.ResolveInputSigningKey(ctx, "key123", KeyNormalizationBlockchainPlugin) assert.Regexp(t, "pop", err) mbi.AssertExpectations(t) @@ -730,7 +708,7 @@ func TestResolveInputSigningKeyBypass(t *testing.T) { ctx, im := newTestIdentityManager(t) - key, err := im.NormalizeSigningKey(ctx, "different-type-of-key", KeyNormalizationNone) + key, err := im.ResolveInputSigningKey(ctx, "different-type-of-key", KeyNormalizationNone) assert.NoError(t, err) assert.Equal(t, "different-type-of-key", key) } @@ -840,7 +818,7 @@ func TestGetMultipartyRootVerifierResolveFailed(t *testing.T) { mmp.On("RootOrg").Return(multiparty.RootOrg{Key: "0x12345"}) mbi := im.blockchain.(*blockchainmocks.Plugin) - mbi.On("NormalizeSigningKey", ctx, "0x12345").Return("", fmt.Errorf("pop")) + mbi.On("ResolveInputSigningKey", ctx, "0x12345").Return("", fmt.Errorf("pop")) _, err := im.GetMultipartyRootVerifier(ctx) assert.Regexp(t, "pop", err) @@ -850,45 +828,6 @@ func TestGetMultipartyRootVerifierResolveFailed(t *testing.T) { } -func TestNormalizeKeyViaBlockchainPluginEmptyRequest(t *testing.T) { - - ctx, im := newTestIdentityManager(t) - - _, err := im.normalizeKeyViaBlockchainPlugin(ctx, "") - assert.Regexp(t, "FF10352", err) - -} - -func TestNormalizeKeyViaBlockchainPluginMissingBlockchain(t *testing.T) { - - ctx, im := newTestIdentityManager(t) - im.blockchain = nil - - _, err := im.normalizeKeyViaBlockchainPlugin(ctx, "testKey") - assert.Regexp(t, "FF10417", err) - -} - -func TestNormalizeKeyViaBlockchainPluginCached(t *testing.T) { - - ctx, im := newTestIdentityManager(t) - - mbi := im.blockchain.(*blockchainmocks.Plugin) - mbi.On("NormalizeSigningKey", ctx, "0x12345").Return("resolved12345", nil).Once() - - v, err := im.normalizeKeyViaBlockchainPlugin(ctx, "0x12345") - assert.NoError(t, err) - assert.Equal(t, core.VerifierRef{ - Type: core.VerifierTypeEthAddress, - Value: "resolved12345", - }, *v) - - v1, err := im.normalizeKeyViaBlockchainPlugin(ctx, "0x12345") - assert.NoError(t, err) - assert.Equal(t, v, v1) - -} - func TestGetMultipartyRootVerifierNotSet(t *testing.T) { ctx, im := newTestIdentityManager(t) diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index 7b463445d7..1d716fd253 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -534,7 +534,7 @@ func (or *orchestrator) SubmitNetworkAction(ctx context.Context, action *core.Ne if or.multiparty == nil { return i18n.NewError(ctx, coremsgs.MsgActionNotSupported) } - key, err := or.identity.NormalizeSigningKey(ctx, "", identity.KeyNormalizationBlockchainPlugin) + key, err := or.identity.ResolveInputSigningKey(ctx, "", identity.KeyNormalizationBlockchainPlugin) if err != nil { return err } diff --git a/internal/orchestrator/orchestrator_test.go b/internal/orchestrator/orchestrator_test.go index 08b93562a3..9f664a315e 100644 --- a/internal/orchestrator/orchestrator_test.go +++ b/internal/orchestrator/orchestrator_test.go @@ -464,7 +464,7 @@ func TestNetworkAction(t *testing.T) { or := newTestOrchestrator() or.namespace.Name = core.LegacySystemNamespace action := &core.NetworkAction{Type: core.NetworkActionTerminate} - or.mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x123", nil) + or.mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x123", nil) or.mmp.On("SubmitNetworkAction", context.Background(), "0x123", action).Return(nil) err := or.SubmitNetworkAction(context.Background(), action) assert.NoError(t, err) @@ -474,7 +474,7 @@ func TestNetworkActionBadKey(t *testing.T) { or := newTestOrchestrator() or.namespace.Name = core.LegacySystemNamespace action := &core.NetworkAction{Type: core.NetworkActionTerminate} - or.mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) + or.mim.On("ResolveInputSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) err := or.SubmitNetworkAction(context.Background(), action) assert.EqualError(t, err, "pop") } diff --git a/mocks/blockchainmocks/plugin.go b/mocks/blockchainmocks/plugin.go index 09319628fd..29c31808b5 100644 --- a/mocks/blockchainmocks/plugin.go +++ b/mocks/blockchainmocks/plugin.go @@ -103,6 +103,27 @@ func (_m *Plugin) DeployContract(ctx context.Context, nsOpID string, signingKey return r0 } +// FormatSigningKey provides a mock function with given fields: ctx, keyRef +func (_m *Plugin) FormatSigningKey(ctx context.Context, keyRef string) (string, error) { + ret := _m.Called(ctx, keyRef) + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, string) string); ok { + r0 = rf(ctx, keyRef) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, keyRef) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GenerateErrorSignature provides a mock function with given fields: ctx, errorDef func (_m *Plugin) GenerateErrorSignature(ctx context.Context, errorDef *fftypes.FFIErrorDefinition) string { ret := _m.Called(ctx, errorDef) @@ -344,27 +365,6 @@ func (_m *Plugin) NormalizeContractLocation(ctx context.Context, location *fftyp return r0, r1 } -// NormalizeSigningKey provides a mock function with given fields: ctx, keyRef -func (_m *Plugin) NormalizeSigningKey(ctx context.Context, keyRef string) (string, error) { - ret := _m.Called(ctx, keyRef) - - var r0 string - if rf, ok := ret.Get(0).(func(context.Context, string) string); ok { - r0 = rf(ctx, keyRef) - } else { - r0 = ret.Get(0).(string) - } - - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, keyRef) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // QueryContract provides a mock function with given fields: ctx, location, method, input, errors, options func (_m *Plugin) QueryContract(ctx context.Context, location *fftypes.JSONAny, method *fftypes.FFIMethod, input map[string]interface{}, errors []*fftypes.FFIError, options map[string]interface{}) (interface{}, error) { ret := _m.Called(ctx, location, method, input, errors, options) @@ -393,6 +393,27 @@ func (_m *Plugin) RemoveFireflySubscription(ctx context.Context, subID string) { _m.Called(ctx, subID) } +// ResolveInputSigningKey provides a mock function with given fields: ctx, keyRef +func (_m *Plugin) ResolveInputSigningKey(ctx context.Context, keyRef string) (string, error) { + ret := _m.Called(ctx, keyRef) + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, string) string); ok { + r0 = rf(ctx, keyRef) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, keyRef) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // SetHandler provides a mock function with given fields: namespace, handler func (_m *Plugin) SetHandler(namespace string, handler blockchain.Callbacks) { _m.Called(namespace, handler) diff --git a/mocks/identitymanagermocks/manager.go b/mocks/identitymanagermocks/manager.go index db1833a82a..cbf9855762 100644 --- a/mocks/identitymanagermocks/manager.go +++ b/mocks/identitymanagermocks/manager.go @@ -191,27 +191,6 @@ func (_m *Manager) GetMultipartyRootVerifier(ctx context.Context) (*core.Verifie return r0, r1 } -// NormalizeSigningKey provides a mock function with given fields: ctx, inputKey, keyNormalizationMode -func (_m *Manager) NormalizeSigningKey(ctx context.Context, inputKey string, keyNormalizationMode int) (string, error) { - ret := _m.Called(ctx, inputKey, keyNormalizationMode) - - var r0 string - if rf, ok := ret.Get(0).(func(context.Context, string, int) string); ok { - r0 = rf(ctx, inputKey, keyNormalizationMode) - } else { - r0 = ret.Get(0).(string) - } - - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, string, int) error); ok { - r1 = rf(ctx, inputKey, keyNormalizationMode) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // ResolveIdentitySigner provides a mock function with given fields: ctx, _a1 func (_m *Manager) ResolveIdentitySigner(ctx context.Context, _a1 *core.Identity) (*core.SignerRef, error) { ret := _m.Called(ctx, _a1) @@ -249,8 +228,29 @@ func (_m *Manager) ResolveInputSigningIdentity(ctx context.Context, signerRef *c return r0 } -// ResolveInputSigningKey provides a mock function with given fields: ctx, inputKey -func (_m *Manager) ResolveInputSigningKey(ctx context.Context, inputKey *core.VerifierRef) (*core.VerifierRef, error) { +// ResolveInputSigningKey provides a mock function with given fields: ctx, inputKey, keyNormalizationMode +func (_m *Manager) ResolveInputSigningKey(ctx context.Context, inputKey string, keyNormalizationMode int) (string, error) { + ret := _m.Called(ctx, inputKey, keyNormalizationMode) + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, string, int) string); ok { + r0 = rf(ctx, inputKey, keyNormalizationMode) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string, int) error); ok { + r1 = rf(ctx, inputKey, keyNormalizationMode) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ResolveInputVerifierRef provides a mock function with given fields: ctx, inputKey +func (_m *Manager) ResolveInputVerifierRef(ctx context.Context, inputKey *core.VerifierRef) (*core.VerifierRef, error) { ret := _m.Called(ctx, inputKey) var r0 *core.VerifierRef @@ -293,6 +293,27 @@ func (_m *Manager) ValidateNodeOwner(ctx context.Context, node *core.Identity, _ return r0, r1 } +// ValidateReceivedSigningKey provides a mock function with given fields: ctx, inputKey, keyNormalizationMode +func (_m *Manager) ValidateReceivedSigningKey(ctx context.Context, inputKey string, keyNormalizationMode int) (string, error) { + ret := _m.Called(ctx, inputKey, keyNormalizationMode) + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, string, int) string); ok { + r0 = rf(ctx, inputKey, keyNormalizationMode) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string, int) error); ok { + r1 = rf(ctx, inputKey, keyNormalizationMode) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // VerifyIdentityChain provides a mock function with given fields: ctx, _a1 func (_m *Manager) VerifyIdentityChain(ctx context.Context, _a1 *core.Identity) (*core.Identity, bool, error) { ret := _m.Called(ctx, _a1) diff --git a/pkg/blockchain/plugin.go b/pkg/blockchain/plugin.go index 9357040836..4d9beb22e7 100644 --- a/pkg/blockchain/plugin.go +++ b/pkg/blockchain/plugin.go @@ -53,10 +53,14 @@ type Plugin interface { // VerifierType returns the verifier (key) type that is used by this blockchain VerifierType() core.VerifierType - // NormalizeSigningKey verifies that the supplied identity string is valid syntax according to the protocol. - // - Can apply transformations to the supplied signing identity (only), such as lower case. - // - Can perform sophisicated resolution, such as resolving a Fabric shortname to a MSP ID, or using an external REST API plugin to resolve a HD wallet address - NormalizeSigningKey(ctx context.Context, keyRef string) (string, error) + // ResolveInputSigningKey allows blockchain specific processing of keys supplied by users + // of this FireFly core API before a transaction is accepted using that signing key. + // May perform sophisticated checks and resolution as determined by the blockchain connector, + // and associated resolution plugins: + // - Such as resolving a Fabric shortname to a MSP ID + // - Such using an external REST API plugin to resolve a HD wallet address, or other key alias + // - Results in a string that can be stored/compared consistently with the key emitted on events signed by this key + ResolveInputSigningKey(ctx context.Context, keyRef string) (string, error) // SubmitBatchPin sequences a batch of message globally to all viewers of a given ledger SubmitBatchPin(ctx context.Context, nsOpID, networkNamespace, signingKey string, batch *BatchPin, location *fftypes.JSONAny) error