Compare commits

...

80 commits

Author SHA1 Message Date
Arnaud J Le Hors
1343ccb628
FAB-17419 Fix off_chain_data sample error (#146)
Before fix:

$ node blockEventListener.js
fabric-samples/off_chain_data/blockProcessing.js:53
              continue();
                      ^

SyntaxError: Unexpected token '('
    at Module._compile (internal/modules/cjs/loader.js:895:18)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10)
    at Module.load (internal/modules/cjs/loader.js:815:32)
    at Function.Module._load (internal/modules/cjs/loader.js:727:14)
    at Module.require (internal/modules/cjs/loader.js:852:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at Object.<anonymous> (fabric-samples/off_chain_data/blockEventListener.js:48:25)
    at Module._compile (internal/modules/cjs/loader.js:959:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10)
    at Module.load (internal/modules/cjs/loader.js:815:32)

After fix:

$ node blockEventListener.js
Wallet path: fabric-samples/off_chain_data/wallet
2020-03-31T06:14:26.643Z - error: [Channel.js]: Channel:mychannel received discovery error:failed constructing descriptor for chaincodes:<name:"_lifecycle" >
Listening for block events, nextblock: 0
Added block 0 to ProcessingMap
Added block 1 to ProcessingMap
Added block 2 to ProcessingMap
------------------------------------------------
Block Number: 0
------------------------------------------------
Block Number: 1
------------------------------------------------
Block Number: 2

Signed-off-by: Arnaud J Le Hors <lehors@us.ibm.com>
2020-03-31 20:49:21 +02:00
Brett Logan
0e3a7a7a30
Change Fabric Binary Pull Logic (#147)
Signed-off-by: Brett Logan <brett.t.logan@ibm.com>
2020-03-31 16:02:06 +02:00
Arnaud J Le Hors
337f82c513 Fixes Fabcar Java chaincode build dependency (#107)
This change updates build.gradle to fabric 1.4.4.

Signed-off-by: Arnaud J Le Hors <lehors@us.ibm.com>
2020-01-24 14:13:33 +00:00
Brett Logan
2c1d2ad5b9 [FABCI-482] Update Nexus URL's to Artifactory (#93)
Signed-off-by: Brett Logan <brett.t.logan@ibm.com>
2020-01-20 15:30:21 +00:00
Brett Logan
562791dd2b Add support for versioning NodeJS (#105)
Signed-off-by: Brett Logan <brett.t.logan@ibm.com>
2020-01-17 21:38:31 +01:00
Brett Logan
d015ca1f82 Update fabric version (#94)
Signed-off-by: Brett Logan <brett.t.logan@ibm.com>
2020-01-16 22:25:40 +01:00
Arnaud J Le Hors
0d7c7a1643
Merge pull request #74 from danipisca07/release-1.4
Fix port numbers for peers in high-throughput.
The test build failed for some unrelated reason that needs to be investigated independently.
2019-11-30 07:46:32 +01:00
Arnaud J Le Hors
ba63e6533d
Merge pull request #64 from LF-Certification/release-1.4
Added stop script to remove `fabcar` chaincode containers and images.
I note that the test build failed but it clearly has nothing to do with this change. Fabcar java doesn't seem to be working. This will need to be addressed independently.
2019-11-29 21:32:19 +01:00
Daniele Piscaglia
cd5b68d040 Fix port numbers for peers in high-throughput
Signed-off-by: danipisca07 <danielepiscaglia@libero.it>
2019-11-15 12:58:01 +01:00
Ry Jones
bc72f3e3a6 Remove Stalebot
Signed-off-by: Ry Jones <ry@linux.com>
2019-11-04 22:43:20 -05:00
Ry Jones
ce0d06f599
Merge branch 'release-1.4' into release-1.4 2019-10-28 01:01:47 -07:00
Arnaud J Le Hors
e4f147f396
Merge pull request #71 from hyperledger/samples_stalebot_1.4
Cherrypick stalebot settings from master
2019-10-27 17:21:52 +01:00
Ry Jones
99657d19c7
Merge branch 'release-1.4' into release-1.4 2019-10-27 09:04:54 -07:00
Brett Logan
797b991b4f Change stalebot settings
Signed-off-by: Brett Logan <Brett.T.Logan@ibm.com>
2019-10-26 11:52:34 -04:00
Simon Stone
750474d458 [FAB-16850] Set up CI with Azure Pipelines
Signed-off-by: Simon Stone <sstone1@uk.ibm.com>
Change-Id: I3821a329ec5eb439ce0f27cfbc71b28e6b0b8a09
2019-10-17 12:48:04 +01:00
Simon Stone
b92ff73374 [FAB-16849] Various updates for Java version of FabCar
- Update .gitignore
- Use builds on Sonatype, not Nexus
- Enable new discovery as localhost flag

Signed-off-by: Simon Stone <sstone1@uk.ibm.com>
Change-Id: Ia0904cedf953b5ecbf6aaf859245a9bb431d3f76
(cherry picked from commit 81aabf4c0b)
2019-10-17 11:01:22 +00:00
Matthew B. White
9915995df7 [FAB-16844] Modify pattern for cc images
- remove images that match dev-*
- correcting a dependency

Change-Id: I603dc822260be827ca36677e5c05aa5f196858ae
Signed-off-by: Matthew B. White <whitemat@uk.ibm.com>
2019-10-16 11:48:02 +01:00
Ry Jones
ca5bcb27ae [IN-68] Add default GitHub SECURITY policy
this file must exist on the default branch

Signed-off-by: Ry Jones <ry@linux.com>
Change-Id: Ie805816e929f4449689214c74964b71eac56e31d
(cherry picked from commit 7b65a25a86)
2019-09-29 01:36:29 +00:00
Daniel Ruthardt
0fce873325 Added license header and "signed-off-by".
Signed-off-by: Daniel Ruthardt <druthardt@contractor.linuxfoundation.org>
2019-09-26 20:57:57 +02:00
Daniel Ruthardt
877baa597c Added stop script to remove fabcar chaincode containers and images.
Signed-off-by: Daniel Ruthardt <druthardt@contractor.linuxfoundation.org>
2019-09-26 20:57:57 +02:00
rthatcher
ecd08c0357 [FAB-16474] marbles02 chaincode error
Signed-off-by: rthatcher <robert.thatcher@uk.ibm.com>
Change-Id: Ib8780cb2a4cbae8c5a55708682490b9c8230b519
2019-09-24 14:04:44 +01:00
bjzhang03
7e8edb3189 [FAB-16619] Fix the policy warning
This fixes #FAB-16619

Change-Id: I251d10bc9dc9baf4f7e7d20cc11a34703baffc52
Signed-off-by: bjzhang03 <bjzhang03@foxmail.com>
2019-09-17 16:56:20 +08:00
bjzhang03
70ce148927 [FAB-16592] Add the etcdraft into the config
This is fix #FAB-16592

Signed-off-by: bjzhang03 <bjzhang03@foxmail.com>
Change-Id: If246f455c65403de2edcdc58ff35cde04279950d
2019-09-17 09:54:51 +08:00
vijaypunugubati
ddf013ba01 FAB-16608 Update base_version on ci.prop
Update ci.prop file to bring 1.4.4-stables images from
nexus on verify and merge jobs.

Signed-off-by: vijaypunugubati <vijaypunugubati@gmail.com>
Change-Id: I25a1ed222aae5bbf7fad79002b18ea59b19c0d89
2019-09-16 09:31:51 -04:00
jaehyun
0b980ebda7 [FAB-16362] adding chaincode excution comments
adding chaincode excution comments

Signed-off-by: jaehyun <jaehyun@lgcns.com>
Change-Id: I61ce32561f68fb8db8e0dc3f0d18b0564aaafb70
(cherry picked from commit 48082cfa95)
2019-09-06 12:12:02 +00:00
Ry Jones
b4e097ff7c [FAB-16487] Update eslint
Signed-off-by: Ry Jones <ry@linux.com>
Change-Id: I69233df8716f0bc081b67c771fb7eeaac6fc9d52
(cherry picked from commit a6ce915106)
2019-08-31 18:34:46 +00:00
Simon Stone
d7932fd420 Merge "[FAB-16402] Fabcar only needs two endorsements" into release-1.4 2019-08-27 08:19:35 +00:00
Varun Agarwal
f86ec95726 [FAB-16390] Added filter for invalid transactions
Signed-off-by: Varun Agarwal <varunagarwal315@gmail.com>
Change-Id: Idb6c57e047bba9a176b312f86d05c2ee21aeb175
2019-08-25 14:19:02 +05:30
David Enyeart
78fe781a67 [FAB-16402] Fabcar only needs two endorsements
Fabcar test currently invokes on 4 peers. Only need endorsement on 2 peers.
This will help the CLI invokes to finish sooner, and eliminate some CI failures.

Change-Id: Iec6bb7c9032ea6344c1d1917ffa3188c3b05c1e0
Signed-off-by: David Enyeart <enyeart@us.ibm.com>
2019-08-24 09:13:57 -04:00
David Enyeart
a963990313 Merge "[FAB-16344] Upgrade scripts for v1.4.3" into release-1.4 2019-08-23 22:57:21 +00:00
bharadwajambati1
a4460a9947 [FAB-16344] Upgrade scripts for v1.4.3
Signed-off-by: bharadwajambati1 <bharadwaj.ambati1@ibm.com>
Change-Id: Icd4eb98e7953288cc51577a7952b5680997934c7
2019-08-23 11:21:51 -04:00
vijaypunugubati
549e9fdd09 Remove AnsiColor wrapper in Fabric Samples
FABCI-402 #done

Signed-off-by: vijaypunugubati <vijaypunugubati@gmail.com>
Change-Id: Ie4ee8c1eecc63d959b2a8d188d737c5b03face67
2019-08-22 11:17:14 -04:00
David Enyeart
fc5975b285 [FAB-16322] fabric-samples to V1_4_3 channel capability
Update fabric-samples to V1_4_3 channel capability to
enable the new NodeOU support.

Change-Id: I63b2a70e612c2fd72c58272543f68b1b8687bdbb
Signed-off-by: David Enyeart <enyeart@us.ibm.com>
2019-08-15 23:47:43 -04:00
NIKHIL E GUPTA
3d364ed082 [FAB-16296] Fixes for interest rate sample
backporting fixes from master to v1.4 for
interest rate sample

Change-Id: If7648c91c53dff737103de178bd8a09556765951
Signed-off-by: NIKHIL E GUPTA <negupta@us.ibm.com>
2019-08-13 10:17:40 -04:00
Arnaud J Le Hors
e80379a06f Merge "[FAB-14813] Channel event sample in fabric-samples" into release-1.4 2019-08-08 00:04:55 +00:00
Arnaud J Le Hors
da7f3cd0cc Merge "[FAB-16036] Fix a error of get query in testAPI.sh" into release-1.4 2019-08-07 23:18:44 +00:00
Chris Elder
1efd213110 [FAB-14813] Channel event sample in fabric-samples
Add a channel event handler sample based on block events.

Scope:

create a block event handler
write events received to the console
write events received to a log file
write events to an off chain couchdb database
demonstrate a basic map reduce view for aggregation

Change-Id: I5420ddc7070dbee785218ce5960f7604ac799f90
Signed-off-by: Chris Elder <chris.elder@us.ibm.com>
2019-08-06 21:43:26 +00:00
Simon Stone
d26e27e0d1 Merge "[FAB-16147] Compilation and Lint Checks" into release-1.4 2019-08-02 09:31:08 +00:00
Matthew B. White
11d6ee14a9 [FAB-16147] Compilation and Lint Checks
Add in makefile to call the compilation and liniting
Only the applications and contracts currently
Testing needs to follow

Change-Id: I5604a71ea025cd01a1f27968122ea119697db7a5
Signed-off-by: Matthew B. White <whitemat@uk.ibm.com>
2019-07-31 11:47:17 +01:00
Simon Stone
dc8e60b4e3 [FGJ-4] CI tests for FabCar Java sample
Signed-off-by: Simon Stone <sstone1@uk.ibm.com>
Change-Id: I2b28c69a2f3ec0e3d87252ef4a585b4a46fddcbd
2019-07-31 09:24:31 +01:00
Simon Stone
9040e28b55 [FAB-15897] Improve FabCar test logging
Collect logs from all existing Docker containers instead
of just limiting it to a predefined (and incorrect) set.

Also clean up the directory structure for the logs, and
remove any networks/volumes after each test run.

Signed-off-by: Simon Stone <sstone1@uk.ibm.com>
Change-Id: Ifcf88baeb9ba4d42f757f7cd23ab2a178ab39b41
2019-07-30 17:55:24 +01:00
Matthew B. White
dcce485561 [FAB-15213] Update Commercial Paper for Java
Update with Java Contract

Change-Id: I1a70473f038576d741c8c9ac83e527b5e51e88ca
Signed-off-by: Matthew B. White <whitemat@uk.ibm.com>

[FAB-15213] Update Commercial Paper for Java

Change-Id: Ie116962a6c3952e52269323492f5f292e9b65e95
Signed-off-by: Matthew B. White <whitemat@uk.ibm.com>
2019-07-30 14:37:05 +01:00
andrew-coleman
8c057e951b FGJ-4 add license header to fabcar java sample
Change-Id: Ic658fe3bdece9875ca3ceaf28d94c5fb48879083
Signed-off-by: andrew-coleman <andrew_coleman@uk.ibm.com>
2019-07-25 13:32:39 +01:00
Simon Stone
9a8acd5752 Merge "FGJ-4 split java fabcar into separate classes" into release-1.4 2019-07-25 12:27:31 +00:00
andrew-coleman
f1c46f033c FGJ-4 split java fabcar into separate classes
Incorporate review comments from previous CR
Split enroll/register/transactions into separate classes

Change-Id: I384cec59c7f53a37864bfc28be11e785a61421f3
Signed-off-by: andrew-coleman <andrew_coleman@uk.ibm.com>
2019-07-25 11:42:16 +01:00
andrew-coleman
c57f10f5f6 FGJ-4 commercial paper client sample
commercial paper sample for Java Gateway SDK (client app)

Change-Id: I80c6b9dbc36631004903244a20e6a492138c7751
Signed-off-by: andrew-coleman <andrew_coleman@uk.ibm.com>
2019-07-24 10:17:55 +01:00
Simon Stone
8f92861104 Merge "FGJ-4 Fabcar sample" into release-1.4 2019-07-24 09:10:02 +00:00
andrew-coleman
abb7207e24 FGJ-4 Fabcar sample
Implementation of Fabcar client for Java Gateway SDK
Changes to first-network to generate the CCP files with
embedded PEM certificates rather than paths to files on disk

Change-Id: Iff15425e96ce28c6f96079cee474c35868fab554
Signed-off-by: andrew-coleman <andrew_coleman@uk.ibm.com>
2019-07-23 15:50:25 +01:00
Nao Nishijima
1826dbfda7 [FAB-16036] Fix a error of get query in testAPI.sh
This CR add a space in parameter expansion to get a transation id.
testAPI.sh tries to get a transaction id using parameter expansion from
MESSAGE variable and accesses a URL incluse the transaction id. However
the transaction id includes a space at the beginning and the access will
be failed.
By ridding of the space, the access will successes.

Signed-off-by: Nao Nishijima <nao.nishijima.xt@hitachi.com>
Reported-by: YAMAUCHI,KAITO <kaito.yamauchi.kk@hitachi-solutions.com>
Change-Id: I0c52418044deb3b7d8c30cb64a5908e32462bd09
2019-07-22 06:17:32 +00:00
Yukihiko
9e0eed19a4 [FAB-15104] Remove scripts/bootstrap.sh
Removed scripts/bootstrap.sh file and updated the README.md
with steps to download bootstrap.sh from Fabric repository.

Remove versions from fabric-samples readme so that
it doesn't need to be maintained for each release.
Also clarify the bootstrap.sh download instructions.

Signed-off-by: Yukihiko <hirayanagi@jp.fujitsu.com>
Change-Id: I50357c702c8b357fedaf8ccd1ec97ef6c4429371
(cherry picked from commit 5be56d3f77)
2019-07-19 19:12:40 +00:00
James Taylor
cf5855dd5d [FAB-15993] use new annotations
Contracts now need to use new Fabric annotations instead of swagger info annotations

Change-Id: I038ba39025db27c5298390cd9ef28413b5b8ef31
Signed-off-by: James Taylor <jamest@uk.ibm.com>
2019-07-17 16:53:35 +01:00
David Enyeart
3429e22a9e Merge "[FAB-15723] Fix script and instruction with ccenv" into release-1.4 2019-07-12 21:21:59 +00:00
Surya Lanka
d50fbc4f69 [FAB-15803] Upgrade to v1.4.2
Upgrading to v1.4.2 from v1.4.1 and enabling
v1_4_2 capabilities on orderer system channel
and applicaiton channel for channel and orderer groups

Signed-off-by: Surya Lanka <suryalnvs@gmail.com>
Change-Id: I41e575ba8b56122a55fe148b65972884aaf49627
2019-07-12 17:57:48 +00:00
Tatsuya Sato
015fc15dc2 [FAB-15723] Fix script and instruction with ccenv
This patch fixes the script and instruction with the ccenv container.

Running chaincode dev-mode fails because bash was removed from the
ccenv by FAB-15670.
This patch changes the command from /bin/bash to /bin/sh.

FAB-15723 #done

Change-Id: Ibf31ce9170e606988302bf46d8dac98b62e2043e
Signed-off-by: Tatsuya Sato <Tatsuya.Sato@hal.hitachi.com>
(cherry picked from commit 1774a25de8)
2019-07-12 17:10:28 +00:00
Simon Stone
36ef140439 [FAB-15649]Fix Fabcar to install Chaincode on all peers
CI Fabcar javascript test fails because a query proposal is
sent to a peer which does not have Chaincode. The query handler
in fabric-network does not consider if Chaincode is installed on
target peers.

As a workaround, this CR adds steps installing Chaincode
on all peers during the setup.

Signed-off-by: Simon Stone <sstone1@uk.ibm.com>
Change-Id: I771e3bae0abd2d6a3b3b7d295efdf6417c3c1c21
2019-07-12 17:33:04 +01:00
James Taylor
62fa4f8bc0 [FAB-15213] Add Java FabCar sample contract
Change-Id: Ie15dd31f0e889df6042238a1e64067fcf32c4ec7
Signed-off-by: James Taylor <jamest@uk.ibm.com>
2019-07-10 13:53:15 +01:00
BigManing
3da5f8a450 Fix doc link
Change-Id: I24cae31cc3df080b8906812b81f63b15795dc6e5
Signed-off-by: BigManing <lingshui2008@qq.com>
(cherry picked from commit a8a55395af)
2019-06-03 11:07:35 +02:00
Arnaud J Le Hors
ad87f324b9 Merge "[FAB-9033] TypeScript sample uses latest type defs" into release-1.4 2019-05-17 07:25:02 +00:00
James Taylor
334a66f17e [FAB-15287] Remove Commercial Paper metadata
This reverts the metadata added in commit 6c28eca339.

Change-Id: Id38c819a19477562bdc98a272c4fb39fb1a79112
Signed-off-by: James Taylor <jamest@uk.ibm.com>
2019-05-02 11:43:41 +01:00
Taku Shimosawa
3d53f79be3 [FAB-9033] TypeScript sample uses latest type defs
This patchset removes the type defintions for the TypeScript
version of balance-transfer, and makes it use the definitions
in the npm repository.

Change-Id: I711d438354101f48240dfec115d747d65448ee2a
Signed-off-by: Taku Shimosawa <taku.shimosawa@hal.hitachi.com>
2019-04-30 17:15:18 -07:00
Simon Stone
f59e563d27 Merge "Fix balance-transfer script" into release-1.4 2019-04-29 09:24:32 +00:00
Simon Stone
0bc0a69793 [FAB-14532] Make LL FabCar use BYFN, not basic-network
Update low level FabCar to use BYFN. As a result, the
sample client applications need to change so that they
use the correct TLS certificates and URLs, and so that
they use service discovery.

Change-Id: I2805a00fd745416e6b006af7b87147551e511922
Signed-off-by: Simon Stone <sstone1@uk.ibm.com>
2019-04-25 17:02:35 +01:00
Simon Stone
2a5a59b60a [FAB-14487] Make FabCar use BYFN, not basic-network
Update FabCar to use BYFN. As a result, the sample
client applications need to change so that they use
the correct connection profile paths, and so that
they use service discovery.

Change-Id: If02b7fb4ad308c6a7d1e1aa9f953e1bc4e942719
Signed-off-by: Simon Stone <sstone1@uk.ibm.com>
2019-04-25 17:02:35 +01:00
Simon Stone
8271a472f8 [FAB-14486] Extend BYFN to opt skip chaincode deploy
Add a new "-n" option to byfn.sh that optionally skips
the deployment of the abstore chaincode. When BYFN is
used as a network for other samples, we don't really
want the default chaincode deployed.

Change-Id: I6b4043a5c0bcedbeec431cc4a860a3b12da8d8f6
Signed-off-by: Simon Stone <sstone1@uk.ibm.com>
2019-04-25 14:49:08 +01:00
Simon Stone
3a1d29ce93 [FAB-14485] Extend BYFN to opt inc cert authorities
Add a new "-a" option to byfn.sh that optionally deploys
certificate authorities (in Docker containers) for
organisation 1 and 2.

Change-Id: Ib58c46941aa6e8e58bac01aa3349e97d1f93b930
Signed-off-by: Simon Stone <sstone1@uk.ibm.com>
(cherry picked from commit 0c4141f2a1)
2019-04-25 13:06:24 +00:00
Matthew White
5d0bfb9989 Merge "[FAB-14330] Add connection profiles for BYFN and EYFN" into release-1.4 2019-04-25 13:04:13 +00:00
NickLatkovich
a1a648f12a FAB-14444
Awaiting of wallet importing in fabcar

Change-Id: Ib4a43f75850728794b90b58add7956de113cac80
Signed-off-by: NickLatkovich <nicklatkovich@gmail.com>
(cherry picked from commit d63047cac9)
2019-04-24 21:46:55 +00:00
Simon Stone
ec9eb7fa73 Merge "[FAB-13823] Commercial Paper fixes" into release-1.4 2019-04-24 18:01:05 +00:00
rameshthoomu
6c0203a9b0 FABCI-284 Update CI Pipeline script
This patch updates CI pipeline scripts which utilizes global shared
library reusable functions. It also creates ci.properties file with
all the parameters required to test the fabric-samples patch.

Change-Id: Ib2fd948eae9f2e37535144489279773836400358
Signed-off-by: rameshthoomu <rameshbabu.thoomu@gmail.com>
2019-03-29 11:05:06 -04:00
preminem
6be46eed05 Fix balance-transfer script
Change-Id: I610d9cd3b91b3be83fa62ea126c7b326e092239d
Signed-off-by: preminem <preminem@ruc.edu.cn>
2019-03-26 11:48:08 +00:00
Yoav Tock
72edb7e3bb FAB-14531 BYFN Raft with 5 nodes
Extend the 3-node etcd/raft cluster in BYFN to 5 nodes, in
order to better support the documentation effort. This will
allow users to experiment creating channels with less then
5 nodes, but avoid the pitfalls of a 2-node cluster.

Change-Id: I5ba1d6039b4bb4864b2b97271de81fbfe91b4fb5
Signed-off-by: Yoav Tock <tock@il.ibm.com>
2019-03-24 14:19:20 +02:00
Yoav Tock
83fe6c32df FAB-12762 Add etcd/raft consensus option to BYFN
Augment the fabric-samples first-network sample to include an option
to choose etcd/raft as consensus-type.

Extend the -o flag so that it allows users to choose between the
solo, kafka, or etcdraft consensus-type for the ordering service.

Use three orderer nodes.

Change-Id: Ibc4c3564220466aef0a87baee4a2d594e5554a62
Signed-off-by: Yoav Tock <tock@il.ibm.com>
2019-03-24 13:46:47 +02:00
Matthew B. White
6c28eca339 [FAB-13823] Commercial Paper fixes
Change-Id: I35e3e02fe9672ea79bd96e4d49926c900dfa627d
Signed-off-by: Matthew B. White <whitemat@uk.ibm.com>
2019-03-06 13:30:38 +00:00
Simon Stone
349d88d184 [FAB-14330] Add connection profiles for BYFN and EYFN
Add connection profiles as part of the BYFN and EYFN
samples. The connection profiles can be used by client
applications using the Fabric SDKs to connect to those
networks.

Each organisation needs its own connection profile
that contains the set of peers that organisation
should  use to connect to the network. Orderers and
channels are not needed, as they can be determined
by using service discovery.

Connection profiles can be specified in either JSON
or YAML, so provide both.

Change-Id: Ie8e3d2aef6475b324e5be8ebdada4c594c2235ae
Signed-off-by: Simon Stone <sstone1@uk.ibm.com>
2019-02-25 11:38:06 +00:00
Gari Singh
026aa9ec01 Merge "[FAB-14268] Make BYFN/EYFN ports match external ports" into release-1.4 2019-02-23 20:52:34 +00:00
David Enyeart
4ed3933a8d Merge "FAB-13489 fabric-samples add error msg" into release-1.4 2019-02-22 19:45:32 +00:00
Simon Stone
e5dc89e61d [FAB-14268] Make BYFN/EYFN ports match external ports
Update both BYFN and EYFN so that the peer request and
chaincode ports match the externally mapped ports. This
enables applications both inside and outside the Docker
network to use service discovery to interact with these
networks (see the JIRA for more details).

Change-Id: I73c36dfdb269ec4225376fb04b1e7a087363e4cc
Signed-off-by: Simon Stone <sstone1@uk.ibm.com>
(cherry picked from commit f942010fa6)
2019-02-22 19:43:15 +00:00
Bret Harrison
463d2ecaff FAB-13489 fabric-samples add error msg
Add error messages and update console logging.

Change-Id: Ic4ffd73ffa098121d7af03f8d2e5383b79f832c0
Signed-off-by: Bret Harrison <beharrison@nc.rr.com>
2019-01-14 19:37:10 +00:00
Sambhav Nidamarty
881ba56c8e FAB-13575 Update Jenkins files for release-1.4
Update the Jenkins scripts for the fabric-samples
tests in the release-1.4 branch.

Change-Id: I5f9c3d555898da354ecc62bd355f52e650c9eac1
Signed-off-by: Sambhav Nidamarty <sambhavdutt@gmail.com>
2019-01-10 17:18:48 +00:00
David Enyeart
bb39b6ed09 [FAB-13570] Align fabric-samples with 1.4.0 release
Change-Id: Ic0291f07e2aba519bcd05238d002eecd5ec43891
Signed-off-by: David Enyeart <enyeart@us.ibm.com>
2019-01-09 15:36:16 -05:00
210 changed files with 22966 additions and 1724 deletions

27
.github/stale.yml vendored
View file

@ -1,27 +0,0 @@
# SPDX-License-Identifier: Apache-2.0
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 0
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 1
# Issues with these labels will never be considered stale
# CAUTION: These issues are likely to get _less_ attention since stale bot
# will never nag anyone about them. Stale bot just reflects the community's
# actual priorities and adding labels to this list will not change that.
# If issues you care about are going stale, you need to work with the
# community to raise their profile, e.g. add more information, reach out on
# Rocket.Chat, join a community call, etc.
# WARNING: Please do not change these labels without seeking community
# consensus first!
# Label to use when marking an issue as stale
staleLabel: stale
only: pulls
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
Thank you for your contribution!
Please use gerrit for the changes, see
[documentation here](https://hyperledger-fabric.readthedocs.io/en/latest/CONTRIBUTING.html)
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
Thank you for your contribution!
Please use gerrit for the changes, see
[documentation here](https://hyperledger-fabric.readthedocs.io/en/latest/CONTRIBUTING.html)

1
.gitignore vendored
View file

@ -9,3 +9,4 @@
/config
.DS_Store
.project
.idea

View file

@ -9,10 +9,10 @@ docs to learn how to make contributions to this exciting project.
## Code of Conduct Guidelines <a name="conduct"></a>
See our [Code of Conduct Guidelines](../blob/master/CODE_OF_CONDUCT.md).
See our [Code of Conduct Guidelines](./CODE_OF_CONDUCT.md).
## Maintainers <a name="maintainers"></a>
Should you have any questions or concerns, please reach out to one of the project's [Maintainers](../blob/master/MAINTAINERS.md).
Should you have any questions or concerns, please reach out to one of the project's [Maintainers](./MAINTAINERS.md).
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.

155
Jenkinsfile vendored
View file

@ -1,155 +0,0 @@
// Copyright IBM Corp All Rights Reserved
//
// SPDX-License-Identifier: Apache-2.0
//
// Pipeline script for fabric-samples
node ('hyp-x') { // trigger build on x86_64 node
timestamps {
try {
def ROOTDIR = pwd() // workspace dir (/w/workspace/<job_name>
def nodeHome = tool 'nodejs-8.11.3'
env.ARCH = "amd64"
env.VERSION = sh(returnStdout: true, script: 'curl -O https://raw.githubusercontent.com/hyperledger/fabric/master/Makefile && cat Makefile | grep "BASE_VERSION =" | cut -d "=" -f2').trim()
env.VERSION = "$VERSION" // BASE_VERSION from fabric Makefile
env.BASE_IMAGE_VER = sh(returnStdout: true, script: 'cat Makefile | grep "BASEIMAGE_RELEASE =" | cut -d "=" -f2').trim() // BASEIMAGE Version from fabric Makefile
env.IMAGE_TAG = "${ARCH}-${VERSION}-stable" // fabric latest stable version from nexus
env.PROJECT_VERSION = "${VERSION}-stable"
env.BASE_IMAGE_TAG = "${ARCH}-${BASE_IMAGE_VER}" //fabric baseimage version
env.PROJECT_DIR = "gopath/src/github.com/hyperledger"
env.GOPATH = "$WORKSPACE/gopath"
env.PATH = "$GOPATH/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:${nodeHome}/bin:$PATH"
def jobname = sh(returnStdout: true, script: 'echo ${JOB_NAME} | grep -q "verify" && echo patchset || echo merge').trim()
def failure_stage = "none"
// delete working directory
deleteDir()
stage("Fetch Patchset") { // fetch gerrit refspec on latest commit
try {
if (jobname == "patchset") {
println "$GERRIT_REFSPEC"
println "$GERRIT_BRANCH"
checkout([
$class: 'GitSCM',
branches: [[name: '$GERRIT_REFSPEC']],
extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: 'gopath/src/github.com/hyperledger/$PROJECT'], [$class: 'CheckoutOption', timeout: 10]],
userRemoteConfigs: [[credentialsId: 'hyperledger-jobbuilder', name: 'origin', refspec: '$GERRIT_REFSPEC:$GERRIT_REFSPEC', url: '$GIT_BASE']]])
} else {
// Clone fabric-samples on merge
println "Clone $PROJECT repository"
checkout([
$class: 'GitSCM',
branches: [[name: 'refs/heads/$GERRIT_BRANCH']],
extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: 'gopath/src/github.com/hyperledger/$PROJECT']],
userRemoteConfigs: [[credentialsId: 'hyperledger-jobbuilder', name: 'origin', refspec: '+refs/heads/$GERRIT_BRANCH:refs/remotes/origin/$GERRIT_BRANCH', url: '$GIT_BASE']]])
}
dir("${ROOTDIR}/$PROJECT_DIR/$PROJECT") {
sh '''
# Print last two commit details
echo
git log -n2 --pretty=oneline --abbrev-commit
echo
'''
}
}
catch (err) {
failure_stage = "Fetch patchset"
currentBuild.result = 'FAILURE'
throw err
}
}
// clean environment and get env data
stage("Clean Environment - Get Env Info") {
try {
dir("${ROOTDIR}/$PROJECT_DIR/fabric-samples/scripts/Jenkins_Scripts") {
sh './CI_Script.sh --clean_Environment --env_Info'
}
}
catch (err) {
failure_stage = "Clean Environment - Get Env Info"
currentBuild.result = 'FAILURE'
throw err
}
}
// Pull Third_party Images
stage("Pull third_party Images") {
// making the output color coded
wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'xterm']) {
try {
dir("${ROOTDIR}/$PROJECT_DIR/fabric-samples/scripts/Jenkins_Scripts") {
sh './CI_Script.sh --pull_Thirdparty_Images'
}
}
catch (err) {
failure_stage = "Pull third_party docker images"
currentBuild.result = 'FAILURE'
throw err
}
}
}
// Pull Fabric, fabric-ca Images
stage("Pull Docker Images") {
// making the output color coded
wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'xterm']) {
try {
dir("${ROOTDIR}/$PROJECT_DIR/fabric-samples/scripts/Jenkins_Scripts") {
sh './CI_Script.sh --pull_Docker_Images'
}
}
catch (err) {
failure_stage = "Pull fabric, fabric-ca docker images"
currentBuild.result = 'FAILURE'
throw err
}
}
}
// Run byfn, eyfn tests (default, custom channel, couchdb, nodejs chaincode)
stage("Run byfn_eyfn Tests") {
// making the output color coded
wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'xterm']) {
try {
dir("${ROOTDIR}/$PROJECT_DIR/fabric-samples/scripts/Jenkins_Scripts") {
sh './CI_Script.sh --byfn_eyfn_Tests'
}
}
catch (err) {
failure_stage = "byfn_eyfn_Tests"
currentBuild.result = 'FAILURE'
throw err
}
}
}
// Run fabcar tests
stage("Run FabCar Tests") {
// making the output color coded
wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'xterm']) {
try {
dir("${ROOTDIR}/$PROJECT_DIR/fabric-samples/scripts/Jenkins_Scripts") {
sh './CI_Script.sh --fabcar_Tests'
}
}
catch (err) {
failure_stage = "fabcar_Tests"
currentBuild.result = 'FAILURE'
throw err
}
}
}
} finally {
// Archive the artifacts
archiveArtifacts allowEmptyArchive: true, artifacts: '**/*.log'
// Sends notification to Rocket.Chat jenkins-robot channel
if (env.JOB_NAME == "fabric-samples-merge-job") {
if (currentBuild.result == 'FAILURE') { // Other values: SUCCESS, UNSTABLE
rocketSend message: "Build Notification - STATUS: *${currentBuild.result}* - BRANCH: *${env.GERRIT_BRANCH}* - PROJECT: *${env.PROJECT}* - (<${env.BUILD_URL}|Open>)"
}
}
}
// End Timestamps block
}
// End Node block
}

View file

@ -9,16 +9,30 @@ intend to use to ensure alignment.
## Download Binaries and Docker Images
The [`scripts/bootstrap.sh`](https://github.com/hyperledger/fabric-samples/blob/release-1.3/scripts/bootstrap.sh)
script will preload all of the requisite docker
images for Hyperledger Fabric and tag them with the 'latest' tag. Optionally,
specify a version for fabric, fabric-ca and thirdparty images. Default versions
are 1.4.0-rc2, 1.4.0-rc2 and 0.4.14 respectively.
The installation instructions will utilize `scripts/bootstrap.sh` (available in the fabric repository)
script to download all of the requisite Hyperledger Fabric binaries and docker
images, and tag the images with the 'latest' tag. Optionally,
specify a version for fabric, fabric-ca and thirdparty images. If versions
are not passed, the latest available versions will be downloaded.
The script will also clone fabric-samples repository using the version tag that
is aligned with the Fabric version.
You can also download the script and execute locally:
```bash
# Fetch bootstrap.sh from fabric repository using
curl -sS https://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap.sh -o ./scripts/bootstrap.sh
# Change file mode to executable
chmod +x ./scripts/bootstrap.sh
# Download binaries and docker images
./scripts/bootstrap.sh [version] [ca version] [thirdparty_version]
```
### Continuous Integration
Please have a look at [Continuous Integration Process](docs/fabric-samples-ci.md)
## License <a name="license"></a>
Hyperledger Project source code files are made available under the Apache

12
SECURITY.md Normal file
View file

@ -0,0 +1,12 @@
# Hyperledger Security Policy
## Reporting a Security Bug
If you think you have discovered a security issue in any of the Hyperledger projects, we'd love to hear from you. We will take all security bugs seriously and if confirmed upon investigation we will patch it within a reasonable amount of time and release a public security bulletin discussing the impact and credit the discoverer.
There are two ways to report a security bug. The easiest is to email a description of the flaw and any related information (e.g. reproduction steps, version) to [security at hyperledger dot org](mailto:security@hyperledger.org).
The other way is to file a confidential security bug in our [JIRA bug tracking system](https://jira.hyperledger.org). Be sure to set the “Security Level” to “Security issue”.
The process by which the Hyperledger Security Team handles security bugs is documented further in our [Defect Response page](https://wiki.hyperledger.org/display/HYP/Defect+Response) on our [wiki](https://wiki.hyperledger.org).

View file

@ -10,6 +10,6 @@
"engine-strict": true,
"license": "Apache-2.0",
"dependencies": {
"fabric-shim": "1.4.0-rc2"
"fabric-shim": "~1.4.0"
}
}

View file

@ -24,8 +24,8 @@
"express-bearer-token": "^2.1.0",
"express-jwt": "^5.1.0",
"express-session": "^1.15.2",
"fabric-ca-client": "1.4.0-rc2",
"fabric-client": "1.4.0-rc2",
"fabric-ca-client": "~1.4.0",
"fabric-client": "~1.4.0",
"fs-extra": "^2.0.0",
"jsonwebtoken": "^7.3.0",
"log4js": "^0.6.38"

View file

@ -185,16 +185,19 @@ echo
echo "POST invoke chaincode on peers of Org1 and Org2"
echo
curl -s -X POST \
VALUES=$(curl -s -X POST \
http://localhost:4000/channels/mychannel/chaincodes/mycc \
-H "authorization: Bearer $ORG1_TOKEN" \
-H "content-type: application/json" \
-d "{
\"peers\": [\"peer0.org1.example.com\",\"peer0.org2.example.com\"],
\"fcn\":\"move\",
\"args\":[\"a\",\"b\",\"10\"]
}"
echo
\"peers\": [\"peer0.org1.example.com\",\"peer0.org2.example.com\"],
\"fcn\":\"move\",
\"args\":[\"a\",\"b\",\"10\"]
}")
echo $VALUES
# Assign previous invoke transaction id to TRX_ID
MESSAGE=$(echo $VALUES | jq -r ".message")
TRX_ID=${MESSAGE#*ID: }
echo
echo "GET query chaincode on peer1 of Org1"
@ -213,7 +216,7 @@ BLOCK_INFO=$(curl -s -X GET \
-H "authorization: Bearer $ORG1_TOKEN" \
-H "content-type: application/json")
echo $BLOCK_INFO
# Assign previvious block hash to HASH
# Assign previous block hash to HASH
HASH=$(echo $BLOCK_INFO | jq -r ".header.previous_hash")
echo

View file

@ -18,6 +18,7 @@ import * as util from 'util';
import * as fs from 'fs';
import * as path from 'path';
import * as helper from './helper';
import { Peer, ProposalResponse, ChaincodeQueryResponse } from 'fabric-client';
// tslint:disable-next-line:no-var-requires
const config = require('../app_config.json');
@ -53,7 +54,8 @@ export async function installChaincode(
targets: helper.newPeers(peers, org),
chaincodePath,
chaincodeId: chaincodeName,
chaincodeVersion
chaincodeVersion,
txId: client.newTransactionID(true)
};
try {
@ -64,7 +66,7 @@ export async function installChaincode(
const proposal = results[1];
let allGood = true;
proposalResponses.forEach((pr) => {
proposalResponses.forEach((pr: ProposalResponse) => {
let oneGood = false;
if (pr.response && pr.response.status === 200) {
oneGood = true;
@ -76,9 +78,10 @@ export async function installChaincode(
});
if (allGood) {
const proposalResponse = proposalResponses[0] as ProposalResponse;
logger.info(util.format(
'Successfully sent install Proposal and received ProposalResponse: Status - %s',
proposalResponses[0].response.status));
proposalResponse.response.status));
logger.debug('\nSuccessfully Installed chaincode on organization ' + org +
'\n');
return 'Successfully Installed chaincode on organization ' + org;
@ -145,4 +148,4 @@ export async function getInstalledChaincodes(
logger.error('Failed to query with error:' + err.stack ? err.stack : err);
return 'Failed to query with error:' + err.stack ? err.stack : err;
}
}
}

View file

@ -18,11 +18,14 @@ import * as util from 'util';
import * as fs from 'fs';
import * as path from 'path';
import * as helper from './helper';
import { ChannelEventHub, Peer, ProposalResponse, ChaincodeInvokeRequest,
ChaincodeQueryRequest, ChannelInfo } from 'fabric-client';
const logger = helper.getLogger('ChannelApi');
// tslint:disable-next-line:no-var-requires
const config = require('../app_config.json');
const allEventhubs: EventHub[] = [];
const allEventhubs: ChannelEventHub[] = [];
function buildTarget(peer: string, org: string): Peer {
let target: Peer = null;
@ -132,40 +135,10 @@ export async function joinChannel(
block: genesisBlock
};
const eventhubs = helper.newEventHubs(peers, org);
eventhubs.forEach((eh) => {
eh.connect();
allEventhubs.push(eh);
});
const eventPromises: Array<Promise<any>> = [];
eventhubs.forEach((eh) => {
const txPromise = new Promise((resolve, reject) => {
const handle = setTimeout(reject, parseInt(config.eventWaitTime, 10));
eh.registerBlockEvent((block: any) => {
clearTimeout(handle);
// in real-world situations, a peer may have more than one channels so
// we must check that this block came from the channel we asked the peer to join
if (block.data.data.length === 1) {
// Config block must only contain one transaction
const channel_header = block.data.data[0].payload.header.channel_header;
if (channel_header.channel_id === channelName) {
resolve();
} else {
reject();
}
}
});
});
eventPromises.push(txPromise);
});
const sendPromise = channel.joinChannel(request2);
const results = await Promise.all([sendPromise].concat(eventPromises));
const results = await channel.joinChannel(request2);
logger.debug(util.format('Join Channel R E S P O N S E : %j', results));
if (results[0] && results[0][0] && results[0][0].response && results[0][0]
.response.status === 200) {
if (results[0] && results[0].response && results[0].response.status === 200) {
logger.info(util.format(
'Successfully joined peers in organization %s to the channel \'%s\'',
org, channelName));
@ -216,7 +189,7 @@ export async function instantiateChainCode(
let allGood = true;
proposalResponses.forEach((pr) => {
proposalResponses.forEach((pr: ProposalResponse) => {
let oneGood = false;
if (pr.response && pr.response.status === 200) {
oneGood = true;
@ -228,15 +201,17 @@ export async function instantiateChainCode(
});
if (allGood) {
const responses = proposalResponses as ProposalResponse[];
const proposalResponse = responses[0];
logger.info(util.format(
// tslint:disable-next-line:max-line-length
'Successfully sent Proposal and received ProposalResponse: Status - %s, message - "%s", metadata - "%s", endorsement signature: %s',
proposalResponses[0].response.status, proposalResponses[0].response.message,
proposalResponses[0].response.payload, proposalResponses[0].endorsement
proposalResponse.response.status, proposalResponse.response.message,
proposalResponse.response.payload, proposalResponse.endorsement
.signature));
const request2 = {
proposalResponses,
proposalResponses: responses,
proposal
};
// set the transaction listener and set a timeout of 30sec
@ -245,15 +220,7 @@ export async function instantiateChainCode(
const deployId = txId.getTransactionID();
const ORGS = helper.getOrgs();
const eh = client.newEventHub();
const data = fs.readFileSync(path.join(__dirname, ORGS[org].peers['peer1'][
'tls_cacerts'
]));
eh.setPeerAddr(ORGS[org].peers['peer1']['events'], {
'pem': Buffer.from(data).toString(),
'ssl-target-name-override': ORGS[org].peers['peer1']['server-hostname']
});
const eh = channel.newChannelEventHub('peer1');
eh.connect();
const txPromise: Promise<any> = new Promise((resolve, reject) => {
@ -262,7 +229,7 @@ export async function instantiateChainCode(
reject();
}, 30000);
eh.registerTxEvent(deployId, (tx, code) => {
eh.registerTxEvent(deployId, (tx: string, code: string) => {
// logger.info(
// 'The chaincode instantiate transaction has been committed on peer ' +
// eh._ep._endpoint.addr);
@ -346,7 +313,7 @@ export async function invokeChaincode(
const proposal = results[1];
let allGood = true;
proposalResponses.forEach((pr) => {
proposalResponses.forEach((pr: ProposalResponse) => {
let oneGood = false;
if (pr.response && pr.response.status === 200) {
oneGood = true;
@ -358,15 +325,17 @@ export async function invokeChaincode(
});
if (allGood) {
const responses = proposalResponses as ProposalResponse[];
const proposalResponse = responses[0];
logger.debug(util.format(
// tslint:disable-next-line:max-line-length
'Successfully sent Proposal and received ProposalResponse: Status - %s, message - "%s", metadata - "%s", endorsement signature: %s',
proposalResponses[0].response.status, proposalResponses[0].response.message,
proposalResponses[0].response.payload, proposalResponses[0].endorsement
proposalResponse.response.status, proposalResponse.response.message,
proposalResponse.response.payload, proposalResponse.endorsement
.signature));
const request2 = {
proposalResponses,
proposalResponses: responses,
proposal
};
@ -384,7 +353,7 @@ export async function invokeChaincode(
const eventhubs = helper.newEventHubs(peerNames, org);
eventhubs.forEach((eh: EventHub) => {
eventhubs.forEach((eh: ChannelEventHub) => {
eh.connect();
const txPromise = new Promise((resolve, reject) => {
@ -452,11 +421,9 @@ export async function queryChaincode(
const user = await helper.getRegisteredUsers(username, org);
const txId = client.newTransactionID();
// send query
const request: ChaincodeQueryRequest = {
chaincodeId: chaincodeName,
txId,
fcn,
args
};
@ -470,7 +437,7 @@ export async function queryChaincode(
if (responsePayloads) {
responsePayloads.forEach((rp) => {
responsePayloads.forEach((rp: Buffer) => {
logger.info(args[0] + ' now has ' + rp.toString('utf8') +
' after the move');
return args[0] + ' now has ' + rp.toString('utf8') +
@ -501,7 +468,7 @@ export async function getBlockByNumber(
const responsePayloads = await channel.queryBlock(parseInt(blockNumber, 10), target);
if (responsePayloads) {
logger.debug(responsePayloads);
logger.debug(responsePayloads.toString());
return responsePayloads; // response_payloads.data.data[0].buffer;
} else {
logger.error('response_payloads is null');
@ -554,7 +521,7 @@ export async function getChainInfo(peer: string, username: string, org: string)
if (blockChainInfo) {
// FIXME: Save this for testing 'getBlockByHash' ?
logger.debug('===========================================');
logger.debug(blockChainInfo.currentBlockHash);
logger.debug(blockChainInfo.currentBlockHash.toString());
logger.debug('===========================================');
// logger.debug(blockchainInfo);
return blockChainInfo;
@ -583,7 +550,7 @@ export async function getChannels(peer: string, username: string, org: string) {
if (response) {
logger.debug('<<< channels >>>');
const channelNames: string[] = [];
response.channels.forEach((ci) => {
response.channels.forEach((ci: ChannelInfo) => {
channelNames.push('channel id: ' + ci.channel_id);
});
return response;

View file

@ -19,13 +19,14 @@ import * as path from 'path';
import * as fs from 'fs';
import * as util from 'util';
import config from '../config';
import hfc = require('fabric-client');
import Client = require('fabric-client');
import { User, UserOpts, Channel } from 'fabric-client';
// tslint:disable-next-line:no-var-requires
const copService = require('fabric-ca-client');
const logger = log4js.getLogger('Helper');
logger.setLevel('DEBUG');
hfc.setLogger(logger);
Client.setLogger(logger);
let ORGS: any;
const clients = {};
@ -44,7 +45,7 @@ function readAllFiles(dir: string) {
}
function getKeyStoreForOrg(org: string) {
return hfc.getConfigSetting('keyValueStore') + '_' + org;
return Client.getConfigSetting('keyValueStore') + '_' + org;
}
function setupPeers(channel: any, org: string, client: Client) {
@ -87,7 +88,7 @@ function getMspID(org: string) {
function newRemotes(names: string[], forPeers: boolean, userOrg: string) {
const client = getClientForOrg(userOrg);
const channel = getChannelForOrg(userOrg);
const targets: any[] = [];
// find the peer that match the names
names.forEach((n) => {
@ -100,11 +101,11 @@ function newRemotes(names: string[], forPeers: boolean, userOrg: string) {
'ssl-target-name-override': ORGS[userOrg].peers[n]['server-hostname']
};
const peer = client.newPeer(ORGS[userOrg].peers[n].requests, grpcOpts);
if (forPeers) {
targets.push(client.newPeer(ORGS[userOrg].peers[n].requests, grpcOpts));
targets.push(peer);
} else {
const eh = client.newEventHub();
eh.setPeerAddr(ORGS[userOrg].peers[n].events, grpcOpts);
const eh = channel.newChannelEventHub(peer);
targets.push(eh);
}
}
@ -118,13 +119,13 @@ function newRemotes(names: string[], forPeers: boolean, userOrg: string) {
}
async function getAdminUser(userOrg: string): Promise<User> {
const users = hfc.getConfigSetting('admins');
const users = Client.getConfigSetting('admins');
const username = users[0].username;
const password = users[0].secret;
const client = getClientForOrg(userOrg);
const store = await hfc.newDefaultKeyValueStore({
const store = await Client.newDefaultKeyValueStore({
path: getKeyStoreForOrg(getOrgName(userOrg))
});
@ -145,13 +146,14 @@ async function getAdminUser(userOrg: string): Promise<User> {
});
logger.info('Successfully enrolled user \'' + username + '\'');
const userOptions: UserOptions = {
const userOptions: UserOpts = {
username,
mspid: getMspID(userOrg),
cryptoContent: {
privateKeyPEM: enrollment.key.toBytes(),
signedCertPEM: enrollment.certificate
}
},
skipPersistence: false
};
const member = await client.createUser(userOptions);
@ -167,7 +169,7 @@ export function newEventHubs(names: string[], org: string) {
}
export function setupChaincodeDeploy() {
process.env.GOPATH = path.join(__dirname, hfc.getConfigSetting('CC_SRC_PATH'));
process.env.GOPATH = path.join(__dirname, Client.getConfigSetting('CC_SRC_PATH'));
}
export function getOrgs() {
@ -184,26 +186,26 @@ export function getChannelForOrg(org: string): Channel {
export function init() {
hfc.addConfigFile(path.join(__dirname, config.networkConfigFile));
hfc.addConfigFile(path.join(__dirname, '../app_config.json'));
Client.addConfigFile(path.join(__dirname, config.networkConfigFile));
Client.addConfigFile(path.join(__dirname, '../app_config.json'));
ORGS = hfc.getConfigSetting('network-config');
ORGS = Client.getConfigSetting('network-config');
// set up the client and channel objects for each org
for (const key in ORGS) {
if (key.indexOf('org') === 0) {
const client = new hfc();
const client = new Client();
const cryptoSuite = hfc.newCryptoSuite();
const cryptoSuite = Client.newCryptoSuite();
// TODO: Fix it up as setCryptoKeyStore is only available for s/w impl
(cryptoSuite as any).setCryptoKeyStore(
hfc.newCryptoKeyStore({
Client.newCryptoKeyStore({
path: getKeyStoreForOrg(ORGS[key].name)
}));
client.setCryptoSuite(cryptoSuite);
const channel = client.newChannel(hfc.getConfigSetting('channelName'));
const channel = client.newChannel(Client.getConfigSetting('channelName'));
channel.addOrderer(newOrderer(client));
clients[key] = client;
@ -223,7 +225,7 @@ export async function getRegisteredUsers(
const client = getClientForOrg(userOrg);
const store = await hfc.newDefaultKeyValueStore({
const store = await Client.newDefaultKeyValueStore({
path: getKeyStoreForOrg(getOrgName(userOrg))
});
@ -259,13 +261,14 @@ export async function getRegisteredUsers(
}
logger.debug(username + ' enrolled successfully');
const userOptions: UserOptions = {
const userOptions: UserOpts = {
username,
mspid: getMspID(userOrg),
cryptoContent: {
privateKeyPEM: message.key.toBytes(),
signedCertPEM: message.certificate
}
},
skipPersistence: false
};
const member = await client.createUser(userOptions);
@ -286,15 +289,15 @@ export async function getOrgAdmin(userOrg: string): Promise<User> {
const certPEM = readAllFiles(certPath)[0].toString();
const client = getClientForOrg(userOrg);
const cryptoSuite = hfc.newCryptoSuite();
const cryptoSuite = Client.newCryptoSuite();
if (userOrg) {
(cryptoSuite as any).setCryptoKeyStore(
hfc.newCryptoKeyStore({ path: getKeyStoreForOrg(getOrgName(userOrg)) }));
Client.newCryptoKeyStore({ path: getKeyStoreForOrg(getOrgName(userOrg)) }));
client.setCryptoSuite(cryptoSuite);
}
const store = await hfc.newDefaultKeyValueStore({
const store = await Client.newDefaultKeyValueStore({
path: getKeyStoreForOrg(getOrgName(userOrg))
});
@ -306,6 +309,7 @@ export async function getOrgAdmin(userOrg: string): Promise<User> {
cryptoContent: {
privateKeyPEM: keyPEM,
signedCertPEM: certPEM
}
},
skipPersistence: false
});
}

View file

@ -10,6 +10,7 @@
"license": "Apache-2.0",
"devDependencies": {
"@types/body-parser": "^1.16.5",
"@types/bytebuffer": "^5.0.36",
"@types/cors": "^2.8.1",
"@types/express-jwt": "0.0.37",
"@types/express-session": "^1.15.3",
@ -18,7 +19,7 @@
"@types/node": "^8.0.33",
"express-bearer-token": "^2.1.0",
"jsonwebtoken": "^8.1.0",
"ts-node": "^3.3.0",
"ts-node": "^7.0.1",
"tslint": "^5.6.0",
"tslint-microsoft-contrib": "^5.0.1",
"typescript": "^2.5.3"
@ -30,8 +31,8 @@
"express": "^4.16.1",
"express-jwt": "^5.3.0",
"express-session": "^1.15.6",
"fabric-ca-client": "1.4.0-rc2",
"fabric-client": "1.4.0-rc2",
"fabric-ca-client": "~1.4.0",
"fabric-client": "~1.4.0",
"log4js": "^0.6.38"
}
}

View file

@ -51,21 +51,13 @@ function installNodeModules() {
echo "============== Installing node modules ============="
npm install
fi
copyIndex fabric-client/index.d.ts
copyIndex fabric-ca-client/index.d.ts
echo
}
function copyIndex() {
if [ ! -f node_modules/$1 ]; then
cp types/$1 node_modules/$1
fi
}
restartNetwork
installNodeModules
PORT=4000 ts-node app.ts
PORT=4000 `npm bin`/ts-node app.ts

View file

@ -1,18 +0,0 @@
/**
* Copyright 2017 Kapil Sachdeva All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
declare module 'fabric-ca-client' {
}

View file

@ -1,312 +0,0 @@
/**
* Copyright 2017 Kapil Sachdeva All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
declare enum Status {
UNKNOWN = 0,
SUCCESS = 200,
BAD_REQUEST = 400,
FORBIDDEN = 403,
NOT_FOUND = 404,
REQUEST_ENTITY_TOO_LARGE = 413,
INTERNAL_SERVER_ERROR = 500,
SERVICE_UNAVAILABLE = 503
}
type ChaicodeType = "golang" | "car" | "java";
interface ProtoBufObject {
toBuffer(): Buffer;
}
interface KeyOpts {
ephemeral: boolean;
}
interface ConnectionOptions {
}
interface ConfigSignature extends ProtoBufObject {
signature_header: Buffer;
signature: Buffer;
}
interface ICryptoKey {
getSKI(): string;
isSymmetric(): boolean;
isPrivate(): boolean;
getPublicKey(): ICryptoKey;
toBytes(): string;
}
interface ICryptoKeyStore {
getKey(ski: string): Promise<string>;
putKey(key: ICryptoKey): Promise<ICryptoKey>;
}
interface IKeyValueStore {
getValue(name: string): Promise<string>;
setValue(name: string, value: string): Promise<string>;
}
interface IdentityFiles {
privateKey: string;
signedCert: string;
}
interface IdentityPEMs {
privateKeyPEM: string;
signedCertPEM: string;
}
interface UserOptions {
username: string;
mspid: string;
cryptoContent: IdentityFiles | IdentityPEMs;
}
interface ICryptoSuite {
decrypt(key: ICryptoKey, cipherText: Buffer, opts: any): Buffer;
deriveKey(key: ICryptoKey): ICryptoKey;
encrypt(key: ICryptoKey, plainText: Buffer, opts: any): Buffer;
getKey(ski: string): Promise<ICryptoKey>;
generateKey(opts: KeyOpts): Promise<ICryptoKey>;
hash(msg: string, opts: any): string;
importKey(pem: string, opts: KeyOpts): ICryptoKey | Promise<ICryptoKey>;
sign(key: ICryptoKey, digest: Buffer): Buffer;
verify(key: ICryptoKey, signature: Buffer, digest: Buffer): boolean;
}
interface ChannelRequest {
name: string;
orderer: Orderer;
envelope?: Buffer;
config?: Buffer;
txId?: TransactionId;
signatures: ConfigSignature[];
}
interface TransactionRequest {
proposalResponses: ProposalResponse[];
proposal: Proposal;
}
interface BroadcastResponse {
status: string;
}
interface IIdentity {
serialize(): Buffer;
getMSPId(): string;
isValid(): boolean;
getOrganizationUnits(): string;
verify(msg: Buffer, signature: Buffer, opts: any): boolean;
}
interface ISigningIdentity {
sign(msg: Buffer, opts: any): Buffer;
}
interface ChaincodeInstallRequest {
targets: Peer[];
chaincodePath: string;
chaincodeId: string;
chaincodeVersion: string;
chaincodePackage?: Buffer;
chaincodeType?: ChaicodeType;
}
interface ChaincodeInstantiateUpgradeRequest {
targets?: Peer[];
chaincodeType?: string;
chaincodeId: string;
chaincodeVersion: string;
txId: TransactionId;
fcn?: string;
args?: string[];
'endorsement-policy'?: any;
}
interface ChaincodeInvokeRequest {
targets?: Peer[];
chaincodeId: string;
txId: TransactionId;
fcn?: string;
args: string[];
}
interface ChaincodeQueryRequest {
targets?: Peer[];
chaincodeId: string;
txId: TransactionId;
fcn?: string;
args: string[];
}
interface ChaincodeInfo {
name: string;
version: string;
path: string;
input: string;
escc: string;
vscc: string;
}
interface ChannelInfo {
channel_id: string;
}
interface ChaincodeQueryResponse {
chaincodes: ChaincodeInfo[];
}
interface ChannelQueryResponse {
channels: ChannelInfo[];
}
interface OrdererRequest {
txId: TransactionId;
}
interface JoinChannelRequest {
txId: TransactionId;
targets: Peer[];
block: Buffer;
}
interface ResponseObject {
status: Status;
message: string;
payload: Buffer;
}
interface Proposal {
header: ByteBuffer;
payload: ByteBuffer;
extension: ByteBuffer;
}
interface Header {
channel_header: ByteBuffer;
signature_header: ByteBuffer;
}
interface ProposalResponse {
version: number;
timestamp: Date;
response: ResponseObject;
payload: Buffer;
endorsement: any;
}
type ProposalResponseObject = [Array<ProposalResponse>, Proposal, Header];
declare class Orderer {
}
declare class Peer {
setName(name: string): void;
getName(): string;
}
declare class EventHub {
connect(): void;
disconnect(): void;
getPeerAddr(): string;
setPeerAddr(url: string, opts: ConnectionOptions): void;
isconnected(): boolean;
registerBlockEvent(onEvent: (b: any) => void, onError?: (err: Error) => void): number;
registerTxEvent(txId: string, onEvent: (txId: any, code: string) => void, onError?: (err: Error) => void): void;
unregisterTxEvent(txId: string): void;
}
declare class Channel {
initialize(): Promise<void>;
addOrderer(orderer: Orderer): void;
addPeer(peer: Peer): void;
getGenesisBlock(request: OrdererRequest): Promise<any>;
getChannelConfig(): Promise<any>;
joinChannel(request: JoinChannelRequest): Promise<ProposalResponse>;
sendInstantiateProposal(request: ChaincodeInstantiateUpgradeRequest): Promise<ProposalResponseObject>;
sendTransactionProposal(request: ChaincodeInvokeRequest): Promise<ProposalResponseObject>;
sendTransaction(request: TransactionRequest): Promise<BroadcastResponse>;
queryByChaincode(request: ChaincodeQueryRequest): Promise<Buffer[]>;
queryBlock(blockNumber: number, target: Peer): Promise<any>;
queryTransaction(txId: string, target: Peer): Promise<any>;
queryInstantiatedChaincodes(target: Peer): Promise<ChaincodeQueryResponse>;
queryInfo(target: Peer): Promise<any>;
getOrderers(): Orderer[];
getPeers(): Peer[];
}
declare abstract class BaseClient {
static setLogger(logger: any): void;
static addConfigFile(path: string): void;
static getConfigSetting(name: string, default_value?: any): any;
static newCryptoSuite(): ICryptoSuite;
static newCryptoKeyStore(obj?: { path: string }): ICryptoKeyStore;
static newDefaultKeyValueStore(obj?: { path: string }): Promise<IKeyValueStore>;
setCryptoSuite(suite: ICryptoSuite): void;
getCryptoSuite(): ICryptoSuite;
}
declare class TransactionId {
getTransactionID(): string;
}
interface UserConfig {
enrollmentID: string;
name: string
roles?: string[];
affiliation?: string;
}
declare class User {
isEnrolled(): boolean;
getName(): string;
getRoles(): string[];
setRoles(roles: string[]): void;
getAffiliation(): string;
setAffiliation(affiliation: string): void;
getIdentity(): IIdentity;
getSigningIdentity(): ISigningIdentity;
setCryptoSuite(suite: ICryptoSuite): void;
setEnrollment(privateKey: ICryptoKey, certificate: string, mspId: string): Promise<void>;
}
declare class Client extends BaseClient {
isDevMode(): boolean;
getUserContext(name: string, checkPersistence: boolean): Promise<User> | User;
setUserContext(user: User, skipPersistence?: boolean): Promise<User>;
setDevMode(mode: boolean): void;
newOrderer(url: string, opts: ConnectionOptions): Orderer;
newChannel(name: string): Channel;
newPeer(url: string, opts: ConnectionOptions): Peer;
newEventHub(): EventHub;
newTransactionID(): TransactionId;
extractChannelConfig(envelope: Buffer): Buffer;
createChannel(request: ChannelRequest): Promise<BroadcastResponse>;
createUser(opts: UserOptions): Promise<User>;
signChannelConfig(config: Buffer): ConfigSignature;
setStateStore(store: IKeyValueStore): void;
installChaincode(request: ChaincodeInstallRequest): Promise<ProposalResponseObject>;
queryInstalledChaincodes(target: Peer): Promise<ChaincodeQueryResponse>;
queryChannels(target: Peer): Promise<ChannelQueryResponse>;
}
declare module 'fabric-client' {
export = Client;
}

View file

@ -13,6 +13,7 @@ export MSYS_NO_PATHCONV=1
docker-compose -f docker-compose.yml down
docker-compose -f docker-compose.yml up -d ca.example.com orderer.example.com peer0.org1.example.com couchdb
docker ps -a
# wait for Hyperledger Fabric to start
# incase of errors when running later commands, issue export FABRIC_START_TIMEOUT=<larger number>

View file

@ -74,24 +74,24 @@ Terminal 2 - Build & start the chaincode
.. code:: bash
docker exec -it chaincode bash
docker exec -it chaincode sh
You should see the following:
.. code:: bash
.. code:: sh
root@d2629980e76b:/opt/gopath/src/chaincode#
/opt/gopath/src/chaincode $
Now, compile your chaincode:
.. code:: bash
.. code:: sh
cd chaincode_example02/go
go build -o chaincode_example02
Now run the chaincode:
.. code:: bash
.. code:: sh
CORE_PEER_ADDRESS=peer:7052 CORE_CHAINCODE_ID_NAME=mycc:0 ./chaincode_example02

View file

@ -78,7 +78,7 @@ services:
- CORE_PEER_LOCALMSPID=DEFAULT
- CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp
working_dir: /opt/gopath/src/chaincode
command: /bin/bash -c 'sleep 6000000'
command: /bin/sh -c 'sleep 6000000'
volumes:
- /var/run/:/host/var/run/
- ./msp:/etc/hyperledger/msp

View file

@ -0,0 +1,4 @@
bin/
.classpath
.settings/
.gradle

View file

@ -10,6 +10,6 @@
"engine-strict": true,
"license": "Apache-2.0",
"dependencies": {
"fabric-shim": "1.4.0-rc2"
"fabric-shim": "~1.4.0"
}
}

61
chaincode/fabcar/java/.gitignore vendored Normal file
View file

@ -0,0 +1,61 @@
#
# SPDX-License-Identifier: Apache-2.0
#
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
# Gradle
.gradle
/build/
# Ignore Gradle GUI config
gradle-app.setting
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
# Cache of project
.gradletasknamecache
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
# gradle/wrapper/gradle-wrapper.properties
# Eclipse files
.project
.classpath
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
.externalToolBuilders/
*.launch

View file

@ -0,0 +1,14 @@
# Java FabCar contract sample
The directions for using this sample are documented in the Hyperledger Fabric
[Writing Your First Application](https://hyperledger-fabric.readthedocs.io/en/latest/write_first_app.html) tutorial.
The tutorial is based on JavaScript, however the same concepts are applicable when using Java.
To install and instantiate the Java version of `FabCar`, use the following command instead of the command shown in the [Launch the network](https://hyperledger-fabric.readthedocs.io/en/release-1.4/write_first_app.html#launch-the-network) section of the tutorial:
```
./startFabric.sh javascript
```
*NOTE:* After navigating to the documentation, choose the documentation version that matches your version of Fabric

View file

@ -0,0 +1,81 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
plugins {
id 'checkstyle'
id 'com.github.johnrengelman.shadow' version '2.0.4'
id 'java-library'
id 'jacoco'
}
group 'org.hyperledger.fabric.samples'
version '1.0-SNAPSHOT'
dependencies {
implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:1.4+'
implementation 'com.owlike:genson:1.5'
testImplementation 'org.junit.jupiter:junit-jupiter:5.4.2'
testImplementation 'org.assertj:assertj-core:3.11.1'
testImplementation 'org.mockito:mockito-core:2.+'
}
repositories {
maven {
url "https://hyperledger.jfrog.io/hyperledger/fabric-maven"
}
jcenter()
maven {
url 'https://jitpack.io'
}
}
checkstyle {
toolVersion '8.21'
configFile file("config/checkstyle/checkstyle.xml")
}
checkstyleMain {
source ='src/main/java'
}
checkstyleTest {
source ='src/test/java'
}
shadowJar {
baseName = 'chaincode'
version = null
classifier = null
manifest {
attributes 'Main-Class': 'org.hyperledger.fabric.contract.ContractRouter'
}
}
jacocoTestCoverageVerification {
afterEvaluate {
classDirectories = files(classDirectories.files.collect {
fileTree(dir: it, exclude: [
'org/hyperledger/fabric/samples/fabcar/Start.*'
])
})
}
violationRules {
rule {
limit {
minimum = 1.0
}
}
}
finalizedBy jacocoTestReport
}
test {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed"
}
}
check.dependsOn jacocoTestCoverageVerification

View file

@ -0,0 +1,178 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<!--
Checkstyle configuration that matches the Eclipse formatter
Checkstyle is very configurable. Be sure to read the documentation at
http://checkstyle.sourceforge.net (or in your downloaded distribution).
Most Checks are configurable, be sure to consult the documentation.
To completely disable a check, just comment it out or delete it from the file.
Finally, it is worth reading the documentation.
-->
<module name="Checker">
<!--
If you set the basedir property below, then all reported file
names will be relative to the specified directory. See
https://checkstyle.org/5.x/config.html#Checker
<property name="basedir" value="${basedir}"/>
-->
<property name="fileExtensions" value="java, properties, xml"/>
<module name="SuppressionFilter">
<property name="file" value="config/checkstyle/suppressions.xml"/>
<property name="optional" value="false"/>
</module>
<!-- Excludes all 'module-info.java' files -->
<!-- See https://checkstyle.org/config_filefilters.html -->
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value="module\-info\.java$"/>
</module>
<!-- Checks that a package-info.java file exists for each package. -->
<!-- See http://checkstyle.sourceforge.net/config_javadoc.html#JavadocPackage -->
<!-- <module name="JavadocPackage"/> -->
<!-- Checks whether files end with a new line. -->
<!-- See http://checkstyle.sourceforge.net/config_misc.html#NewlineAtEndOfFile -->
<module name="NewlineAtEndOfFile"/>
<!-- Checks that property files contain the same keys. -->
<!-- See http://checkstyle.sourceforge.net/config_misc.html#Translation -->
<module name="Translation"/>
<!-- Checks for Size Violations. -->
<!-- See http://checkstyle.sourceforge.net/config_sizes.html -->
<module name="FileLength"/>
<!-- Checks for whitespace -->
<!-- See http://checkstyle.sourceforge.net/config_whitespace.html -->
<module name="FileTabCharacter"/>
<!-- Miscellaneous other checks. -->
<!-- See http://checkstyle.sourceforge.net/config_misc.html -->
<module name="RegexpSingleline">
<property name="format" value="\s+$"/>
<property name="minimum" value="0"/>
<property name="maximum" value="0"/>
<property name="message" value="Line has trailing spaces."/>
</module>
<!-- Checks for Headers -->
<!-- See http://checkstyle.sourceforge.net/config_header.html -->
<!-- <module name="Header"> -->
<!-- <property name="headerFile" value="${checkstyle.header.file}"/> -->
<!-- <property name="fileExtensions" value="java"/> -->
<!-- </module> -->
<module name="TreeWalker">
<!-- Checks for Javadoc comments. -->
<!-- See http://checkstyle.sourceforge.net/config_javadoc.html -->
<!-- <module name="JavadocMethod"/> -->
<!-- <module name="JavadocType"/> -->
<!-- <module name="JavadocVariable"/> -->
<!-- <module name="JavadocStyle"/> -->
<!-- <module name="MissingJavadocMethod"/> -->
<!-- Checks for Naming Conventions. -->
<!-- See http://checkstyle.sourceforge.net/config_naming.html -->
<module name="ConstantName"/>
<module name="LocalFinalVariableName"/>
<module name="LocalVariableName"/>
<module name="MemberName"/>
<module name="MethodName"/>
<module name="PackageName"/>
<module name="ParameterName"/>
<module name="StaticVariableName"/>
<module name="TypeName"/>
<!-- Checks for imports -->
<!-- See http://checkstyle.sourceforge.net/config_import.html -->
<module name="AvoidStarImport"/>
<module name="IllegalImport"/> <!-- defaults to sun.* packages -->
<module name="RedundantImport"/>
<module name="UnusedImports">
<property name="processJavadoc" value="false"/>
</module>
<!-- Checks for Size Violations. -->
<!-- See http://checkstyle.sourceforge.net/config_sizes.html -->
<module name="LineLength">
<property name="max" value="120"/>
</module>
<module name="MethodLength"/>
<module name="ParameterNumber"/>
<!-- Checks for whitespace -->
<!-- See http://checkstyle.sourceforge.net/config_whitespace.html -->
<module name="EmptyForIteratorPad"/>
<module name="GenericWhitespace"/>
<module name="MethodParamPad"/>
<module name="NoWhitespaceAfter"/>
<module name="NoWhitespaceBefore"/>
<module name="OperatorWrap"/>
<module name="ParenPad"/>
<module name="TypecastParenPad"/>
<module name="WhitespaceAfter"/>
<module name="WhitespaceAround"/>
<!-- Modifier Checks -->
<!-- See http://checkstyle.sourceforge.net/config_modifiers.html -->
<module name="ModifierOrder"/>
<module name="RedundantModifier"/>
<!-- Checks for blocks. You know, those {}'s -->
<!-- See http://checkstyle.sourceforge.net/config_blocks.html -->
<module name="AvoidNestedBlocks"/>
<module name="EmptyBlock"/>
<module name="LeftCurly"/>
<module name="NeedBraces"/>
<module name="RightCurly"/>
<!-- Checks for common coding problems -->
<!-- See http://checkstyle.sourceforge.net/config_coding.html -->
<module name="EmptyStatement"/>
<module name="EqualsHashCode"/>
<module name="HiddenField">
<property name="ignoreConstructorParameter" value="true"/>
</module>
<module name="IllegalInstantiation"/>
<module name="InnerAssignment"/>
<module name="MagicNumber"/>
<module name="MissingSwitchDefault"/>
<module name="MultipleVariableDeclarations"/>
<module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/>
<!-- Checks for class design -->
<!-- See http://checkstyle.sourceforge.net/config_design.html -->
<module name="DesignForExtension"/>
<module name="FinalClass"/>
<module name="HideUtilityClassConstructor"/>
<module name="InterfaceIsType"/>
<module name="VisibilityModifier">
<property name="allowPublicFinalFields" value="true"/>
</module>
<!-- Miscellaneous other checks. -->
<!-- See http://checkstyle.sourceforge.net/config_misc.html -->
<module name="ArrayTypeStyle"/>
<module name="FinalParameters"/>
<module name="TodoComment"/>
<module name="UpperEll"/>
</module>
</module>

View file

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
<suppressions>
<suppress files="ChaincodeTest.java" checks="ParameterNumber" />
</suppressions>

Binary file not shown.

View file

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

172
chaincode/fabcar/java/gradlew vendored Executable file
View file

@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
chaincode/fabcar/java/gradlew.bat vendored Normal file
View file

@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View file

@ -0,0 +1,5 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
rootProject.name = 'java-chaincode-bootstrap'

View file

@ -0,0 +1,79 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.fabric.samples.fabcar;
import java.util.Objects;
import org.hyperledger.fabric.contract.annotation.DataType;
import org.hyperledger.fabric.contract.annotation.Property;
import com.owlike.genson.annotation.JsonProperty;
@DataType()
public final class Car {
@Property()
private final String make;
@Property()
private final String model;
@Property()
private final String color;
@Property()
private final String owner;
public String getMake() {
return make;
}
public String getModel() {
return model;
}
public String getColor() {
return color;
}
public String getOwner() {
return owner;
}
public Car(@JsonProperty("make") final String make, @JsonProperty("model") final String model,
@JsonProperty("color") final String color, @JsonProperty("owner") final String owner) {
this.make = make;
this.model = model;
this.color = color;
this.owner = owner;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if ((obj == null) || (getClass() != obj.getClass())) {
return false;
}
Car other = (Car) obj;
return Objects.deepEquals(new String[] {getMake(), getModel(), getColor(), getOwner()},
new String[] {other.getMake(), other.getModel(), other.getColor(), other.getOwner()});
}
@Override
public int hashCode() {
return Objects.hash(getMake(), getModel(), getColor(), getOwner());
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()) + " [make=" + make + ", model="
+ model + ", color=" + color + ", owner=" + owner + "]";
}
}

View file

@ -0,0 +1,190 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.fabric.samples.fabcar;
import java.util.ArrayList;
import java.util.List;
import org.hyperledger.fabric.contract.Context;
import org.hyperledger.fabric.contract.ContractInterface;
import org.hyperledger.fabric.contract.annotation.Contact;
import org.hyperledger.fabric.contract.annotation.Contract;
import org.hyperledger.fabric.contract.annotation.Default;
import org.hyperledger.fabric.contract.annotation.Info;
import org.hyperledger.fabric.contract.annotation.License;
import org.hyperledger.fabric.contract.annotation.Transaction;
import org.hyperledger.fabric.shim.ChaincodeException;
import org.hyperledger.fabric.shim.ChaincodeStub;
import org.hyperledger.fabric.shim.ledger.KeyValue;
import org.hyperledger.fabric.shim.ledger.QueryResultsIterator;
import com.owlike.genson.Genson;
/**
* Java implementation of the Fabric Car Contract described in the Writing Your
* First Application tutorial
*/
@Contract(
name = "FabCar",
info = @Info(
title = "FabCar contract",
description = "The hyperlegendary car contract",
version = "0.0.1-SNAPSHOT",
license = @License(
name = "Apache 2.0 License",
url = "http://www.apache.org/licenses/LICENSE-2.0.html"),
contact = @Contact(
email = "f.carr@example.com",
name = "F Carr",
url = "https://hyperledger.example.com")))
@Default
public final class FabCar implements ContractInterface {
private final Genson genson = new Genson();
private enum FabCarErrors {
CAR_NOT_FOUND,
CAR_ALREADY_EXISTS
}
/**
* Retrieves a car with the specified key from the ledger.
*
* @param ctx the transaction context
* @param key the key
* @return the Car found on the ledger if there was one
*/
@Transaction()
public Car queryCar(final Context ctx, final String key) {
ChaincodeStub stub = ctx.getStub();
String carState = stub.getStringState(key);
if (carState.isEmpty()) {
String errorMessage = String.format("Car %s does not exist", key);
System.out.println(errorMessage);
throw new ChaincodeException(errorMessage, FabCarErrors.CAR_NOT_FOUND.toString());
}
Car car = genson.deserialize(carState, Car.class);
return car;
}
/**
* Creates some initial Cars on the ledger.
*
* @param ctx the transaction context
*/
@Transaction()
public void initLedger(final Context ctx) {
ChaincodeStub stub = ctx.getStub();
String[] carData = {
"{ \"make\": \"Toyota\", \"model\": \"Prius\", \"color\": \"blue\", \"owner\": \"Tomoko\" }",
"{ \"make\": \"Ford\", \"model\": \"Mustang\", \"color\": \"red\", \"owner\": \"Brad\" }",
"{ \"make\": \"Hyundai\", \"model\": \"Tucson\", \"color\": \"green\", \"owner\": \"Jin Soo\" }",
"{ \"make\": \"Volkswagen\", \"model\": \"Passat\", \"color\": \"yellow\", \"owner\": \"Max\" }",
"{ \"make\": \"Tesla\", \"model\": \"S\", \"color\": \"black\", \"owner\": \"Adrian\" }",
"{ \"make\": \"Peugeot\", \"model\": \"205\", \"color\": \"purple\", \"owner\": \"Michel\" }",
"{ \"make\": \"Chery\", \"model\": \"S22L\", \"color\": \"white\", \"owner\": \"Aarav\" }",
"{ \"make\": \"Fiat\", \"model\": \"Punto\", \"color\": \"violet\", \"owner\": \"Pari\" }",
"{ \"make\": \"Tata\", \"model\": \"nano\", \"color\": \"indigo\", \"owner\": \"Valeria\" }",
"{ \"make\": \"Holden\", \"model\": \"Barina\", \"color\": \"brown\", \"owner\": \"Shotaro\" }"
};
for (int i = 0; i < carData.length; i++) {
String key = String.format("CAR%03d", i);
Car car = genson.deserialize(carData[i], Car.class);
String carState = genson.serialize(car);
stub.putStringState(key, carState);
}
}
/**
* Creates a new car on the ledger.
*
* @param ctx the transaction context
* @param key the key for the new car
* @param make the make of the new car
* @param model the model of the new car
* @param color the color of the new car
* @param owner the owner of the new car
* @return the created Car
*/
@Transaction()
public Car createCar(final Context ctx, final String key, final String make, final String model,
final String color, final String owner) {
ChaincodeStub stub = ctx.getStub();
String carState = stub.getStringState(key);
if (!carState.isEmpty()) {
String errorMessage = String.format("Car %s already exists", key);
System.out.println(errorMessage);
throw new ChaincodeException(errorMessage, FabCarErrors.CAR_ALREADY_EXISTS.toString());
}
Car car = new Car(make, model, color, owner);
carState = genson.serialize(car);
stub.putStringState(key, carState);
return car;
}
/**
* Retrieves every car between CAR0 and CAR999 from the ledger.
*
* @param ctx the transaction context
* @return array of Cars found on the ledger
*/
@Transaction()
public Car[] queryAllCars(final Context ctx) {
ChaincodeStub stub = ctx.getStub();
final String startKey = "CAR0";
final String endKey = "CAR999";
List<Car> cars = new ArrayList<Car>();
QueryResultsIterator<KeyValue> results = stub.getStateByRange(startKey, endKey);
for (KeyValue result: results) {
Car car = genson.deserialize(result.getStringValue(), Car.class);
cars.add(car);
}
Car[] response = cars.toArray(new Car[cars.size()]);
return response;
}
/**
* Changes the owner of a car on the ledger.
*
* @param ctx the transaction context
* @param key the key
* @param newOwner the new owner
* @return the updated Car
*/
@Transaction()
public Car changeCarOwner(final Context ctx, final String key, final String newOwner) {
ChaincodeStub stub = ctx.getStub();
String carState = stub.getStringState(key);
if (carState.isEmpty()) {
String errorMessage = String.format("Car %s does not exist", key);
System.out.println(errorMessage);
throw new ChaincodeException(errorMessage, FabCarErrors.CAR_NOT_FOUND.toString());
}
Car car = genson.deserialize(carState, Car.class);
Car newCar = new Car(car.getMake(), car.getModel(), car.getColor(), newOwner);
String newCarState = genson.serialize(newCar);
stub.putStringState(key, newCarState);
return newCar;
}
}

View file

@ -0,0 +1,74 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.fabric.samples.fabcar;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
public final class CarTest {
@Nested
class Equality {
@Test
public void isReflexive() {
Car car = new Car("Toyota", "Prius", "blue", "Tomoko");
assertThat(car).isEqualTo(car);
}
@Test
public void isSymmetric() {
Car carA = new Car("Toyota", "Prius", "blue", "Tomoko");
Car carB = new Car("Toyota", "Prius", "blue", "Tomoko");
assertThat(carA).isEqualTo(carB);
assertThat(carB).isEqualTo(carA);
}
@Test
public void isTransitive() {
Car carA = new Car("Toyota", "Prius", "blue", "Tomoko");
Car carB = new Car("Toyota", "Prius", "blue", "Tomoko");
Car carC = new Car("Toyota", "Prius", "blue", "Tomoko");
assertThat(carA).isEqualTo(carB);
assertThat(carB).isEqualTo(carC);
assertThat(carA).isEqualTo(carC);
}
@Test
public void handlesInequality() {
Car carA = new Car("Toyota", "Prius", "blue", "Tomoko");
Car carB = new Car("Ford", "Mustang", "red", "Brad");
assertThat(carA).isNotEqualTo(carB);
}
@Test
public void handlesOtherObjects() {
Car carA = new Car("Toyota", "Prius", "blue", "Tomoko");
String carB = "not a car";
assertThat(carA).isNotEqualTo(carB);
}
@Test
public void handlesNull() {
Car car = new Car("Toyota", "Prius", "blue", "Tomoko");
assertThat(car).isNotEqualTo(null);
}
}
@Test
public void toStringIdentifiesCar() {
Car car = new Car("Toyota", "Prius", "blue", "Tomoko");
assertThat(car.toString()).isEqualTo("Car@61a77e4f [make=Toyota, model=Prius, color=blue, owner=Tomoko]");
}
}

View file

@ -0,0 +1,262 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.fabric.samples.fabcar;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.ThrowableAssert.catchThrowable;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.hyperledger.fabric.contract.Context;
import org.hyperledger.fabric.shim.ChaincodeException;
import org.hyperledger.fabric.shim.ChaincodeStub;
import org.hyperledger.fabric.shim.ledger.KeyValue;
import org.hyperledger.fabric.shim.ledger.QueryResultsIterator;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.InOrder;
public final class FabCarTest {
private final class MockKeyValue implements KeyValue {
private final String key;
private final String value;
MockKeyValue(final String key, final String value) {
super();
this.key = key;
this.value = value;
}
@Override
public String getKey() {
return this.key;
}
@Override
public String getStringValue() {
return this.value;
}
@Override
public byte[] getValue() {
return this.value.getBytes();
}
}
private final class MockCarResultsIterator implements QueryResultsIterator<KeyValue> {
private final List<KeyValue> carList;
MockCarResultsIterator() {
super();
carList = new ArrayList<KeyValue>();
carList.add(new MockKeyValue("CAR000",
"{\"color\":\"blue\",\"make\":\"Toyota\",\"model\":\"Prius\",\"owner\":\"Tomoko\"}"));
carList.add(new MockKeyValue("CAR001",
"{\"color\":\"red\",\"make\":\"Ford\",\"model\":\"Mustang\",\"owner\":\"Brad\"}"));
carList.add(new MockKeyValue("CAR002",
"{\"color\":\"green\",\"make\":\"Hyundai\",\"model\":\"Tucson\",\"owner\":\"Jin Soo\"}"));
carList.add(new MockKeyValue("CAR007",
"{\"color\":\"violet\",\"make\":\"Fiat\",\"model\":\"Punto\",\"owner\":\"Pari\"}"));
carList.add(new MockKeyValue("CAR009",
"{\"color\":\"brown\",\"make\":\"Holden\",\"model\":\"Barina\",\"owner\":\"Shotaro\"}"));
}
@Override
public Iterator<KeyValue> iterator() {
return carList.iterator();
}
@Override
public void close() throws Exception {
// do nothing
}
}
@Test
public void invokeUnknownTransaction() {
FabCar contract = new FabCar();
Context ctx = mock(Context.class);
Throwable thrown = catchThrowable(() -> {
contract.unknownTransaction(ctx);
});
assertThat(thrown).isInstanceOf(ChaincodeException.class).hasNoCause()
.hasMessage("Undefined contract method called");
assertThat(((ChaincodeException) thrown).getPayload()).isEqualTo(null);
verifyZeroInteractions(ctx);
}
@Nested
class InvokeQueryCarTransaction {
@Test
public void whenCarExists() {
FabCar contract = new FabCar();
Context ctx = mock(Context.class);
ChaincodeStub stub = mock(ChaincodeStub.class);
when(ctx.getStub()).thenReturn(stub);
when(stub.getStringState("CAR000"))
.thenReturn("{\"color\":\"blue\",\"make\":\"Toyota\",\"model\":\"Prius\",\"owner\":\"Tomoko\"}");
Car car = contract.queryCar(ctx, "CAR000");
assertThat(car).isEqualTo(new Car("Toyota", "Prius", "blue", "Tomoko"));
}
@Test
public void whenCarDoesNotExist() {
FabCar contract = new FabCar();
Context ctx = mock(Context.class);
ChaincodeStub stub = mock(ChaincodeStub.class);
when(ctx.getStub()).thenReturn(stub);
when(stub.getStringState("CAR000")).thenReturn("");
Throwable thrown = catchThrowable(() -> {
contract.queryCar(ctx, "CAR000");
});
assertThat(thrown).isInstanceOf(ChaincodeException.class).hasNoCause()
.hasMessage("Car CAR000 does not exist");
assertThat(((ChaincodeException) thrown).getPayload()).isEqualTo("CAR_NOT_FOUND".getBytes());
}
}
@Test
void invokeInitLedgerTransaction() {
FabCar contract = new FabCar();
Context ctx = mock(Context.class);
ChaincodeStub stub = mock(ChaincodeStub.class);
when(ctx.getStub()).thenReturn(stub);
contract.initLedger(ctx);
InOrder inOrder = inOrder(stub);
inOrder.verify(stub).putStringState("CAR000",
"{\"color\":\"blue\",\"make\":\"Toyota\",\"model\":\"Prius\",\"owner\":\"Tomoko\"}");
inOrder.verify(stub).putStringState("CAR001",
"{\"color\":\"red\",\"make\":\"Ford\",\"model\":\"Mustang\",\"owner\":\"Brad\"}");
inOrder.verify(stub).putStringState("CAR002",
"{\"color\":\"green\",\"make\":\"Hyundai\",\"model\":\"Tucson\",\"owner\":\"Jin Soo\"}");
inOrder.verify(stub).putStringState("CAR003",
"{\"color\":\"yellow\",\"make\":\"Volkswagen\",\"model\":\"Passat\",\"owner\":\"Max\"}");
inOrder.verify(stub).putStringState("CAR004",
"{\"color\":\"black\",\"make\":\"Tesla\",\"model\":\"S\",\"owner\":\"Adrian\"}");
inOrder.verify(stub).putStringState("CAR005",
"{\"color\":\"purple\",\"make\":\"Peugeot\",\"model\":\"205\",\"owner\":\"Michel\"}");
inOrder.verify(stub).putStringState("CAR006",
"{\"color\":\"white\",\"make\":\"Chery\",\"model\":\"S22L\",\"owner\":\"Aarav\"}");
inOrder.verify(stub).putStringState("CAR007",
"{\"color\":\"violet\",\"make\":\"Fiat\",\"model\":\"Punto\",\"owner\":\"Pari\"}");
inOrder.verify(stub).putStringState("CAR008",
"{\"color\":\"indigo\",\"make\":\"Tata\",\"model\":\"nano\",\"owner\":\"Valeria\"}");
inOrder.verify(stub).putStringState("CAR009",
"{\"color\":\"brown\",\"make\":\"Holden\",\"model\":\"Barina\",\"owner\":\"Shotaro\"}");
}
@Nested
class InvokeCreateCarTransaction {
@Test
public void whenCarExists() {
FabCar contract = new FabCar();
Context ctx = mock(Context.class);
ChaincodeStub stub = mock(ChaincodeStub.class);
when(ctx.getStub()).thenReturn(stub);
when(stub.getStringState("CAR000"))
.thenReturn("{\"color\":\"blue\",\"make\":\"Toyota\",\"model\":\"Prius\",\"owner\":\"Tomoko\"}");
Throwable thrown = catchThrowable(() -> {
contract.createCar(ctx, "CAR000", "Nissan", "Leaf", "green", "Siobhán");
});
assertThat(thrown).isInstanceOf(ChaincodeException.class).hasNoCause()
.hasMessage("Car CAR000 already exists");
assertThat(((ChaincodeException) thrown).getPayload()).isEqualTo("CAR_ALREADY_EXISTS".getBytes());
}
@Test
public void whenCarDoesNotExist() {
FabCar contract = new FabCar();
Context ctx = mock(Context.class);
ChaincodeStub stub = mock(ChaincodeStub.class);
when(ctx.getStub()).thenReturn(stub);
when(stub.getStringState("CAR000")).thenReturn("");
Car car = contract.createCar(ctx, "CAR000", "Nissan", "Leaf", "green", "Siobhán");
assertThat(car).isEqualTo(new Car("Nissan", "Leaf", "green", "Siobhán"));
}
}
@Test
void invokeQueryAllCarsTransaction() {
FabCar contract = new FabCar();
Context ctx = mock(Context.class);
ChaincodeStub stub = mock(ChaincodeStub.class);
when(ctx.getStub()).thenReturn(stub);
when(stub.getStateByRange("CAR0", "CAR999")).thenReturn(new MockCarResultsIterator());
Car[] cars = contract.queryAllCars(ctx);
final List<Car> expectedCars = new ArrayList<Car>();
expectedCars.add(new Car("Toyota", "Prius", "blue", "Tomoko"));
expectedCars.add(new Car("Ford", "Mustang", "red", "Brad"));
expectedCars.add(new Car("Hyundai", "Tucson", "green", "Jin Soo"));
expectedCars.add(new Car("Fiat", "Punto", "violet", "Pari"));
expectedCars.add(new Car("Holden", "Barina", "brown", "Shotaro"));
assertThat(cars).containsExactlyElementsOf(expectedCars);
}
@Nested
class ChangeCarOwnerTransaction {
@Test
public void whenCarExists() {
FabCar contract = new FabCar();
Context ctx = mock(Context.class);
ChaincodeStub stub = mock(ChaincodeStub.class);
when(ctx.getStub()).thenReturn(stub);
when(stub.getStringState("CAR000"))
.thenReturn("{\"color\":\"blue\",\"make\":\"Toyota\",\"model\":\"Prius\",\"owner\":\"Tomoko\"}");
Car car = contract.changeCarOwner(ctx, "CAR000", "Dr Evil");
assertThat(car).isEqualTo(new Car("Toyota", "Prius", "blue", "Dr Evil"));
}
@Test
public void whenCarDoesNotExist() {
FabCar contract = new FabCar();
Context ctx = mock(Context.class);
ChaincodeStub stub = mock(ChaincodeStub.class);
when(ctx.getStub()).thenReturn(stub);
when(stub.getStringState("CAR000")).thenReturn("");
Throwable thrown = catchThrowable(() -> {
contract.changeCarOwner(ctx, "CAR000", "Dr Evil");
});
assertThat(thrown).isInstanceOf(ChaincodeException.class).hasNoCause()
.hasMessage("Car CAR000 does not exist");
assertThat(((ChaincodeException) thrown).getPayload()).isEqualTo("CAR_NOT_FOUND".getBytes());
}
}
}

View file

@ -12,6 +12,6 @@
"engine-strict": true,
"license": "Apache-2.0",
"dependencies": {
"fabric-shim": "1.4.0-rc2"
"fabric-shim": "~1.4.0"
}
}

View file

@ -17,8 +17,8 @@
"author": "Hyperledger",
"license": "Apache-2.0",
"dependencies": {
"fabric-contract-api": "1.4.0-rc2",
"fabric-shim": "1.4.0-rc2"
"fabric-contract-api": "~1.4.0",
"fabric-shim": "~1.4.0"
},
"devDependencies": {
"chai": "^4.1.2",

View file

@ -21,8 +21,8 @@
"author": "Hyperledger",
"license": "Apache-2.0",
"dependencies": {
"fabric-contract-api": "1.4.0-rc2",
"fabric-shim": "1.4.0-rc2"
"fabric-contract-api": "~1.4.0",
"fabric-shim": "~1.4.0"
},
"devDependencies": {
"@types/chai": "^4.1.7",

View file

@ -462,10 +462,10 @@ let Chaincode = class {
}
const queryString = args[0];
const pageSize = parseInt(args[2], 10);
const bookmark = args[3];
const pageSize = parseInt(args[1], 10);
const bookmark = args[2];
const { iterator, metadata } = await stub.GetQueryResultWithPagination(queryString, pageSize, bookmark);
const { iterator, metadata } = await stub.getQueryResultWithPagination(queryString, pageSize, bookmark);
const getAllResults = thisClass['getAllResults'];
const results = await getAllResults(iterator, false);
// use RecordsCount and Bookmark to keep consistency with the go sample

View file

@ -10,6 +10,6 @@
"engine-strict": true,
"license": "Apache-2.0",
"dependencies": {
"fabric-shim": "1.4.0-rc2"
"fabric-shim": "~1.4.0"
}
}

View file

@ -8,19 +8,19 @@ SPDX-License-Identifier: Apache-2.0
// ==== Invoke marbles, pass private data as base64 encoded bytes in transient map ====
//
// export MARBLE=$(echo -n "{\"name\":\"marble1\",\"color\":\"blue\",\"size\":35,\"owner\":\"tom\",\"price\":99}" | base64)
// export MARBLE=$(echo -n "{\"name\":\"marble1\",\"color\":\"blue\",\"size\":35,\"owner\":\"tom\",\"price\":99}" | base64 | tr -d \\n)
// peer chaincode invoke -C mychannel -n marblesp -c '{"Args":["initMarble"]}' --transient "{\"marble\":\"$MARBLE\"}"
//
// export MARBLE=$(echo -n "{\"name\":\"marble2\",\"color\":\"red\",\"size\":50,\"owner\":\"tom\",\"price\":102}" | base64)
// export MARBLE=$(echo -n "{\"name\":\"marble2\",\"color\":\"red\",\"size\":50,\"owner\":\"tom\",\"price\":102}" | base64 | tr -d \\n)
// peer chaincode invoke -C mychannel -n marblesp -c '{"Args":["initMarble"]}' --transient "{\"marble\":\"$MARBLE\"}"
//
// export MARBLE=$(echo -n "{\"name\":\"marble3\",\"color\":\"blue\",\"size\":70,\"owner\":\"tom\",\"price\":103}" | base64)
// export MARBLE=$(echo -n "{\"name\":\"marble3\",\"color\":\"blue\",\"size\":70,\"owner\":\"tom\",\"price\":103}" | base64 | tr -d \\n)
// peer chaincode invoke -C mychannel -n marblesp -c '{"Args":["initMarble"]}' --transient "{\"marble\":\"$MARBLE\"}"
//
// export MARBLE_OWNER=$(echo -n "{\"name\":\"marble2\",\"owner\":\"jerry\"}" | base64)
// export MARBLE_OWNER=$(echo -n "{\"name\":\"marble2\",\"owner\":\"jerry\"}" | base64 | tr -d \\n)
// peer chaincode invoke -C mychannel -n marblesp -c '{"Args":["transferMarble"]}' --transient "{\"marble_owner\":\"$MARBLE_OWNER\"}"
//
// export MARBLE_DELETE=$(echo -n "{\"name\":\"marble1\"}" | base64)
// export MARBLE_DELETE=$(echo -n "{\"name\":\"marble1\"}" | base64 | tr -d \\n)
// peer chaincode invoke -C mychannel -n marblesp -c '{"Args":["delete"]}' --transient "{\"marble_delete\":\"$MARBLE_DELETE\"}"
// ==== Query marbles, since queries are not recorded on chain we don't need to hide private data in transient map ====

56
ci/azure-pipelines.yml Normal file
View file

@ -0,0 +1,56 @@
#
# SPDX-License-Identifier: Apache-2.0
#
trigger:
- master
- release-1.4
variables:
NODE_VER: '10.x'
PATH: $(Agent.BuildDirectory)/bin:/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin
jobs:
- job: fabcar_go
displayName: FabCar (Go)
pool:
vmImage: ubuntu-18.04
dependsOn: []
timeoutInMinutes: 60
steps:
- template: install-deps.yml
- template: install-fabric.yml
- template: fabcar-go.yml
- job: fabcar_java
displayName: FabCar (Java)
pool:
vmImage: ubuntu-18.04
dependsOn: []
timeoutInMinutes: 60
steps:
- template: install-deps.yml
- template: install-fabric.yml
- template: fabcar-java.yml
- job: fabcar_javascript
displayName: FabCar (JavaScript)
pool:
vmImage: ubuntu-18.04
dependsOn: []
timeoutInMinutes: 60
steps:
- template: install-deps.yml
- template: install-fabric.yml
- template: fabcar-javascript.yml
- job: fabcar_typescript
displayName: FabCar (TypeScript)
pool:
vmImage: ubuntu-18.04
dependsOn: []
timeoutInMinutes: 60
steps:
- template: install-deps.yml
- template: install-fabric.yml
- template: fabcar-typescript.yml

8
ci/fabcar-go.yml Normal file
View file

@ -0,0 +1,8 @@
#
# SPDX-License-Identifier: Apache-2.0
#
steps:
- script: bash startFabric.sh go
workingDirectory: fabcar
displayName: Start Fabric

14
ci/fabcar-java.yml Normal file
View file

@ -0,0 +1,14 @@
#
# SPDX-License-Identifier: Apache-2.0
#
steps:
- script: bash startFabric.sh java
workingDirectory: fabcar
displayName: Start Fabric
- script: retry -- mvn dependency:go-offline
workingDirectory: fabcar/java
displayName: Install FabCar application dependencies
- script: mvn test
workingDirectory: fabcar/java
displayName: Run FabCar application

19
ci/fabcar-javascript.yml Normal file
View file

@ -0,0 +1,19 @@
#
# SPDX-License-Identifier: Apache-2.0
#
steps:
- script: bash startFabric.sh javascript
workingDirectory: fabcar
displayName: Start Fabric
- script: retry -- npm install
workingDirectory: fabcar/javascript
displayName: Install FabCar application dependencies
- script: |
set -ex
node enrollAdmin
node registerUser
node invoke
node query
workingDirectory: fabcar/javascript
displayName: Run FabCar application

22
ci/fabcar-typescript.yml Normal file
View file

@ -0,0 +1,22 @@
#
# SPDX-License-Identifier: Apache-2.0
#
steps:
- script: bash startFabric.sh typescript
workingDirectory: fabcar
displayName: Start Fabric
- script: retry -- npm install
workingDirectory: fabcar/typescript
displayName: Install FabCar application dependencies
- script: npm run build
workingDirectory: fabcar/typescript
displayName: Build FabCar application
- script: |
set -ex
node dist/enrollAdmin
node dist/registerUser
node dist/invoke
node dist/query
workingDirectory: fabcar/typescript
displayName: Run FabCar application

11
ci/install-deps.yml Normal file
View file

@ -0,0 +1,11 @@
#
# SPDX-License-Identifier: Apache-2.0
#
steps:
- script: sudo sh -c "curl https://raw.githubusercontent.com/kadwanev/retry/master/retry -o /usr/local/bin/retry && chmod +x /usr/local/bin/retry"
displayName: Install retry CLI
- task: NodeTool@0
inputs:
versionSpec: $(NODE_VER)
displayName: 'Install Node.js'

27
ci/install-fabric.yml Normal file
View file

@ -0,0 +1,27 @@
#
# SPDX-License-Identifier: Apache-2.0
#
steps:
- script: |
set -eo pipefail
curl -L --retry 5 --retry-delay 3 https://hyperledger.jfrog.io/hyperledger/fabric-binaries/hyperledger-fabric-linux-amd64-1.4-stable.tar.gz | tar xz
displayName: Download Fabric CLI
- script: |
set -eo pipefail
curl -L --retry 5 --retry-delay 3 https://hyperledger.jfrog.io/hyperledger/fabric-binaries/hyperledger-fabric-ca-linux-amd64-1.4-stable.tar.gz | tar xz
displayName: Download Fabric CA CLI
- script: |
set -ex
version=1.4
for i in ca ccenv javaenv peer orderer tools; do
docker pull hyperledger-fabric.jfrog.io/fabric-$i:amd64-$version-stable
docker tag hyperledger-fabric.jfrog.io/fabric-$i:amd64-$version-stable hyperledger/fabric-$i:amd64-$version-stable
docker tag hyperledger-fabric.jfrog.io/fabric-$i:amd64-$version-stable hyperledger/fabric-$i:amd64-$version
docker tag hyperledger-fabric.jfrog.io/fabric-$i:amd64-$version-stable hyperledger/fabric-$i:$version
docker tag hyperledger-fabric.jfrog.io/fabric-$i:amd64-$version-stable hyperledger/fabric-$i:latest
done
docker pull hyperledger/fabric-couchdb:0.4.15
docker tag hyperledger/fabric-couchdb:0.4.15 hyperledger/fabric-couchdb:latest
displayName: Pull Fabric Docker images

View file

@ -0,0 +1,17 @@
.PHONY: all
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
all: digibank magnetocorp
digibank:
cd ${ROOT_DIR}/../organization/$@/application-java; mvn clean compile package
cd ${ROOT_DIR}/../organization/$@/contract-java; ./gradlew clean build shadowJar
cd ${ROOT_DIR}/../organization/$@/application; npm install && npm run lint
cd ${ROOT_DIR}/../organization/$@/contract; npm install && npm run lint
magnetocorp:
cd ${ROOT_DIR}/../organization/$@/application-java; mvn clean compile package
cd ${ROOT_DIR}/../organization/$@/contract-java; ./gradlew clean build shadowJar
cd ${ROOT_DIR}/../organization/$@/application; npm install && npm run lint
cd ${ROOT_DIR}/../organization/$@/contract; npm install && npm run lint

View file

@ -1,8 +0,0 @@
organization/magnetocorp/application/node_modules/
organization/magnetocorp/contract/node_modules/
organization/magnetocorp/identity/user/
organization/digibank/application/node_modules/
organization/digibank/contract/node_modules/
organization/digibank/identity/user/
package-lock.json
.vscode

156
commercial-paper/README.md Normal file
View file

@ -0,0 +1,156 @@
# Commercial Paper Tutorial
This folder contains the code for an introductory tutorial to Smart Contract development. It is based around the scenario of Commercial Paper.
The full tutorial, including full scenario details and line by line code walkthroughs is in the [Hyperledger Fabric documentation](https://hyperledger-fabric.readthedocs.io/en/release-1.4/tutorial/commercial_paper.html).
## Scenario
In this tutorial two organizations, MagnetoCorp and DigiBank, trade commercial paper with each other using PaperNet, a Hyperledger Fabric blockchain network.
Once youve set up a basic network, youll act as Isabella, an employee of MagnetoCorp, who will issue a commercial paper on its behalf. Youll then switch hats to take the role of Balaji, an employee of DigiBank, who will buy this commercial paper, hold it for a period of time, and then redeem it with MagnetoCorp for a small profit.
![](https://hyperledger-fabric.readthedocs.io/en/release-1.4/_images/commercial_paper.diagram.1.png)
## Quick Start
You are strongly advised to read the full tutorial to get information about the code and the scenario. Below are the quick start instructions for running the tutorial, but no details on the how or why it works.
### Steps
1) Start the Hyperledger Fabric infrastructure
_although the scenario has two organizations, the 'basic' or 'developement' Fabric infrastructure will be used_
2) Install and Instantiate the Contracts
3) Run client applications in the roles of MagnetoCorp and Digibank to trade the commecial paper
- Issue the Paper as Magnetocorp
- Buy the paper as DigiBank
- Redeem the paper as DigiBank
## Setup
You will need a a machine with the following
- Docker and docker-compose installed
- Node.js v8 if you want to run Javascript client applications
- Java v8 if you want to run Java client applications
- Maven to build the Java applications
It is advised to have 3 console windows open; one to monitor the infrastructure and one each for MagnetoCorp and DigiBank
If you haven't already clone the repository to a directory of your choice, and change to the `commercial-paper` directory
```
git clone https://github.com/hyperledger/fabric-samples.git
cd fabric-samples/commercial-paper
```
This `README.md` file is in the the `commercial-paper` directory, the source code for client applications and the contracts ins in the `ogranization` directory, and some helper scripts are in the `roles` directory.
## Running the Infrastructure
In one console window, run the `./roles/network-starter.sh` script; this will start the basic infrastructure and also start monitoring all the docker containers.
You can cancel this if you wish to reuse the terminal, but it's best left open.
### Install and Instantiate the contract
The contract code is available as either JavaScript or Java. You can use either one, and the choice of contract language does not affect the choice of client langauge.
In your 'MagnetoCorp' window run the following command
`./roles/magnetocorp.sh`
This will start a docker container for Fabric CLI commands, and put you in the correct directory for the source code.
**For a JavaScript Contract:**
```
docker exec cliMagnetoCorp peer chaincode install -n papercontract -v 0 -p /opt/gopath/src/github.com/contract -l node
docker exec cliMagnetoCorp peer chaincode instantiate -n papercontract -v 0 -l node -c '{"Args":["org.papernet.commercialpaper:instantiate"]}' -C mychannel -P "AND ('Org1MSP.member')"
```
**For a Java Contract:**
```
docker exec cliMagnetoCorp peer chaincode install -n papercontract -v 0 -p /opt/gopath/src/github.com/contract-java -l java
docker exec cliMagnetoCorp peer chaincode instantiate -n papercontract -v 0 -l java -c '{"Args":["org.papernet.commercialpaper:instantiate"]}' -C mychannel -P "AND ('Org1MSP.member')"
```
> If you want to try both a Java and JavaScript Contract, then you will need to restart the infrastructure and deploy the other contract.
## Client Applications
Note for Java applications you will need to compile the Java Code using maven. Use this command in each application-java directory
```
mvn clean package
```
Note for JavaScript applications you will need to install the dependencies first. Use this command in each application directory
```
npm install
```
> Note that there is NO dependency between the langauge of any one client application and any contract. Mix and match as you wish!
### Issue the paper
This is running as *MagnetoCorp* so you can stay in the same window. These commands are to be run in the
`commercial-paper/organization/magnetocorp/application` directory or the `commercial-paper/organization/magnetocorp/application-java`
*Add the Identity to be used*
```
node addToWallet.js
# or
java -cp target/commercial-paper-0.0.1-SNAPSHOT.jar org.magnetocorp.AddToWallet
```
*Issue the Commercial Paper*
```
node issue.js
# or
java -cp target/commercial-paper-0.0.1-SNAPSHOT.jar org.magnetocorp.Issue
```
### Buy and Redeem the paper
This is running as *Digibank*; you've not acted as this organization before so in your 'Digibank' window run the following command in the
`fabric-samples/commercial-paper/` directory
`./roles/digibank.sh`
You can now run the applications to buy and redeem the paper. Change to either the
`commercial-paper/organization/digibank/application` directory or `commercial-paper/organization/digibank/application-java`
*Add the Identity to be used*
```
node addToWallet.js
# or
java -cp target/commercial-paper-0.0.1-SNAPSHOT.jar org.digibank.AddToWallet
```
*Buy the paper*
```
node buy.js
# or
java -cp target/commercial-paper-0.0.1-SNAPSHOT.jar org.digibank.Buy
```
*Redeem*
```
node redeem.js
# or
java -cp target/commercial-paper-0.0.1-SNAPSHOT.jar org.digibank.Redeem
```

View file

@ -0,0 +1 @@
identity

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View file

@ -0,0 +1 @@
target/

View file

@ -0,0 +1,6 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.8

View file

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

View file

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>commercial-paper</groupId>
<artifactId>commercial-paper</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>hyperledger</id>
<name>Hyperledger Artifactory</name>
<url>https://hyperledger.jfrog.io/hyperledger/fabric-maven</url>
</repository>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<properties>
<fabric-chaincode-java.version>1.4.2</fabric-chaincode-java.version>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View file

@ -0,0 +1,99 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>commercial-paper</groupId>
<artifactId>commercial-paper</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<!-- Generic properties -->
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- fabric-chaincode-java -->
<fabric-chaincode-java.version>1.4.2</fabric-chaincode-java.version>
</properties>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<!-- Attach the shade goal into the package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>hyperledger</id>
<name>Hyperledger Artifactory</name>
<url>https://hyperledger.jfrog.io/hyperledger/fabric-maven</url>
</repository>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.hyperledger.fabric-gateway-java</groupId>
<artifactId>fabric-gateway-java</artifactId>
<version>1.4.0-SNAPSHOT</version>
</dependency>
<!-- Used for datatype annotations only -->
<dependency>
<groupId>org.hyperledger.fabric-chaincode-java</groupId>
<artifactId>fabric-chaincode-shim</artifactId>
<version>${fabric-chaincode-java.version}</version>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.json/json -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20180813</version>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,44 @@
/*
SPDX-License-Identifier: Apache-2.0
*/
package org.digibank;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.hyperledger.fabric.gateway.GatewayException;
import org.hyperledger.fabric.gateway.Wallet;
import org.hyperledger.fabric.gateway.Wallet.Identity;
public class AddToWallet {
public static void main(String[] args) {
try {
// A wallet stores a collection of identities
Path walletPath = Paths.get("..", "identity", "user", "balaji", "wallet");
Wallet wallet = Wallet.createFileSystemWallet(walletPath);
// Location of credentials to be stored in the wallet
Path credentialPath = Paths.get("..", "..", "..", "..","basic-network", "crypto-config",
"peerOrganizations", "org1.example.com", "users", "Admin@org1.example.com", "msp");
Path certificatePem = credentialPath.resolve(Paths.get("signcerts",
"Admin@org1.example.com-cert.pem"));
Path privateKey = credentialPath.resolve(Paths.get("keystore",
"cd96d5260ad4757551ed4a5a991e62130f8008a0bf996e4e4b84cd097a747fec_sk"));
// Load credentials into wallet
String identityLabel = "Admin@org1.example.com";
Identity identity = Identity.createIdentity("Org1MSP", Files.newBufferedReader(certificatePem), Files.newBufferedReader(privateKey));
wallet.put(identityLabel, identity);
} catch (IOException e) {
System.err.println("Error adding to wallet");
e.printStackTrace();
}
}
}

View file

@ -0,0 +1,72 @@
/*
SPDX-License-Identifier: Apache-2.0
*/
package org.digibank;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.concurrent.TimeoutException;
import org.hyperledger.fabric.gateway.Contract;
import org.hyperledger.fabric.gateway.Gateway;
import org.hyperledger.fabric.gateway.GatewayException;
import org.hyperledger.fabric.gateway.Network;
import org.hyperledger.fabric.gateway.Wallet;
import org.papernet.CommercialPaper;
public class Buy {
private static final String ENVKEY="CONTRACT_NAME";
public static void main(String[] args) {
Gateway.Builder builder = Gateway.createBuilder();
String contractName="papercontract";
// get the name of the contract, in case it is overridden
Map<String,String> envvar = System.getenv();
if (envvar.containsKey(ENVKEY)){
contractName=envvar.get(ENVKEY);
}
try {
// A wallet stores a collection of identities
Path walletPath = Paths.get("..", "identity", "user", "balaji", "wallet");
Wallet wallet = Wallet.createFileSystemWallet(walletPath);
String userName = "Admin@org1.example.com";
Path connectionProfile = Paths.get("..", "gateway", "networkConnection.yaml");
// Set connection options on the gateway builder
builder.identity(wallet, userName).networkConfig(connectionProfile).discovery(false);
// Connect to gateway using application specified parameters
try(Gateway gateway = builder.connect()) {
// Access PaperNet network
System.out.println("Use network channel: mychannel.");
Network network = gateway.getNetwork("mychannel");
// Get addressability to commercial paper contract
System.out.println("Use org.papernet.commercialpaper smart contract.");
Contract contract = network.getContract(contractName, "org.papernet.commercialpaper");
// Buy commercial paper
System.out.println("Submit commercial paper buy transaction.");
byte[] response = contract.submitTransaction("buy", "MagnetoCorp", "00001", "MagnetoCorp", "DigiBank", "4900000", "2020-05-31");
// Process response
System.out.println("Process buy transaction response.");
CommercialPaper paper = CommercialPaper.deserialize(response);
System.out.println(paper);
}
} catch (GatewayException | IOException | TimeoutException | InterruptedException e) {
e.printStackTrace();
System.exit(-1);
}
}
}

View file

@ -0,0 +1,72 @@
/*
SPDX-License-Identifier: Apache-2.0
*/
package org.digibank;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.concurrent.TimeoutException;
import org.hyperledger.fabric.gateway.Contract;
import org.hyperledger.fabric.gateway.Gateway;
import org.hyperledger.fabric.gateway.GatewayException;
import org.hyperledger.fabric.gateway.Network;
import org.hyperledger.fabric.gateway.Wallet;
import org.papernet.CommercialPaper;
public class Redeem {
private static final String ENVKEY="CONTRACT_NAME";
public static void main(String[] args) {
Gateway.Builder builder = Gateway.createBuilder();
String contractName="papercontract";
// get the name of the contract, in case it is overridden
Map<String,String> envvar = System.getenv();
if (envvar.containsKey(ENVKEY)){
contractName=envvar.get(ENVKEY);
}
try {
// A wallet stores a collection of identities
Path walletPath = Paths.get("..", "identity", "user", "balaji", "wallet");
Wallet wallet = Wallet.createFileSystemWallet(walletPath);
String userName = "Admin@org1.example.com";
Path connectionProfile = Paths.get("..", "gateway", "networkConnection.yaml");
// Set connection options on the gateway builder
builder.identity(wallet, userName).networkConfig(connectionProfile).discovery(false);
// Connect to gateway using application specified parameters
try(Gateway gateway = builder.connect()) {
// Access PaperNet network
System.out.println("Use network channel: mychannel.");
Network network = gateway.getNetwork("mychannel");
// Get addressability to commercial paper contract
System.out.println("Use org.papernet.commercialpaper smart contract.");
Contract contract = network.getContract("papercontract", "org.papernet.commercialpaper");
// Redeem commercial paper
System.out.println("Submit commercial paper redeem transaction.");
byte[] response = contract.submitTransaction("redeem", "MagnetoCorp", "00001", "DigiBank", "2020-11-30");
// Process response
System.out.println("Process redeem transaction response.");
CommercialPaper paper = CommercialPaper.deserialize(response);
System.out.println(paper);
}
} catch (GatewayException | IOException | TimeoutException | InterruptedException e) {
e.printStackTrace();
System.exit(-1);
}
}
}

View file

@ -0,0 +1,181 @@
/*
* SPDX-License-Identifier:
*/
package org.papernet;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.papernet.ledgerapi.State;
import org.hyperledger.fabric.contract.annotation.DataType;
import org.hyperledger.fabric.contract.annotation.Property;
import org.json.JSONObject;
import org.json.JSONPropertyIgnore;
@DataType()
public class CommercialPaper extends State {
// Enumerate commercial paper state values
public final static String ISSUED = "ISSUED";
public final static String TRADING = "TRADING";
public final static String REDEEMED = "REDEEMED";
@Property()
private String state="";
public String getState() {
return state;
}
public CommercialPaper setState(String state) {
this.state = state;
return this;
}
@JSONPropertyIgnore()
public boolean isIssued() {
return this.state.equals(CommercialPaper.ISSUED);
}
@JSONPropertyIgnore()
public boolean isTrading() {
return this.state.equals(CommercialPaper.TRADING);
}
@JSONPropertyIgnore()
public boolean isRedeemed() {
return this.state.equals(CommercialPaper.REDEEMED);
}
public CommercialPaper setIssued() {
this.state = CommercialPaper.ISSUED;
return this;
}
public CommercialPaper setTrading() {
this.state = CommercialPaper.TRADING;
return this;
}
public CommercialPaper setRedeemed() {
this.state = CommercialPaper.REDEEMED;
return this;
}
@Property()
private String paperNumber;
@Property()
private String issuer;
@Property()
private String issueDateTime;
@Property()
private int faceValue;
@Property()
private String maturityDateTime;
@Property()
private String owner;
public String getOwner() {
return owner;
}
public CommercialPaper setOwner(String owner) {
this.owner = owner;
return this;
}
public CommercialPaper() {
super();
}
public CommercialPaper setKey() {
this.key = State.makeKey(new String[] { this.paperNumber });
return this;
}
public String getPaperNumber() {
return paperNumber;
}
public CommercialPaper setPaperNumber(String paperNumber) {
this.paperNumber = paperNumber;
return this;
}
public String getIssuer() {
return issuer;
}
public CommercialPaper setIssuer(String issuer) {
this.issuer = issuer;
return this;
}
public String getIssueDateTime() {
return issueDateTime;
}
public CommercialPaper setIssueDateTime(String issueDateTime) {
this.issueDateTime = issueDateTime;
return this;
}
public int getFaceValue() {
return faceValue;
}
public CommercialPaper setFaceValue(int faceValue) {
this.faceValue = faceValue;
return this;
}
public String getMaturityDateTime() {
return maturityDateTime;
}
public CommercialPaper setMaturityDateTime(String maturityDateTime) {
this.maturityDateTime = maturityDateTime;
return this;
}
@Override
public String toString() {
return "Paper::" + this.key + " " + this.getPaperNumber() + " " + getIssuer() + " " + getFaceValue();
}
/**
* Deserialize a state data to commercial paper
*
* @param {Buffer} data to form back into the object
*/
public static CommercialPaper deserialize(byte[] data) {
JSONObject json = new JSONObject(new String(data, UTF_8));
String issuer = json.getString("issuer");
String paperNumber = json.getString("paperNumber");
String issueDateTime = json.getString("issueDateTime");
String maturityDateTime = json.getString("maturityDateTime");
String owner = json.getString("owner");
int faceValue = json.getInt("faceValue");
String state = json.getString("state");
return createInstance(issuer, paperNumber, issueDateTime, maturityDateTime, faceValue,owner,state);
}
public static byte[] serialize(CommercialPaper paper) {
return State.serialize(paper);
}
/**
* Factory method to create a commercial paper object
*/
public static CommercialPaper createInstance(String issuer, String paperNumber, String issueDateTime,
String maturityDateTime, int faceValue, String owner, String state) {
return new CommercialPaper().setIssuer(issuer).setPaperNumber(paperNumber).setMaturityDateTime(maturityDateTime)
.setFaceValue(faceValue).setKey().setIssueDateTime(issueDateTime).setOwner(owner).setState(state);
}
}

View file

@ -0,0 +1,60 @@
/*
SPDX-License-Identifier: Apache-2.0
*/
package org.papernet.ledgerapi;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.json.JSONObject;
/**
* State class. States have a class, unique key, and a lifecycle current state
* the current state is determined by the specific subclass
*/
public class State {
protected String key;
/**
* @param {String|Object} class An identifiable class of the instance
* @param {keyParts[]} elements to pull together to make a key for the objects
*/
public State() {
}
String getKey() {
return this.key;
}
public String[] getSplitKey() {
return State.splitKey(this.key);
}
/**
* Convert object to buffer containing JSON data serialization Typically used
* before putState()ledger API
*
* @param {Object} JSON object to serialize
* @return {buffer} buffer with the data to store
*/
public static byte[] serialize(Object object) {
String jsonStr = new JSONObject(object).toString();
return jsonStr.getBytes(UTF_8);
}
/**
* Join the keyParts to make a unififed string
*
* @param (String[]) keyParts
*/
public static String makeKey(String[] keyParts) {
return String.join(":", keyParts);
}
public static String[] splitKey(String key) {
System.out.println("Splittin gkey " + key + " " + java.util.Arrays.asList(key.split(":")));
return key.split(":");
}
}

View file

@ -0,0 +1 @@
node_modules

View file

@ -18,85 +18,85 @@ SPDX-License-Identifier: Apache-2.0
const fs = require('fs');
const yaml = require('js-yaml');
const { FileSystemWallet, Gateway } = require('fabric-network');
const CommercialPaper = require('../contract/lib/paper.js');
const CommercialPaper = require('../../magnetocorp/contract/lib/paper.js');
// A wallet stores a collection of identities for use
const wallet = new FileSystemWallet('../identity/user/balaji/wallet');
// Main program function
async function main() {
async function main () {
// A gateway defines the peers used to access Fabric networks
const gateway = new Gateway();
// A gateway defines the peers used to access Fabric networks
const gateway = new Gateway();
// Main try/catch block
try {
// Main try/catch block
try {
// Specify userName for network access
// const userName = 'isabella.issuer@magnetocorp.com';
const userName = 'Admin@org1.example.com';
// Specify userName for network access
// const userName = 'isabella.issuer@magnetocorp.com';
const userName = 'Admin@org1.example.com';
// Load connection profile; will be used to locate a gateway
let connectionProfile = yaml.safeLoad(fs.readFileSync('../gateway/networkConnection.yaml', 'utf8'));
// Load connection profile; will be used to locate a gateway
let connectionProfile = yaml.safeLoad(fs.readFileSync('../gateway/networkConnection.yaml', 'utf8'));
// Set connection options; identity and wallet
let connectionOptions = {
identity: userName,
wallet: wallet,
discovery: { enabled:false, asLocalhost: true }
// Set connection options; identity and wallet
let connectionOptions = {
identity: userName,
wallet: wallet,
discovery: { enabled: false, asLocalhost: true }
};
};
// Connect to gateway using application specified parameters
console.log('Connect to Fabric gateway.');
// Connect to gateway using application specified parameters
console.log('Connect to Fabric gateway.');
await gateway.connect(connectionProfile, connectionOptions);
await gateway.connect(connectionProfile, connectionOptions);
// Access PaperNet network
console.log('Use network channel: mychannel.');
// Access PaperNet network
console.log('Use network channel: mychannel.');
const network = await gateway.getNetwork('mychannel');
const network = await gateway.getNetwork('mychannel');
// Get addressability to commercial paper contract
console.log('Use org.papernet.commercialpaper smart contract.');
// Get addressability to commercial paper contract
console.log('Use org.papernet.commercialpaper smart contract.');
const contract = await network.getContract('papercontract', 'org.papernet.commercialpaper');
const contract = await network.getContract('papercontract', 'org.papernet.commercialpaper');
// buy commercial paper
console.log('Submit commercial paper buy transaction.');
// buy commercial paper
console.log('Submit commercial paper buy transaction.');
const buyResponse = await contract.submitTransaction('buy', 'MagnetoCorp', '00001', 'MagnetoCorp', 'DigiBank', '4900000', '2020-05-31');
const buyResponse = await contract.submitTransaction('buy', 'MagnetoCorp', '00001', 'MagnetoCorp', 'DigiBank', '4900000', '2020-05-31');
// process response
console.log('Process buy transaction response.');
// process response
console.log('Process buy transaction response.');
let paper = CommercialPaper.fromBuffer(buyResponse);
let paper = CommercialPaper.fromBuffer(buyResponse);
console.log(`${paper.issuer} commercial paper : ${paper.paperNumber} successfully purchased by ${paper.owner}`);
console.log('Transaction complete.');
console.log(`${paper.issuer} commercial paper : ${paper.paperNumber} successfully purchased by ${paper.owner}`);
console.log('Transaction complete.');
} catch (error) {
} catch (error) {
console.log(`Error processing transaction. ${error}`);
console.log(error.stack);
console.log(`Error processing transaction. ${error}`);
console.log(error.stack);
} finally {
} finally {
// Disconnect from the gateway
console.log('Disconnect from Fabric gateway.')
gateway.disconnect();
// Disconnect from the gateway
console.log('Disconnect from Fabric gateway.');
gateway.disconnect();
}
}
}
main().then(() => {
console.log('Buy program complete.');
console.log('Buy program complete.');
}).catch((e) => {
console.log('Buy program exception.');
console.log(e);
console.log(e.stack);
process.exit(-1);
console.log('Buy program exception.');
console.log(e);
console.log(e.stack);
process.exit(-1);
});

File diff suppressed because it is too large Load diff

View file

@ -4,14 +4,15 @@
"description": "",
"main": "buy.js",
"scripts": {
"lint": "eslint .",
"test": "rm -rf _idwallet && node addToWallet.js && node buy.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"fabric-network": "1.4.0-rc2",
"fabric-client": "1.4.0-rc2",
"fabric-network": "~1.4.0",
"fabric-client": "~1.4.0",
"js-yaml": "^3.12.0"
},
"devDependencies": {

View file

@ -26,76 +26,76 @@ const wallet = new FileSystemWallet('../identity/user/balaji/wallet');
// Main program function
async function main() {
// A gateway defines the peers used to access Fabric networks
const gateway = new Gateway();
// A gateway defines the peers used to access Fabric networks
const gateway = new Gateway();
// Main try/catch block
try {
// Main try/catch block
try {
// Specify userName for network access
// const userName = 'isabella.issuer@magnetocorp.com';
const userName = 'Admin@org1.example.com';
// Specify userName for network access
// const userName = 'isabella.issuer@magnetocorp.com';
const userName = 'Admin@org1.example.com';
// Load connection profile; will be used to locate a gateway
let connectionProfile = yaml.safeLoad(fs.readFileSync('../gateway/networkConnection.yaml', 'utf8'));
// Load connection profile; will be used to locate a gateway
let connectionProfile = yaml.safeLoad(fs.readFileSync('../gateway/networkConnection.yaml', 'utf8'));
// Set connection options; identity and wallet
let connectionOptions = {
identity: userName,
wallet: wallet,
discovery: { enabled:false, asLocalhost: true }
};
// Set connection options; identity and wallet
let connectionOptions = {
identity: userName,
wallet: wallet,
discovery: { enabled:false, asLocalhost: true }
};
// Connect to gateway using application specified parameters
console.log('Connect to Fabric gateway.');
// Connect to gateway using application specified parameters
console.log('Connect to Fabric gateway.');
await gateway.connect(connectionProfile, connectionOptions);
await gateway.connect(connectionProfile, connectionOptions);
// Access PaperNet network
console.log('Use network channel: mychannel.');
// Access PaperNet network
console.log('Use network channel: mychannel.');
const network = await gateway.getNetwork('mychannel');
const network = await gateway.getNetwork('mychannel');
// Get addressability to commercial paper contract
console.log('Use org.papernet.commercialpaper smart contract.');
// Get addressability to commercial paper contract
console.log('Use org.papernet.commercialpaper smart contract.');
const contract = await network.getContract('papercontract', 'org.papernet.commercialpaper');
const contract = await network.getContract('papercontract', 'org.papernet.commercialpaper');
// redeem commercial paper
console.log('Submit commercial paper redeem transaction.');
// redeem commercial paper
console.log('Submit commercial paper redeem transaction.');
const redeemResponse = await contract.submitTransaction('redeem', 'MagnetoCorp', '00001', 'DigiBank', '2020-11-30');
const redeemResponse = await contract.submitTransaction('redeem', 'MagnetoCorp', '00001', 'DigiBank', '2020-11-30');
// process response
console.log('Process redeem transaction response.');
// process response
console.log('Process redeem transaction response.');
let paper = CommercialPaper.fromBuffer(redeemResponse);
let paper = CommercialPaper.fromBuffer(redeemResponse);
console.log(`${paper.issuer} commercial paper : ${paper.paperNumber} successfully redeemed with ${paper.owner}`);
console.log('Transaction complete.');
console.log(`${paper.issuer} commercial paper : ${paper.paperNumber} successfully redeemed with ${paper.owner}`);
console.log('Transaction complete.');
} catch (error) {
} catch (error) {
console.log(`Error processing transaction. ${error}`);
console.log(error.stack);
console.log(`Error processing transaction. ${error}`);
console.log(error.stack);
} finally {
} finally {
// Disconnect from the gateway
console.log('Disconnect from Fabric gateway.')
gateway.disconnect();
// Disconnect from the gateway
console.log('Disconnect from Fabric gateway.');
gateway.disconnect();
}
}
}
main().then(() => {
console.log('Redeem program complete.');
console.log('Redeem program complete.');
}).catch((e) => {
console.log('Redeem program exception.');
console.log(e);
console.log(e.stack);
process.exit(-1);
console.log('Redeem program exception.');
console.log(e);
console.log(e.stack);
process.exit(-1);
});

View file

@ -0,0 +1 @@
Suggest that you change to this dir /home/matthew/go/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/digibank

View file

@ -0,0 +1,5 @@
.gradle/
build/
bin/
.classpath
.settings/

View file

@ -0,0 +1,51 @@
plugins {
id 'com.github.johnrengelman.shadow' version '2.0.3'
id 'java'
}
version '0.0.1'
sourceCompatibility = 1.8
repositories {
mavenLocal()
mavenCentral()
maven {
url 'https://jitpack.io'
}
maven {
url "https://hyperledger.jfrog.io/hyperledger/fabric-maven"
}
}
dependencies {
compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.2'
compile group: 'org.json', name: 'json', version: '20180813'
testImplementation 'org.junit.jupiter:junit-jupiter:5.4.2'
testImplementation 'org.assertj:assertj-core:3.11.1'
testImplementation 'org.mockito:mockito-core:2.+'
}
shadowJar {
baseName = 'chaincode'
version = null
classifier = null
manifest {
attributes 'Main-Class': 'org.hyperledger.fabric.contract.ContractRouter'
}
}
test {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed"
}
}
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" << "-parameters"
}

View file

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View file

@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

View file

@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View file

@ -0,0 +1,2 @@
rootProject.name = 'java-contractcontract'

View file

@ -0,0 +1,183 @@
/*
* SPDX-License-Identifier:
*/
package org.example;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.example.ledgerapi.State;
import org.hyperledger.fabric.contract.annotation.DataType;
import org.hyperledger.fabric.contract.annotation.Property;
import org.json.JSONObject;
import org.json.JSONPropertyIgnore;
@DataType()
public class CommercialPaper extends State {
// Enumerate commercial paper state values
public final static String ISSUED = "ISSUED";
public final static String TRADING = "TRADING";
public final static String REDEEMED = "REDEEMED";
@Property()
private String state="";
public String getState() {
return state;
}
public CommercialPaper setState(String state) {
this.state = state;
return this;
}
@JSONPropertyIgnore()
public boolean isIssued() {
return this.state.equals(CommercialPaper.ISSUED);
}
@JSONPropertyIgnore()
public boolean isTrading() {
return this.state.equals(CommercialPaper.TRADING);
}
@JSONPropertyIgnore()
public boolean isRedeemed() {
return this.state.equals(CommercialPaper.REDEEMED);
}
public CommercialPaper setIssued() {
this.state = CommercialPaper.ISSUED;
return this;
}
public CommercialPaper setTrading() {
this.state = CommercialPaper.TRADING;
return this;
}
public CommercialPaper setRedeemed() {
this.state = CommercialPaper.REDEEMED;
return this;
}
@Property()
private String paperNumber;
@Property()
private String issuer;
@Property()
private String issueDateTime;
@Property()
private int faceValue;
@Property()
private String maturityDateTime;
@Property()
private String owner;
public String getOwner() {
return owner;
}
public CommercialPaper setOwner(String owner) {
this.owner = owner;
return this;
}
public CommercialPaper() {
super();
}
public CommercialPaper setKey() {
this.key = State.makeKey(new String[] { this.paperNumber });
return this;
}
public String getPaperNumber() {
return paperNumber;
}
public CommercialPaper setPaperNumber(String paperNumber) {
this.paperNumber = paperNumber;
return this;
}
public String getIssuer() {
return issuer;
}
public CommercialPaper setIssuer(String issuer) {
this.issuer = issuer;
return this;
}
public String getIssueDateTime() {
return issueDateTime;
}
public CommercialPaper setIssueDateTime(String issueDateTime) {
this.issueDateTime = issueDateTime;
return this;
}
public int getFaceValue() {
return faceValue;
}
public CommercialPaper setFaceValue(int faceValue) {
this.faceValue = faceValue;
return this;
}
public String getMaturityDateTime() {
return maturityDateTime;
}
public CommercialPaper setMaturityDateTime(String maturityDateTime) {
this.maturityDateTime = maturityDateTime;
return this;
}
@Override
public String toString() {
return "Paper::" + this.key + " " + this.getPaperNumber() + " " + getIssuer() + " " + getFaceValue();
}
/**
* Deserialize a state data to commercial paper
*
* @param {Buffer} data to form back into the object
*/
public static CommercialPaper deserialize(byte[] data) {
JSONObject json = new JSONObject(new String(data, UTF_8));
String issuer = json.getString("issuer");
String paperNumber = json.getString("paperNumber");
String issueDateTime = json.getString("issueDateTime");
String maturityDateTime = json.getString("maturityDateTime");
String owner = json.getString("owner");
int faceValue = json.getInt("faceValue");
String state = json.getString("state");
return createInstance(issuer, paperNumber, issueDateTime, maturityDateTime, faceValue,owner,state);
}
public static byte[] serialize(CommercialPaper paper) {
return State.serialize(paper);
}
/**
* Factory method to create a commercial paper object
*/
public static CommercialPaper createInstance(String issuer, String paperNumber, String issueDateTime,
String maturityDateTime, int faceValue, String owner, String state) {
return new CommercialPaper().setIssuer(issuer).setPaperNumber(paperNumber).setMaturityDateTime(maturityDateTime)
.setFaceValue(faceValue).setKey().setIssueDateTime(issueDateTime).setOwner(owner).setState(state);
}
}

View file

@ -0,0 +1,15 @@
package org.example;
import org.hyperledger.fabric.contract.Context;
import org.hyperledger.fabric.shim.ChaincodeStub;
class CommercialPaperContext extends Context {
public CommercialPaperContext(ChaincodeStub stub) {
super(stub);
this.paperList = new PaperList(this);
}
public PaperList paperList;
}

View file

@ -0,0 +1,170 @@
/*
SPDX-License-Identifier: Apache-2.0
*/
package org.example;
import java.util.logging.Logger;
import org.example.ledgerapi.State;
import org.hyperledger.fabric.contract.Context;
import org.hyperledger.fabric.contract.ContractInterface;
import org.hyperledger.fabric.contract.annotation.Contact;
import org.hyperledger.fabric.contract.annotation.Contract;
import org.hyperledger.fabric.contract.annotation.Default;
import org.hyperledger.fabric.contract.annotation.Info;
import org.hyperledger.fabric.contract.annotation.License;
import org.hyperledger.fabric.contract.annotation.Transaction;
import org.hyperledger.fabric.shim.ChaincodeStub;
/**
* A custom context provides easy access to list of all commercial papers
*/
/**
* Define commercial paper smart contract by extending Fabric Contract class
*
*/
@Contract(name = "org.papernet.commercialpaper", info = @Info(title = "MyAsset contract", description = "", version = "0.0.1", license = @License(name = "SPDX-License-Identifier: ", url = ""), contact = @Contact(email = "java-contract@example.com", name = "java-contract", url = "http://java-contract.me")))
@Default
public class CommercialPaperContract implements ContractInterface {
// use the classname for the logger, this way you can refactor
private final static Logger LOG = Logger.getLogger(CommercialPaperContract.class.getName());
@Override
public Context createContext(ChaincodeStub stub) {
return new CommercialPaperContext(stub);
}
public CommercialPaperContract() {
}
/**
* Define a custom context for commercial paper
*/
/**
* Instantiate to perform any setup of the ledger that might be required.
*
* @param {Context} ctx the transaction context
*/
@Transaction
public void instantiate(CommercialPaperContext ctx) {
// No implementation required with this example
// It could be where data migration is performed, if necessary
LOG.info("No data migration to perform");
}
/**
* Issue commercial paper
*
* @param {Context} ctx the transaction context
* @param {String} issuer commercial paper issuer
* @param {Integer} paperNumber paper number for this issuer
* @param {String} issueDateTime paper issue date
* @param {String} maturityDateTime paper maturity date
* @param {Integer} faceValue face value of paper
*/
@Transaction
public CommercialPaper issue(CommercialPaperContext ctx, String issuer, String paperNumber, String issueDateTime,
String maturityDateTime, int faceValue) {
System.out.println(ctx);
// create an instance of the paper
CommercialPaper paper = CommercialPaper.createInstance(issuer, paperNumber, issueDateTime, maturityDateTime,
faceValue,issuer,"");
// Smart contract, rather than paper, moves paper into ISSUED state
paper.setIssued();
// Newly issued paper is owned by the issuer
paper.setOwner(issuer);
System.out.println(paper);
// Add the paper to the list of all similar commercial papers in the ledger
// world state
ctx.paperList.addPaper(paper);
// Must return a serialized paper to caller of smart contract
return paper;
}
/**
* Buy commercial paper
*
* @param {Context} ctx the transaction context
* @param {String} issuer commercial paper issuer
* @param {Integer} paperNumber paper number for this issuer
* @param {String} currentOwner current owner of paper
* @param {String} newOwner new owner of paper
* @param {Integer} price price paid for this paper
* @param {String} purchaseDateTime time paper was purchased (i.e. traded)
*/
@Transaction
public CommercialPaper buy(CommercialPaperContext ctx, String issuer, String paperNumber, String currentOwner,
String newOwner, int price, String purchaseDateTime) {
// Retrieve the current paper using key fields provided
String paperKey = State.makeKey(new String[] { paperNumber });
CommercialPaper paper = ctx.paperList.getPaper(paperKey);
// Validate current owner
if (!paper.getOwner().equals(currentOwner)) {
throw new RuntimeException("Paper " + issuer + paperNumber + " is not owned by " + currentOwner);
}
// First buy moves state from ISSUED to TRADING
if (paper.isIssued()) {
paper.setTrading();
}
// Check paper is not already REDEEMED
if (paper.isTrading()) {
paper.setOwner(newOwner);
} else {
throw new RuntimeException(
"Paper " + issuer + paperNumber + " is not trading. Current state = " + paper.getState());
}
// Update the paper
ctx.paperList.updatePaper(paper);
return paper;
}
/**
* Redeem commercial paper
*
* @param {Context} ctx the transaction context
* @param {String} issuer commercial paper issuer
* @param {Integer} paperNumber paper number for this issuer
* @param {String} redeemingOwner redeeming owner of paper
* @param {String} redeemDateTime time paper was redeemed
*/
@Transaction
public CommercialPaper redeem(CommercialPaperContext ctx, String issuer, String paperNumber, String redeemingOwner,
String redeemDateTime) {
String paperKey = CommercialPaper.makeKey(new String[] { paperNumber });
CommercialPaper paper = ctx.paperList.getPaper(paperKey);
// Check paper is not REDEEMED
if (paper.isRedeemed()) {
throw new RuntimeException("Paper " + issuer + paperNumber + " already redeemed");
}
// Verify that the redeemer owns the commercial paper before redeeming it
if (paper.getOwner().equals(redeemingOwner)) {
paper.setOwner(paper.getIssuer());
paper.setRedeemed();
} else {
throw new RuntimeException("Redeeming owner does not own paper" + issuer + paperNumber);
}
ctx.paperList.updatePaper(paper);
return paper;
}
}

View file

@ -0,0 +1,31 @@
/*
SPDX-License-Identifier: Apache-2.0
*/
package org.example;
import org.example.ledgerapi.StateList;
import org.hyperledger.fabric.contract.Context;
public class PaperList {
private StateList stateList;
public PaperList(Context ctx) {
this.stateList = StateList.getStateList(ctx, PaperList.class.getSimpleName(), CommercialPaper::deserialize);
}
public PaperList addPaper(CommercialPaper paper) {
stateList.addState(paper);
return this;
}
public CommercialPaper getPaper(String paperKey) {
return (CommercialPaper) this.stateList.getState(paperKey);
}
public PaperList updatePaper(CommercialPaper paper) {
this.stateList.updateState(paper);
return this;
}
}

View file

@ -0,0 +1,60 @@
/*
SPDX-License-Identifier: Apache-2.0
*/
package org.example.ledgerapi;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.json.JSONObject;
/**
* State class. States have a class, unique key, and a lifecycle current state
* the current state is determined by the specific subclass
*/
public class State {
protected String key;
/**
* @param {String|Object} class An identifiable class of the instance
* @param {keyParts[]} elements to pull together to make a key for the objects
*/
public State() {
}
String getKey() {
return this.key;
}
public String[] getSplitKey() {
return State.splitKey(this.key);
}
/**
* Convert object to buffer containing JSON data serialization Typically used
* before putState()ledger API
*
* @param {Object} JSON object to serialize
* @return {buffer} buffer with the data to store
*/
public static byte[] serialize(Object object) {
String jsonStr = new JSONObject(object).toString();
return jsonStr.getBytes(UTF_8);
}
/**
* Join the keyParts to make a unififed string
*
* @param (String[]) keyParts
*/
public static String makeKey(String[] keyParts) {
return String.join(":", keyParts);
}
public static String[] splitKey(String key) {
System.out.println("Splittin gkey " + key + " " + java.util.Arrays.asList(key.split(":")));
return key.split(":");
}
}

View file

@ -0,0 +1,6 @@
package org.example.ledgerapi;
@FunctionalInterface
public interface StateDeserializer {
State deserialize(byte[] buffer);
}

View file

@ -0,0 +1,48 @@
package org.example.ledgerapi;
import org.example.ledgerapi.impl.StateListImpl;
import org.hyperledger.fabric.contract.Context;
public interface StateList {
/*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* StateList provides a named virtual container for a set of ledger states. Each
* state has a unique key which associates it with the container, rather than
* the container containing a link to the state. This minimizes collisions for
* parallel transactions on different states.
*/
/**
* Store Fabric context for subsequent API access, and name of list
*/
static StateList getStateList(Context ctx, String listName, StateDeserializer deserializer) {
return new StateListImpl(ctx, listName, deserializer);
}
/**
* Add a state to the list. Creates a new state in worldstate with appropriate
* composite key. Note that state defines its own key. State object is
* serialized before writing.
*/
public StateList addState(State state);
/**
* Get a state from the list using supplied keys. Form composite keys to
* retrieve state from world state. State data is deserialized into JSON object
* before being returned.
*/
public State getState(String key);
/**
* Update a state in the list. Puts the new state in world state with
* appropriate composite key. Note that state defines its own key. A state is
* serialized before writing. Logic is very similar to addState() but kept
* separate becuase it is semantically distinct.
*/
public StateList updateState(State state);
}

View file

@ -0,0 +1,100 @@
package org.example.ledgerapi.impl;
import java.util.Arrays;
import org.example.ledgerapi.State;
import org.example.ledgerapi.StateDeserializer;
import org.example.ledgerapi.StateList;
import org.hyperledger.fabric.contract.Context;
import org.hyperledger.fabric.shim.ChaincodeStub;
import org.hyperledger.fabric.shim.ledger.CompositeKey;
/*
SPDX-License-Identifier: Apache-2.0
*/
/**
* StateList provides a named virtual container for a set of ledger states. Each
* state has a unique key which associates it with the container, rather than
* the container containing a link to the state. This minimizes collisions for
* parallel transactions on different states.
*/
public class StateListImpl implements StateList {
private Context ctx;
private String name;
private Object supportedClasses;
private StateDeserializer deserializer;
/**
* Store Fabric context for subsequent API access, and name of list
*
* @param deserializer
*/
public StateListImpl(Context ctx, String listName, StateDeserializer deserializer) {
this.ctx = ctx;
this.name = listName;
this.deserializer = deserializer;
}
/**
* Add a state to the list. Creates a new state in worldstate with appropriate
* composite key. Note that state defines its own key. State object is
* serialized before writing.
*/
@Override
public StateList addState(State state) {
System.out.println("Adding state " + this.name);
ChaincodeStub stub = this.ctx.getStub();
System.out.println("Stub=" + stub);
String[] splitKey = state.getSplitKey();
System.out.println("Split key " + Arrays.asList(splitKey));
CompositeKey ledgerKey = stub.createCompositeKey(this.name, splitKey);
System.out.println("ledgerkey is ");
System.out.println(ledgerKey);
byte[] data = State.serialize(state);
System.out.println("ctx" + this.ctx);
System.out.println("stub" + this.ctx.getStub());
this.ctx.getStub().putState(ledgerKey.toString(), data);
return this;
}
/**
* Get a state from the list using supplied keys. Form composite keys to
* retrieve state from world state. State data is deserialized into JSON object
* before being returned.
*/
@Override
public State getState(String key) {
CompositeKey ledgerKey = this.ctx.getStub().createCompositeKey(this.name, State.splitKey(key));
byte[] data = this.ctx.getStub().getState(ledgerKey.toString());
if (data != null) {
State state = this.deserializer.deserialize(data);
return state;
} else {
return null;
}
}
/**
* Update a state in the list. Puts the new state in world state with
* appropriate composite key. Note that state defines its own key. A state is
* serialized before writing. Logic is very similar to addState() but kept
* separate becuase it is semantically distinct.
*/
@Override
public StateList updateState(State state) {
CompositeKey ledgerKey = this.ctx.getStub().createCompositeKey(this.name, state.getSplitKey());
byte[] data = State.serialize(state);
this.ctx.getStub().putState(ledgerKey.toString(), data);
return this;
}
}

View file

@ -0,0 +1,25 @@
package org.hyperledger.fabric;
import org.hyperledger.fabric.contract.ContractRouter;
import org.hyperledger.fabric.contract.metadata.MetadataBuilder;
public class DevRouter extends ContractRouter {
public DevRouter(String[] args) {
super(args);
System.out.println("+++DevRouter Starting...... +++");
}
public static DevRouter getDevRouter() {
String args[] = new String[] { "--id", "unittestchaincode" };
DevRouter dr = new DevRouter(args);
dr.findAllContracts();
MetadataBuilder.initialize(dr.getRoutingRegistry(), dr.getTypeRegistry());
// to output the metadata created
String metadata = MetadataBuilder.debugString();
System.out.println(metadata);
return dr;
}
}

View file

@ -0,0 +1,57 @@
/*
* SPDX-License-Identifier: Apache License 2.0
*/
package org.hyperledger.fabric.example;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.hyperledger.fabric.DevRouter;
import org.hyperledger.fabric.shim.ChaincodeStub;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
@TestInstance(Lifecycle.PER_CLASS)
public final class CommercialPaperContractTest {
DevRouter devRouter;
@BeforeAll
public void scanContracts() {
this.devRouter = DevRouter.getDevRouter();
}
ChaincodeStub newStub(String[] args) {
ChaincodeStub stub = mock(ChaincodeStub.class);
List<String> allargs = new ArrayList<String>();
Collections.addAll(allargs, args);
when(stub.getArgs()).thenReturn(allargs.stream().map(String::getBytes).collect(Collectors.toList()));
when(stub.getStringArgs()).thenReturn(allargs);
return stub;
}
@Nested
class IssuePaper {
// @Test
// public void regularIssue() {
// Response resp;
// ChaincodeStub stub = newStub(new String[] { "issue", "issuerName", "paper001", "today", "year", "420" });
// //
//
// resp = devRouter.invoke(stub);
// assertThat(resp.getStatus()).isEqualTo(Status.SUCCESS);
// assertThat(resp.getStringPayload()).isEqualTo("false");
// }
}
}

View file

@ -0,0 +1 @@
node_modules/

View file

@ -42,8 +42,12 @@ class StateList {
async getState(key) {
let ledgerKey = this.ctx.stub.createCompositeKey(this.name, State.splitKey(key));
let data = await this.ctx.stub.getState(ledgerKey);
let state = State.deserialize(data, this.supportedClasses);
return state;
if (data){
let state = State.deserialize(data, this.supportedClasses);
return state;
} else {
return null;
}
}
/**

View file

@ -72,7 +72,7 @@ class CommercialPaper extends State {
}
static fromBuffer(buffer) {
return CommercialPaper.deserialize(Buffer.from(JSON.parse(buffer)));
return CommercialPaper.deserialize(buffer);
}
toBuffer() {

View file

@ -31,7 +31,7 @@ class CommercialPaperContext extends Context {
class CommercialPaperContract extends Contract {
constructor() {
// Unique namespace when multiple contracts per chaincode file
// Unique name when multiple contracts per chaincode file
super('org.papernet.commercialpaper');
}
@ -77,7 +77,7 @@ class CommercialPaperContract extends Contract {
await ctx.paperList.addPaper(paper);
// Must return a serialized paper to caller of smart contract
return paper.toBuffer();
return paper;
}
/**
@ -111,12 +111,12 @@ class CommercialPaperContract extends Contract {
if (paper.isTrading()) {
paper.setOwner(newOwner);
} else {
throw new Error('Paper ' + issuer + paperNumber + ' is not trading. Current state = ' + cp.getCurrentState());
throw new Error('Paper ' + issuer + paperNumber + ' is not trading. Current state = ' +paper.getCurrentState());
}
// Update the paper
await ctx.paperList.updatePaper(paper);
return paper.toBuffer();
return paper;
}
/**
@ -148,7 +148,7 @@ class CommercialPaperContract extends Contract {
}
await ctx.paperList.updatePaper(paper);
return paper.toBuffer();
return paper;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "papernet-js",
"version": "0.0.1",
"name": "papercontract",
"version": "0.0.3",
"description": "Papernet Contract",
"main": "index.js",
"engines": {
@ -18,8 +18,8 @@
"author": "hyperledger",
"license": "Apache-2.0",
"dependencies": {
"fabric-contract-api": "1.4.0-rc2",
"fabric-shim": "1.4.0-rc2"
"fabric-contract-api": "~1.4.0",
"fabric-shim": "~1.4.0"
},
"devDependencies": {
"chai": "^4.1.2",

View file

@ -26,6 +26,9 @@ description: "The basic network"
#
version: "1.0"
client:
organization: Org1
#
# [Optional]. But most apps would have this section so that channel objects can be constructed
# based on the content below. If an app is creating channels, then it likely will not need this

View file

@ -0,0 +1 @@
identity

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View file

@ -0,0 +1 @@
target/

View file

@ -0,0 +1,3 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8
encoding/src=UTF-8

View file

@ -0,0 +1,6 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.8

View file

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

View file

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>commercial-paper</groupId>
<artifactId>commercial-paper</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>hyperledger</id>
<name>Hyperledger Artifactory</name>
<url>https://hyperledger.jfrog.io/hyperledger/fabric-maven</url>
</repository>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<properties>
<fabric-chaincode-java.version>1.4.2</fabric-chaincode-java.version>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

Some files were not shown because too many files have changed in this diff Show more