hyperledger-labs / fabric-opssc

Operations Smart Contract (OpsSC) for Hyperledger Fabric v2.x
Apache License 2.0
26 stars 10 forks source link

Operations Smart Contract (OpsSC) for Hyperledger Fabric v2.x

Overview

Operations Smart Contract (OpsSC) is smart contract-based system operations for blockchain-based systems. This enables decentralized system operations over multiple organizations effectively. This repository provides a system operation tool using the OpsSC for Hyperledger Fabric v2.x.

In the OpsSC:

This enables execution of cross-domain operations without a single point of trust (SPOT) and sharing credentials by blockchain consensus establishment. Also it enables to execute unified procedures with unified configuration parameters based on the smart contract.

In Fabric v2.x, individual operational tasks (e.g., peer commands) has been refined, and SPOT is eliminated (e.g., introduced the new chaincode lifecycle). The OpsSC for Fabric v2.x aims to enhance negotiation and (decentralized) automation capabilities to enable more efficient (typical) end-to-end operational workflows using these individual tasks and more.

As the first step for applying this to Fabric v2.x, we have developed a purpose-specific OpsSC which is essential for managing the Fabric network.

Materials

Please refer to the following files to get the detail of OpsSC for Hyperledger Fabric v2.x.

Other related materials

The other materials (the OpsSC concept etc.):

Feedback and contribution welcome!

Prerequisites

Components

The current implementation of the OpsSC for Hyperledger Fabric v2.x consists of the following components:

Currently, the OpsSC chaincodes and the Fabric ConfigTX CLI are implemented in Go. On the other hand, the OpsSC agent and API server are implemented in TypeScript. The main reason for using two languages is that the Fabric SDK Go is not yet GA at the time of development.

Folder structures

(fabric-opssc)
|- chaincode/                  ... Source code for the OpsSC chaincodes (in Go)
|   |- chaincode-ops/          ... Source code for the OpsSC chaincode for operating chaincode (in Go)
|   |- channel-ops/            ... Source code for the OpsSC chaincode for operating channel (in Go)
|- common/                     ... Source code for common features for the OpsSC agent and API server (in TypeScript)
|- configtx-cli/               ... Source code for the Fabric ConfigTX CLI (in Go)
|- docs/                       ... Documents for OpsSC (e.g., Design memo)
|- integration/                ... Integration tests for the OpsSC (in TypeScript)
|- opssc-agent/                ... Source code for the OpsSC agent (in TypeScript)
|- opssc-api-server/           ... Source code for the OpsSC API server (in TypeScript)
|- sample-environments/        ... Sample environments for trying to run the OpsSC
|   |- fabric-samples/
|       |- test-network        ... Docker-based sample environment (This is based on test-network in fabric-samples. This is internally used by the integration tests.)
|   |- k8s-support/            ... K8s-based sample environment (This is based on test-network-k8s in fabric-samples.)
|- Dockerfile-for-agent        ... Docker image definition for the OpsSC agent
|- Dockerfile-for-api-server   ... Docker image definition for the OpsSC API server
|- Makefile                    ... Make file to build docker images and run the integration tests etc.

Assumed Hyperledger Fabric environment

The current implementation assumes the following Fabric network:

Try the OpsSC in the sample environment

This repository includes a sample environment for running the OpsSC based on test-network in fabric-samples. Running the OpsSC sample environment gives you a rough idea of how the OpsSC works and how to use it in a Fabric network.

NOTE: This sample will collide with the original test-network in fabric-samples and destroy the environment. So, please tear down the existing test-network environment before trying the sample.

The following shows how to set up this sample environment first. After that, as a typical example of decentralized operation using the OpsSC, it will explain a procedure for creating a new channel, deploying a new chaincode on the channel and adding a new organization using the OpsSC.

System configuration of the test-network

The original test-network provides scripts to run a simple Fabric test network and to create channels and deploy chaincodes in centralized manner. After deploying the test network, you can try to do decentralized operations over multiple organizations by using the OpsSC.

The test network customized for the OpsSC has the following initial configuration:

The customized test network has the following differences from the original version:

Preparations

Preparation 1: Download binaries and docker images for Hyperledger Fabric

By running the following commands, download the binaries and docker images for Hyperledger Fabric used by test-network:

$ cd ${FABRIC_OPSSC}/sample-environments/fabric-samples
$ export FABRIC_VERSION=2.5.2
$ export FABRIC_CA_VERSION=1.5.6
$ curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/main/scripts/install-fabric.sh | bash -s -- -f ${FABRIC_VERSION} -c ${FABRIC_CA_VERSION} b d

$ ls bin # Confirm the target version binaries are downloaded
configtxgen  configtxlator  cryptogen  discover  fabric-ca-client  fabric-ca-server  idemixgen  orderer  osnadmin  peer

${FABRIC_OPSSC} means the fabric-opssc directory.

See the official documentation for more details.

Preparation 2: Build Fabric ConfigTX CLI

Build the Fabric ConfigTX CLI by running the following commands:

$ cd ${FABRIC_OPSSC}/configtx-cli
$ make build

$ ls bin # Command to confirm the binary is created
fabric-configtx-cli

Preparation 3: Build docker images for OpsSC Agent and API Server

Build the docker images for OpsSC Agent and API Server by running the following commands:

$ cd ${FABRIC_OPSSC}
$ make docker

$ docker images # Command to confirm the images are created
REPOSITORY                                                     TAG                              IMAGE ID            CREATED             SIZE
(...)
fabric-opssc/opssc-agent                                       latest                           44e30c583566        44 hours ago        1.49GB
fabric-opssc/opssc-api-server                                  latest                           154c4a550823        44 hours ago        1.43GB
(...)

By default, the command builds images for Fabric v2.5 series. If you want to build images for v2.2 series, you should set the FABRIC_TWO_DIGIT_VERSION variable.

Run the test network

Launch the test network by using the following commands:

$ cd ${FABRIC_OPSSC}/sample-environments/fabric-samples/test-network
$ ./network.sh up -ca -i ${FABRIC_VERSION} -cai ${FABRIC_CA_VERSION}

Initialize the OpsSC on the test network

Create ops-channel as the ops channel and OpsSC chaincodes for operating chaincodes and channels to the ops-channel by running the following commands:

# Create the ops channel
$ export OPS_CHANNEL_ID=ops-channel
$ ./network.sh createChannel -c ${OPS_CHANNEL_ID}

# Deploy the OpsSC chaincodes on the ops channel
$ export OPS_CC_NAME=channel-ops
$ ./network.sh deployCC -c ${OPS_CHANNEL_ID} -ccn ${OPS_CC_NAME} -ccp ../../../chaincode/${OPS_CC_NAME} -ccl go

$ export OPS_CC_NAME=chaincode-ops
$ ./network.sh deployCC -c ${OPS_CHANNEL_ID} -ccn ${OPS_CC_NAME} -ccp ../../../chaincode/${OPS_CC_NAME} -ccl go

# Add channel information (including joining organizations) for the system channel and the ops channel to the OpsSC
$ ./registerNetworkInfoToOpsSC.sh ${OPS_CHANNEL_ID} system-channel system
$ ./registerNetworkInfoToOpsSC.sh ${OPS_CHANNEL_ID} ${OPS_CHANNEL_ID} ops
# Launch the OpsSC agents and API servers for Org1MSP and Org2MSP
$ docker-compose -f docker/docker-compose-opssc-api-servers.yaml up -d
$ docker-compose -f docker/docker-compose-opssc-agents.yaml up -d

# Do health check for the agents and servers
## Check for the API server for Org1MSP
$ curl -X GET http://localhost:5000/healthz
OK
## Check for the API server for Org2MSP
$ curl -X GET http://localhost:5001/healthz
OK
## Check for the agent for Org1MSP
$ curl -X GET http://localhost:5500/healthz
OK
## Check for the agent for Org2MSP
$ curl -X GET http://localhost:5501/healthz
OK

The above commands are executed in a centralized manner. From here on, decentralized operations over multiple organizations in the test network can be executed by using the OpsSC.

Create a new channel using the OpsSC

To create a new channel (named mychannel) based on the "SampleConsortium" consortium, an administrator for Org1MSP sends a request for the channel update proposal to the OpsSC API server first. In the sample environment, the API server for Org1MSP serves on port 5000.

The request is:

$ curl -X POST http://localhost:5000/api/v1/channel/proposals/create_mychannel \
-H "Expect:" \
-H 'Content-Type: application/json; charset=utf-8' \
-d @- <<EOF
{
  "proposal": {
    "channelID": "mychannel",
    "description": "Create mychannel",
    "action": "create",
    "opsProfile": {
      "Consortium": "SampleConsortium",
      "Application": {
        "Capabilities": [
          "V2_0"
        ],
        "Policies": {
          "Readers": {
            "Type": "ImplicitMeta",
            "Rule": "ANY Readers"
          },
          "Writers": {
            "Type": "ImplicitMeta",
            "Rule": "ANY Writers"
          },
          "Admins": {
            "Type": "ImplicitMeta",
            "Rule": "ANY Admins"
          },
          "LifecycleEndorsement": {
            "Type": "ImplicitMeta",
            "Rule": "MAJORITY Endorsement"
          },
          "Endorsement": {
            "Type": "ImplicitMeta",
            "Rule": "MAJORITY Endorsement"
          }
        },
        "Organizations": [
          "Org1MSP",
          "Org2MSP"
        ]
      }
    }
  }
}
EOF
"create_mychannel" # 200 OK with the proposal ID

Next, an administrator for Org2MSP confirms the contents of the proposal and votes for the proposal via the API server. In the sample environment, the API server for Org2MSP serves on port 5001.

The command to get the proposal with the ID is the following:

$ curl -X GET http://localhost:5001/api/v1/channel/proposals/create_mychannel | jq
{
  "docType": "proposal",
  "ID": "create_mychannel",
  "channelID": "mychannel",
  "description": "Create mychannel",
  "creator": "Org1MSP",
  "status": "proposed",
  "opsProfile": {
    "Application": {
      "Capabilities": [
        "V2_0"
      ],
      "Organizations": [
        "Org1MSP",
        "Org2MSP"
      ],
(...)

The command to vote for the proposal is:

$ curl -X POST http://localhost:5001/api/v1/channel/proposals/create_mychannel/vote
"" # 200 OK

When creating a channel, it will be passed if a majority of the votes for the proposal are collected by the organizations participating in the system channel.

After the proposal is passed (approved), the agents create mychannel based on the proposal and join all their peers described in the connection profile to mychannel automatically.

By using the following command, wait for the status of the proposal to be committed:

$ curl -X GET http://localhost:5001/api/v1/channel/proposals/create_mychannel | jq
{
  "docType": "proposal",
  "ID": "create_mychannel",
  "channelID": "mychannel",
  "description": "Create mychannel",
  "creator": "Org1MSP",
  "status": "committed", # Updated the status to committed
(...)

By using the following command, you can confirm the channel information:

$ curl -X GET http://localhost:5001/api/v1/channel/getChannels | jq
[
  {
    "docType": "channel",
    "ID": "mychannel",
    "channelType": "application",
    "organizations": {
      "Org1MSP": "",
      "Org2MSP": ""
    }
  },
  (...)
]

Deploy a new chaincode by using the OpsSC

To deploy a new chaincode (basic) to mychannel, an administrator for Org1MSP sends a request for the chaincode update proposal to the OpsSC API server first.

These commands are:

# Convert the endorsement policy for the chaincode to base64 because the API only accepts base64 encoded endorsement policy.
$ echo -n /Channel/Application/Endorsement | base64
L0NoYW5uZWwvQXBwbGljYXRpb24vRW5kb3JzZW1lbnQ=

# Send the request
$ curl -X POST http://localhost:5000/api/v1/chaincode/proposals/deploy_basic \
-H "Expect:" \
-H 'Content-Type: application/json; charset=utf-8' \
-d @- <<EOF
{
  "proposal": {
    "channelID": "mychannel",
    "chaincodeName": "basic",
    "chaincodePackage": {
      "repository": "github.com/hyperledger-labs/fabric-opssc",
      "pathToSourceFiles": "sample-environments/fabric-samples/asset-transfer-basic/chaincode-go",
      "commitID": "main",
      "type": "golang"
    },
    "chaincodeDefinition": {
      "sequence": 1,
      "initRequired": false,
      "validationParameter": "L0NoYW5uZWwvQXBwbGljYXRpb24vRW5kb3JzZW1lbnQ="
    }
  }
}
EOF
{"docType":"proposal","ID":"deploy_basic","creator":"Org1MSP","channelID":"mychannel",(...)} # 200 OK with the requested proposal

Next, an administrator for Org2MSP confirms the contents of the proposal and votes for the proposal via the API server.

The command to get the proposal with the ID is the following:

$ curl -X GET http://localhost:5001/api/v1/chaincode/proposals/deploy_basic
{"docType":"proposal","ID":"deploy_basic","creator":"Org1MSP","channelID":"mychannel","chaincodeName":"basic", ... ,"status":"proposed",...}

The command to vote for the proposal is:

$ curl -X POST http://localhost:5001/api/v1/chaincode/proposals/deploy_basic/vote
"" # 200 OK

When deploying a chaincode, it will be passed if a majority of the votes for the proposal are collected by the organizations participating in the channel.

After the proposal is passed (approved), an agent for each organization downloads the source code of the chaincode from the remote repository specified in the proposal. Then, the agents package and install the downloaded source code and approve and commit the chaincode definition based on the installed chaincode and the content of proposal.

By using the following command, wait for the status of the proposal to be committed:

$ curl -X GET http://localhost:5001/api/v1/chaincode/proposals/deploy_basic | jq 'select(.status == "committed")' # wait for the status to be "committed"
{
  "docType": "proposal",
  "ID": "deploy_basic",
  (...)
  "status": "committed",
  (...)
}

By using the following commands, can confirm that the chaincode is deployed:

# Confirm basic is installed on the organization (the following command is for Org2MSP)
$ curl -X GET 'http://localhost:5001/api/v1/chaincode/getInstalledChaincodes' | jq '.installed_chaincodes[] | select(.label == "basic_1")'
{
  "package_id": "basic_1:7cb90e2dd24972089aaac0180a5c448f3fa7bb9b5cc990d9dcb66ae414e1c027",
  "label": "basic_1",
  "references": {
    "mychannel": {
      "chaincodes": [
        {
          "name": "basic",
          "version": "1"
        }
      ]
    }
  }
}

# Confirm basic is committed on mychannel (the following command is for Org2MSP)
$ curl -X GET 'http://localhost:5001/api/v1/chaincode/queryChaincodeDefinition?channelID=mychannel&chaincodeName=basic' | jq
{
  "sequence": "1",
  "version": "1",
  "endorsement_plugin": "escc",
  "validation_plugin": "vscc",
  "validation_parameter": "EiAvQ2hhbm5lbC9BcHBsaWNhdGlvbi9FbmRvcnNlbWVudA==",
  "collections": {},
  "approvals": {
    "Org2MSP": true,
    "Org1MSP": true
  }
}

By using the following commands, can invoke and query the chaincode as a test:

$ curl -X POST 'http://localhost:5000/api/v1/utils/invokeTransaction' \
-H "Expect:" \
-H 'Content-Type: application/json; charset=utf-8' \
-d @- <<EOF
{
  "channelID": "mychannel",
  "ccName": "basic",
  "func": "CreateAsset",
  "args": ["asset101", "blue", "5", "Tomoko", "300"]
}
EOF
""

$ curl -X GET 'http://localhost:5000/api/v1/utils/queryTransaction?channelID=mychannel&ccName=basic&func=GetAllAssets&args=[]' | jq
[
  {
    "ID": "asset101",
    "color": "blue",
    "size": 5,
    "owner": "Tomoko",
    "appraisedValue": 300
  }
]

Add a new organization to each channel using the OpsSC

Belows are the steps to add a new organization (named Org4MSP), which has a peer and an ordering nodes as same as the other organizations, to each channel. These steps are a bit more complicated than the operations described above.

First, keys and certificates for peers and orderers for Org4MSP should be prepared. Here, execute the following utility script to launch a CA for Org4MSP and then issue keys and certificates for peers and orderers for Org4MSP using the CA.

# Launch a CA for Org4MSP and then issue keys and certificates for peers and orderers for Org4MSP using the CA
$ ./create-org4-artifacts-for-test-network.sh

# Convert keys and certificates (PEM files) to JSON and store them as environment variables (for simplifying the following steps)
$ export ORG4_CA_CERT=$(cat organizations/peerOrganizations/org4.example.com/msp/cacerts/localhost-13054-ca-org4.pem | sed -e ':loop; N; $!b loop; s/\n/\\n/g')
$ echo "$ORG4_CA_CERT"

$ export ORG4_TLS_CA_CERT=$(cat organizations/peerOrganizations/org4.example.com/msp/tlscacerts/ca.crt | sed -e ':loop; N; $!b loop; s/\n/\\n/g')
$ echo "$ORG4_TLS_CA_CERT"

$ export ORG4_ORDERER_SERVER_TLS_CERT=$(cat organizations/peerOrganizations/org4.example.com/orderers/orderer0.org4.example.com/tls/server.crt | sed -e ':loop; N; $!b loop; s/\n/\\n/g')
$ echo "$ORG4_ORDERER_SERVER_TLS_CERT"

The above will be done outside of OpsSC because the step itself does not require inter organizational negotiation. Here, let's assume that Org4MSP does the above and shares the MSP information including the certificates with Org1MSP.

Next, an administrator for Org1MSP sends a request for the channel update proposal to add Org4MSP to system-channel to the OpsSC API server.

The request is:

$ curl -X POST http://localhost:5000/api/v1/channel/proposals/add_org4_to_system-channel \
-H "Expect:" \
-H 'Content-Type: application/json; charset=utf-8' \
-d @- <<EOF
{
  "proposal": {
    "channelID": "system-channel",
    "description": "Add org4 to system channel",
    "action": "update",
    "opsProfile": [
      {
        "Command": "set-org",
        "Parameters": {
          "OrgType": "Consortiums|Orderer",
          "Org": {
            "Name": "Org4MSP",
            "ID": "Org4MSP",
            "MSP": {
              "RootCerts": [
                "$ORG4_CA_CERT"
              ],
              "TLSRootCerts": [
                "$ORG4_TLS_CA_CERT"
              ],
              "NodeOUs": {
                "Enable": true,
                "ClientOUIdentifier": {
                  "OrganizationalUnitIdentifier": "client",
                  "Certificate": "$ORG4_CA_CERT"
                },
                "PeerOUIdentifier": {
                  "OrganizationalUnitIdentifier": "peer",
                  "Certificate": "$ORG4_CA_CERT"
                },
                "AdminOUIdentifier": {
                  "OrganizationalUnitIdentifier": "admin",
                  "Certificate": "$ORG4_CA_CERT"
                },
                "OrdererOUIdentifier": {
                  "OrganizationalUnitIdentifier": "orderer",
                  "Certificate": "$ORG4_CA_CERT"
                }
              }
            },
            "Policies": {
              "Readers": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.admin', 'Org4MSP.peer', 'Org4MSP.client')"
              },
              "Writers": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.admin', 'Org4MSP.client')"
              },
              "OrderingReaders": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.admin', 'Org4MSP.orderer')"
              },
              "OrderingWriters": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.admin', 'Org4MSP.orderer')"
              },
              "Admins": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.admin')"
              },
              "Endorsement": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.peer')"
              }
            },
            "AnchorPeers": [
              {
                "Host": "peer0.org4.example.com",
                "Port": 13051
              }
            ],
            "OrdererEndpoints": [
              "orderer0.org4.example.com:13050"
            ]
          }
        }
      },
      {
        "Command": "set-consenter",
        "Parameters": {
          "Consenter": {
            "Host": "orderer0.org4.example.com",
            "Port": 13050,
            "ClientTLSCert": "$ORG4_ORDERER_SERVER_TLS_CERT",
            "ServerTLSCert": "$ORG4_ORDERER_SERVER_TLS_CERT"
          }
        }
      }
    ]
  }
}
EOF
"add_org4_to_system-channel" # 200 OK with the proposal ID

Then, an administrator for Org2MSP votes for the proposal via the API server:

$ curl -X POST http://localhost:5001/api/v1/channel/proposals/add_org4_to_system-channel/vote
""

Do the same for the remaining channels (ops-channel and mychannel):

$ curl -X POST http://localhost:5000/api/v1/channel/proposals/add_org4_to_ops-channel \
-H "Expect:" \
-H 'Content-Type: application/json; charset=utf-8' \
-d @- <<EOF
{
  "proposal": {
    "channelID": "ops-channel",
    "description": "Add org4 to ops-channel",
    "action": "update",
    "opsProfile": [
      {
        "Command": "set-org",
        "Parameters": {
          "OrgType": "Application|Orderer",
          "Org": {
            "Name": "Org4MSP",
            "ID": "Org4MSP",
            "MSP": {
              "RootCerts": [
                "$ORG4_CA_CERT"
              ],
              "TLSRootCerts": [
                "$ORG4_TLS_CA_CERT"
              ],
              "NodeOUs": {
                "Enable": true,
                "ClientOUIdentifier": {
                  "OrganizationalUnitIdentifier": "client",
                  "Certificate": "$ORG4_CA_CERT"
                },
                "PeerOUIdentifier": {
                  "OrganizationalUnitIdentifier": "peer",
                  "Certificate": "$ORG4_CA_CERT"
                },
                "AdminOUIdentifier": {
                  "OrganizationalUnitIdentifier": "admin",
                  "Certificate": "$ORG4_CA_CERT"
                },
                "OrdererOUIdentifier": {
                  "OrganizationalUnitIdentifier": "orderer",
                  "Certificate": "$ORG4_CA_CERT"
                }
              }
            },
            "Policies": {
              "Readers": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.admin', 'Org4MSP.peer', 'Org4MSP.client')"
              },
              "Writers": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.admin', 'Org4MSP.client')"
              },
              "OrderingReaders": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.admin', 'Org4MSP.orderer')"
              },
              "OrderingWriters": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.admin', 'Org4MSP.orderer')"
              },
              "Admins": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.admin')"
              },
              "Endorsement": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.peer')"
              }
            },
            "AnchorPeers": [
              {
                "Host": "peer0.org4.example.com",
                "Port": 13051
              }
            ],
            "OrdererEndpoints": [
              "orderer0.org4.example.com:13050"
            ]
          }
        }
      },
      {
        "Command": "set-consenter",
        "Parameters": {
          "Consenter": {
            "Host": "orderer0.org4.example.com",
            "Port": 13050,
            "ClientTLSCert": "$ORG4_ORDERER_SERVER_TLS_CERT",
            "ServerTLSCert": "$ORG4_ORDERER_SERVER_TLS_CERT"
          }
        }
      }
    ]
  }
}
EOF
"add_org4_to_ops-channel" # 200 OK with the proposal ID
$ curl -X POST http://localhost:5001/api/v1/channel/proposals/add_org4_to_ops-channel/vote
""
$ curl -X POST http://localhost:5000/api/v1/channel/proposals/add_org4_to_mychannel \
-H "Expect:" \
-H 'Content-Type: application/json; charset=utf-8' \
-d @- <<EOF
{
  "proposal": {
    "channelID": "mychannel",
    "description": "Add org4 to mychannel",
    "action": "update",
    "opsProfile": [
      {
        "Command": "set-org",
        "Parameters": {
          "OrgType": "Application|Orderer",
          "Org": {
            "Name": "Org4MSP",
            "ID": "Org4MSP",
            "MSP": {
              "RootCerts": [
                "$ORG4_CA_CERT"
              ],
              "TLSRootCerts": [
                "$ORG4_TLS_CA_CERT"
              ],
              "NodeOUs": {
                "Enable": true,
                "ClientOUIdentifier": {
                  "OrganizationalUnitIdentifier": "client",
                  "Certificate": "$ORG4_CA_CERT"
                },
                "PeerOUIdentifier": {
                  "OrganizationalUnitIdentifier": "peer",
                  "Certificate": "$ORG4_CA_CERT"
                },
                "AdminOUIdentifier": {
                  "OrganizationalUnitIdentifier": "admin",
                  "Certificate": "$ORG4_CA_CERT"
                },
                "OrdererOUIdentifier": {
                  "OrganizationalUnitIdentifier": "orderer",
                  "Certificate": "$ORG4_CA_CERT"
                }
              }
            },
            "Policies": {
              "Readers": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.admin', 'Org4MSP.peer', 'Org4MSP.client')"
              },
              "Writers": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.admin', 'Org4MSP.client')"
              },
              "OrderingReaders": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.admin', 'Org4MSP.orderer')"
              },
              "OrderingWriters": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.admin', 'Org4MSP.orderer')"
              },
              "Admins": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.admin')"
              },
              "Endorsement": {
                "Type": "Signature",
                "Rule": "OR('Org4MSP.peer')"
              }
            },
            "AnchorPeers": [
              {
                "Host": "peer0.org4.example.com",
                "Port": 13051
              }
            ],
            "OrdererEndpoints": [
              "orderer0.org4.example.com:13050"
            ]
          }
        }
      },
      {
        "Command": "set-consenter",
        "Parameters": {
          "Consenter": {
            "Host": "orderer0.org4.example.com",
            "Port": 13050,
            "ClientTLSCert": "$ORG4_ORDERER_SERVER_TLS_CERT",
            "ServerTLSCert": "$ORG4_ORDERER_SERVER_TLS_CERT"
          }
        }
      }
    ]
  }
}
EOF
"add_org4_to_mychannel" # 200 OK with the proposal ID
$ curl -X POST http://localhost:5001/api/v1/channel/proposals/add_org4_to_mychannel/vote
""

By using the following command, you can see that Org4MSP is added to each channel:

$ curl -X GET http://localhost:5001/api/v1/channel/getChannels | jq
[
  {
    "docType": "channel",
    "ID": "mychannel",
    "channelType": "application",
    "organizations": {
      "Org1MSP": "",
      "Org2MSP": "",
      "Org4MSP": "" # Added
    }
  },
  (...)
]

Next, execute the following utility script to launch the peer, the ordering node, the OpsSC agent and the API server for Org4MSP:

# Launch the peer, the ordering node, the OpsSC agent and the API server for Org4MSP
$ ./launch-org4-nodes-for-test-network.sh

This script internally fetches the system config block and then launches nodes for Org4MSP using the system config block. In actual use cases, an organization which already has joined in the network (Org1MSP or Org2MSP) should fetch the block and send it to Org4MSP.

After launching the nodes, the agent for Org4MSP automatically joins the organization to the channels and deploys the OpsSC chaincodes on the peer. It also deploys the other existing chaincodes which has been deployed via OpsSC on the peer.

By running the following commands, you can confirm whether the agent and API server for Org4MSP get ready:

## Check for the API server for Org4MSP
$ curl -X GET http://localhost:5003/healthz
OK
## Check for the agent for Or4MSP (NOTE: Take about 2-3 minutes to be "OK")
$ curl -X GET http://localhost:5503/healthz
OK

By running the following commands, you can confirm that the nodes for Org4MSP get ready and deployed basic chaincode which were deployed the previous operations.

$ export PATH=${PWD}/../bin:$PATH
$ export FABRIC_CFG_PATH=$PWD/../config/

$ export CORE_PEER_TLS_ENABLED=true
$ export CORE_PEER_LOCALMSPID="Org4MSP"
$ export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt
$ export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org4.example.com/users/Admin@org4.example.com/msp
$ export CORE_PEER_ADDRESS=localhost:13051

$ peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'

(Optional.) Tear down the test network

You can tear down the sample environment by using the following command.

$ cd ${FABRIC_OPSSC}/integration
$ ./teardownDockerEnv.sh

If any of the above steps fail in the middle, reset the environment with this command and try again.

Learn more

Integration test

For other more detailed usage, refer to the integration test.

Running with k8s environments

See the documents

Limitations

The current implementation has limitations. The main limitations are as follows:

Future work

Changes

v0.4.0 (May 16, 2023)

v0.3.0 (Oct. 27, 2022)

v0.2.0 (Oct. 5, 2021)

v0.1.0 (Jan. 9, 2021)

Authors

License

Apache-2.0 (See LICENSE)