mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-17 15:35:09 +00:00
Compare commits
80 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1343ccb628 | ||
|
|
0e3a7a7a30 | ||
|
|
337f82c513 | ||
|
|
2c1d2ad5b9 | ||
|
|
562791dd2b | ||
|
|
d015ca1f82 | ||
|
|
0d7c7a1643 | ||
|
|
ba63e6533d | ||
|
|
cd5b68d040 | ||
|
|
bc72f3e3a6 | ||
|
|
ce0d06f599 | ||
|
|
e4f147f396 | ||
|
|
99657d19c7 | ||
|
|
797b991b4f | ||
|
|
750474d458 | ||
|
|
b92ff73374 | ||
|
|
9915995df7 | ||
|
|
ca5bcb27ae | ||
|
|
0fce873325 | ||
|
|
877baa597c | ||
|
|
ecd08c0357 | ||
|
|
7e8edb3189 | ||
|
|
70ce148927 | ||
|
|
ddf013ba01 | ||
|
|
0b980ebda7 | ||
|
|
b4e097ff7c | ||
|
|
d7932fd420 | ||
|
|
f86ec95726 | ||
|
|
78fe781a67 | ||
|
|
a963990313 | ||
|
|
a4460a9947 | ||
|
|
549e9fdd09 | ||
|
|
fc5975b285 | ||
|
|
3d364ed082 | ||
|
|
e80379a06f | ||
|
|
da7f3cd0cc | ||
|
|
1efd213110 | ||
|
|
d26e27e0d1 | ||
|
|
11d6ee14a9 | ||
|
|
dc8e60b4e3 | ||
|
|
9040e28b55 | ||
|
|
dcce485561 | ||
|
|
8c057e951b | ||
|
|
9a8acd5752 | ||
|
|
f1c46f033c | ||
|
|
c57f10f5f6 | ||
|
|
8f92861104 | ||
|
|
abb7207e24 | ||
|
|
1826dbfda7 | ||
|
|
9e0eed19a4 | ||
|
|
cf5855dd5d | ||
|
|
3429e22a9e | ||
|
|
d50fbc4f69 | ||
|
|
015fc15dc2 | ||
|
|
36ef140439 | ||
|
|
62fa4f8bc0 | ||
|
|
3da5f8a450 | ||
|
|
ad87f324b9 | ||
|
|
334a66f17e | ||
|
|
3d53f79be3 | ||
|
|
f59e563d27 | ||
|
|
0bc0a69793 | ||
|
|
2a5a59b60a | ||
|
|
8271a472f8 | ||
|
|
3a1d29ce93 | ||
|
|
5d0bfb9989 | ||
|
|
a1a648f12a | ||
|
|
ec9eb7fa73 | ||
|
|
6c0203a9b0 | ||
|
|
6be46eed05 | ||
|
|
72edb7e3bb | ||
|
|
83fe6c32df | ||
|
|
6c28eca339 | ||
|
|
349d88d184 | ||
|
|
026aa9ec01 | ||
|
|
4ed3933a8d | ||
|
|
e5dc89e61d | ||
|
|
463d2ecaff | ||
|
|
881ba56c8e | ||
|
|
bb39b6ed09 |
210 changed files with 22966 additions and 1724 deletions
27
.github/stale.yml
vendored
27
.github/stale.yml
vendored
|
|
@ -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
1
.gitignore
vendored
|
|
@ -9,3 +9,4 @@
|
|||
/config
|
||||
.DS_Store
|
||||
.project
|
||||
.idea
|
||||
|
|
@ -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
155
Jenkinsfile
vendored
|
|
@ -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
|
||||
}
|
||||
24
README.md
24
README.md
|
|
@ -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
12
SECURITY.md
Normal 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).
|
||||
|
||||
|
|
@ -10,6 +10,6 @@
|
|||
"engine-strict": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"fabric-shim": "1.4.0-rc2"
|
||||
"fabric-shim": "~1.4.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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' {
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
4
chaincode/chaincode_example02/java/.gitignore
vendored
Normal file
4
chaincode/chaincode_example02/java/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
bin/
|
||||
.classpath
|
||||
.settings/
|
||||
.gradle
|
||||
|
|
@ -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
61
chaincode/fabcar/java/.gitignore
vendored
Normal 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
|
||||
14
chaincode/fabcar/java/README.md
Normal file
14
chaincode/fabcar/java/README.md
Normal 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
|
||||
81
chaincode/fabcar/java/build.gradle
Normal file
81
chaincode/fabcar/java/build.gradle
Normal 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
|
||||
178
chaincode/fabcar/java/config/checkstyle/checkstyle.xml
Normal file
178
chaincode/fabcar/java/config/checkstyle/checkstyle.xml
Normal 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>
|
||||
9
chaincode/fabcar/java/config/checkstyle/suppressions.xml
Normal file
9
chaincode/fabcar/java/config/checkstyle/suppressions.xml
Normal 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>
|
||||
BIN
chaincode/fabcar/java/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
chaincode/fabcar/java/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
chaincode/fabcar/java/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
chaincode/fabcar/java/gradle/wrapper/gradle-wrapper.properties
vendored
Normal 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
172
chaincode/fabcar/java/gradlew
vendored
Executable 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
84
chaincode/fabcar/java/gradlew.bat
vendored
Normal 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
|
||||
5
chaincode/fabcar/java/settings.gradle
Normal file
5
chaincode/fabcar/java/settings.gradle
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
rootProject.name = 'java-chaincode-bootstrap'
|
||||
|
|
@ -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 + "]";
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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]");
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,6 @@
|
|||
"engine-strict": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"fabric-shim": "1.4.0-rc2"
|
||||
"fabric-shim": "~1.4.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -10,6 +10,6 @@
|
|||
"engine-strict": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"fabric-shim": "1.4.0-rc2"
|
||||
"fabric-shim": "~1.4.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
56
ci/azure-pipelines.yml
Normal 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
8
ci/fabcar-go.yml
Normal 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
14
ci/fabcar-java.yml
Normal 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
19
ci/fabcar-javascript.yml
Normal 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
22
ci/fabcar-typescript.yml
Normal 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
11
ci/install-deps.yml
Normal 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
27
ci/install-fabric.yml
Normal 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
|
||||
17
commercial-paper/.build/makefile
Normal file
17
commercial-paper/.build/makefile
Normal 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
|
||||
8
commercial-paper/.gitignore
vendored
8
commercial-paper/.gitignore
vendored
|
|
@ -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
156
commercial-paper/README.md
Normal 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 you’ve set up a basic network, you’ll act as Isabella, an employee of MagnetoCorp, who will issue a commercial paper on its behalf. You’ll 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.
|
||||
|
||||

|
||||
|
||||
## 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
|
||||
```
|
||||
1
commercial-paper/organization/digibank/.gitignore
vendored
Normal file
1
commercial-paper/organization/digibank/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
identity
|
||||
|
|
@ -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>
|
||||
1
commercial-paper/organization/digibank/application-java/.gitignore
vendored
Normal file
1
commercial-paper/organization/digibank/application-java/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
target/
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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(":");
|
||||
}
|
||||
|
||||
}
|
||||
1
commercial-paper/organization/digibank/application/.gitignore
vendored
Normal file
1
commercial-paper/organization/digibank/application/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
node_modules
|
||||
|
|
@ -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);
|
||||
|
||||
});
|
||||
2411
commercial-paper/organization/digibank/application/package-lock.json
generated
Normal file
2411
commercial-paper/organization/digibank/application/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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": {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1 @@
|
|||
Suggest that you change to this dir /home/matthew/go/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/digibank
|
||||
5
commercial-paper/organization/digibank/contract-java/.gitignore
vendored
Normal file
5
commercial-paper/organization/digibank/contract-java/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
.gradle/
|
||||
build/
|
||||
bin/
|
||||
.classpath
|
||||
.settings/
|
||||
|
|
@ -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"
|
||||
}
|
||||
BIN
commercial-paper/organization/digibank/contract-java/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
commercial-paper/organization/digibank/contract-java/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
|
|
@ -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
|
||||
172
commercial-paper/organization/digibank/contract-java/gradlew
vendored
Executable file
172
commercial-paper/organization/digibank/contract-java/gradlew
vendored
Executable 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
commercial-paper/organization/digibank/contract-java/gradlew.bat
vendored
Normal file
84
commercial-paper/organization/digibank/contract-java/gradlew.bat
vendored
Normal 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
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
rootProject.name = 'java-contractcontract'
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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(":");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package org.example.ledgerapi;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface StateDeserializer {
|
||||
State deserialize(byte[] buffer);
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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");
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
1
commercial-paper/organization/digibank/contract/.gitignore
vendored
Normal file
1
commercial-paper/organization/digibank/contract/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
node_modules/
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class CommercialPaper extends State {
|
|||
}
|
||||
|
||||
static fromBuffer(buffer) {
|
||||
return CommercialPaper.deserialize(Buffer.from(JSON.parse(buffer)));
|
||||
return CommercialPaper.deserialize(buffer);
|
||||
}
|
||||
|
||||
toBuffer() {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
4755
commercial-paper/organization/digibank/contract/package-lock.json
generated
Normal file
4755
commercial-paper/organization/digibank/contract/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
1
commercial-paper/organization/magnetocorp/.gitignore
vendored
Normal file
1
commercial-paper/organization/magnetocorp/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
identity
|
||||
|
|
@ -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>
|
||||
1
commercial-paper/organization/magnetocorp/application-java/.gitignore
vendored
Normal file
1
commercial-paper/organization/magnetocorp/application-java/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
target/
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
eclipse.preferences.version=1
|
||||
encoding/<project>=UTF-8
|
||||
encoding/src=UTF-8
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
||||
|
|
@ -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
Loading…
Reference in a new issue