Repository: hyperledger/firefly
Pull request #1141 (2023-01-12 23:00:58)

Add option to invoke the addressResolver on every call
The address resolver is a very useful plug point for FireFly with EVM based chains that have sophisticated signing infrastructures.

We have a requirement for the interface to be called on every API call that has a `key` input on the Hyperledger FireFly API, regardless of whether the input string conforms to an `0x` address already, and regardless of how many times it is called.

This PR introduces a single new config option `alwaysResolve` to do this.

I added a second commit on this PR, after doing quite a detailed review of every place we were calling the address
resolver. I found the terminology was still confusing (know we've had a few changes) and make a tweak.

I also made the following changes:
- Removed two places within the `ethereum` connector it was using the `NormalizeSigningKey` function, to just format an ethereum address. That is now fixed
- I removed the additional cache on address resolution that was in the `Identity Manager`, because this would have got int the way of the removal of the cache in the blockchain layer. Also, _both_ Ethereum and Fabric already had caches for the expensive logic that wasn't just string formatting, so it seemed completely redundant.
- Fixed an intermittent coverage gap in Webhooks, fixing also the fact we were logging an error when there wasn't one, and removing a return of an error from `doDelivery` that was always `nil`




Patch:
diff --git a/.golangci.yml b/.golangci.yml
index 00d61e57b..b983567a5 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 c28874a3b..1000d191b 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`|`<nil>`
 |bodyTemplate|The body go template string to use when making HTTP requests|[Go Template](https://pkg.go.dev/text/template) `string`|`<nil>`
 |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`|`<nil>`
 |ttl|Time to live of cached items for operations|`string`|`<nil>`
 
-## cache.signingkey
-
-|Key|Description|Type|Default Value|
-|---|-----------|----|-------------|
-|limit|Max number of cached signing keys for identity manager|`int`|`<nil>`
-|ttl|Time to live of cached signing keys for identity manager|`string`|`<nil>`
-
 ## 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`|`<nil>`
 |bodyTemplate|The body go template string to use when making HTTP requests|[Go Template](https://pkg.go.dev/text/template) `string`|`<nil>`
 |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 29091d06c..a7c107847 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/assets/token_approval.go b/internal/assets/token_approval.go
index 28ec45d73..435e630e1 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_pool.go b/internal/assets/token_pool.go
index 93644430c..87fd56e99 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_transfer.go b/internal/assets/token_transfer.go
index 29be87679..86cc2e7a6 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/blockchain/ethereum/address_resolver.go b/internal/blockchain/ethereum/address_resolver.go
index c1346e5d5..abe61b4e5 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/config.go b/internal/blockchain/ethereum/config.go
index f250004fc..875dc9bb5 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 38cc391f6..ed348f903 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(), &ethLocation); err != nil {
 		return nil, i18n.NewError(ctx, coremsgs.MsgContractLocationInvalid, err)
@@ -757,8 +768,8 @@ func parseContractLocation(ctx context.Context, location *fftypes.JSONAny) (*Loc
 	return &ethLocation, 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/fabric/fabric.go b/internal/blockchain/fabric/fabric.go
index 1c699d262..9ec154946 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/contracts/manager.go b/internal/contracts/manager.go
index 21e46df4d..75e93f979 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/coreconfig/coreconfig.go b/internal/coreconfig/coreconfig.go
index b3ba1c9fa..e65f7826d 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 393e911d6..c81d59d00 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 5a4abd5c5..04bee92a7 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/events/webhooks/webhooks.go b/internal/events/webhooks/webhooks.go
index 4e534f97e..1d9facbb2 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/identity/identitymanager.go b/internal/identity/identitymanager.go
index 1902f9bec..9ff0e3705 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/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go
index 7b463445d..1d716fd25 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/mocks/blockchainmocks/plugin.go b/mocks/blockchainmocks/plugin.go
index 09319628f..29c31808b 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 db1833a82..cbf985576 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 935704083..4d9beb22e 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


Test patch:
diff --git a/internal/apiserver/route_post_verifiers_resolve_test.go b/internal/apiserver/route_post_verifiers_resolve_test.go
index 956571350..e080f1c4f 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_test.go b/internal/assets/token_approval_test.go
index 0e7768c3f..cc81d85db 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_test.go b/internal/assets/token_pool_test.go
index 7c2ace87e..e44d84d79 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_test.go b/internal/assets/token_transfer_test.go
index 83a591719..d02078814 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_test.go b/internal/blockchain/ethereum/address_resolver_test.go
index e89746ece..bdca0cee7 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/ethereum_test.go b/internal/blockchain/ethereum/ethereum_test.go
index 0ea79022a..d98ebb053 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_test.go b/internal/blockchain/fabric/fabric_test.go
index 53d4b3dba..783fdc344 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(<nil>)")
 }
 
@@ -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_test.go b/internal/contracts/manager_test.go
index 897433528..fcf5d80ff 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/definitions/sender_identity_test.go b/internal/definitions/sender_identity_test.go
index 1f32ff4af..4e035ee30 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_test.go b/internal/events/webhooks/webhooks_test.go
index 690beda47..aab2cb572 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_test.go b/internal/identity/identitymanager_test.go
index b17a4d47c..5e522d58b 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_test.go b/internal/orchestrator/orchestrator_test.go
index 08b93562a..9f664a315 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")
 }