diff --git a/docs-cactus/architecture/component-diagram.puml b/docs-cactus/architecture/component-diagram.puml deleted file mode 100644 index 092d14b972..0000000000 --- a/docs-cactus/architecture/component-diagram.puml +++ /dev/null @@ -1,67 +0,0 @@ -@startuml Sequence Diagram - Transaction - -title Hyperledger Cactus\nSequence Diagram - Transaction - -left to right direction - -frame "Hyperledger Cactus" as 1cactus { - package "Core" as 2core <> #LightSlateGray { - interface "IStoragePlugin" as 3istorageplugin <> { - } - interface "Connector" as 3connector <> { - } - interface "LedgerResolver" as 3ledgerresolver <> { - } - interface "IdentityPlugin" as 3identityplugin <> { - } - } - - package "Persistence" as 2persistence <> #LightGreen { - class "TransactionLogger" as 3transactionlogger <> { - } - } - - package "Validator" as 2validator <> { - class "ValidatorNode" as 3validatornode <> { - } - } - - frame Connectors { - package "ConnectorFabric" as 2connectorfabric <> { - ConnectorFabric ..> 3connector : <> - } - - package "ConnectorCorda" as 2connectorcorda <> { - ConnectorCorda ..> 3connector : <> - } - - package "ConnectorBesu" as 2connectorbesu <> { - ConnectorBesu ..> 3connector : <> - } - } - - package "API Server" as 2apiserver <> #LightCyan { - class "RequestValidator" as 3requestvalidator <> { - } - class "ExchangeProposal" as 3exchangeproposal <> { - } - } - - package "StoragePluginFabric" as 2storagepluginfabric <> #LightPink { - StoragePluginFabric ..> 3istorageplugin : <> - } - - frame "Identity" { - package "IdentityPluginIndy" as 2identitypluginindy <> #LightPink { - IdentityPluginIndy ..> 3identityplugin: <> - } - package "IdentityPluginWeb" as 2identitypluginweb <> #LightPink { - IdentityPluginWeb ..> 3identityplugin: <> - } - package "IdentityPluginOAuth" as 2identitypluginoauth <> #LightPink { - IdentityPluginOAuth ..> 3identityplugin: <> - } - } -} - -@enduml diff --git a/docs-cactus/source/packages.rst b/docs-cactus/source/packages.rst deleted file mode 100644 index f734d14254..0000000000 --- a/docs-cactus/source/packages.rst +++ /dev/null @@ -1,29 +0,0 @@ -Cactus Components ------------------ - -This section contains the components to form Hyperledger Cactus. - -.. toctree:: - :maxdepth: 1 - - Busines Logic - Api Client - CMD Api Server - Cactus Cockpit - Cactus Common - Cactus Core - Core Api - Consortium Manual - Keychain Memory - Keychain Vault - Connector Besu - Connector Corda - Connector Fabric - Test Api Client - Test CMD Api Server - Test Consortium Manual - Test Connector Besu - Test Tooling - Config - Ledger Plugin - Routing Interface diff --git a/docs-cactus/source/support.rst b/docs-cactus/source/support.rst deleted file mode 100644 index 8e8b3d7ee7..0000000000 --- a/docs-cactus/source/support.rst +++ /dev/null @@ -1,15 +0,0 @@ -Ledger Support for Connectors ------------------------------ - -This section contains the ledger supported versions for connectors in Hyperledger Cactus. - -.. toctree:: - :maxdepth: 1 - - Besu - Corda - Fabric - Iroha - xDai - Substrate - diff --git a/docs-cactus/source/support/fabric.md b/docs-cactus/source/support/fabric.md deleted file mode 100644 index f85bd4d766..0000000000 --- a/docs-cactus/source/support/fabric.md +++ /dev/null @@ -1,62 +0,0 @@ -Fabric Support ------------------ - -```{note} -The deployContract feature is for development and test case authoring only, not recommended to be used in production environments for managing smart contracts. -``` -
- Hyperledger Cactus v0.9.0 - - | Fabric version | deployContract* | invokeContract | runTransaction | - | --- | :---: | :---: | :---: | - | Fabric 2.2.0 | ✅ [test]() | ✅ [test]() | ✅ [test]() | - -
- -
- Hyperledger Cactus v0.8.0 - - | Fabric version | deployContract* | invokeContract | runTransaction | - | --- | :---: | :---: | :---: | - | Fabric 2.2.0 | ✅ [test](https://github.com/hyperledger/cactus/blob/v0.8.0/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/deploy-cc-from-javascript-source.test.ts) | ✅ [test](https://github.com/hyperledger/cactus/blob/v0.8.0/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts) | ✅ [test](https://github.com/hyperledger/cactus/blob/v0.8.0/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts) | - -
- -
- Hyperledger Cactus v0.7.0 - - | Fabric version | deployContract* | invokeContract | runTransaction | - | --- | :---: | :---: | :---: | - | Fabric 2.2.0 | ✅ [test](https://github.com/hyperledger/cactus/blob/v0.7.0/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/deploy-cc-from-javascript-source.test.ts) | ✅ [test](https://github.com/hyperledger/cactus/blob/v0.7.0/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts) | ✅ [test](https://github.com/hyperledger/cactus/blob/v0.7.0/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts) | - -
- -
- Hyperledger Cactus v0.6.0 - - | Fabric version | deployContract* | invokeContract | runTransaction | - | --- | :---: | :---: | :---: | - | Fabric 2.2.0 | ✅ [test](https://github.com/hyperledger/cactus/blob/v0.6.0/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/deploy-cc-from-javascript-source.test.ts) | ✅ [test](https://github.com/hyperledger/cactus/blob/v0.6.0/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts) | ✅ [test](https://github.com/hyperledger/cactus/blob/v0.6.0/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts) | - -
- -
- Hyperledger Cactus v0.5.0 - - | Fabric version | deployContract* | invokeContract | runTransaction | - | --- | :---: | :---: | :---: | - | Fabric 2.2.0 | ✅ [test](https://github.com/hyperledger/cactus/blob/v0.5.0/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/deploy-cc-from-javascript-source.test.ts) | ✅ [test](https://github.com/hyperledger/cactus/blob/v0.5.0/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts) | ✅ [test](https://github.com/hyperledger/cactus/blob/v0.5.0/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts) | - -
- -
- Hyperledger Cactus v0.4.1 - - | Fabric version | deployContract* | invokeContract | runTransaction | - | --- | :---: | :---: | :---: | - | Fabric 2.2.0 | ❌ | ✅ [test](https://github.com/hyperledger/cactus/blob/v0.4.1/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts) | ✅ [test](https://github.com/hyperledger/cactus/blob/v0.4.1/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts) | - -
- -
- diff --git a/docs/docs/cactus/support.md b/docs/docs/cactus/support.md index 7e0fb0a35b..7b87201cc4 100644 --- a/docs/docs/cactus/support.md +++ b/docs/docs/cactus/support.md @@ -6,7 +6,6 @@ This section contains the ledger supported versions for connectors in Hyperledge * [Besu](support/besu.md) * [Corda](support/corda.md) * [Fabric](support/fabric.md) -* [Quorum](support/quorum.md) * [xDai](support/xdai.md) * [Substrate](support/substrate.md) diff --git a/docs/docs/cactus/support/xdai.md b/docs/docs/cactus/support/xdai.md index 8f825a8829..04fbed46e8 100644 --- a/docs/docs/cactus/support/xdai.md +++ b/docs/docs/cactus/support/xdai.md @@ -115,6 +115,6 @@ xDai 1.8.27 -[Previous](quorum.md "Quorum Support") [Next](substrate.md "Substrate Support") +[Previous](fabric.md "Fabric Support") [Next](substrate.md "Substrate Support") * * * diff --git a/docs/docs/weaver/getting-started/enabling-weaver-network/corda.md b/docs/docs/weaver/getting-started/enabling-weaver-network/corda.md index 108393ee6a..bd526d71d4 100644 --- a/docs/docs/weaver/getting-started/enabling-weaver-network/corda.md +++ b/docs/docs/weaver/getting-started/enabling-weaver-network/corda.md @@ -121,10 +121,10 @@ repositories { } } dependencies { - implementation(group: 'org.hyperledger.cacti.weaver.sdk.corda', name: 'weaver-sdk-corda', version: "2.0.0-alpha.1") - implementation(group: 'org.hyperledger.cacti.weaver.imodule.corda', name: 'interop-contracts', version: "2.0.0-alpha.1") - implementation(group: 'org.hyperledger.cacti.weaver.imodule.corda', name: 'interop-workflows', version: "2.0.0-alpha.1") - implementation(group: 'org.hyperledger.cacti.weaver.protos', name: 'protos-java-kt', version: "2.0.0-alpha.1") + implementation(group: 'org.hyperledger.cacti.weaver.sdk.corda', name: 'weaver-sdk-corda', version: "2.0.0-rc.2") + implementation(group: 'org.hyperledger.cacti.weaver.imodule.corda', name: 'interop-contracts', version: "2.0.0-rc.2") + implementation(group: 'org.hyperledger.cacti.weaver.imodule.corda', name: 'interop-workflows', version: "2.0.0-rc.2") + implementation(group: 'org.hyperledger.cacti.weaver.protos', name: 'protos-java-kt', version: "2.0.0-rc.2") } ``` (Or check out the [package website](https://github.com/hyperledger/cacti/packages/1856827) and select a different version.) @@ -445,7 +445,7 @@ Weaver provides a [pre-built image](https://github.com/hyperledger/cacti/pkgs/co RELAY_PORT= EXTERNAL_NETWORK= DOCKER_IMAGE_NAME=ghcr.io/hyperledger/cacti-weaver-relay-server - DOCKER_TAG=2.0.0-alpha.1 + DOCKER_TAG=2.0.0-rc.2 ``` - The `PATH_TO_CONFIG` variable should point to the properties file typically named `config.toml` (you can name this whatever you wish). See further below for instructions to write this file. - The `RELAY_NAME` variable specifies a unique name for this relay. It should match what's specified in the `config.toml` (more on that below). @@ -536,7 +536,7 @@ Weaver provides a [pre-built image](https://github.com/hyperledger/cacti/pkgs/co DRIVER_RPC_PASSWORD= EXTERNAL_NETWORK= DOCKER_IMAGE_NAME=ghcr.io/hyperledger/cacti-weaver-driver-corda - DOCKER_TAG=2.0.0-alpha.1 + DOCKER_TAG=2.0.0-rc.2 RELAY_TLS= RELAY_TLSCA_TRUST_STORE= RELAY_TLSCA_TRUST_STORE_PASSWORD= diff --git a/docs/docs/weaver/getting-started/enabling-weaver-network/fabric.md b/docs/docs/weaver/getting-started/enabling-weaver-network/fabric.md index 25bec14ba9..a8ded4578d 100644 --- a/docs/docs/weaver/getting-started/enabling-weaver-network/fabric.md +++ b/docs/docs/weaver/getting-started/enabling-weaver-network/fabric.md @@ -83,8 +83,8 @@ Below, we list the template functions with sample code that you, as a developer, ```go require( ... - github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1 - github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/assetexchange/v2 v2.0.0-alpha.1 + github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-rc.2 + github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/assetexchange/v2 v2.0.0-rc.2 ... ) ``` @@ -176,8 +176,8 @@ Below, we list the template functions with sample code that you, as a developer, ```go require( ... - github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1 - github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha.1 + github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-rc.2 + github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-rc.2 ... ) ``` @@ -327,7 +327,7 @@ Consider a scenario inspired by the [global trade use case](../../user-stories/g (In preparation, a suitable access control policy must be recorded on `tradelogisticschannel` in `trade-logistics-network`, and a suitable verification policy must be recorded on `tradefinancechannel` in `trade-finance-network`. We will see how to do this in the "Startup and Boostrap" section later.) -You will need to insert some code in the Layer-2 application that accepts a B/L and submits a `RecordBillOfLading` transaction in `trade-finance-network`. (No code changes need to be made in any application in the other network.) The logic to accept a B/L should be replaced (or you can simply add an alternative) by a call to the `interopFlow` function offered by the [cacti-weaver-sdk-fabric](https://github.com/hyperledger/cacti/pkgs/npm/cacti-weaver-sdk-fabric) library (there's an [equivalent library in Golang](https://github.com/hyperledger/cacti/releases/tag/weaver%2Fsdks%2Ffabric%2Fgo-sdk%2Fv2.0.0-alpha.1) too). The following code sample illustrates this (the Golang equivalent is left to the reader): +You will need to insert some code in the Layer-2 application that accepts a B/L and submits a `RecordBillOfLading` transaction in `trade-finance-network`. (No code changes need to be made in any application in the other network.) The logic to accept a B/L should be replaced (or you can simply add an alternative) by a call to the `interopFlow` function offered by the [cacti-weaver-sdk-fabric](https://github.com/hyperledger/cacti/pkgs/npm/cacti-weaver-sdk-fabric) library (there's an [equivalent library in Golang](https://github.com/hyperledger/cacti/releases/tag/weaver%2Fsdks%2Ffabric%2Fgo-sdk%2Fv2.0.0-rc.2) too). The following code sample illustrates this (the Golang equivalent is left to the reader): ```js const ihelper = require('@hyperledger/cacti-weaver-sdk-fabric').InteroperableHelper; const interopcc = ; // Use Fabric SDK functions: (new Gateway()).getNetwork(...).getContract() @@ -536,7 +536,7 @@ Weaver provides a [pre-built image](https://github.com/hyperledger/cacti/pkgs/co RELAY_PORT= EXTERNAL_NETWORK= DOCKER_IMAGE_NAME=ghcr.io/hyperledger/cacti-weaver-relay-server - DOCKER_TAG=2.0.0-alpha.1 + DOCKER_TAG=2.0.0-rc.2 ``` - The `PATH_TO_CONFIG` variable should point to the properties file typically named `config.toml` (you can name this whatever you wish). See further below for instructions to write this file. - The `RELAY_NAME` variable specifies a unique name for this relay. It should match what's specified in the `config.toml` (more on that below). @@ -630,7 +630,7 @@ Weaver provides a [pre-built image](https://github.com/hyperledger/cacti/pkgs/co EXTERNAL_NETWORK= TLS_CREDENTIALS_DIR= DOCKER_IMAGE_NAME=ghcr.io/hyperledger/cacti-weaver-driver-fabric - DOCKER_TAG=2.0.0-alpha.1 + DOCKER_TAG=2.0.0-rc.2 DRIVER_TLS= DRIVER_TLS_CERT_PATH=path_to_tls_cert_pem_for_driver DRIVER_TLS_KEY_PATH=path_to_tls_key_pem_for_driver diff --git a/weaver/core/network/corda-interop-app/build.gradle b/weaver/core/network/corda-interop-app/build.gradle index 69c4b08304..07488310cc 100644 --- a/weaver/core/network/corda-interop-app/build.gradle +++ b/weaver/core/network/corda-interop-app/build.gradle @@ -49,7 +49,7 @@ buildscript { plugins { id 'java' id 'org.jetbrains.dokka' version '0.10.1' - id "com.jfrog.artifactory" version "4.16.1" + id "com.jfrog.artifactory" version "5.2.3" id "maven-publish" } diff --git a/weaver/docs/docs/external/getting-started/enabling-weaver-network/corda.md b/weaver/docs/docs/external/getting-started/enabling-weaver-network/corda.md deleted file mode 100644 index 9c44bfa0f3..0000000000 --- a/weaver/docs/docs/external/getting-started/enabling-weaver-network/corda.md +++ /dev/null @@ -1,626 +0,0 @@ ---- -id: corda -title: Corda ---- - - - -After testing the Weaver interoperation mechanisms on [basic sample networks](../test-network/overview.md), you may be interested in finding out how you can equip an existing real network, whether in development or in production, to exercise these mechanisms. In this document, we will demonstrate how to equip a Corda network and application with Weaver components and capabilities. - -## Model - -The figure below illustrates a typical Corda network. The infrastructure consists of a set of nodes (each maintaining its share of the global state in a local vault), notaries, and CAs. On the nodes are installed one or more CorDapps, representing shared business logic across subsets of those nodes. The core of a CorDapp consists of a collection of workflows (or flows) and contracts acting on states; we layer the flows above the contracts in thebelow image just to illustrate that flows represent transaction (state update) triggers, and contract validations occur during the executions of flows. Further up in the stack lie client applications associated with CorDapps that can are used to trigger flows (and by implication, contracts). - -![alt text](../../../../static/enabling-weaver/corda-network-model.png) - -Such a network equipped with Weaver components and capabilities will look like the figure below. Legacy components are marked in grey and Weaver and bridging components in green. - -![alt text](../../../../static/enabling-weaver/corda-weaver-model.png) - -The relay and driver are the only additional infrastructure that need to be installed. One or more relays can be installed, as can one or more drivers. The drivers are illustrated in the client layer rather than in the bottom layer because, though they are coupled with relays, they trigger flows just like any client application does. - -Existing CorDapp flows and contracts deployed on the network's nodes remain undisturbed. All that is required is the deployment of an Interoperation CorDapp (flows and contracts) on every node that needs to offer or consume state from foreign networks. - -Client applications will need some additional code and configuration because the decisions to exercise interoperation mechanisms (relay queries for data sharing or atomic asset exchanges) are strictly part of business logic. But Weaver's Corda Interoperation Java-Kotlin SDK offers various helper functions to ease this process and keep the adaptation to a minimum, as we wil see later in this document. Finally, an _identity service_ must be offered by the network to expose its CAs' certificate chains to foreign networks, thereby laying the basis for interoperation. This service simply needs to offer a REST endpoint, and can be implemented as a standalone application or (more conveniently) as an augmentation of one or more of the existing client layer applications. - -## Procedural Overview - -A Corda network is typically created in phases, in the following sequence: -1. **Development**: This involves writing CorDapp which consists of contracts and workflows, and client layer applications. The cordapp's deployment name/ID and its transaction API must be designed first, but subsequent development of the two layers of applications can then proceed parallelly. -2. **Pre-Configuration**: This involves creating a desired specification (as a set of configuration diles) of the network topology and the ledgers it maintains. -3. **Startup and Bootstrap**: This is the launch phase, in which the network components and applications are started and bootstrapped (i.e., configured with initial state and operating rules). - -Assuming that the reader is familiar with this procedure, we will walk through the changes required in each phase to make your network ready for interoperation using Weaver components and code templates. This will involve code addition and adaptation, deployment of additional modules, additional configuration, and creation of additional ledger state records. The requirements and effort will vary with the mode of interoperation you wish to support in your Fabric network. - -## Development Phase - -A Corda distributed application's business logic code spans three layers as illustrated in the network model: - -### CorDapp - -CorDapps (Corda Distributed Applications) are distributed applications that run on the Corda platform. The goal of a CorDapp is to allow nodes to reach agreement on updates to the ledger. They achieve this goal by defining flows that Corda node owners can invoke over RPC. - -#### For Data Sharing - -No code changes are required for Weaver enablement, because data sharing involves: -- View packaging (and optionally, encryption) logic and access control logic in a source network, and -- View validation logic in a destination network - -This logic is standard and independent of contract, workflow, and state, particulars. It is already implemented in the Interoperation CorDapp offered by Weaver. Hence you just need to deploy that CorDapp to exercise data sharing from, or to, your application CorDapp. Your application CorDapp can be oblivious of the Interoperation CorDapp's workings and of the view request-response protocol. - -#### For Asset Exchange - -To exchange an asset using Weaver, the asset's state on the ledger must be controlled in the following ways: -- Locked in favor of a party -- Claimed by the party to whom the asset is pledged -- Returned to the original owner if it is not claimed within a given timeframe - -In addition, the state of the asset (i.e., whether it is locked), and its current and targeted owners, must be determinable by looking at the ledger records. - -The bookkeeping logic required to maintain records of locks can be abstracted away from the particulars of a digital asset and its workflow. But as such assets and their properties (including ownership) can be, and are, encoded in an arbitrary number of ways, we cannot provide a one-size-fits all set of functions (like in the data sharing protocol) to exchange any kind of asset. Instead, we must rely on the application CorDapp managing an asset, as it knows precisely what the asset's properties are and how they can be updated and queried on the ledger. - -What Weaver offers, therefore, is the following: -- Lock management logic implemented in the Interoperation CorDapp that treats each asset as an abstract object (an instance of generic corda's `ContractState`) and is agnostic of the assets' internals. It consumes (burns) the asset state and creates a new `HTLC` state that indicates that the asset is locked, while in claim and unlock new asset state is created (minted) with appropriate owner while consuming `HTLC` state. This logic can be exercised in by installing Interoperation CorDapp on the nodes. -- A set of template functions with sample (and extensible) code that must be added to the application CorDapp to augment the above lock management functions. - -Below, we list the template functions with sample code that you, as a developer, must use and adapt within your CorDapp. - -- **Flow to get Asset State**: For non-fungible assets, create a flow like: - ```kotlin - class RetrieveStateAndRef( - val type: String, - val id: String - ): FlowLogic> - ``` - And for fungible assets, create a flow like: - ```kotlin - class RetrieveStateAndRef( - val type: String, - val quantity: Long - ): FlowLogic> - ``` - The name of these flows can be anything, but the parameters should be same, and return type should `StateAndRef`. These flows are supposed to get the `StateAndRef` object to the asset state that has to be locked, which can be identified by `type` and `id` for non-fungible assets, and `type` and `quantity` for fungible assets. -- **Flow to update owner in asset state**: Create a flow like: - ```kotlin - class UpdateOwnerFromPointer( - val statePointer: StaticPointer - ) : FlowLogic() - ``` - Again the name can be anything but the function parameter should be same, i.e. take a `StaticPointer` and return the `ContractState` of the asset involved in asset exchange. This flow is supposed to resolve the `StaticPointer` to actual asset, and update the owner of this asset to the caller of this flow. - -#### For Asset Transfer - -_TBD_ - -### Contracts CorDapp - -No code changes are required for Weaver enablement. For asset exchange, Weaver assumes that application CorDapp that manages assets must already have a asset creation (mint) contract command and asset deletion (burn) contract command, which can be invoked when `Issuer` party is involved in the transaction. - -## Client Layer applications - -Weaver provides an SDK to help you adapt your applications to exercise the various interoperability modes. These are called out as **SDK Helpers** in the network model illustrated earlier. Your Corda network's Client layer applications have business logic embedded in them that, broadly speaking, accept data from users and other external agents and invoke workflows from CorDapp over RPC. When you use Weaver for network interoperability, other options can be added, namely requesting and accepting data from foreign networks, and triggering locks and claims for atomic exchanges spanning two networks. Weaver's Corda Interoperation SDK offers a library to exercise these options. But this will involve modification to the application's business logic. -To use Weaver's Corda SDK, you need to create a [personal access token](https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token) with `read:packages` access in GitHub, to access Weaver packages. -You also need to add the following to your application's `build.gradle` file: -```groovy -repositories { - maven { - url https://maven.pkg.github.com/hyperledger/cacti - credentials { - username - password - } - } -} -dependencies { - implementation(group: 'org.hyperledger.cacti.weaver.sdk.corda', name: 'weaver-sdk-corda', version: "2.0.0-rc.2") - implementation(group: 'org.hyperledger.cacti.weaver.imodule.corda', name: 'interop-contracts', version: "2.0.0-rc.2") - implementation(group: 'org.hyperledger.cacti.weaver.imodule.corda', name: 'interop-workflows', version: "2.0.0-rc.2") - implementation(group: 'org.hyperledger.cacti.weaver.protos', name: 'protos-java-kt', version: "2.0.0-rc.2") -} -``` -(Or check out the [package website](https://github.com/hyperledger/cacti/packages/1856827) and select a different version.) - -#### For Identity Administration - -A Corda network needs to share its security domain (or membership) configuration, i.e., its nodes' CA certificate chains, with a foreign network with which it seeks to interoperate. Though such sharing can be implemented using several different mechanisms, ranging from manual to automated, the simplest and most modular way is to expose a REST endpoint that agents in foreign networks can reach. Further, this REST endpoint can be implemented as a standalone web application or it can be an extension of one or more of the existing client layer applications. (Multiple apps can expose the same endpoint serving the same information for redundancy.) We will demonstrate an example of this while leaving other implementation modes to the user. -Let's say a Corda network consists of two nodes called `PartyA` and `PartyB`, each running a client layer application with a web server whose URL prefixes are `http://partya.mynetwork.com:9000` and `http://partyb.mynetwork.com:9000` respectively. Each app then can expose a REST endpoint (again, as an example) `http://partya.mynetwork.com:9000/node_sec_grp` and `http://partyb.mynetwork.com:9000/node_sec_grp` respectively. -At each web server's backend, you need to implement logic to retrieve the node's ID and it's associated certificated chains. Sample code is given below for a Kotlin implementation built on `weaver-sdk-corda`. You can use this code verbatim, except for some minor changes like ``, other parameters like security domain, and list of names of nodes as appropriate for your environment: - -```kotlin -import org.hyperledger.cacti.weaver.sdk.corda.CredentialsCreator -import com.google.protobuf.util.JsonFormat - - -@RestController -@CrossOrigin -@RequestMapping("/") // The paths for HTTP requests are relative to this base path. -class Controller { - // Expose "node_sec_grp" endpoint using Rest Controller - @RequestMapping(value = ["/node_sec_grp"], method = arrayOf(RequestMethod.GET), produces = arrayOf("application/json")) - private fun GetNetworkConfig(): String { - val jsonPrinter = JsonFormat.printer().includingDefaultValueFields() - - val credentialsCreator = CredentialsCreator( - "/build/nodes", - "mynetwork", // security domain name - ["PartyA", "PartyB"], // list of nodes - "", - "" - ) - - // Generate Membership - val membership = credentialsCreator.createMembership() - return jsonPrinter.print(membership) - } -} -``` -An agent from a foreign network can query either `http://partya.mynetwork.com:9000/sec_group` or `http://partyb.mynetwork.com:9000/sec_group` and obtain the security domain (or membership) configuration of the entire network. - -#### For Data Sharing - -Consider a scenario inspired by the [global trade use case](../../user-stories/global-trade.md) where a letter of credit (L/C) management business logic is installed in the `trade-finance-network` network, supports a flow named `UploadBillOfLading`, which validates and records a bill of lading (B/L) supplied by a user via a UI. Weaver will enable such a B/L to be fetched from a different network `trade-logistics-network` by querying the function `GetBillOfLading` exposed by the chaincode `shipmentcc` installed in the `tradelogisticschannel` channel (_The trade logistics network can be built on Corda as well. The steps for Weaver-enablement will mostly be the same, with the exception of view address creation logic. Here, for demonstration purposes, we assume that that counter-party network is built on Fabric_). - -(In preparation, a suitable access control policy must be recorded on `tradelogisticschannel` in `trade-logistics-network`, and a suitable verification policy must be recorded in the vault of `trade-finance-network`. We will see how to do this in the [Startup and Bootstrap Weaver Components](#startup-and-bootstrap-weaver-components) section later.) - -You will need to insert some code in the client layer application that accepts a B/L and submits a `UploadBillOfLading` request in `trade-finance-network`. (No code changes need to be made in any application in the other network.) The logic to accept a B/L should be replaced (or you can simply add an alternative) by a call to the `InteroperableHelper.interopFlow` function offered by the [cacti-weaver-sdk-corda](https://github.com/hyperledger/cacti/packages/1856827) library. The following code sample illustrates this: - -```kt -import org.hyperledger.cacti.weaver.sdk.corda.InteroperableHelper -import com.mynetwork.flow.UploadBillOfLading - -val viewAddress = InteroperableHelper.createFabricViewAddress( - 'trade-logistics-network', // Security Domain/Group - ], // Replace with remote network's relay - 'tradelogisticschannel', // Remote network's channel - 'shipmentcc', // Remote network's cc - 'GetBillOfLading', // Remote network's cc Fun - [ ] // Replace with a value that can be used to look up the right B/L -) -try { - val response = InteroperableHelper.interopFlow( - proxy, // CordaRPCOps instance to start flows - viewAddress, - [:] // Replace with local network's relay address and port - ).fold({ - println("Error in Interop Flow: ${it.message}") - }, { - val linearId = it.toString() - val BoLString = InteroperableHelper.getExternalStatePayloadString( - proxy, - linearId - ) - val result = proxy.startFlow(::UploadBillOfLading, BoLString) - println("$result") - } -} catch (e: Exception) { - println("Error: ${e.toString()}") -} -``` - -Let us understand this code snippet better. The function `UploadBillOfLading` expects one argument, the bill of lading contents. The `InteroperableHelper.createFabricViewAddress` is used to create view address that is to passed to `InteroperableHelper.interopFlow` function. The equivalent function to create a view address for a remote Corda network is `InteroperableHelper.createCordaViewAddress`. - -The rest of the code ought to be self-explanatory. Values are hardcoded for explanation purposes. - -**Enabling TLS**: -By default, the TLS is set to false in `interopFlow`, i.e. disabled. But if you want to enable TLS, can pass additional parameters to the `interopFlow` function as follows: -```kt -val response = InteroperableHelper.interopFlow( - proxy, // CordaRPCOps instance to start flows - viewAddress, - [:], // Replace with local network's relay address and port - 'trade-finance-network', // Local network name (destination) - true, // Boolean indication TLS is enabled. - // JKS file path containing relay server TLS CA certificates - , // password used to create the JKS file -) -``` -OR -```kt -val response = InteroperableHelper.interopFlow( - proxy, // CordaRPCOps instance to start flows - viewAddress, - [:], // Replace with local network's relay address and port - 'trade-finance-network', // Local network name (destination) - true, // Boolean indication TLS is enabled. - , // colon-separated list of CA certificate file paths -) -``` - -#### For Asset exchange - -Let's take an example of asset exchange between `Alice` and `Bob`, where Bob wants to purchase an asset of type `Gold` with id `A123` from `Alice` in `BondNetwork` in exchange for `200` tokens of type `CBDC01` in `TokenNetwork`. - -`Alice` needs to select a secret text (say `s`), and hash it (say `H`) using say `SHA512`, which will be used to lock her asset in `BondNetwork`. To lock the non-fungible asset using hash `H` and timeout duration of 10 minutes, you need to add following code snippet in your application: -```kotlin -import org.hyperledger.cacti.weaver.sdk.corda.AssetManager -import org.hyperledger.cacti.weaver.sdk.corda.HashFunctions - -var hash: HashFunctions.Hash = HashFunctions.SHA512 -hash.setSerializedHashBase64(H) -val proxy = -val issuer = -val recipient = -val contractId = AssetManager.createHTLC( - proxy, - "Gold", // Type - "A123", // ID - recipient, - hash, - 10L, // Duration tmeout in secs, L denotes Long - 1, // 1 if timeout is Duration, 0 if timeout is in absolute epochs - "com.cordaSimpleApplication.flow.RetrieveStateAndRef", // full name of "Flow to get Asset State" - AssetContract.Commands.Delete(), // Contract command for Asset to Burn/Delete the state - issuer, - observers // Optional parameter for list of observers for this transaction -) -``` - -Now `Bob` will lock his tokens in `TokenNetwork`. To lock the fungible asset using same hash `H` and timeout of 5 minutes (half the timeout duration used by Alice in `BondNetwork`), add following code snippet in your application: -```kotlin -import org.hyperledger.cacti.weaver.sdk.corda.AssetManager -import org.hyperledger.cacti.weaver.sdk.corda.HashFunctions - -var hash: HashFunctions.Hash = HashFunctions.SHA512 -hash.setSerializedHashBase64(H) -val proxy = -val issuer = -val recipient = -val contractId = AssetManager.createFungibleHTLC( - proxy, - "CBDC01", // Type - "200", // Quantity - recipient, - hash, - 5L, // Duration timeout in secs, L denotes Long - 1, // 1 if timeout is Duration, 0 if timeout is in absolute epochs - "com.cordaSimpleApplication.flow.RetrieveStateAndRef", // full name of "Flow to get Asset State" - AssetContract.Commands.Delete(), // Contract command for Asset to Burn/Delete the state - issuer, - observers // Optional parameter for list of observers for this transaction -) -``` - -The above locks will return `contractId`, that has to be stored and will be used in other HTLC functions. - -To query whether the assets are locked or not in any network, use following query function: -```kotlin -val isLockedBoolean = AssetManager.isAssetLockedInHTLC( - rpc.proxy, - contractId -) -``` - -Now to claim the asset using the secret text (pre-image of hash) `s`, add following code snippet: -```kotlin -var hash: HashFunctions.Hash = HashFunctions.SHA512() -hash.setPreimage(s) -val issuer = -val proxu = -val res = AssetManager.claimAssetInHTLC( - proxy, - contractId, // ContractId obtained during lock - hash, - AssetContract.Commands.Issue(), // Contract command for issuing/minting asset - "com.cordaSimpleApplication.flow.UpdateAssetOwnerFromPointer", // full name of flow to update owner in asset state - issuer, - observers // Optional parameter for list of observers for this transaction -) -// return value is boolean indicating success or failure of claim -``` -The above function can be adapted to both `BondNetwork` and `TokenNetwork`. - -If the asset has to be unlocked, use following code snippet: -```kotlin -val issuer = -val proxu = -val res = AssetManager.reclaimAssetInHTLC( - rpc.proxy, - contractId, // ContractId obtained during lock - AssetContract.Commands.Issue(), // Contract command for issuing/minting asset - issuer, - observers // Optional parameter for list of observers for this transaction -) -// return value is boolean indicating success or failure of claim -``` - -#### For Asset Transfer - -_TBD_ - -## Pre-Configuration Phase - -No changes are required in your network's pre-configuration process for Weaver enablement. - -Typically, pre-configuration involves: - -* Generating node folders for each participating node in the network, which contains CorDapps, certificates, persistence db, etc sub directories. Using Gradle task `net.corda.plugins.Cordform` or `net.corda.plugins.Dockerform`, the folders get created under the directory `build/nodes` (this path is used in above sample code for Identity Service). - -* The RPC address, username and password specified in above task will be used to create an instance of `CordaRPCOps`, which is the first argument for most `weaver-sdk-corda` static functions as we saw in previous section. For example, one of them is `InteroperableHelper.interopFlow`: -```kotlin -val response = InteroperableHelper.interopFlow( - proxy, // CordaRPCOps instance to start flows - viewAddress, - [:], // Replace with local network's relay address and port -) -``` -Also, the Corda Driver (which we will setup in the following sections) needs a specific RPC user to be created, so make sure to add that in the Gradle task above, and note the credentials. - -* Sample `net.corda.plugins.Dockerform` task: -```groovy -task prepareDockerNodes(type: net.corda.plugins.Dockerform, dependsOn: ['jar']) { - def HOST_ADDRESS = "0.0.0.0" - nodeDefaults { - projectCordapp { - deploy = false - } - } - node { - name "O=Notary,L=London,C=GB" - notary = [validating : true] - p2pPort 10004 - rpcSettings { - address("$HOST_ADDRESS:10003") - adminAddress("$HOST_ADDRESS:10005") - } - cordapps.clear() - } - node { - name "O=PartyA,L=London,C=GB" - p2pPort 10007 - rpcSettings { - address("$HOST_ADDRESS:10003") - adminAddress("$HOST_ADDRESS:10005") - } - rpcUsers = [ - [ user: "user1", "password": "test", "permissions": ["ALL"]], - [ user: "driverUser1", "password": "test", "permissions": ["ALL"]]] // <-- Driver RPC User - } - node { - name "O=PartyB,L=London,C=GB" - p2pPort 10009 - rpcSettings { - address("$HOST_ADDRESS:10003") - adminAddress("$HOST_ADDRESS:10005") - } - rpcUsers = [ - [ user: "user1", "password": "test", "permissions": ["ALL"]], - [ user: "driverUser1", "password": "test", "permissions": ["ALL"]]] // <-- Driver RPC User - } -} -``` - -## Startup and Bootstrap Phase - -To launch a network using containerized components, you will typically use a Docker Compose or Kubernetes configuration file. No modifications are needed to the node's configurations. Sample instructions are given below for networks launched using Docker Compose; we leave it to the reader to adapt these to their custom launch processes. - -### For Asset Exchange - -The asset exchange mode currently requires only the Interoperation CorDapp module from Weaver. Relays and drivers are not necessary. In the future, we expect to make the asset exchange protocol moe automated using these components; the instructions here will be updated appropriately. - -### Install Interoperation CorDapp on Nodes - -After bootstrapping the nodes folder, copy the following two CorDapps in `build/nodes/PartyA/cordapps` and `build/nodes/PartyB/cordapps` folders (`PartyA` and `PartyB` node names are for example only): -- [org.hyperledger.cacti.weaver.imodule.corda.interop-contracts](https://github.com/hyperledger/cacti/packages/1856825) -- [org.hyperledger.cacti.weaver.imodule.corda.interop-workflows](https://github.com/hyperledger/cacti/packages/1856826) - -| Notes | -|:------| -| You can follow any installation process for this CorDapp, but make sure it is installed on all the nodes that maintain the states involved in cross-network operations in their vaults. | - -### For Data Sharing or Asset Transfer - -Both the data sharing and asset transfer modes require the Interoperation CorDapp, relays, and drivers, to be deployed. - -#### Install Interoperation CorDapp on Nodes - -After bootstrapping the nodes folder, copy the following two CorDapps in `build/nodes/PartyA/cordapps` and `build/nodes/PartyB/cordapps` folders (`PartyA` and `PartyB` node names are for example only): -- [org.hyperledger.cacti.weaver.imodule.corda.interop-contracts](https://github.com/hyperledger/cacti/packages/1856825) -- [org.hyperledger.cacti.weaver.imodule.corda.interop-workflows](https://github.com/hyperledger/cacti/packages/1856826) - -| Notes | -|:------| -| You can follow any installation process for this CorDapp, but make sure it is installed on all the nodes that maintain the states involved in cross-network operations in their vaults. | - -#### Launch Relay - -You need to run one or more relays for network-to-network communication. Here we provide instructions to run one relay running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple relays, which will be useful from a failover perspective.) - -Weaver provides a [pre-built image](https://github.com/hyperledger/cacti/pkgs/container/cacti-weaver-relay-server) for the relay. Before launching a container, you just need to customize its configuration for your Fabric network, which you can do by simply creating a folder (let's call it `relay_config`) and configuring the following files in it: -- `.env`: This sets suitable environment variables within the relay container. Copy the `.env.template` file [from the repository](https://github.com/hyperledger/cacti/blob/main/weaver/core/relay/.env.template) and customize it for your purposes, as indicated in the below sample: - ``` - PATH_TO_CONFIG=./config.toml - RELAY_NAME=<"name" in config.toml> - RELAY_PORT= - EXTERNAL_NETWORK= - DOCKER_IMAGE_NAME=ghcr.io/hyperledger/cacti-weaver-relay-server - DOCKER_TAG=2.0.0-rc.2 - ``` - - The `PATH_TO_CONFIG` variable should point to the properties file typically named `config.toml` (you can name this whatever you wish). See further below for instructions to write this file. - - The `RELAY_NAME` variable specifies a unique name for this relay. It should match what's specified in the `config.toml` (more on that below). - - The `RELAY_PORT` variable specifies the port this relay server will listen on. It should match what's specified in the `config.toml` (more on that below). - - The `EXTERNAL_NETWORK` variable should be set to the [name](https://docs.docker.com/compose/networking/) of your Fabric network. - - The `DOCKER_*` variables are used to specify the image on which the container will be built. Make sure you set `DOCKER_TAG` to the latest version you see on [GitHub](https://github.com/hyperledger/cacti/pkgs/container/cacti-weaver-relay-server). - - For more details, see the [Relay Docker README](https://github.com/hyperledger/cacti/blob/main/weaver/core/relay/relay-docker.md) ("Relay Server Image" and "Running With Docker Compose" sections). - -- `config.toml`: This is the file specified in the `PATH_TO_CONFIG` variable in the `.env`. It specifies properties of this relay and the driver(s) it supports. A sample is given below: - ```toml showLineNumbers - name= - port= - host="0.0.0.0" - db_path="db//requests" - remote_db_path="db//remote_request" - - # FOR TLS - cert_path="credentials/fabric_cert.pem" - key_path="credentials/fabric_key" - tls= - - [networks] - [networks.] - network="" - - [relays] - [relays.] - hostname="" - port="" - - [drivers] - [drivers.] - hostname="" - port="" - ``` - - `` should be a unique ID representing this relay; e.g., `my_network_relay`. It should match the `RELAY_NAME` value in `.env`. - - `` is the port number the relay server will listen on. It should match the `RELAY_PORT` value in `.env`. - - `db_path` and `remote_db_path` are used internally by the relay to store data. Replace `` with the same value set for the `name` parameter. (These can point to any filesystem paths in the relay's container.) - - If you set `tls` to `true`, the relay will enforce TLS communication. The `cert_path` and `key_path` should point to a Fabric TLS certificate and key respectively, such as those created using the `cryptogen` tool. - - `` is a unique identifier for your local network. You can set it to whatever value you wish. - - `` refers to the driver used by this relay to respond to requests. This also refers to one of the drivers's specifications in the `drivers` section further below. In this code snippet, we have defined one driver. (The names in lines 14 and 22 must match.) In lines 23 and 24 respectively, you should specify the hostname and port for the driver (whose configuration we will handle later). - - The `relays` section specifies all foreign relays this relay can connect to. The `` value should be a unique ID for a given foreign relay, and this value will be used by your Layer-2 applications when constructing view addresses for data sharing requests. In lines 18 and 19, you should specify the hostname and port for the foreign relay. - - **Enabling TLS**: - - You can make your relay accept TLS connections by specifying a TLS certificate file path and private key file path in `cert_path` and `key_path` respectively, and set `tls` to `true`. - - To communicate with a foreign relay using TLS, specify that relay's TLS CA certificate path in `tlsca_cert_path` (currently only one certificate can be configured) and set `tls` to `true` by extending that relay's section as follows (*Note*: this CA certificate should match the one specified in the `cert_path` property in the foreign relay's `config.toml` file): - ```toml - [relays] - [relays.] - hostname="" - port="" - tls= - tlsca_cert_path="" - ``` - - To communicate with a driver using TLS, specify the driver's TLS CA certificate in `tlsca_cert_path` (currently only one certificate can be configured) and set `tls` to `true` by extending that driver's section as follows (*Note*: this CA certificate must match the certificate used by the driver using the `DRIVER_TLS_CERT_PATH` property in its `.env` configuration file, which we will examine later): - ```toml - [drivers] - [drivers.] - hostname="" - port="" - tls= - tlsca_cert_path="" - ``` - - | Notes | - |:------| - | You can specify more than one foreign relay instance in the `relays` section. | - | You can specify more than one driver instance in the `drivers` section. | - -- `docker-compose.yaml`: This specifies the properties of the relay container. You can use the [file in the repository](https://github.com/hyperledger/cacti/blob/main/weaver/core/relay/docker-compose.yaml) verbatim. - -To start the relay server, navigate to the folder containing the above files and run the following: -```bash -docker-compose up -d relay-server -``` - -#### Launch Driver - -You need to run one or more drivers through which your relay can interact with your Corda network. Here we provide instructions to run one Corda driver running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple drivers, which will be useful both from a failover perspective and to interact with different subsets of your Corda network.) - -Weaver provides a [pre-built image](https://github.com/hyperledger/cacti/pkgs/container/cacti-weaver-driver-corda) for the Corda driver. Before launching a container, you just need to customize the container configuration for your Corda network, which you can do by simply configuring the following: -- `.env`: This sets suitable environment variables within the driver container. Copy the `.env.docker.template` file [from the repository](https://github.com/hyperledger/cacti/blob/main/weaver/core/drivers/corda-driver/.env.docker.template) and customize it for your purposes, as indicated in the below sample: - ``` - NETWORK_NAME= - DRIVER_PORT= - DRIVER_RPC_USERNAME= - DRIVER_RPC_PASSWORD= - EXTERNAL_NETWORK= - DOCKER_IMAGE_NAME=ghcr.io/hyperledger/cacti-weaver-driver-corda - DOCKER_TAG=2.0.0-rc.2 - RELAY_TLS= - RELAY_TLSCA_TRUST_STORE= - RELAY_TLSCA_TRUST_STORE_PASSWORD= - RELAY_TLSCA_CERT_PATHS= - DRIVER_TLS= - DRIVER_TLS_CERT_PATH= - DRIVER_TLS_KEY_PATH= - ``` - - `NETWORK_NAME` is only used as suffix for container and has no other significance. - - `DRIVER_PORT` variable should be set to the port this driver will listen on. - - `DRIVER_RPC_USERNAME` variable should be set to rpc user created [above](#pre-configuration) for the driver. - - `DRIVER_RPC_PASSWORD` variable should be set to password of above rpc user. - - `EXTERNAL_NETWORK` variable should be set to the [name](https://docs.docker.com/compose/networking/) of your Corda network. - - **Enabling TLS**: - - You can make your driver accept TLS connections by specifying `DRIVER_TLS` as `true` and specifying a TLS certificate file path and private key file path in `DRIVER_TLS_CERT_PATH` and `DRIVER_TLS_KEY_PATH` respectively. The same certificate should be specified in this driver's definition in the `drivers` section in the `config.toml` file of your relay in the `tlsca_cert_path` property (see the earlier section on relay configuration). - - To communicate with your network' relay using TLS (i.e., if the relay is TLS-enabled), specify that relay's TLS CA certificate path in `RELAY_TLSCA_CERT_PATH` (currently only one certificate can be configured) and set `RELAY_TLS` to `true`. This CA certificate should match the one specified in the `cert_path` property in the relay's `config.toml` file (see the earlier section on relay configuration): - - You can point to the folder in your host system containing the certificate and key using the `TLS_CREDENTIALS_DIR` variable. (This folder will be synced to the `/corda-driver/credentials` folder in the Fabric Driver container as specified in the [docker-compose file](https://github.com/hyperledger/cacti/blob/main/weaver/core/drivers/fabric-driver/docker-compose.yml).) Make sure you point to the right certificate and key file paths within the container using the `DRIVER_TLS_CERT_PATH`, `DRIVER_TLS_KEY_PATH`, and `RELAY_TLSCA_CERT_PATH` variables. - -- `docker-compose.yaml`: This specifies the properties of the driver container. You can use the [file in the repository](https://github.com/hyperledger/cacti/blob/main/weaver/core/drivers/corda-driver/docker-compose.yml) verbatim. - -To start the driver, navigate to the folder containing the above files and run the following: -```bash -docker-compose up -d -``` - -#### Vault Initialization - -To prepare your network for interoperation with a foreign network, you need to record the following to your vault using the [Corda SDK](https://github.com/hyperledger/cacti/packages/1856827) (`org.hyperledger.cacti.weaver.sdk.corda.weaver-sdk-corda`): -- **Access control policies**: - Let's take the example of the request made from `trade-finance-network` to `trade-logistics-network` for a B/L earlier in this document. `trade-logistics-network` can have a policy of the following form permitting access to the `GetBillOfLading` function from a client representing the `PartyA` node in `trade-finance-network` as follows: - ```json - { - "securityDomain":"trade-finance-network", - "rules": - [ - { - "principal":"", - "principalType":"certificate", - "resource":"exporternode:10003;carriernode:10003#com.mynetwork.flow.GetBillOfLading:*", - "read":true - } - ] - } - ``` - In this sample, a single rule is specified for requests coming from `trade-finance-network`: it states that a workflow call to `com.mynetwork.flow.GetBillOfLading` made to `exporter` and `carrier` nodes of remote Corda network is permitted for a requestor whose certificate is specified in the `principal` attribute. The `*` at the end indicates that any arguments passed to the function will pass the access control check. The `exporternode:10003` and `carriernode:10003` are of form `:`, for `exporter` and `carrier` nodes respectively in the remote Corda network. - - You need to record this policy rule on your Corda network's vault by invoking either the `AccessControlPolicyManager.createAccessControlPolicyState` function or the `AccessControlPolicyManager.updateAccessControlPolicyState` function on the `weaver-sdk-corda`; use the former if you are recording a set of rules for the given `securityDomain` for the first time and the latter to overwrite a set of rules recorded earlier. The above JSON needs to be converted to protobuf object of `org.hyperledger.cacti.weaver.protos.common.access_control.AccessControl.AccessControlPolicy`, using google's protobuf library, and the object is the second argument of above functions (first being the instance of CordaRPCOps). - -- **Verification policies**: - Taking the same example as above, an example of a verification policy for a B/L requested by the `trade-finance-network` from the `trade-logistics-network` is as follows: - ```json - { - "securityDomain":"trade-logistics-network", - "identifiers": - [ - { - "pattern":"tradelogisticschannel:shipmentcc:GetBillOfLading:*", - "policy": - { - "type":"Signature", - "criteria": - [ - "ExporterMSP", - "CarrierMSP" - ] - } - } - ] - } - ``` - In this sample, a single verification policy rule is specified for data views coming from `trade-logistics-network`: it states that the data returned by the `GetBillOfLading` query made to the `shipmentcc` chaincode on the `tradelogisticschannel` channel requires as proof two signatures, one from a peer in the organization whose MSP ID is `ExporterMSP` and another from a peer in the organization whose MSP ID is `CarrierMSP`. - - | Notes | - |:------| - | If the remote network is built on Corda, the resource specified in the access control policy can be used here as the `pattern`, with different node names specified in the `criteria`. | - - You need to record this policy rule on your Corda network's vault by invoking Corda sdk's function `VerificationPolicyManager.createVerificationPolicyState(proxy, verificationPolicyProto)`, where `proxy` is an instance of `CordaRPCOps` as described in previous sections, and `verificationPolicyProto` is an object of protobuf `org.hyperledger.cacti.weaver.protos.common.verification_policy.VerificationPolicyOuterClass.VerificationPolicy`. You can examine the full proto structure [here](https://github.com/hyperledger/cacti/blob/main/weaver/common/protos/common/verification_policy.proto). (_Google's protobuf library can be used to convert above JSON to protobuf object._) - - | Notes | - |:------| - | For any cross-network data request, make sure an access control policy is recorded in the _source network_ (`trade-logistics-network` in the above example) and a corresponding verification policy is recorded in the _destination network_ (`trade-finance-network` in the above example) before any relay request is triggered. | -- **Foreign network security domain (membership) configuration**: - Run the following procedure (pseudocode) to record security domain configuration for every foreign network you wish your Corda network to interoperate with (you will need to collect the identity service URLs for all the foreign networks first): - ``` - for each foreign network: - send an HTTP GET request to the network's identity service (using 'curl' or 'wget' from a shell script or equivalent programming language APIs). - convert the response string to protobuf object of 'org.hyperledger.cacti.weaver.protos.common.membership.MembershipOuterClass.Membership'. - invoke 'MembershipManager.createMembershipState(proxy, membershipProto)' or 'MembershipManager.updateMembershipState(proxy, membershipProto)' on Corda sdk. - ``` - As in the above two cases, use `createMembershipState` to record a confiuration for the first time for a given `securityDomain` and `updateMembershipState` to overwrite a configuration. - - | Notes | - |:------| - | Security domain configurations (organization lists and their certificate chains) for any Fabric/Corda network are subject to change, so you should run the above procedure periodically in a loop. | - -Your Corda network is now up and running with the necessary Weaver components, and your network's vault is bootstrapped with the initial configuration necessary for cross-network interactions! diff --git a/weaver/docs/docs/external/getting-started/enabling-weaver-network/fabric.md b/weaver/docs/docs/external/getting-started/enabling-weaver-network/fabric.md deleted file mode 100644 index 04226b6eb2..0000000000 --- a/weaver/docs/docs/external/getting-started/enabling-weaver-network/fabric.md +++ /dev/null @@ -1,848 +0,0 @@ ---- -id: fabric -title: Hyperledger Fabric ---- - - - -After testing the Weaver interoperation mechanisms on [basic sample networks](../test-network/overview.md), you may be interested in finding out how you can equip an existing real network, whether in development or in production, to exercise these mechanisms. In this document, we will demonstrate how to equip a Fabric network and application with Weaver components and capabilities. - -## Model - -The figure below illustrates a typical Fabric network. The infrastructure consists of a set of peers, ordering service nodes, and CAs that perform the roles of MSPs; each serves a given _organization_ which is one of the constituent units of the network. On the peers are installed one or more smart contracts (_chaincode_), representing shared business logic across the different organizations. Further up lie the so-called Layer-2 (or client) applications that consist of organization-specific business logic and invoke the smart contracts using APIs exposed by the Fabric SDK and with wallet credentials issued by their respective organizations' CAs. - -![alt text](../../../../static/enabling-weaver/fabric-network-model.png) - -Such a network equipped with Weaver components and capabilities will look like the figure below. Legacy components are marked in grey and Weaver and bridging components in green. - -![alt text](../../../../static/enabling-weaver/fabric-weaver-model.png) - -The relay and driver are the only additional infrastructure that need to be installed. One or more relays can be installed, as can one or more drivers. The drivers are illustrated in Layer-2 rather than in the bottom layer because, though they are coupled with relays, they exercise contracts using the Fabric SDK and organization-issued credentials just like any Layer-2 application does. - -Existing chaincode deployed on the network's channels remain undisturbed. All that is required in the smart contracts layer is the deployment of the Fabric Interoperation Chaincode on every channel that needs to offer or consume state from foreign networks. - -Layer-2, or client, applications will need some additional code and configuration because the decisions to exercise interoperation mechanisms (relay queries for data sharing or atomic asset exchanges) are strictly part of business logic. But Weaver's Fabric Interoperation Node SDK offers various helper functions to ease this process and keep the adaptation to a minimum, as we wil see later in this document. Finally, an _identity service_ must be offered by the network to expose its CAs' certificate chains to foreign networks, thereby laying the basis for interoperation. This service simply needs to offer a REST endpoint, and can be implemented as a standalone application or (more conveniently) as an augmentation of one or more of the existing Layer-2 applications. - -## Procedural Overview - -A Hyperledger Fabric network is typically created in phases, in the following sequence: -1. **Development**: This involves writing chaincode and Layer-2 applications. The chaincode's deployment name/ID and its transaction API must be designed first, but subsequent development of the two layers of applications can then proceed parallelly. -2. **Pre-Configuration**: This involves creating a desired specification (as a set of configuration diles) of the network topology and the ledgers it maintains. -3. **Startup and Bootstrap**: This is the launch phase, in which the network components and applications are started and bootstrapped (i.e., configured with initial state and operating rules). - -Assuming that the reader is familiar with this procedure, we will walk through the changes required in each phase to make your network ready for interoperation using Weaver components and code templates. This will involve code addition and adaptation, deployment of additional modules, additional configuration, and creation of additional ledger state records. The requirements and effort will vary with the mode of interoperation you wish to support in your Fabric network. - -## Development Phase - -A Fabric distributed application's business logic code spans two layers as illustrated in the network model. - -### Chaincode - -These are smart contracts embodied in code, managing business workflow state and digital assets. - -#### For Data Sharing - -No code changes are required for Weaver enablement, because data sharing involves: -- View packaging (and optionally, encryption) logic and access control logic in a source network, and -- View validation logic in a destination network - -This logic is standard and independent of smart contract, asset, and state, particulars. It is already implemented in the Fabric Interoperation Chaincode offered by Weaver. Hence you just need to deploy that chaincode to exercise data sharing from, or to, your application chaincode. Your application chaincode can be oblivious of the Fabric Interoperation Chaincode's workings and of the view request-response protocol. - -#### For Asset Exchange - -To exchange an asset using Weaver, the asset's state on the ledger must be controlled in the following ways: -- Locked in favor of a party -- Claimed by the party to whom the asset is pledged -- Returned to the original owner if it is not claimed within a given timeframe - -In addition, the state of the asset (i.e., whether it is locked), and its current and targeted owners, must be determinable by looking at the ledger records. - -The bookkeeping logic required to maintain records of locks can be abstracted away from the particulars of a digital asset and its workflow. But as such assets and their properties (including ownership) can be, and are, encoded in an arbitrary number of ways, we cannot provide a one-size-fits all set of functions (like in the data sharing protocol) to exchange any kind of asset. Instead, we must rely on the application contract (chaincode) managing an asset, as it knows precisely what the asset's properties are and how they can be updated and queried on the ledger (channel). - -What Weaver offers, therefore, is the following: -- Lock management (bookkeeping) logic implemented in the Fabric Interoperation Chaincode that treats each asset as an abstract object and is agnostic of the assets' internals. This logic can be exercised in one of two ways: - - Importing the [`assetexchange`](https://pkg.go.dev/github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/assetexchange/v2) library from the Fabric Interoperation Chaincode into your application chaincode, or - - Invoking them within the Fabric Interoperation Chaincode using a [chaincode-to-chaincode call](https://pkg.go.dev/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStub.InvokeChaincode). -- A set of template functions with sample (and extensible) code that must be added to the application chaincode to exercise the above lock management functions. - -Below, we list the template functions with sample code that you, as a developer, must use and adapt within your chaincode, in either mode (library import or chaincode invocations). - -| Notes | -|:------| -| The instructions here apply only to chaincode implemented in Go, because Weaver presently offers only a Go version of the Fabric Interoperation Chaincode. | - -- _Using the [`assetexchange`](https://pkg.go.dev/github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/assetexchange/v2) Library_: This method doesn't require the [`Fabric Interoperation Chaincode`](https://pkg.go.dev/github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/contracts/interop/v2) to be installed. In your smart contract's `go.mod`, add the following in the `require` section (the sample below uses the current versions for dependency packages; update them to the latest versions offered by Cacti): - ```go - require( - ... - github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-rc.2 - github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/assetexchange/v2 v2.0.0-rc.2 - ... - ) - ``` - The following functions need to be added to your chaincode, and the smart contract class/type used below is called `SmartContract` (_Note_: the function signature, i.e. the name, arguments, and return values, need to be exactly what is given in the below samples; you can have additional code to manage asset state as per need): - 1. **LockAsset** - ```go - import ( - ... - "github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/assetexchange/v2" - ) - func (s *SmartContract) LockAsset(ctx contractapi.TransactionContextInterface, assetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) { - // Add some safety checks before calling LockAsset from library - // Caller of this chaincode is supposed to be the Locker and the owner of the asset being locked. - contractId, err := assetexchange.LockAsset(ctx, "", assetExchangeAgreementSerializedProto64, lockInfoSerializedProto64) - if err != nil { - return "", logThenErrorf(err.Error()) - } - // Post proccessing of asset after LockAsset called like change status of the asset so that it can't be spent. - ... - return contractId, nil - } - ``` - Here `assetExchangeAgreementSerializedProto64` is a serialized protobuf in Base64 encoded string of `AssetExchangeAgreement` protobuf structure, and can be used to extract details like asset id, type of asset and recipient. Check the structure definition [here](https://github.com/hyperledger/cacti/blob/main/weaver/rfcs/formats/assets/exchange.md#representing-two-party-asset-exchange-agreements). - Similarly `lockInfoSerializedProto64` is a serialized protobuf in Base64 encoded string of `AssetLock` protobuf structure. Check the structure definition [here](https://github.com/hyperledger/cacti/blob/main/weaver/rfcs/formats/assets/exchange.md#representing-locks-on-assets). - 2. **LockFungibleAsset** - ```go - func (s *SmartContract) LockFungibleAsset(ctx contractapi.TransactionContextInterface, fungibleAssetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) { - // Add some safety checks before calling LockFungibleAsset from library - // Caller of this chaincode is supposed to be the Locker and the owner of the asset being locked. - contractId, err := assetexchange.LockFungibleAsset(ctx, "", fungibleAssetExchangeAgreementSerializedProto64, lockInfoSerializedProto64) - if err != nil { - return "", logThenErrorf(err.Error()) - } - // Post proccessing of asset after LockFungibleAsset called like reduce the amount of tokens owned by the locker, or mark it locked so that it can't be spent. - ... - return contractId, nil - } - ``` - Here `fungibleAssetExchangeAgreementSerializedProto64` is a serialized protobuf in Base64 encoded string of `FungibleAssetExchangeAgreement` protobuf structure, and can be used to extract details like asset quantity, type of asset and recipient. Check the structure definition [here](https://github.com/hyperledger/cacti/blob/main/weaver/rfcs/formats/assets/exchange.md#representing-two-party-asset-exchange-agreements). - 3. **IsAssetLockedQueryUsingContractId** - ```go - func (s *SmartContract) IsAssetLockedQueryUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) { - return assetexchange.IsAssetLockedQueryUsingContractId(ctx, contractId) - } - ``` - 4. **ClaimAssetUsingContractId** - ```go - func (s *SmartContract) ClaimAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId, claimInfoSerializedProto64 string) (bool, error) { - // Note recipient will be the caller for this function - claimed := false - err := assetexchange.ClaimAssetUsingContractId(ctx, contractId, claimInfoSerializedProto64) - if err != nil { - return false, logThenErrorf(err.Error()) - } - claimed = true - // After the above function call, update the owner of the asset with recipeint/caller - ... - return claimed, nil - } - ``` - 5. **UnlockAssetUsingContractId** - ```go - func (s *SmartContract) UnlockAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) { - unlocked := false - err := assetexchange.UnlockAssetUsingContractId(ctx, contractId) - if err != nil { - return false, logThenErrorf(err.Error()) - } - unlocked = true - ... - return true, nil - } - ``` - - In addition, you should add the following extra utility functions to enable client applications to query and discover asset state: - ```go - func (s *SmartContract) GetHTLCHashByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) { - return assetexchange.GetHTLCHashByContractId(ctx, contractId) - } - func (s *SmartContract) GetHTLCHashPreImageByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) { - return assetexchange.GetHTLCHashPreImageByContractId(ctx, contractId) - } - ``` - - There is an alternative API to implement asset exchange using this library, which doesn't involve contract IDs. For details, see the [Asset Exchange Library README](https://github.com/hyperledger/cacti/blob/main/weaver/core/network/fabric-interop-cc/libs/assetexchange/README.md#without-contractid). - -- _Using the [`Fabric Interoperation Chaincode`](https://pkg.go.dev/github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/contracts/interop/v2)_: This method requires the Fabric Interoperation Chaincode to be installed on all peers of the channel, using a special chaincode ID (e.g., `interop`, which is what we will use later in this document). Your application chaincode needs to implement the interface `github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2`. - In your smart contract's `go.mod`, add the following in the `require` section (update the version to the latest Cacti version): - ```go - require( - ... - github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-rc.2 - github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-rc.2 - ... - ) - ``` - In the SmartContract class definition file, add the following code: - ```go - import ( - ... - am "github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2" - ) - type SmartContract struct { - contractapi.Contract - amc am.AssetManagementContract - } - ``` - The following functions need to be added to your chaincode (_Note_: the function signature, i.e. the name, arguments, and return values, need to be exactly what is given in the below samples; you can have additional code to manage asset state as per need): - 1. **LockAsset** - ```go - func (s *SmartContract) LockAsset(ctx contractapi.TransactionContextInterface, assetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) { - // Add some safety checks before calling LockAsset from library - // Caller of this chaincode is supposed to be the Locker and the owner of the asset being locked. - contractId, err := s.amc.LockAsset(ctx, "", assetExchangeAgreementSerializedProto64, lockInfoSerializedProto64) - if err != nil { - return "", logThenErrorf(err.Error()) - } - // Post proccessing of asset after LockAsset called like change status of the asset so that it can't be spent. - ... - return contractId, nil - } - ``` - Here `assetExchangeAgreementSerializedProto64` is a serialized protobuf in Base64 encoded string of `AssetExchangeAgreement` protobuf structure, and can be used to extract details like asset id, type of asset and recipient. Check the structure definition [here](https://github.com/hyperledger/cacti/blob/main/weaver/rfcs/formats/assets/exchange.md#representing-two-party-asset-exchange-agreements). - Similarly `lockInfoSerializedProto64` is a serialized protobuf in Base64 encoded string of `AssetLock` protobuf structure. Check the structure definition [here](https://github.com/hyperledger/cacti/blob/main/weaver/rfcs/formats/assets/exchange.md#representing-locks-on-assets). - 2. **LockFungibleAsset** - ```go - func (s *SmartContract) LockFungibleAsset(ctx contractapi.TransactionContextInterface, fungibleAssetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) { - // Add some safety checks before calling LockFungibleAsset from library - // Caller of this chaincode is supposed to be the Locker and the owner of the asset being locked. - contractId, err := s.amc.LockFungibleAsset(ctx, "", fungibleAssetExchangeAgreementSerializedProto64, lockInfoSerializedProto64) - if err != nil { - return "", logThenErrorf(err.Error()) - } - // Post proccessing of asset after LockFungibleAsset called like reduce the amount of tokens owned by the locker, or mark it locked so that it can't be spent. - ... - return contractId, nil - } - ``` - Here `fungibleAssetExchangeAgreementSerializedProto64` is a serialized protobuf in Base64 encoded string of `FungibleAssetExchangeAgreement` protobuf structure, and can be used to extract details like asset quantity, type of asset and recipient. Check the structure definition [here](https://github.com/hyperledger/cacti/blob/main/weaver/rfcs/formats/assets/exchange.md#representing-two-party-asset-exchange-agreements). - 3. **IsAssetLockedQueryUsingContractId** - ```go - func (s *SmartContract) IsAssetLockedQueryUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) { - return s.amc.IsAssetLockedQueryUsingContractId(ctx, contractId) - } - ``` - 4. **ClaimAssetUsingContractId** - ```go - func (s *SmartContract) ClaimAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId, claimInfoSerializedProto64 string) (bool, error) { - // Note recipient will be the caller for this function - claimed := false - err := s.amc.ClaimAssetUsingContractId(ctx, contractId, claimInfoSerializedProto64) - if err != nil { - return false, logThenErrorf(err.Error()) - } - claimed = true - // After the above function call, update the owner of the asset with recipeint/caller - ... - return claimed, nil - } - ``` - 5. **UnlockAssetUsingContractId** - ```go - func (s *SmartContract) UnlockAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) { - unlocked := false - err := s.amc.UnlockAssetUsingContractId(ctx, contractId) - if err != nil { - return false, logThenErrorf(err.Error()) - } - unlocked = true - ... - return true, nil - } - ``` - In addition, you should add the following extra utility functions to enable client applications to query and discover asset state: - ```go - func (s *SmartContract) GetHTLCHashByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) { - return s.amc.GetHTLCHashByContractId(ctx, contractId) - } - func (s *SmartContract) GetHTLCHashPreImageByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) { - return s.amc.GetHTLCHashPreImageByContractId(ctx, contractId) - } - ``` - -#### For Asset Transfer - -_TBD_ - -### Client (or Layer-2) Applications - -Weaver provides an SDK to help you adapt your applications to exercise the various interoperability modes. These are called out as **Interoperation Helpers** in the network model illustrated earlier. Your Fabric network's Layer-2 applications have business logic embedded in them that, broadly speaking, accept data from users and other external agents and invoke smart contracts using library functions and APIs offered by the Fabric SDK. When you use Weaver for network interoperability, other options can be added, namely requesting and accepting data from foreign networks, and triggering locks and claims for atomic exchanges spanning two networks. Weaver's Fabric Interoperation SDK (currently implemented both in Node.js and Golang) offers a library to exercise these options, supplementing the Fabric SDK. But this will involve modification to the application's business logic. - -| Notes | -|:------| -| The instructions here apply to applications implemented in Node.js (JavaScript and TypeScript), using the Weaver Node SDK for Fabric. We will add instructions later for Go applications using the Weaver Go SDK for Fabric. | - -To import and use the Weaver SDK, you need to add the following dependency to the `dependencies` section of your Node.js application's `package.json` file: -```json -"@hyperledger/cacti-weaver-sdk-fabric": "latest", -``` -(Instead of `latest`, you can select a particular version from the [package website](https://github.com/hyperledger/cacti/pkgs/npm/cacti-weaver-sdk-fabric).) - -Before you run `npm install` to fetch the dependencies, make sure you create a [personal access token](https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token) with `read:packages` access in GitHub. Create an `.npmrc` file in the same folder as the `package.json` with the following contents: - -``` -@hyperledger:registry=https://npm.pkg.github.com/hyperledger -//npm.pkg.github.com/:_authToken= -``` -Replace `` in this file with the token you created in GitHub. - -First, you must incorporate some code for Weaver's network administration, specifically identity management. Then, using the given sample code and examples, you can adapt your applications for each interoperability mode. - -#### For Identity Administration - -A Fabric network channel must share its security domain (or membership) configuration, i.e., its organizations' CA certificate chains, with a foreign network with which it seeks to interoperate. Each organization must run an IIN Agent for this purpose. The set of IIN Agents, a.k.a. the _local membership_ must be recorded in the ledger before those agents can be operational. In your Fabric network application suite, one or more applications will exist for network administration; the following code snippet should be added in at least one of those applications to record local membership as a prerequisite for interoperability: - ```typescript - import { MembershipManager } from '@hyperledger/cacti-weaver-sdk-fabric' - - const gateway = - - try { - const response = await MembershipManager.createLocalMembership( - gateway, - members, // list of all organization MSPIDs that are part of the channel - securityDomain, // name of the local network's security domain - channelName, // Channel Name - contractName // Fabric Interoperation Chaincode installation ID on the channel - ) - } catch (e) { - // On error try updating local membership - const response = await MembershipManager.updateLocalMembership(gateway, members, securityDomain, channelName, contractName) - } - ``` - - `` should be replaced with standard (boilerplate) code to get a handle to your network's gateway. This requires a special wallet identity, namely one with a `network-admin` attribute indicating that the caller is a trusted network administrator who is authorized to record local memberships on the `channelName` channel. - - `members` must consist of the list of organizational MSP IDs for the `channelName` channel. - -#### For Data Sharing - -Consider a scenario inspired by the [global trade use case](../../user-stories/global-trade.md) where a letter of credit (L/C) management business logic (chaincode `letterofcreditcc`) installed in the `tradefinancechannel` channel in the `trade-finance-network` network supports a transaction `RecordBillOfLading`, which validates and records a bill of lading (B/L) supplied by a user via a UI. Weaver will enable such a B/L to be fetched from a different network `trade-logistics-network` by querying the function `GetBillOfLading` exposed by the chaincode `shipmentcc` installed in the `tradelogisticschannel` channel. - -(In preparation, a suitable access control policy must be recorded on `tradelogisticschannel` in `trade-logistics-network`, and a suitable verification policy must be recorded on `tradefinancechannel` in `trade-finance-network`. We will see how to do this in the "Startup and Boostrap" section later.) - -You will need to insert some code in the Layer-2 application that accepts a B/L and submits a `RecordBillOfLading` transaction in `trade-finance-network`. (No code changes need to be made in any application in the other network.) The logic to accept a B/L should be replaced (or you can simply add an alternative) by a call to the `interopFlow` function offered by the [cacti-weaver-sdk-fabric](https://github.com/hyperledger/cacti/pkgs/npm/cacti-weaver-sdk-fabric) library (there's an [equivalent library in Golang](https://github.com/hyperledger/cacti/releases/tag/weaver%2Fsdks%2Ffabric%2Fgo-sdk%2Fv2.0.0-rc.2) too). The following code sample illustrates this (the Golang equivalent is left to the reader): -```js showLineNumbers -const ihelper = require('@hyperledger/cacti-weaver-sdk-fabric').InteroperableHelper; -const interopcc = ; // Use Fabric SDK functions: (new Gateway()).getNetwork(...).getContract() -const keyCert = await ihelper.getKeyAndCertForRemoteRequestbyUserName(, ); // Read key and certificate for from wallet (get handle using Fabric SDK Wallets API) -// Collect view addresses for relay requests in the context of an interop flow -interopJSONs.push({ - NetworkID: 'trade-logistics-network', - RemoteEndpoint: ], // Replace with remote network's relay address and port - ChannelID: 'tradelogisticschannel', - ChaincodeID: 'shipmentcc', - ChaincodeFunc: 'GetBillOfLading', - ccArgs: [ ], // Replace with a value that can be used to look up the right B/L - Sign: true -}); -const indices = [ 1 ]; -// Trigger an end-to-end interoperation (data sharing) protocol -// Send a request to a foreign network via your relay, receive the response and submit a transaction to a local chaincode -const flowResponse = await ihelper.interopFlow( - interopcc, - 'trade-finance-network', - { - channel: 'tradefinancechannel', - contractName: 'letterofcreditcc', - ccFunc: 'RecordBillOfLading', - ccArgs: [ , '' ] - }, - , // Replace with this Layer-2 application's organization's MSP ID - [:], // Replace with local network's relay address and port - indices, - interopJSONs, - keyCert, - , // List of orgs to submit transaction to local i.e. trade logistics network - false, // Boolean flag to indicate whether return without submit transaction to local i.e. trade logistics network - false, // Boolean flag indicating no TLS communication with relay - [], // Keep it empty when TLS is disabled - , // Boolean flag to indicate whether to use to end-to-end encryption -); -// List of errors to check for -if (!flowResponse.views || flowResponse.views.length === 0 || !flowResponse.result || flowResponse.views.length !== argIndices.length) { - throw ; -} -``` -Let us understand this code snippet better. The structure in lines 20-25 specifies the local chaincode transaction that is to be triggered after remote data (view) has been requested and obtained via relays. The function `RecordBillOfLading` expects two arguments as specified in line 24: the first is the common shipment reference that is used by the letter of credit in `trade-finance-network` and the bill of lading in `trade-logistics-network`, and the second is the bill of lading contents. When the `interopFlow` function is called, this argument is left blank because it is supposed to be filled with contents obtained from a view request. The array list `indices`, which is passed as an argument to `interopFlow` therefore contains the index value `1` (line 14), indicating which argument ought to be substituted with view data. The `interopJSONs` array correspondingly contains a list of view addresses that are to be supplied to the relay. The `` if set to `true` will enable end-to-end confidentiality, i.e. payload will be encrypted from `trade-finance-network`'s Weaver chaincode, and will be decrypted in SDK (i.e. Layer-2 client application) at `trade-logistics-network`, but relays and drivers in between will not be able to see the payload. By default this flag is set to `false`. - -| Notes | -|:------| -| A local chaincode invocation may require multiple view requests to different networks, which is why `indices` and `interopJSONs` are arrays; they therefore must have the same lengths. | - -The rest of the code ought to be self-explanatory. Values are hardcoded for explanation purposes, but you can refactor the above code by reading view addresses corresponding to chaincode invocations from a configuration file. - -**Enabling TLS**: -By default, the TLS is set to false in `interopFlow`, i.e. disabled. But if you want to enable TLS, can pass additional parameters to the `interopFlow` function as follows: -```TypeScript -const flowResponse = await ihelper.interopFlow( - interopcc, - 'trade-finance-network', - { - channel: 'tradefinancechannel', - contractName: 'letterofcreditcc', - ccFunc: 'RecordBillOfLading', - ccArgs: [ , '' ] - }, - , // Replace with this Layer-2 application's organization's MSP ID - [:], // Replace with local network's relay address and port - indices, - interopJSONs, - keyCert, - , // List of orgs to submit transaction to in trade logistics network - false, // Boolean flag to indicate whether return without submit transaction to local i.e. trade logistics network - true, // Boolean indication TLS is enabled. - , // list of CA certificate file paths -); -``` - -#### For Asset Exchange - -Let's take an example of asset exchange between `Alice` and `Bob`, where Bob wants to purchase an asset of type `Gold` with id `A123` from `Alice` in `BondNetwork` in exchange for `200` tokens of type `CBDC01` in `TokenNetwork`. - -`Alice` needs to select a secret text (say `s`), and hash it (say `H`) using say `SHA512`, which will be used to lock her asset in `BondNetwork`. At the place in your application where an asset exchange is to be initiated, you need to add code to enable Alice to lock the non-fungible asset using hash `H` and timeout duration of 10 minutes: -```typescript -import { AssetManager, HashFunctions } from '@hyperledger/cacti-weaver-sdk-fabric' - -const hash = HashFunctions.SHA512(); // Create Hash instance of one of the supported Hash Algorithm -hash.setSerializedHashBase64(H); // Set the Hash -const timeout = Math.floor(Date.now()/1000) + 10 * 60; - -const bondContract = ; - -const result = await AssetManager.createHTLC( - bondContract, - "Gold", // Asset ID - "A123", // Asset Type - bobCertificate, // Certificate of Bob in Bond Network - hash, // Hash generated by Alice using her secret s - timeout, // Timeout in epoch for 10 mins from current time - null // Optional callback function to be called after the asset is locked -); -let bondContractId = result.result; // Unique ID for this asset exchange contract in BondNetwork -``` - -| Notes | -|:------| -| Note that 'Alice' and 'Bob' and the asset specifics can be parameterized in the above code, which can be reused for arbitrary asset exchange scenarios in your business workflow. The above code is only meant to be a sample. | - -Now `Bob` will lock his tokens in `TokenNetwork`. To lock the fungible asset using same hash `H` and timeout of 5 minutes (half the timeout duration used by Alice in `BondNetwork`), add the following code snippet in your application: -```typescript -const hash = HashFunctions.SHA512(); // Create Hash instance of one of the supported Hash Algorithm -hash.setSerializedHashBase64(H); // Set the Hash -const timeout = Math.floor(Date.now()/1000) + 5 * 60; - -const tokenContract = ; -const result = await AssetManager.createFungibleHTLC( - tokenContract, - "CBDC01", // Token ID - 200, // Token Quantity - aliceCertificate, // Certificate of Alice in Token Network - hash, // Hash H used by Alice in Bond Network - timeout, // Timeout in epoch for 5 mins from current time - null // Optional callback function to be called after the asset is locked -) -const tokenContractId = result.result // Unique ID for this asset exchange contract in TokenNetwork -``` - -Wherever the lock status of the asset is required in your application, you should insert a query function call as follows: -```typescript -const contract = ; -// Below contractId is the ID obtained during lock -const isLocked = AssetManager.isAssetLockedInHTLCqueryUsingContractId(contract, contractId) -``` - -Wherever a participant (either 'Alice' or 'Bob' in this example) needs to claim a locked asset using the secret text (pre-image of hash) `s` in your application, insert the following code snippet (*Note*: typically one would insert this in event callback functions or in functions that are polling the ledger to monitor whether the asset is locked in favor of a given recipient): -```typescript -const hash = HashFunctions.SHA512(); // Create Hash instance of one of the supported Hash Algorithm -hash.setPreimage(s) // Set Pre-Image s -const contract = ; -const claimSuccess = await AssetManager.claimAssetInHTLCusingContractId( - contract, - contractId, // contractId obtained during lock - hash -) -// return value claimSuccess is boolean indicating success or failure of claim -``` - -Wherever the asset must be unlocked in your application (typically, an event callback function triggered upon the expiration of the time lock), insert the following code snippet: -```typescript -const contract = ; -const reclaimSuccess = await AssetManager.reclaimAssetInHTLCusingContractId( - contract, - contractId // contractId obtained during lock -) -// return value 'reclaimSuccess' is a boolean indicating success or failure of reclaim -``` - -#### For Asset Transfer - -_TBD_ - -## Pre-Configuration Phase - -Typically, pre-configuration in a Fabric network involves generating (after creating the channel specifications and policies): -- _Channel artifacts_: orderer genesis block, channel transaction, and anchor peer configurations from a `configtx.yaml` file (using Fabric's `configtxgen` tool) -- _Crypto artifacts_: keys and certificates for CAs, peers, orderers, and clients from a `crypto-config.yaml` file (using Fabric's `cryptogen` tool) -- _Connection profiles_: one for every network organization, which will be used by the organization's Layer-2 applications to connect to the network's peers and CAs - -No changes are required in this process to support any of the three interoperation modes using Weaver. The connection profiles generated above will be used by certain Weaver modules, as we will see later. The only additional step required is to generate special wallet identities for the following: -- Network administrator: one or more identities containing the `network-admin` attribute; only a user/application possessing this identity may record special (privileged) information regarding memberships and policies on the channel. -- Fabric Driver: one or more identities (for each deployed driver) containing the `relay` attribute; only a relay-driver combination possessing this identity may run data sharing-related operations on the deployed Fabric Interoperation Chaincode. -- IIN Agent: one or more identities (for each deployed agent) containing the `iin-agent` attribute: only an agent may submit foreign network membership records to the Fabric Interoperation Chaincode. - -Later we will see how the components possessing these identities are deployed. - -## Startup and Bootstrap Phase - -After writing application code and creating the network configuration files, the components of a Fabric network (peers, CAs, and ordering service) are launched. In this section, we will list the additional tasks you, as a Fabric network administrator, must perform to make your network ready to interoperate. - -To launch a network using containerized components, you will typically use a Docker Compose or Kubernetes configuration file. No modifications are needed to the peers', orderers', and CAs' configurations. Sample instructions are given below for networks launched using Docker Compose; we leave it to the reader to adapt these to their custom launch processes. - -### For Asset Exchange - -The asset exchange mode currently requires only the Fabric Interoperation Chaincode module from Weaver. Relays, drivers, and IIN agents, are not necessary. In the future, we expect to make the asset exchange protocol moe automated using these components; the instructions here will be updated appropriately. - -#### Install the Fabric Interoperation Chaincode - -Install the Fabric Interoperation Chaincode in the relevant channel(s), i.e., those that run chaincodes that will be involved in asset exchanges. This is a Go module that can be fetched from `github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/contracts/interop`. Following that, you an install it using the appropriate Fabric process: in Fabric v2, you will need to package, install, approve, and commit this module on the selected channels in your network. - -### For Data Sharing or Asset Transfer - -Both the data sharing and asset transfer modes require the Fabric Interoperation Chaincode, relays, drivers, and IIN agents, to be deployed. - -#### Install the Fabric Interoperation Chaincode - -Install the Fabric Interoperation Chaincode in the relevant channel(s), i.e., those that run chaincodess that will be involved in data sharing (and asset transfers, which require multiple data shares). This is a Go module that can be fetched from `github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/contracts/interop`. Following that, you an install it using the appropriate Fabric process: in Fabric v2, you will need to package, install, approve, and commit this module on the selected channels in your network. - -#### Launch Relay - -You need to run one or more relays for network-to-network communication. Here we provide instructions to run one relay running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple relays, which will be useful from a failover perspective.) - -Weaver provides a [pre-built image](https://github.com/hyperledger/cacti/pkgs/container/cacti-weaver-relay-server) for the relay. Before launching a container, you just need to customize its configuration for your Fabric network, which you can do by simply creating a folder (let's call it `relay_config`) and configuring the following files in it: -- `.env`: This sets suitable environment variables within the relay container. Copy the `.env.template` file [from the repository](https://github.com/hyperledger/cacti/blob/main/weaver/core/relay/.env.template) and customize it for your purposes, as indicated in the below sample: - ``` - PATH_TO_CONFIG=./config.toml - RELAY_NAME=<"name" in config.toml> - RELAY_PORT= - EXTERNAL_NETWORK= - DOCKER_IMAGE_NAME=ghcr.io/hyperledger/cacti-weaver-relay-server - DOCKER_TAG=2.0.0-rc.2 - ``` - - The `PATH_TO_CONFIG` variable should point to the properties file typically named `config.toml` (you can name this whatever you wish). See further below for instructions to write this file. - - The `RELAY_NAME` variable specifies a unique name for this relay. It should match what's specified in the `config.toml` (more on that below). - - The `RELAY_PORT` variable specifies the port this relay server will listen on. It should match what's specified in the `config.toml` (more on that below). - - The `EXTERNAL_NETWORK` variable should be set to the [name](https://docs.docker.com/compose/networking/) of your Fabric network. - - The `DOCKER_*` variables are used to specify the image on which the container will be built. Make sure you set `DOCKER_TAG` to the latest version you see on [GitHub](https://github.com/hyperledger/cacti/pkgs/container/cacti-weaver-relay-server). - - For more details, see the [Relay Docker README](https://github.com/hyperledger/cacti/blob/main/weaver/core/relay/relay-docker.md) ("Relay Server Image" and "Running With Docker Compose" sections). - -- `config.toml`: This is the file specified in the `PATH_TO_CONFIG` variable in the `.env`. It specifies properties of this relay and the driver(s) it supports. A sample is given below: - ```toml showLineNumbers - name= - port= - host="0.0.0.0" - db_path="db//requests" - remote_db_path="db//remote_request" - - # FOR TLS - cert_path="credentials/fabric_cert.pem" - key_path="credentials/fabric_key" - tls= - - [networks] - [networks.] - network="" - - [relays] - [relays.] - hostname="" - port="" - - [drivers] - [drivers.] - hostname="" - port="" - ``` - - `` should be a unique ID representing this relay; e.g., `my_network_relay`. It should match the `RELAY_NAME` value in `.env`. - - `` is the port number the relay server will listen on. It should match the `RELAY_PORT` value in `.env`. - - `db_path` and `remote_db_path` are used internally by the relay to store data. Replace `` with the same value set for the `name` parameter. (These can point to any filesystem paths in the relay's container.) - - If you set `tls` to `true`, the relay will enforce TLS communication. The `cert_path` and `key_path` should point to a Fabric TLS certificate and key respectively, such as those created using the `cryptogen` tool. - - `` is a unique identifier for your local network. You can set it to whatever value you wish. - - `` refers to the driver used by this relay to respond to requests. This also refers to one of the drivers's specifications in the `drivers` section further below. In this code snippet, we have defined one driver. (The names in lines 14 and 22 must match.) In lines 23 and 24 respectively, you should specify the hostname and port for the driver (whose configuration we will handle later). - - The `relays` section specifies all foreign relays this relay can connect to. The `` value should be a unique ID for a given foreign relay, and this value will be used by your Layer-2 applications when constructing view addresses for data sharing requests. In lines 18 and 19, you should specify the hostname and port for the foreign relay. - - **Enabling TLS**: - - You can make your relay accept TLS connections by specifying a TLS certificate file path and private key file path in `cert_path` and `key_path` respectively, and set `tls` to `true`. - - To communicate with a foreign relay using TLS, specify that relay's TLS CA certificate path in `tlsca_cert_path` (currently only one certificate can be configured) and set `tls` to `true` by extending that relay's section as follows (*Note*: this CA certificate should match the one specified in the `cert_path` property in the foreign relay's `config.toml` file): - ```toml - [relays] - [relays.] - hostname="" - port="" - tls= - tlsca_cert_path="" - ``` - - To communicate with a driver using TLS, specify the driver's TLS CA certificate in `tlsca_cert_path` (currently only one certificate can be configured) and set `tls` to `true` by extending that driver's section as follows (*Note*: this CA certificate must match the certificate used by the driver using the `DRIVER_TLS_CERT_PATH` property in its `.env` configuration file, which we will examine later): - ```toml - [drivers] - [drivers.] - hostname="" - port="" - tls= - tlsca_cert_path="" - ``` - - | Notes | - |:------| - | You can specify more than one foreign relay instance in the `relays` section. | - | You can specify more than one driver instance in the `drivers` section. | - -- `docker-compose.yaml`: This specifies the properties of the relay container. You can use the [file in the repository](https://github.com/hyperledger/cacti/blob/main/weaver/core/relay/docker-compose.yaml) verbatim. - -To start the relay server, navigate to the folder containing the above files and run the following: -```bash -docker-compose up -d relay-server -``` - -#### Launch Driver - -You need to run one or more drivers through which your relay can interact with your Fabric network. Here we provide instructions to run one Fabric driver running in a Docker container, which is sufficient for data sharing. (Later, we will provide instructions to run multiple drivers, which will be useful both from a failover perspective and to interact with different subsets of your Fabric network, like private data collections.) - -Weaver provides a [pre-built image](https://github.com/hyperledger/cacti/pkgs/container/cacti-weaver-driver-fabric) for the Fabric driver. Before launching a container, you just need to customize its configuration for your Fabric network, which you can do by simply creating a folder (let's call it `driver_config`) and configuring the following files in it: -- `.env`: This sets suitable environment variables within the driver container. Copy the `.env.docker.template` file [from the repository](https://github.com/hyperledger/cacti/blob/main/weaver/core/drivers/fabric-driver/.env.docker.template) and customize it for your purposes, as indicated in the below sample: - ``` - CONNECTION_PROFILE= - DRIVER_CONFIG=./config.json - RELAY_ENDPOINT=: - NETWORK_NAME= - DRIVER_PORT= - INTEROP_CHAINCODE= - EXTERNAL_NETWORK= - TLS_CREDENTIALS_DIR= - DOCKER_IMAGE_NAME=ghcr.io/hyperledger/cacti-weaver-driver-fabric - DOCKER_TAG=2.0.0-rc.2 - DRIVER_TLS= - DRIVER_TLS_CERT_PATH=path_to_tls_cert_pem_for_driver - DRIVER_TLS_KEY_PATH=path_to_tls_key_pem_for_driver - RELAY_TLS= - RELAY_TLSCA_CERT_PATH=path_to_tls_ca_cert_pem_for_relay - ``` - - `` should point to the path of a connection profile you generated in the "Pre-Configuration" section. A Fabric driver obtains client credentials from one of the organizations in your network, so pick an organization and point to the right connection profile. - - The `DRIVER_CONFIG` variable should point to the `config.json` (you can name this whatever you wish) specified below. - - `` should be set to the hostname of the relay server machine and `` should match the `port` value in the relay's `config.toml` (see above). - - The `NETWORK_NAME` variable should be a unique ID referring to the Fabric network. It will be used to distinguish container names and wallet paths. (This setting is relevant in situations where a driver is used to query multiple network channels.) - - The `DRIVER_PORT` variable should be set to the port this driver will listen on. - - The `INTEROP_CHAINCODE` variable should be set to the ID of the Fabric Interop Chaincode installed on your Fabric network channel. - - The `EXTERNAL_NETWORK` variable should be set to the [name](https://docs.docker.com/compose/networking/) of your Fabric network. - - **Enabling TLS**: - - You can make your driver accept TLS connections by specifying `DRIVER_TLS` as `true` and specifying a TLS certificate file path and private key file path in `DRIVER_TLS_CERT_PATH` and `DRIVER_TLS_KEY_PATH` respectively. The same certificate should be specified in this driver's definition in the `drivers` section in the `config.toml` file of your relay in the `tlsca_cert_path` property (see the earlier section on relay configuration). - - To communicate with your network' relay using TLS (i.e., if the relay is TLS-enabled), specify that relay's TLS CA certificate path in `RELAY_TLSCA_CERT_PATH` (currently only one certificate can be configured) and set `RELAY_TLS` to `true`. This CA certificate should match the one specified in the `cert_path` property in the relay's `config.toml` file (see the earlier section on relay configuration): - - You can point to the folder in your host system containing the certificate and key using the `TLS_CREDENTIALS_DIR` variable. (This folder will be synced to the `/fabric-driver/credentials` folder in the Fabric Driver container as specified in the [docker-compose file](https://github.com/hyperledger/cacti/blob/main/weaver/core/drivers/fabric-driver/docker-compose.yml).) Make sure you point to the right certificate and key file paths within the container using the `DRIVER_TLS_CERT_PATH`, `DRIVER_TLS_KEY_PATH`, and `RELAY_TLSCA_CERT_PATH` variables. - -- `config.json`: This contains settings used to connect to a CA of a Fabric network organization and enroll a client. A sample is given below: - ```json - { - "admin":{ - "name":"admin", - "secret":"adminpw" - }, - "relay": { - "name":"relay", - "affiliation":"", - "role": "client", - "attrs": [{ "name": "relay", "value": "true", "ecert": true }] - }, - "mspId":"", - "caUrl":"" - } - ``` - - As in the `.env` configuration, you should pick an organization for the driver to associate with. The `admin` section specifies the registrar name and password (this should be familiar to any Fabric network administrator) used to enroll clients. Default values of `admin` and `adminpw` are specified above as examples, which you should replace with the right values configured in your network organization's CA. - - `` should be what's specified in your organization's Fabric CA server configuration. The default is `org1.department1`, but you should look up the appropriate value from the CA server's configuration file. - - `` should be set to the (or an) MSP ID of the selected organization. - - `` should be set to the CA server's endpoint. If you launched your CA server as a container from a docker-compose file, this should be set to the container's service name. - - | Notes | - |:------| - | If your connection profile already contains specifications for a CA server, you can leave the `` value as a blank. | - -- `docker-compose.yaml`: This specifies the properties of the driver container. You can use the [file in the repository](https://github.com/hyperledger/cacti/blob/main/weaver/core/drivers/fabric-driver/docker-compose.yml) verbatim. - -To start the driver, navigate to the folder containing the above files and run the following: -```bash -docker-compose up -d -``` - -#### Launch IIN Agents - -You need to run one IIN Agent for each organization in the Fabric network channel you are enabling Weaver in. This agent runs a protocol with other organizations' agents and with targeted foreign networks' agents to sync and record foreign networks' memberships to the channel ledger. - -Weaver provides a [pre-built image](https://github.com/hyperledger/cacti/pkgs/container/cacti-weaver-iin-agent) for the IIN Agent. Before launching a container, you just need to customize its configuration for your Fabric network organization, which you can do by simply creating a folder (let's call it `iin_agent_config_`) and configuring the following files in it: -- `config.json`: This contains settings used to connect to a Fabric network organization and its CA (part of the organization's MSP). A sample is given below: - ``` - { - "admin":{ - "name":"admin", - "secret":"adminpw" - }, - "agent": { - "name":"iin-agent", - "affiliation":"", - "role": "client", - "attrs": [{ "name": "iin-agent", "value": "true", "ecert": true }] - }, - "mspId":"", - "ordererMspIds": [], - "ccpPath": "", - "walletPath": "", - "caUrl": "", - "local": "false" - } - ``` -- `dnsconfig.json`: This specifies the list of known IIN agents of your network (i.e., belonging to other organizations) and of foreign networks. A sample DNS configuration file is given below: - ``` - { - "": { - "": { - "endpoint": "", - "tls": , - "tlsCACertPath": "" - }, - "": { - "endpoint": "", - "tls": , - "tlsCACertPath": "" - } - }, - "": { - "": { - "endpoint": "", - "tls": , - "tlsCACertPath": "" - }, - "": { - "endpoint": "", - "tls": , - "tlsCACertPath": "" - } - } - } - ``` - - Each security domain (i.e., unique ledger, like a Fabric channel) scopes a set of JSON objects, each containing specifications of an IIN Agent. The key (`` for example) in each is the IIN Agent's name, which can be the organization's MSP ID (for a Fabric network). The value is another JSON object, containing an `endpoint` with a hostname and port for the agent. - - **Enabling TLS**: To communicate with a given IIN Agent using TLS (i.e., if that agent is TLS-enabled), specify `tls` as `true` and that agent's TLS CA certificate path in `tlsCACertPath` (currently only one certificate can be configured) within the JSON object corresponding to that agent. This CA certificate should match the one specified in that IIN Agent's `.env` file, whose configuration we will specify later. -- `security-domain-config.json`: This config file contains list of security domain defined for the network and its members, i.e. it can be list of organizations or channel name. Sample security domain configuration file: - ``` - { - "": "", - "": [ - "", - "" - ] - } - ``` -- `.env`: This sets suitable environment variables within the driver container. Copy the `.env.template` file [from the repository](https://github.com/hyperledger/cacti/blob/main/weaver/core/identity-management/iin-agent/.env.docker.template) and customize it for your purposes, as indicated in the below sample: - ``` - IIN_AGENT_PORT= - IIN_AGENT_TLS= - IIN_AGENT_TLS_CERT_PATH= - IIN_AGENT_TLS_KEY_PATH= - MEMBER_ID= - SECURITY_DOMAIN=network1 - DLT_TYPE=fabric - CONFIG_PATH=./config.json - DNS_CONFIG_PATH=./dnsconfig.json - SECURITY_DOMAIN_CONFIG_PATH=./security-domain-config.json - WEAVER_CONTRACT_ID= - SYNC_PERIOD= - AUTO_SYNC= - TLS_CREDENTIALS_DIR= - DOCKER_IMAGE_NAME=ghcr.io/hyperledger/cacti-weaver-iin-agent - DOCKER_TAG= - EXTERNAL_NETWORK= - ``` - - `IIN_AGENT_ENDPOINT`: The endpoint at which IIN Agent server should listen. E.g.: `0.0.0.0:9500` - - `IIN_AGENT_TLS`: Set this to `true` to enable TLS on IIN Agent server - - `IIN_AGENT_TLS_CERT_PATH`: Path to TLS certificate if TLS is enabled - - `IIN_AGENT_TLS_KEY_PATH`: Path to TLS key if TLS is enabled - - `MEMBER_ID`: Member Id for this IIN Agent. For fabric network, it should be the Organization's MSP ID - - `SECURITY_DOMAIN`: Security domain to which this IIN Agent belongs - - `DLT_TYPE`: To indicate the type of DLT for which this IIN Agent is running. E.g. `fabric` - - `CONFIG_PATH`: Path to ledger specific config file (explained in next subsection) - - `DNS_CONFIG_PATH`: Path to DNS config file explained in previous sub sections - - `SECURITY_DOMAIN_CONFIG_PATH`: Path to security domain config file explained in previous sub sections - - `WEAVER_CONTRACT_ID`: Contract ID for DLT specific Weaver interoperation module installed on network - - `SYNC_PERIOD`: Period at which auto synchronization of memberships from other security domains should happen - - `AUTO_SYNC`: Set this to `true` to enable auto synchronization of memberships from other security domains - - `DOCKER_TAG`: Set this to the desired version of the Weaver IIN Agent [docker image](https://github.com/hyperledger/cacti/pkgs/container/cacti-weaver-iin-agent) - - `EXTERNAL_NETWORK`: Set to the network [name](https://docs.docker.com/compose/networking/) of your Fabric network. - - **Enabling TLS**: - - Make your IIN Agent accept TLS connections by specifying `IIN_AGENT_TLS` as `true` and specifying a TLS certificate file path and private key file path in `IIN_AGENT_TLS_CERT_PATH` and `IIN_AGENT_TLS_KEY_PATH` respectively. The same certificate should be specified in this agent's JSON object in another agent's `dnsconfig.json` file under the appropriate security domain and IIN Agent ID scope. - - You can point to the folder in your host system containing the certificate and key using the `TLS_CREDENTIALS_DIR` variable. (This folder will be synced to the `/opt/iinagent/credentials` folder in the IIN Agent container as specified in the [docker-compose file](https://github.com/hyperledger/cacti/blob/main/weaver/core/identity-management/iin-agent/docker-compose.yml).) Make sure you point to the right certificate and key file paths within the container using the `IIN_AGENT_TLS_CERT_PATH` and `IIN_AGENT_TLS_KEY_PATH` variables respectively. - -- `docker-compose.yaml`: This specifies the properties of the IIN agent container. You can use the [file in the repository](https://github.com/hyperledger/cacti/blob/main/weaver/core/identity-management/iin-agent/docker-compose.yml) verbatim. - -Now to start the IIN agent, navigate to the folder containing the above files and run the following: -```bash -docker-compose up -d -``` - -Repeat the above steps to launch an IIN Agent for every other organization on your channnel, i.e., create similar configuration files in an organization-specific folder. Make sure you: -- Update the organization names in every relevant location in the `config.json`. -- Update `IIN_AGENT_ENDPOINT` and `MEMBER_ID` in the `.env`. - - -#### Ledger Initialization - -To prepare your network for interoperation with a foreign network, you need to record the following to your network channel through the Fabric Interoperation Chaincode: -- **Access control policies**: - Let's take the example of the request made from `trade-finance-network` to `trade-logistics-network` for a B/L earlier in this document. `trade-logistics-network` can have a policy of the following form permitting access to the `GetBillOfLading` function from a client belonging to the `Exporter` organization in `trade-finance-network` as follows: - ```json - { - "securityDomain":"trade-finance-network", - "rules": - [ - { - "principal":"ExporterMSP", - "principalType":"ca", - "resource":"tradelogisticschannel:shipmentcc:GetBillOfLading:*", - "read":true - } - ] - } - ``` - In this sample, a single rule is specified for requests coming from `trade-finance-network`: it states that a `GetBillOfLading` query made to the `shipmentcc` contract installed on the `tradelogisticschannel` channel is permitted for a requestor possessing credentials certified by an MSP with the `ExporterMSP` identity. The `*` at the end indicates that any arguments passed to the function will pass the access control check. - - You need to record this policy rule on your Fabric network's channel by invoking either the `CreateAccessControlPolicy` function or the `UpdateAccessControlPolicy` function on the Fabric Interoperation Chaincode that is already installed on that channel; use the former if you are recording a set of rules for the given `securityDomain` for the first time and the latter to overwrite a set of rules recorded earlier. In either case, the chaincode function will take a single argument, which is the policy in the form of a JSON string (make sure you escape the double quotes before sending the request to avoid parsing errors). You can do this in one of two ways: (1) writing a small piece of code in Layer-2 that invokes the contract using the Fabric SDK Gateway API, or (2) running a `peer chaincode invoke` command from within a Docker container built on the `hyperledger/fabric-tools` image. Either approach should be familiar to a Fabric practitioner. -- **Verification policies**: - Taking the same example as above, an example of a verification policy for a B/L requested by the `trade-finance-network` from the `trade-logistics-network` is as follows: - ```json - { - "securityDomain":"trade-logistics-network", - "identifiers": - [ - { - "pattern":"tradelogisticschannel:shipmentcc:GetBillOfLading:*", - "policy": - { - "type":"Signature", - "criteria": - [ - "ExporterMSP", - "CarrierMSP" - ] - } - } - ] - } - ``` - In this sample, a single verification policy rule is specified for data views coming from `trade-logistics-network`: it states that the data returned by the `GetBillOfLading` query made to the `shipmentcc` chaincode on the `tradelogisticschannel` channel requires as proof two signatures, one from a peer in the organization whose MSP ID is `ExporterMSP` and another from a peer in the organization whose MSP ID is `CarrierMSP`. - - You need to record this policy rule on your Fabric network's channel by invoking either the `CreateVerificationPolicy` function or the `UpdateVerificationPolicy` function on the Fabric Interoperation Chaincode that is already installed on that channel; use the former if you are recording a set of rules for the given `securityDomain` for the first time and the latter to overwrite a set of rules recorded earlier. In either case, the chaincode function will take a single argument, which is the policy in the form of a JSON string (make sure you escape the double quotes before sending the request to avoid parsing errors). As with the access control policy, you can do this in one of two ways: (1) writing a small piece of code in Layer-2 that invokes the contract using the Fabric SDK Gateway API, or (2) running a `peer chaincode invoke` command from within a Docker container built on the `hyperledger/fabric-tools` image. Either approach should be familiar to a Fabric practitioner. - - | Notes | - |:------| - | For any cross-network data request, make sure an access control policy is recorded in the _source network_ (`trade-logistics-network` in the above example) and a corresponding verification policy is recorded in the _destination network_ (`trade-finance-network` in the above example) before any relay request is triggered. | -- **Local network security domain (membership) configuration**: - Recall the code snippet added to your application in the "Identity Administration" section. Exercise that code snippet, exposed either through a function API or an HTTP endpoint, to record the initial local membership for the relevant network channels. - -Your Fabric network is now up and running with the necessary Weaver components, and your network's channel's ledger is bootstrapped with the initial configuration necessary for cross-network interactions! diff --git a/weaver/samples/corda/corda-simple-application/build.gradle b/weaver/samples/corda/corda-simple-application/build.gradle index d99ea6c1f4..2305b6a040 100644 --- a/weaver/samples/corda/corda-simple-application/build.gradle +++ b/weaver/samples/corda/corda-simple-application/build.gradle @@ -37,7 +37,7 @@ buildscript { } plugins { - id "com.jfrog.artifactory" version "4.16.1" + id "com.jfrog.artifactory" version "5.2.3" id "maven-publish" id 'org.jetbrains.dokka' version '0.10.1' }