{"id":22727040,"url":"https://github.com/kchristidis/fabric-example","last_synced_at":"2025-04-13T21:42:59.032Z","repository":{"id":64305252,"uuid":"122212653","full_name":"kchristidis/fabric-example","owner":"kchristidis","description":"A succinct play-by-play of some major Fabric operations","archived":false,"fork":false,"pushed_at":"2018-11-23T18:45:39.000Z","size":91,"stargazers_count":8,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-13T10:08:24.310Z","etag":null,"topics":["documentation","fabric","hyperledger","hyperledger-fabric"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kchristidis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-20T14:58:07.000Z","updated_at":"2025-02-23T16:58:47.000Z","dependencies_parsed_at":"2023-01-15T10:30:54.068Z","dependency_job_id":null,"html_url":"https://github.com/kchristidis/fabric-example","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kchristidis%2Ffabric-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kchristidis%2Ffabric-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kchristidis%2Ffabric-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kchristidis%2Ffabric-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kchristidis","download_url":"https://codeload.github.com/kchristidis/fabric-example/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248788867,"owners_count":21161726,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["documentation","fabric","hyperledger","hyperledger-fabric"],"created_at":"2024-12-10T17:08:37.916Z","updated_at":"2025-04-13T21:42:59.006Z","avatar_url":"https://github.com/kchristidis.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fabric-example\n\nA succinct play-by-play of some major Fabric operations.\n\n## Steps\n\n### Bring up the Vagrant environment\n\n```bash\n$ git clone git@github.com:kchristidis/fabric.git\n$ git checkout fabric-example-1.2\n$ cd devenv\n$ vagrant up\n$ vagrant ssh\n```\n\nATTN: **All commands below** assume `$GOPATH/src/github.com/kchristidis/fabric-example/` as the starting point.\n\n### Bootstrap\n\nEdit `config/cryptogen.yaml` to reflect your network's structure.\n\nGenerate the crypto material for the network:\n\n```bash\n$ cryptogen generate --config=./config/cryptogen.yaml --output=crypto\nclark.example.com\namelia.example.com\n```\n\nCreate the genesis block for the ordering service and consortium:\n\n```bash\n$ configtxgen -configPath=./config -profile SystemGenesis -channelID systemchain -outputBlock ./config/genesis.block\n2018-07-28 13:39:35.906 UTC [common/tools/configtxgen] main -\u003e INFO 001 Loading configuration\n2018-07-28 13:39:35.992 UTC [msp] getMspConfig -\u003e INFO 002 Loading NodeOUs\n2018-07-28 13:39:36.003 UTC [msp] getMspConfig -\u003e INFO 003 Loading NodeOUs\n2018-07-28 13:39:36.004 UTC [common/tools/configtxgen] doOutputBlock -\u003e INFO 004 Generating genesis block\n2018-07-28 13:39:36.007 UTC [common/tools/configtxgen] doOutputBlock -\u003e INFO 005 Writing genesis block\n```\n\nBring up the Docker composition for the entire network:\n\n```bash\n$ cd docker \u0026\u0026 docker-compose up -d\nCreating network \"fabric_default\" with the default driver\nCreating zookeeper.joe.example.com ...\nCreating zookeeper.joe.example.com ... done\nCreating kafka.joe.example.com ...\nCreating kafka.joe.example.com ... done\nCreating joe.example.com ...\nCreating joe.example.com ... done\nCreating p0.clark.example.com ...\nCreating p0.amelia.example.com ...\nCreating p0.clark.example.com\nCreating p0.clark.example.com ... done\nCreating admin.clark.example.com ...\nCreating p0.amelia.example.com ... done\nCreating admin.amelia.example.com ...\nCreating admin.amelia.example.com ... done\n```\n\n```bash\n$ cd docker \u0026\u0026 docker-compose ps\n          Name                 Command       State                       Ports\n---------------------------------------------------------------------------------------------------\nadmin.amelia.example.com   /bin/bash         Up\nadmin.clark.example.com    /bin/bash         Up\njoe.example.com            orderer           Up      0.0.0.0:7050-\u003e7050/tcp\np0.amelia.example.com      peer node start   Up      0.0.0.0:9051-\u003e7051/tcp, 0.0.0.0:9053-\u003e7053/tcp\np0.clark.example.com       peer node start   Up      0.0.0.0:8051-\u003e7051/tcp, 0.0.0.0:8053-\u003e7053/tcp\n```\n\n### Create a channel\n\nGenerate the channel creation transaction:\n\n```bash\n$ configtxgen -configPath=./config -profile ClarksChannel -channelID clarkschannel -outputCreateChannelTx config/clarkschannel.tx\n2018-07-28 13:41:05.479 UTC [common/tools/configtxgen] main -\u003e INFO 001 Loading configuration\n2018-07-28 13:41:05.516 UTC [common/tools/configtxgen] doOutputChannelCreateTx -\u003e INFO 002 Generating new channel configtx\n2018-07-28 13:41:05.530 UTC [msp] getMspConfig -\u003e INFO 003 Loading NodeOUs\n2018-07-28 13:41:05.535 UTC [common/tools/configtxgen] doOutputChannelCreateTx -\u003e INFO 004 Writing new channel tx\n```\n\nCreate the channel via Clark's peer:\n\n```bash\n$ docker exec -ti admin.clark.example.com bash\n$ peer channel create --orderer joe.example.com:7050 --channelID clarkschannel --file $SHARED_PATH/clarkschannel.tx --tls --cafile $ORDERER_CA\n2018-07-28 13:41:27.417 UTC [channelCmd] InitCmdFactory -\u003e INFO 001 Endorser and orderer connections initialized\n2018-07-28 13:41:27.435 UTC [cli/common] readBlock -\u003e INFO 002 Got status: \u0026{NOT_FOUND}\n2018-07-28 13:41:27.442 UTC [channelCmd] InitCmdFactory -\u003e INFO 003 Endorser and orderer connections initialized\n2018-07-28 13:41:27.645 UTC [cli/common] readBlock -\u003e INFO 004 Received block: 0\n```\n\nUse the returned block and have the peer join the channel:\n\n```bash\n$ docker exec -ti admin.clark.example.com bash\n$ peer channel join --blockpath clarkschannel.block\n2018-07-28 13:42:02.755 UTC [channelCmd] InitCmdFactory -\u003e INFO 001 Endorser and orderer connections initialized\n2018-07-28 13:42:02.804 UTC [channelCmd] executeJoin -\u003e INFO 002 Successfully submitted proposal to join channel\n```\n\n### Install, instantiate, invoke chaincode\n\nInstall a chaincode on Clark's peer:\n\n```bash\n$ docker exec -ti admin.clark.example.com bash\n$ peer chaincode install --name clarkschaincode --version 1.0 --path github.com/kchristidis/fabric-example/chaincode\n2018-07-28 13:43:10.203 UTC [chaincodeCmd] checkChaincodeCmdParams -\u003e INFO 001 Using default escc\n2018-07-28 13:43:10.203 UTC [chaincodeCmd] checkChaincodeCmdParams -\u003e INFO 002 Using default vscc\n2018-07-28 13:43:10.401 UTC [chaincodeCmd] install -\u003e INFO 003 Installed remotely response:\u003cstatus:200 payload:\"OK\" \u003e\n```\n\nInstantiate it on the channel:\n\n```bash\n$ docker exec -ti admin.clark.example.com bash\n$ peer chaincode instantiate --orderer joe.example.com:7050 --tls --cafile $ORDERER_CA --channelID clarkschannel --name clarkschaincode --version 1.0 -c '{\"Args\":[\"init\",\"a\", \"100\", \"b\",\"200\"]}' --policy \"OR ('ClarkMSP.member')\"\n2018-07-28 13:43:44.929 UTC [chaincodeCmd] checkChaincodeCmdParams -\u003e INFO 001 Using default escc\n2018-07-28 13:43:44.929 UTC [chaincodeCmd] checkChaincodeCmdParams -\u003e INFO 002 Using default vscc\n```\n\nQuery the chaincode to confirm the instantiation was successful:\n\n```bash\n$ docker exec -ti admin.clark.example.com bash\n$ peer chaincode query --channelID clarkschannel --name clarkschaincode --ctor '{\"Args\":[\"query\", \"a\"]}'\n100\n```\n\nInvoke the chaincode:\n\n```bash\n$ docker exec -ti admin.clark.example.com bash\n$ peer chaincode invoke --orderer joe.example.com:7050  --tls --cafile $ORDERER_CA  --channelID clarkschannel --name clarkschaincode --ctor '{\"Args\":[\"invoke\",\"a\",\"b\",\"10\"]}'\n2018-07-28 13:45:02.241 UTC [chaincodeCmd] chaincodeInvokeOrQuery -\u003e INFO 001 Chaincode invoke successful. result: status:200\n```\n\nQuery the chaincode again to confirm the invocation was successful:\n\n```bash\n$ docker exec -ti admin.clark.example.com bash\n$ peer chaincode query --channelID clarkschannel --name clarkschaincode --ctor '{\"Args\":[\"query\", \"a\"]}'\n90\n```\n\n### Add another org to the channel\n\nLet's get the latest configuration from the channel.\n\n```bash\n$ docker exec -ti admin.clark.example.com bash\n$ peer channel fetch config config_1.pb --channelID clarkschannel --orderer joe.example.com:7050 --tls --cafile $ORDERER_CA\n2018-07-28 13:52:53.724 UTC [channelCmd] InitCmdFactory -\u003e INFO 001 Endorser and orderer connections initialized\n2018-07-28 13:52:53.726 UTC [cli/common] readBlock -\u003e INFO 002 Received block: 2\n2018-07-28 13:52:53.728 UTC [cli/common] readBlock -\u003e INFO 003 Received block: 0\n```\n\nConvert into JSON:\n\n```bash\n$ docker exec -ti admin.clark.example.com bash\n$ configtxlator proto_decode --input config_1.pb --type common.Block | jq .data.data[0].payload.data.config \u003e config_1.json\n```\n\nLet's print the definition for the new org into a JSON file. Do this on your localhost, on this project's root folder (because we need access to the `crypto` folder):\n\n```bash\n$ configtxgen -configPath=./config -channelID clarkschannel -printOrg Amelia \u003e config/amelia.json\n2018-07-28 14:02:37.306 UTC [common/tools/configtxgen] main -\u003e INFO 001 Loading configuration\n2018-07-28 14:02:37.339 UTC [msp] getMspConfig -\u003e INFO 002 Loading NodeOUs\n```\n\nAdd the new org to `Channel/Application`:\n\n```bash\n$ docker exec -ti admin.clark.example.com bash\n$ jq -s '.[0] * {\"channel_group\":{\"groups\":{\"Application\":{\"groups\": {\"Amelia\":.[1]}}}}}' config_1.json $SHARED_PATH/amelia.json \u003e config_mod.json\n```\n\nCreate the protobuf structure that captures the delta between the two configurations (the existing one, and the proposed):\n\n```bash\n$ docker exec -ti admin.clark.example.com bash\n$ configtxlator proto_encode --input config_1.json --type common.Config --output config_1.cc.pb\n$ configtxlator proto_encode --input config_mod.json --type common.Config --output config_mod.cc.pb\n$ configtxlator compute_update --channel_id clarkschannel --original config_1.cc.pb --updated config_mod.cc.pb --output config_upd.pb\n```\n\nConvert this into the envelope structure that will be signed and submitted to the ordering service:\n\n```bash\n$ docker exec -ti admin.clark.example.com bash\n$ configtxlator proto_decode --input config_upd.pb --type common.ConfigUpdate | jq . \u003e config_upd.json\n$ echo '{\"payload\":{\"header\":{\"channel_header\":{\"channel_id\":\"clarkschannel\", \"type\":2}},\"data\":{\"config_update\":'$(cat config_upd.json)'}}}' | jq . \u003e config_upd_env.json\n$ configtxlator proto_encode --input config_upd_env.json --type common.Envelope --output config_upd.env.pb\n```\n\nHave the admin of Clark's peer sign the envelope:\n\n```bash\n$ docker exec -ti admin.clark.example.com bash\n$ peer channel signconfigtx --file config_upd.env.pb\n2018-07-28 14:06:22.880 UTC [channelCmd] InitCmdFactory -\u003e INFO 001 Endorser and orderer connections initialized\n```\n\nNow send the signed envelope to the ordering service:\n\n```bash\n$ docker exec -ti admin.clark.example.com bash\n$ peer channel update --file config_upd.env.pb --channelID clarkschannel --orderer joe.example.com:7050 --tls --cafile $ORDERER_CA\n2018-07-28 14:06:48.764 UTC [channelCmd] InitCmdFactory -\u003e INFO 001 Endorser and orderer connections initialized\n2018-07-28 14:06:48.779 UTC [channelCmd] update -\u003e INFO 002 Successfully submitted channel update\n```\n\nNow have the new org get the channel's genesis block:\n\n```bash\n$ docker exec -ti admin.amelia.example.com bash\n$ peer channel fetch 0 clarkschannel.block --channelID clarkschannel --orderer joe.example.com:7050 --tls --cafile $ORDERER_CA\n2018-07-28 14:07:14.893 UTC [channelCmd] InitCmdFactory -\u003e INFO 001 Endorser and orderer connections initialized\n2018-07-28 14:07:14.896 UTC [cli/common] readBlock -\u003e INFO 002 Received block: 0\n```\n\nAnd use it to join the channel:\n\n```bash\n$ docker exec -ti admin.amelia.example.com bash\n$ peer channel join --blockpath clarkschannel.block\n2018-07-28 14:07:26.107 UTC [channelCmd] InitCmdFactory -\u003e INFO 001 Endorser and orderer connections initialized\n2018-07-28 14:07:26.146 UTC [channelCmd] executeJoin -\u003e INFO 002 Successfully submitted proposal to join channel\n```\n\n### Modify the chaincode\n\nLet's modify the chaincode's endorsement policy so as to include the new org.\n\nLet's install the chaincode on Clark's peer. Same exact bytes, just tag it with a different version.\n\n```bash\n$ docker exec -ti admin.clark.example.com bash\n$ peer chaincode install --name clarkschaincode --version 1.1 --path github.com/kchristidis/fabric-example/chaincode\n2018-07-28 14:07:50.613 UTC [chaincodeCmd] checkChaincodeCmdParams -\u003e INFO 001 Using default escc\n2018-07-28 14:07:50.613 UTC [chaincodeCmd] checkChaincodeCmdParams -\u003e INFO 002 Using default vscc\n2018-07-28 14:07:50.824 UTC [chaincodeCmd] install -\u003e INFO 003 Installed remotely response:\u003cstatus:200 payload:\"OK\" \u003e\n```\n\nDo the same on Amelia's peer:\n\n```bash\n$ docker exec -ti admin.amelia.example.com bash\n$ peer chaincode install --name clarkschaincode --version 1.1 --path github.com/kchristidis/fabric-example/chaincode\n2018-07-28 14:08:20.803 UTC [chaincodeCmd] checkChaincodeCmdParams -\u003e INFO 001 Using default escc\n2018-07-28 14:08:20.804 UTC [chaincodeCmd] checkChaincodeCmdParams -\u003e INFO 002 Using default vscc\n2018-07-28 14:08:21.000 UTC [chaincodeCmd] install -\u003e INFO 003 Installed remotely response:\u003cstatus:200 payload:\"OK\" \u003e\n```\n\nHave the admin on Clark's peer upgrade the chaincode. Note that the call needs to be made by an entity satisfying the instantiation policy. Since that was not explicitly set, it defaults to any admin of any org which was present in the channel at the time of invoking the upgrade.\n\n```bash\n$ peer chaincode upgrade --orderer joe.example.com:7050 --tls --cafile $ORDERER_CA --channelID clarkschannel --name clarkschaincode --version 1.1 -c '{\"Args\":[\"init\",\"a\",\"100\",\"b\",\"200\"]}' --policy \"OR ('ClarkMSP.member','AmeliaMSP.member')\"\n2018-07-28 14:09:23.538 UTC [chaincodeCmd] checkChaincodeCmdParams -\u003e INFO 001 Using default escc\n2018-07-28 14:09:23.538 UTC [chaincodeCmd] checkChaincodeCmdParams -\u003e INFO 002 Using default vscc\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkchristidis%2Ffabric-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkchristidis%2Ffabric-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkchristidis%2Ffabric-example/lists"}