Repository: hyperledger/firefly
Pull request #896 (2022-07-11 14:40:34)

Support tokens only namespaces
Now, multiparty-disabled namespaces can run without a blockchain plugin:
 * All contract routes will be disabled
 * Identity normalizations that rely on a blockchain plugin will either default to the specified input/default key or fail
 * `aggregator` is not started within `EventManager`

codecov-commenter: # [Codecov](https://codecov.io/gh/hyperledger/firefly/pull/896?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger) Report
> Merging [#896](https://codecov.io/gh/hyperledger/firefly/pull/896?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger) (d50061f) into [main](https://codecov.io/gh/hyperledger/firefly/commit/2f705a3d78cbe07e7d1de238f74e1b443805e474?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger) (2f705a3) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

```diff
@@           Coverage Diff            @@
##             main     #896    +/-   ##
========================================
  Coverage   99.97%   99.97%            
========================================
  Files         298      298            
  Lines       19255    19413   +158     
========================================
+ Hits        19251    19409   +158     
  Misses          4        4            
```


| [Impacted Files](https://codecov.io/gh/hyperledger/firefly/pull/896?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger) | Coverage Δ | |
|---|---|---|
| [...ternal/apiserver/route\_get\_contract\_api\_by\_name.go](https://codecov.io/gh/hyperledger/firefly/pull/896/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-aW50ZXJuYWwvYXBpc2VydmVyL3JvdXRlX2dldF9jb250cmFjdF9hcGlfYnlfbmFtZS5nbw==) | `100.00% <100.00%> (ø)` | |
| [...rnal/apiserver/route\_get\_contract\_api\_interface.go](https://codecov.io/gh/hyperledger/firefly/pull/896/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-aW50ZXJuYWwvYXBpc2VydmVyL3JvdXRlX2dldF9jb250cmFjdF9hcGlfaW50ZXJmYWNlLmdv) | `100.00% <100.00%> (ø)` | |
| [...rnal/apiserver/route\_get\_contract\_api\_listeners.go](https://codecov.io/gh/hyperledger/firefly/pull/896/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-aW50ZXJuYWwvYXBpc2VydmVyL3JvdXRlX2dldF9jb250cmFjdF9hcGlfbGlzdGVuZXJzLmdv) | `100.00% <100.00%> (ø)` | |
| [internal/apiserver/route\_get\_contract\_apis.go](https://codecov.io/gh/hyperledger/firefly/pull/896/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-aW50ZXJuYWwvYXBpc2VydmVyL3JvdXRlX2dldF9jb250cmFjdF9hcGlzLmdv) | `100.00% <100.00%> (ø)` | |
| [internal/apiserver/route\_get\_contract\_interface.go](https://codecov.io/gh/hyperledger/firefly/pull/896/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-aW50ZXJuYWwvYXBpc2VydmVyL3JvdXRlX2dldF9jb250cmFjdF9pbnRlcmZhY2UuZ28=) | `100.00% <100.00%> (ø)` | |
| [...erver/route\_get\_contract\_interface\_name\_version.go](https://codecov.io/gh/hyperledger/firefly/pull/896/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-aW50ZXJuYWwvYXBpc2VydmVyL3JvdXRlX2dldF9jb250cmFjdF9pbnRlcmZhY2VfbmFtZV92ZXJzaW9uLmdv) | `100.00% <100.00%> (ø)` | |
| [...nternal/apiserver/route\_get\_contract\_interfaces.go](https://codecov.io/gh/hyperledger/firefly/pull/896/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-aW50ZXJuYWwvYXBpc2VydmVyL3JvdXRlX2dldF9jb250cmFjdF9pbnRlcmZhY2VzLmdv) | `100.00% <100.00%> (ø)` | |
| [...erver/route\_get\_contract\_listener\_by\_name\_or\_id.go](https://codecov.io/gh/hyperledger/firefly/pull/896/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-aW50ZXJuYWwvYXBpc2VydmVyL3JvdXRlX2dldF9jb250cmFjdF9saXN0ZW5lcl9ieV9uYW1lX29yX2lkLmdv) | `100.00% <100.00%> (ø)` | |
| [internal/apiserver/route\_get\_contract\_listeners.go](https://codecov.io/gh/hyperledger/firefly/pull/896/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-aW50ZXJuYWwvYXBpc2VydmVyL3JvdXRlX2dldF9jb250cmFjdF9saXN0ZW5lcnMuZ28=) | `100.00% <100.00%> (ø)` | |
| [...ternal/apiserver/route\_post\_contract\_api\_invoke.go](https://codecov.io/gh/hyperledger/firefly/pull/896/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger#diff-aW50ZXJuYWwvYXBpc2VydmVyL3JvdXRlX3Bvc3RfY29udHJhY3RfYXBpX2ludm9rZS5nbw==) | `100.00% <100.00%> (ø)` | |
| ... and [19 more](https://codecov.io/gh/hyperledger/firefly/pull/896/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/hyperledger/firefly/pull/896?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/hyperledger/firefly/pull/896?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger). Last update [2f705a3...d50061f](https://codecov.io/gh/hyperledger/firefly/pull/896?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperledger).


Patch:
diff --git a/internal/apiserver/route_get_contract_api_by_name.go b/internal/apiserver/route_get_contract_api_by_name.go
index dc87e580d..4df16be89 100644
--- a/internal/apiserver/route_get_contract_api_by_name.go
+++ b/internal/apiserver/route_get_contract_api_by_name.go
@@ -21,6 +21,7 @@ import (
 
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 	"github.com/hyperledger/firefly/pkg/core"
 )
 
@@ -37,6 +38,9 @@ var getContractAPIByName = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return &core.ContractAPI{} },
 	JSONOutputCodes: []int{http.StatusOK},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			return cr.or.Contracts().GetContractAPI(cr.ctx, cr.apiBaseURL, r.PP["apiName"])
 		},
diff --git a/internal/apiserver/route_get_contract_api_interface.go b/internal/apiserver/route_get_contract_api_interface.go
index e7cbae6a8..9b17a1d4d 100644
--- a/internal/apiserver/route_get_contract_api_interface.go
+++ b/internal/apiserver/route_get_contract_api_interface.go
@@ -22,6 +22,7 @@ import (
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly-common/pkg/fftypes"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 )
 
 var getContractAPIInterface = &ffapi.Route{
@@ -37,6 +38,9 @@ var getContractAPIInterface = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return &fftypes.FFI{} },
 	JSONOutputCodes: []int{http.StatusOK},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			return cr.or.Contracts().GetContractAPIInterface(cr.ctx, r.PP["apiName"])
 		},
diff --git a/internal/apiserver/route_get_contract_api_listeners.go b/internal/apiserver/route_get_contract_api_listeners.go
index 818716dda..fd5fed0a3 100644
--- a/internal/apiserver/route_get_contract_api_listeners.go
+++ b/internal/apiserver/route_get_contract_api_listeners.go
@@ -21,6 +21,7 @@ import (
 
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 	"github.com/hyperledger/firefly/pkg/core"
 	"github.com/hyperledger/firefly/pkg/database"
 )
@@ -39,6 +40,9 @@ var getContractAPIListeners = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return []*core.ContractListener{} },
 	JSONOutputCodes: []int{http.StatusOK},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		FilterFactory: database.ContractListenerQueryFactory,
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			return filterResult(cr.or.Contracts().GetContractAPIListeners(cr.ctx, r.PP["apiName"], r.PP["eventPath"], cr.filter))
diff --git a/internal/apiserver/route_get_contract_apis.go b/internal/apiserver/route_get_contract_apis.go
index 6a739f4fc..a061f73b1 100644
--- a/internal/apiserver/route_get_contract_apis.go
+++ b/internal/apiserver/route_get_contract_apis.go
@@ -21,6 +21,7 @@ import (
 
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 	"github.com/hyperledger/firefly/pkg/core"
 	"github.com/hyperledger/firefly/pkg/database"
 )
@@ -36,6 +37,9 @@ var getContractAPIs = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return []*core.ContractAPI{} },
 	JSONOutputCodes: []int{http.StatusOK},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		FilterFactory: database.ContractAPIQueryFactory,
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			return filterResult(cr.or.Contracts().GetContractAPIs(cr.ctx, cr.apiBaseURL, cr.filter))
diff --git a/internal/apiserver/route_get_contract_interface.go b/internal/apiserver/route_get_contract_interface.go
index 05365baa8..e35ec0a1e 100644
--- a/internal/apiserver/route_get_contract_interface.go
+++ b/internal/apiserver/route_get_contract_interface.go
@@ -23,6 +23,7 @@ import (
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly-common/pkg/fftypes"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 )
 
 var getContractInterface = &ffapi.Route{
@@ -40,6 +41,9 @@ var getContractInterface = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return &fftypes.FFI{} },
 	JSONOutputCodes: []int{http.StatusOK},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			interfaceID, err := fftypes.ParseUUID(cr.ctx, r.PP["interfaceId"])
 			if err != nil {
diff --git a/internal/apiserver/route_get_contract_interface_name_version.go b/internal/apiserver/route_get_contract_interface_name_version.go
index ac19838f5..4c2d5d90f 100644
--- a/internal/apiserver/route_get_contract_interface_name_version.go
+++ b/internal/apiserver/route_get_contract_interface_name_version.go
@@ -23,6 +23,7 @@ import (
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly-common/pkg/fftypes"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 )
 
 var getContractInterfaceNameVersion = &ffapi.Route{
@@ -41,6 +42,9 @@ var getContractInterfaceNameVersion = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return &fftypes.FFI{} },
 	JSONOutputCodes: []int{http.StatusOK},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			if strings.EqualFold(r.QP["fetchchildren"], "true") {
 				return cr.or.Contracts().GetFFIWithChildren(cr.ctx, r.PP["name"], r.PP["version"])
diff --git a/internal/apiserver/route_get_contract_interfaces.go b/internal/apiserver/route_get_contract_interfaces.go
index 96617bc2b..16d60ac05 100644
--- a/internal/apiserver/route_get_contract_interfaces.go
+++ b/internal/apiserver/route_get_contract_interfaces.go
@@ -22,6 +22,7 @@ import (
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly-common/pkg/fftypes"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 	"github.com/hyperledger/firefly/pkg/database"
 )
 
@@ -36,6 +37,9 @@ var getContractInterfaces = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return []*fftypes.FFI{} },
 	JSONOutputCodes: []int{http.StatusOK},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		FilterFactory: database.FFIQueryFactory,
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			return filterResult(cr.or.Contracts().GetFFIs(cr.ctx, cr.filter))
diff --git a/internal/apiserver/route_get_contract_listener_by_name_or_id.go b/internal/apiserver/route_get_contract_listener_by_name_or_id.go
index 1704e4cbb..7424515f0 100644
--- a/internal/apiserver/route_get_contract_listener_by_name_or_id.go
+++ b/internal/apiserver/route_get_contract_listener_by_name_or_id.go
@@ -21,6 +21,7 @@ import (
 
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 	"github.com/hyperledger/firefly/pkg/core"
 )
 
@@ -37,6 +38,9 @@ var getContractListenerByNameOrID = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return &core.ContractListener{} },
 	JSONOutputCodes: []int{http.StatusOK},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			return cr.or.Contracts().GetContractListenerByNameOrID(cr.ctx, r.PP["nameOrId"])
 		},
diff --git a/internal/apiserver/route_get_contract_listeners.go b/internal/apiserver/route_get_contract_listeners.go
index baab05240..e0eb7bdfc 100644
--- a/internal/apiserver/route_get_contract_listeners.go
+++ b/internal/apiserver/route_get_contract_listeners.go
@@ -21,6 +21,7 @@ import (
 
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 	"github.com/hyperledger/firefly/pkg/core"
 	"github.com/hyperledger/firefly/pkg/database"
 )
@@ -36,6 +37,9 @@ var getContractListeners = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return []*core.ContractListener{} },
 	JSONOutputCodes: []int{http.StatusOK},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		FilterFactory: database.ContractListenerQueryFactory,
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			return filterResult(cr.or.Contracts().GetContractListeners(cr.ctx, cr.filter))
diff --git a/internal/apiserver/route_post_contract_api_invoke.go b/internal/apiserver/route_post_contract_api_invoke.go
index dbc4e0807..2b0bf8944 100644
--- a/internal/apiserver/route_post_contract_api_invoke.go
+++ b/internal/apiserver/route_post_contract_api_invoke.go
@@ -22,6 +22,7 @@ import (
 
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 	"github.com/hyperledger/firefly/pkg/core"
 )
 
@@ -41,6 +42,9 @@ var postContractAPIInvoke = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return &core.Operation{} },
 	JSONOutputCodes: []int{http.StatusOK, http.StatusAccepted},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			waitConfirm := strings.EqualFold(r.QP["confirm"], "true")
 			r.SuccessStatus = syncRetcode(waitConfirm)
diff --git a/internal/apiserver/route_post_contract_api_listeners.go b/internal/apiserver/route_post_contract_api_listeners.go
index c2130fe87..2ec2aecbe 100644
--- a/internal/apiserver/route_post_contract_api_listeners.go
+++ b/internal/apiserver/route_post_contract_api_listeners.go
@@ -21,6 +21,7 @@ import (
 
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 	"github.com/hyperledger/firefly/pkg/core"
 )
 
@@ -38,6 +39,9 @@ var postContractAPIListeners = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return &core.ContractListener{} },
 	JSONOutputCodes: []int{http.StatusOK},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			return cr.or.Contracts().AddContractAPIListener(cr.ctx, r.PP["apiName"], r.PP["eventPath"], r.Input.(*core.ContractListener))
 		},
diff --git a/internal/apiserver/route_post_contract_api_query.go b/internal/apiserver/route_post_contract_api_query.go
index 004b0e9d9..4b685d9bb 100644
--- a/internal/apiserver/route_post_contract_api_query.go
+++ b/internal/apiserver/route_post_contract_api_query.go
@@ -21,6 +21,7 @@ import (
 
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 	"github.com/hyperledger/firefly/pkg/core"
 )
 
@@ -38,6 +39,9 @@ var postContractAPIQuery = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return make(map[string]interface{}) },
 	JSONOutputCodes: []int{http.StatusOK},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			req := r.Input.(*core.ContractCallRequest)
 			req.Type = core.CallTypeQuery
diff --git a/internal/apiserver/route_post_contract_interface_generate.go b/internal/apiserver/route_post_contract_interface_generate.go
index ec0b52713..0f3136a40 100644
--- a/internal/apiserver/route_post_contract_interface_generate.go
+++ b/internal/apiserver/route_post_contract_interface_generate.go
@@ -22,6 +22,7 @@ import (
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly-common/pkg/fftypes"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 )
 
 var postContractInterfaceGenerate = &ffapi.Route{
@@ -35,6 +36,9 @@ var postContractInterfaceGenerate = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return &fftypes.FFI{} },
 	JSONOutputCodes: []int{http.StatusOK},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			generationRequest := r.Input.(*fftypes.FFIGenerationRequest)
 			return cr.or.Contracts().GenerateFFI(cr.ctx, generationRequest)
diff --git a/internal/apiserver/route_post_contract_invoke.go b/internal/apiserver/route_post_contract_invoke.go
index 02779e311..69bd84db9 100644
--- a/internal/apiserver/route_post_contract_invoke.go
+++ b/internal/apiserver/route_post_contract_invoke.go
@@ -22,6 +22,7 @@ import (
 
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 	"github.com/hyperledger/firefly/pkg/core"
 )
 
@@ -38,6 +39,9 @@ var postContractInvoke = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return &core.Operation{} },
 	JSONOutputCodes: []int{http.StatusOK, http.StatusAccepted},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			waitConfirm := strings.EqualFold(r.QP["confirm"], "true")
 			r.SuccessStatus = syncRetcode(waitConfirm)
diff --git a/internal/apiserver/route_post_contract_query.go b/internal/apiserver/route_post_contract_query.go
index e7fd49df1..9d3997387 100644
--- a/internal/apiserver/route_post_contract_query.go
+++ b/internal/apiserver/route_post_contract_query.go
@@ -21,6 +21,7 @@ import (
 
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 	"github.com/hyperledger/firefly/pkg/core"
 )
 
@@ -35,6 +36,9 @@ var postContractQuery = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return make(map[string]interface{}) },
 	JSONOutputCodes: []int{http.StatusOK},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			req := r.Input.(*core.ContractCallRequest)
 			req.Type = core.CallTypeQuery
diff --git a/internal/apiserver/route_post_new_contract_api.go b/internal/apiserver/route_post_new_contract_api.go
index 5ae7496e2..f5bf7a9f2 100644
--- a/internal/apiserver/route_post_new_contract_api.go
+++ b/internal/apiserver/route_post_new_contract_api.go
@@ -22,6 +22,7 @@ import (
 
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 	"github.com/hyperledger/firefly/pkg/core"
 )
 
@@ -38,6 +39,9 @@ var postNewContractAPI = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return &core.ContractAPI{} },
 	JSONOutputCodes: []int{http.StatusOK, http.StatusAccepted},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			waitConfirm := strings.EqualFold(r.QP["confirm"], "true")
 			r.SuccessStatus = syncRetcode(waitConfirm)
diff --git a/internal/apiserver/route_post_new_contract_interface.go b/internal/apiserver/route_post_new_contract_interface.go
index 4aecbbcc2..1b408739a 100644
--- a/internal/apiserver/route_post_new_contract_interface.go
+++ b/internal/apiserver/route_post_new_contract_interface.go
@@ -23,6 +23,7 @@ import (
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly-common/pkg/fftypes"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 )
 
 var postNewContractInterface = &ffapi.Route{
@@ -38,6 +39,9 @@ var postNewContractInterface = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return &fftypes.FFI{} },
 	JSONOutputCodes: []int{http.StatusOK},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			waitConfirm := strings.EqualFold(r.QP["confirm"], "true")
 			r.SuccessStatus = syncRetcode(waitConfirm)
diff --git a/internal/apiserver/route_post_new_contract_listener.go b/internal/apiserver/route_post_new_contract_listener.go
index 2afcfba9c..5c6f9f33f 100644
--- a/internal/apiserver/route_post_new_contract_listener.go
+++ b/internal/apiserver/route_post_new_contract_listener.go
@@ -21,6 +21,7 @@ import (
 
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 	"github.com/hyperledger/firefly/pkg/core"
 )
 
@@ -35,6 +36,9 @@ var postNewContractListener = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return &core.ContractListener{} },
 	JSONOutputCodes: []int{http.StatusOK},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			return cr.or.Contracts().AddContractListener(cr.ctx, r.Input.(*core.ContractListenerInput))
 		},
diff --git a/internal/apiserver/route_put_contract_api.go b/internal/apiserver/route_put_contract_api.go
index 537571194..28521ea31 100644
--- a/internal/apiserver/route_put_contract_api.go
+++ b/internal/apiserver/route_put_contract_api.go
@@ -23,6 +23,7 @@ import (
 	"github.com/hyperledger/firefly-common/pkg/ffapi"
 	"github.com/hyperledger/firefly-common/pkg/fftypes"
 	"github.com/hyperledger/firefly/internal/coremsgs"
+	"github.com/hyperledger/firefly/internal/orchestrator"
 	"github.com/hyperledger/firefly/pkg/core"
 )
 
@@ -41,6 +42,9 @@ var putContractAPI = &ffapi.Route{
 	JSONOutputValue: func() interface{} { return &core.ContractAPI{} },
 	JSONOutputCodes: []int{http.StatusOK, http.StatusAccepted},
 	Extensions: &coreExtensions{
+		EnabledIf: func(or orchestrator.Orchestrator) bool {
+			return or.Contracts() != nil
+		},
 		CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) {
 			waitConfirm := strings.EqualFold(r.QP["confirm"], "true")
 			r.SuccessStatus = syncRetcode(waitConfirm)
diff --git a/internal/coremsgs/en_error_messages.go b/internal/coremsgs/en_error_messages.go
index 8da0bcfe2..f15978460 100644
--- a/internal/coremsgs/en_error_messages.go
+++ b/internal/coremsgs/en_error_messages.go
@@ -256,4 +256,5 @@ var (
 	MsgActionNotSupported                 = ffe("FF10414", "This action is not supported in this namespace", 400)
 	MsgMessagesNotSupported               = ffe("FF10415", "Messages are not supported in this namespace", 400)
 	MsgInvalidSubscriptionForNetwork      = ffe("FF10416", "Subscription name '%s' is invalid according to multiparty network rules in effect (network version=%d)")
+	MsgBlockchainNotConfigured            = ffe("FF10417", "No blockchain plugin configured")
 )
diff --git a/internal/definitions/handler.go b/internal/definitions/handler.go
index 6c2f150bb..56b0c1b43 100644
--- a/internal/definitions/handler.go
+++ b/internal/definitions/handler.go
@@ -80,16 +80,16 @@ type definitionHandler struct {
 	namespace  string
 	multiparty bool
 	database   database.Plugin
-	blockchain blockchain.Plugin
+	blockchain blockchain.Plugin   // optional
 	exchange   dataexchange.Plugin // optional
 	data       data.Manager
 	identity   identity.Manager
 	assets     assets.Manager
-	contracts  contracts.Manager
+	contracts  contracts.Manager // optional
 }
 
 func newDefinitionHandler(ctx context.Context, ns string, multiparty bool, di database.Plugin, bi blockchain.Plugin, dx dataexchange.Plugin, dm data.Manager, im identity.Manager, am assets.Manager, cm contracts.Manager) (*definitionHandler, error) {
-	if di == nil || bi == nil || dm == nil || im == nil || am == nil || cm == nil {
+	if di == nil || dm == nil || im == nil || am == nil {
 		return nil, i18n.NewError(ctx, coremsgs.MsgInitializationNilDepError, "DefinitionHandler")
 	}
 	return &definitionHandler{
diff --git a/internal/definitions/sender.go b/internal/definitions/sender.go
index d034293b2..542f26f84 100644
--- a/internal/definitions/sender.go
+++ b/internal/definitions/sender.go
@@ -53,7 +53,7 @@ type definitionSender struct {
 	broadcast  broadcast.Manager // optional
 	identity   identity.Manager
 	data       data.Manager
-	contracts  contracts.Manager
+	contracts  contracts.Manager // optional
 	handler    *definitionHandler
 }
 
@@ -71,8 +71,8 @@ func fakeBatch(ctx context.Context, handler func(context.Context, *core.BatchSta
 }
 
 func NewDefinitionSender(ctx context.Context, ns string, multiparty bool, di database.Plugin, bi blockchain.Plugin, dx dataexchange.Plugin, bm broadcast.Manager, im identity.Manager, dm data.Manager, am assets.Manager, cm contracts.Manager) (Sender, Handler, error) {
-	if di == nil || im == nil || dm == nil || cm == nil {
-		return nil, nil, i18n.NewError(ctx, coremsgs.MsgInitializationNilDepError)
+	if di == nil || im == nil || dm == nil {
+		return nil, nil, i18n.NewError(ctx, coremsgs.MsgInitializationNilDepError, "DefinitionSender")
 	}
 	ds := &definitionSender{
 		ctx:        ctx,
diff --git a/internal/events/event_manager.go b/internal/events/event_manager.go
index cae7efb1a..3f28d0602 100644
--- a/internal/events/event_manager.go
+++ b/internal/events/event_manager.go
@@ -99,12 +99,12 @@ type eventManager struct {
 	data                  data.Manager
 	subManager            *subscriptionManager
 	retry                 retry.Retry
-	aggregator            *aggregator
+	aggregator            *aggregator              // optional
 	broadcast             broadcast.Manager        // optional
 	messaging             privatemessaging.Manager // optional
 	assets                assets.Manager
 	sharedDownload        shareddownload.Manager // optional
-	blobReceiver          *blobReceiver
+	blobReceiver          *blobReceiver          // optional
 	newEventNotifier      *eventNotifier
 	newPinNotifier        *eventNotifier
 	defaultTransport      string
@@ -116,7 +116,7 @@ type eventManager struct {
 }
 
 func NewEventManager(ctx context.Context, ns string, ni sysmessaging.LocalNodeInfo, di database.Plugin, bi blockchain.Plugin, im identity.Manager, dh definitions.Handler, dm data.Manager, ds definitions.Sender, bm broadcast.Manager, pm privatemessaging.Manager, am assets.Manager, sd shareddownload.Manager, mm metrics.Manager, txHelper txcommon.Helper, transports map[string]events.Plugin, mp multiparty.Manager) (EventManager, error) {
-	if ni == nil || di == nil || bi == nil || im == nil || dh == nil || dm == nil || ds == nil || am == nil {
+	if ni == nil || di == nil || im == nil || dh == nil || dm == nil || ds == nil || am == nil {
 		return nil, i18n.NewError(ctx, coremsgs.MsgInitializationNilDepError, "EventManager")
 	}
 	newPinNotifier := newEventNotifier(ctx, "pins")
@@ -144,14 +144,16 @@ func NewEventManager(ctx context.Context, ns string, ni sysmessaging.LocalNodeIn
 		defaultTransport:      config.GetString(coreconfig.EventTransportsDefault),
 		newEventNotifier:      newEventNotifier,
 		newPinNotifier:        newPinNotifier,
-		aggregator:            newAggregator(ctx, ns, di, bi, pm, dh, im, dm, newPinNotifier, mm),
 		metrics:               mm,
 		chainListenerCache:    ccache.New(ccache.Configure().MaxSize(config.GetByteSize(coreconfig.EventListenerTopicCacheSize))),
 		chainListenerCacheTTL: config.GetDuration(coreconfig.EventListenerTopicCacheTTL),
 	}
 	ie, _ := eifactory.GetPlugin(ctx, system.SystemEventsTransport)
 	em.internalEvents = ie.(*system.Events)
-	em.blobReceiver = newBlobReceiver(ctx, em.aggregator)
+	if bi != nil {
+		em.aggregator = newAggregator(ctx, ns, di, bi, pm, dh, im, dm, newPinNotifier, mm)
+		em.blobReceiver = newBlobReceiver(ctx, em.aggregator)
+	}
 
 	var err error
 	if em.subManager, err = newSubscriptionManager(ctx, ns, di, dm, newEventNotifier, bm, pm, txHelper, transports); err != nil {
@@ -164,8 +166,10 @@ func NewEventManager(ctx context.Context, ns string, ni sysmessaging.LocalNodeIn
 func (em *eventManager) Start() (err error) {
 	err = em.subManager.start()
 	if err == nil {
-		em.aggregator.start()
-		em.blobReceiver.start()
+		if em.aggregator != nil {
+			em.aggregator.start()
+			em.blobReceiver.start()
+		}
 	}
 	return err
 }
diff --git a/internal/identity/identitymanager.go b/internal/identity/identitymanager.go
index 7646593e7..89ef88cf6 100644
--- a/internal/identity/identitymanager.go
+++ b/internal/identity/identitymanager.go
@@ -56,7 +56,7 @@ type Manager interface {
 
 type identityManager struct {
 	database               database.Plugin
-	blockchain             blockchain.Plugin
+	blockchain             blockchain.Plugin  // optional
 	multiparty             multiparty.Manager // optional
 	namespace              string
 	defaultKey             string
@@ -69,7 +69,7 @@ type identityManager struct {
 }
 
 func NewIdentityManager(ctx context.Context, ns, defaultKey string, di database.Plugin, bi blockchain.Plugin, mp multiparty.Manager) (Manager, error) {
-	if di == nil || bi == nil {
+	if di == nil {
 		return nil, i18n.NewError(ctx, coremsgs.MsgInitializationNilDepError, "IdentityManager")
 	}
 	im := &identityManager{
@@ -106,6 +106,14 @@ func ParseKeyNormalizationConfig(strConfigVal string) int {
 // 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) {
 	if inputKey == "" {
+		if im.blockchain == nil {
+			if im.defaultKey == "" {
+				return "", i18n.NewError(ctx, coremsgs.MsgNodeMissingBlockchainKey)
+			}
+
+			return im.defaultKey, nil
+		}
+
 		verifierRef, err := im.getDefaultVerifier(ctx)
 		if err != nil {
 			return "", err
@@ -130,6 +138,10 @@ func (im *identityManager) NormalizeSigningKey(ctx context.Context, inputKey str
 func (im *identityManager) ResolveInputSigningIdentity(ctx context.Context, signerRef *core.SignerRef) (err error) {
 	log.L(ctx).Debugf("Resolving identity input: key='%s' author='%s'", signerRef.Key, signerRef.Author)
 
+	if im.blockchain == nil {
+		return i18n.NewError(ctx, coremsgs.MsgBlockchainNotConfigured)
+	}
+
 	var verifier *core.VerifierRef
 	switch {
 	case signerRef.Author == "" && signerRef.Key == "":
@@ -259,6 +271,11 @@ func (im *identityManager) normalizeKeyViaBlockchainPlugin(ctx context.Context,
 	if inputKey == "" {
 		return nil, i18n.NewError(ctx, coremsgs.MsgBlockchainKeyNotSet)
 	}
+
+	if im.blockchain == nil {
+		return nil, i18n.NewError(ctx, coremsgs.MsgBlockchainNotConfigured)
+	}
+
 	if cached := im.signingKeyCache.Get(inputKey); cached != nil {
 		cached.Extend(im.identityCacheTTL)
 		return cached.Value().(*core.VerifierRef), nil
diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go
index 57de36fff..a557d2441 100644
--- a/internal/orchestrator/orchestrator.go
+++ b/internal/orchestrator/orchestrator.go
@@ -458,10 +458,12 @@ func (or *orchestrator) initManagers(ctx context.Context) (err error) {
 		}
 	}
 
-	if or.contracts == nil {
-		or.contracts, err = contracts.NewContractManager(ctx, or.namespace, or.database(), or.blockchain(), or.identity, or.operations, or.txHelper, or.syncasync)
-		if err != nil {
-			return err
+	if or.blockchain() != nil {
+		if or.contracts == nil {
+			or.contracts, err = contracts.NewContractManager(ctx, or.namespace, or.database(), or.blockchain(), or.identity, or.operations, or.txHelper, or.syncasync)
+			if err != nil {
+				return err
+			}
 		}
 	}
 


Test patch:
diff --git a/internal/apiserver/route_get_contract_interface_test.go b/internal/apiserver/route_get_contract_interface_test.go
index 7d4b60e6e..a69f0a032 100644
--- a/internal/apiserver/route_get_contract_interface_test.go
+++ b/internal/apiserver/route_get_contract_interface_test.go
@@ -32,6 +32,7 @@ import (
 func TestGetContractInterfaceBadID(t *testing.T) {
 	o, r := newTestAPIServer()
 	o.On("Authorize", mock.Anything, mock.Anything).Return(nil)
+	o.On("Contracts").Return(&contractmocks.Manager{})
 	input := core.Datatype{}
 	var buf bytes.Buffer
 	json.NewEncoder(&buf).Encode(&input)
diff --git a/internal/apiserver/route_post_new_contract_api_test.go b/internal/apiserver/route_post_new_contract_api_test.go
index ec8ba24f1..97c668e6c 100644
--- a/internal/apiserver/route_post_new_contract_api_test.go
+++ b/internal/apiserver/route_post_new_contract_api_test.go
@@ -22,6 +22,7 @@ import (
 	"net/http/httptest"
 	"testing"
 
+	"github.com/hyperledger/firefly/mocks/contractmocks"
 	"github.com/hyperledger/firefly/mocks/definitionsmocks"
 	"github.com/hyperledger/firefly/pkg/core"
 	"github.com/stretchr/testify/assert"
@@ -32,6 +33,7 @@ func TestPostNewContractAPI(t *testing.T) {
 	o, r := newTestAPIServer()
 	o.On("Authorize", mock.Anything, mock.Anything).Return(nil)
 	mds := &definitionsmocks.Sender{}
+	o.On("Contracts").Return(&contractmocks.Manager{})
 	o.On("DefinitionSender").Return(mds)
 	input := core.Datatype{}
 	var buf bytes.Buffer
@@ -50,6 +52,7 @@ func TestPostNewContractAPISync(t *testing.T) {
 	o, r := newTestAPIServer()
 	o.On("Authorize", mock.Anything, mock.Anything).Return(nil)
 	mds := &definitionsmocks.Sender{}
+	o.On("Contracts").Return(&contractmocks.Manager{})
 	o.On("DefinitionSender").Return(mds)
 	input := core.Datatype{}
 	var buf bytes.Buffer
diff --git a/internal/apiserver/route_post_new_contract_interface_test.go b/internal/apiserver/route_post_new_contract_interface_test.go
index b46ceb57e..34b479460 100644
--- a/internal/apiserver/route_post_new_contract_interface_test.go
+++ b/internal/apiserver/route_post_new_contract_interface_test.go
@@ -22,6 +22,7 @@ import (
 	"net/http/httptest"
 	"testing"
 
+	"github.com/hyperledger/firefly/mocks/contractmocks"
 	"github.com/hyperledger/firefly/mocks/definitionsmocks"
 	"github.com/hyperledger/firefly/pkg/core"
 	"github.com/stretchr/testify/assert"
@@ -32,6 +33,7 @@ func TestPostNewContractInterface(t *testing.T) {
 	o, r := newTestAPIServer()
 	o.On("Authorize", mock.Anything, mock.Anything).Return(nil)
 	mds := &definitionsmocks.Sender{}
+	o.On("Contracts").Return(&contractmocks.Manager{})
 	o.On("DefinitionSender").Return(mds)
 	input := core.Datatype{}
 	var buf bytes.Buffer
@@ -50,6 +52,7 @@ func TestPostNewContractInterfaceSync(t *testing.T) {
 	o, r := newTestAPIServer()
 	o.On("Authorize", mock.Anything, mock.Anything).Return(nil)
 	mds := &definitionsmocks.Sender{}
+	o.On("Contracts").Return(&contractmocks.Manager{})
 	o.On("DefinitionSender").Return(mds)
 	input := core.Datatype{}
 	var buf bytes.Buffer
diff --git a/internal/apiserver/route_put_contract_api_test.go b/internal/apiserver/route_put_contract_api_test.go
index 021a1738d..eb6369c03 100644
--- a/internal/apiserver/route_put_contract_api_test.go
+++ b/internal/apiserver/route_put_contract_api_test.go
@@ -22,6 +22,7 @@ import (
 	"net/http/httptest"
 	"testing"
 
+	"github.com/hyperledger/firefly/mocks/contractmocks"
 	"github.com/hyperledger/firefly/mocks/definitionsmocks"
 	"github.com/hyperledger/firefly/pkg/core"
 	"github.com/stretchr/testify/assert"
@@ -33,6 +34,7 @@ func TestPutContractAPI(t *testing.T) {
 	o.On("Authorize", mock.Anything, mock.Anything).Return(nil)
 	mds := &definitionsmocks.Sender{}
 	o.On("DefinitionSender").Return(mds)
+	o.On("Contracts").Return(&contractmocks.Manager{})
 	input := core.Datatype{}
 	var buf bytes.Buffer
 	json.NewEncoder(&buf).Encode(&input)
@@ -51,6 +53,7 @@ func TestPutContractAPISync(t *testing.T) {
 	o.On("Authorize", mock.Anything, mock.Anything).Return(nil)
 	mds := &definitionsmocks.Sender{}
 	o.On("DefinitionSender").Return(mds)
+	o.On("Contracts").Return(&contractmocks.Manager{})
 	input := core.Datatype{}
 	var buf bytes.Buffer
 	json.NewEncoder(&buf).Encode(&input)
diff --git a/internal/identity/identitymanager_test.go b/internal/identity/identitymanager_test.go
index 91023fd7c..dfa08f612 100644
--- a/internal/identity/identitymanager_test.go
+++ b/internal/identity/identitymanager_test.go
@@ -112,6 +112,17 @@ func TestResolveInputSigningIdentityOrgFallbackOk(t *testing.T) {
 
 }
 
+func TestResolveInputSigningIdentityMissingBlockchain(t *testing.T) {
+	ctx, im := newTestIdentityManager(t)
+	im.blockchain = nil
+
+	msgIdentity := &core.SignerRef{
+		Key: "mykey123",
+	}
+	err := im.ResolveInputSigningIdentity(ctx, msgIdentity)
+	assert.Regexp(t, "FF10417", err)
+}
+
 func TestResolveInputSigningIdentityByKeyOk(t *testing.T) {
 
 	ctx, im := newTestIdentityManager(t)
@@ -440,20 +451,54 @@ func TestResolveInputSigningIdentityByOrgVerifierFail(t *testing.T) {
 }
 
 func TestNormalizeSigningKeyDefault(t *testing.T) {
-
 	ctx, im := newTestIdentityManager(t)
+	im.blockchain = nil
 
 	im.defaultKey = "key123"
 
-	mbi := im.blockchain.(*blockchainmocks.Plugin)
-	mbi.On("NormalizeSigningKey", ctx, "key123").Return("fullkey123", nil)
-
 	resolvedKey, err := im.NormalizeSigningKey(ctx, "", KeyNormalizationBlockchainPlugin)
 	assert.NoError(t, err)
-	assert.Equal(t, "fullkey123", resolvedKey)
+	assert.Equal(t, "key123", resolvedKey)
+}
 
-	mbi.AssertExpectations(t)
+func TestGetDefaultVerifierNoBlockchain(t *testing.T) {
+	ctx, im := newTestIdentityManager(t)
+	im.blockchain = nil
+	im.defaultKey = "test"
 
+	verifier, err := im.getDefaultVerifier(ctx)
+	assert.Regexp(t, "FF10417", err)
+	assert.Nil(t, verifier)
+}
+
+func TestNormalizeSigningKeyNoDefaultNoBlockchain(t *testing.T) {
+	ctx, im := newTestIdentityManager(t)
+	im.blockchain = nil
+
+	resolvedKey, err := im.NormalizeSigningKey(ctx, "", KeyNormalizationBlockchainPlugin)
+	assert.Regexp(t, "FF10354", err)
+	assert.Equal(t, "", resolvedKey)
+
+}
+
+func TestNormalizeSigningKeyDefaultNoBlockchainInputFallback(t *testing.T) {
+	ctx, im := newTestIdentityManager(t)
+	im.blockchain = nil
+	im.defaultKey = "key123"
+
+	resolvedKey, err := im.NormalizeSigningKey(ctx, "testKey", KeyNormalizationBlockchainPlugin)
+	assert.Regexp(t, "FF10417", err)
+	assert.Equal(t, "", resolvedKey)
+}
+
+func TestNormalizeSigningKeyDefaultNoBlockchainDefaultKeyFallback(t *testing.T) {
+	ctx, im := newTestIdentityManager(t)
+	im.blockchain = nil
+	im.defaultKey = "key123"
+
+	resolvedKey, err := im.NormalizeSigningKey(ctx, "", KeyNormalizationBlockchainPlugin)
+	assert.NoError(t, err)
+	assert.Equal(t, "key123", resolvedKey)
 }
 
 func TestNormalizeSigningKeyOrgFallbackOk(t *testing.T) {
@@ -663,6 +708,16 @@ func TestNormalizeKeyViaBlockchainPluginEmptyRequest(t *testing.T) {
 
 }
 
+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)