[FAB-15213] Update Commercial Paper for Java

Update with Java Contract

Change-Id: Iced5568a248c1474ae4b6fb0352d23e49ebfc252
Signed-off-by: Matthew B. White <whitemat@uk.ibm.com>
Signed-off-by: James Taylor <jamest@uk.ibm.com>
This commit is contained in:
Matthew B. White 2019-07-25 14:07:28 +01:00 committed by James Taylor
parent 3996db59dc
commit 9b1452508f
76 changed files with 8413 additions and 108 deletions

View file

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

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

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

View file

@ -0,0 +1 @@
identity

View file

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

View file

@ -0,0 +1 @@
target/

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1 @@
node_modules

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

@ -0,0 +1,3 @@
.gradle/
build/
bin/

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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;
}
/**
@ -116,7 +116,7 @@ class CommercialPaperContract extends Contract {
// 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;
}
}

View file

@ -0,0 +1 @@
identity

View file

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

View file

@ -0,0 +1 @@
target/

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,44 @@
/*
SPDX-License-Identifier: Apache-2.0
*/
package org.magnetocorp;
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", "isabella", "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", "User1@org1.example.com", "msp");
Path certificatePem = credentialPath.resolve(Paths.get("signcerts",
"User1@org1.example.com-cert.pem"));
Path privateKey = credentialPath.resolve(Paths.get("keystore",
"c75bd6911aca808941c3557ee7c97e90f3952e379497dc55eb903f31b50abc83_sk"));
// Load credentials into wallet
String identityLabel = "User1@org1.example.com";
Identity identity = Identity.createIdentity("Org1MSP", Files.newBufferedReader(certificatePem), Files.newBufferedReader(privateKey));
wallet.put(identityLabel, identity);
} catch (IOException e) {
System.err.println("Error adding to wallet");
e.printStackTrace();
}
}
}

View file

@ -0,0 +1,73 @@
/*
SPDX-License-Identifier: Apache-2.0
*/
package org.magnetocorp;
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 Issue {
private static final String ENVKEY="CONTRACT_NAME";
public static void main(String[] args) {
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);
}
Gateway.Builder builder = Gateway.createBuilder();
try {
// A wallet stores a collection of identities
Path walletPath = Paths.get("..", "identity", "user", "isabella", "wallet");
Wallet wallet = Wallet.createFileSystemWallet(walletPath);
String userName = "User1@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");
// Issue commercial paper
System.out.println("Submit commercial paper issue transaction.");
byte[] response = contract.submitTransaction("issue", "MagnetoCorp", "00001", "2020-05-31", "2020-11-30", "5000000");
// Process response
System.out.println("Process issue transaction response.");
CommercialPaper paper = CommercialPaper.deserialize(response);
System.out.println(paper);
}
} catch (GatewayException | IOException | TimeoutException | InterruptedException e) {
e.printStackTrace();
System.exit(-1);
}
}
}

View file

@ -0,0 +1,183 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package org.papernet;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.hyperledger.fabric.contract.annotation.DataType;
import org.hyperledger.fabric.contract.annotation.Property;
import org.json.JSONObject;
import org.json.JSONPropertyIgnore;
import org.papernet.ledgerapi.State;
@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(issuer).setState(state);
}
}

View file

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

View file

@ -0,0 +1 @@
node_modules

View file

@ -27,76 +27,76 @@ const wallet = new FileSystemWallet('../identity/user/isabella/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 = 'User1@org1.example.com';
// Specify userName for network access
// const userName = 'isabella.issuer@magnetocorp.com';
const userName = 'User1@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');
// issue commercial paper
console.log('Submit commercial paper issue transaction.');
// issue commercial paper
console.log('Submit commercial paper issue transaction.');
const issueResponse = await contract.submitTransaction('issue', 'MagnetoCorp', '00001', '2020-05-31', '2020-11-30', '5000000');
const issueResponse = await contract.submitTransaction('issue', 'MagnetoCorp', '00001', '2020-05-31', '2020-11-30', '5000000');
// process response
console.log('Process issue transaction response.');
// process response
console.log('Process issue transaction response.'+issueResponse);
let paper = CommercialPaper.fromBuffer(issueResponse);
let paper = CommercialPaper.fromBuffer(issueResponse);
console.log(`${paper.issuer} commercial paper : ${paper.paperNumber} successfully issued for value ${paper.faceValue}`);
console.log('Transaction complete.');
console.log(`${paper.issuer} commercial paper : ${paper.paperNumber} successfully issued for value ${paper.faceValue}`);
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('Issue program complete.');
console.log('Issue program complete.');
}).catch((e) => {
console.log('Issue program exception.');
console.log(e);
console.log(e.stack);
process.exit(-1);
console.log('Issue program exception.');
console.log(e);
console.log(e.stack);
process.exit(-1);
});

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="bin/main" path="src/main/java">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/test" path="src/test/java">
<attributes>
<attribute name="gradle_scope" value="test"/>
<attribute name="gradle_used_by_scope" value="test"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>

View file

@ -0,0 +1,3 @@
.gradle/
build/
bin/

View file

@ -0,0 +1,2 @@
connection.project.dir=
eclipse.preferences.version=1

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,182 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
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) {
System.out.println("Byte data is "+ new String(data, UTF_8));
JSONObject json = new JSONObject(new String(data, UTF_8));
String issuer = json.getString("issuer");
String paperNumber = json.getString("paperNumber");
String issueDateTime = json.getString("issueDateTime");
String maturityDateTime = json.getString("maturityDateTime");
String owner = json.getString("owner");
int faceValue = json.getInt("faceValue");
String state = json.getString("state");
return createInstance(issuer, paperNumber, issueDateTime, maturityDateTime, faceValue,owner,state);
}
public static byte[] serialize(CommercialPaper paper) {
return State.serialize(paper);
}
/**
* Factory method to create a commercial paper object
*/
public static CommercialPaper createInstance(String issuer, String paperNumber, String issueDateTime,
String maturityDateTime, int faceValue, String owner, String state) {
return new CommercialPaper().setIssuer(issuer).setPaperNumber(paperNumber).setMaturityDateTime(maturityDateTime)
.setFaceValue(faceValue).setKey().setIssueDateTime(issueDateTime).setOwner(owner).setState(state);
}
}

View file

@ -0,0 +1,18 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package org.example;
import org.hyperledger.fabric.contract.Context;
import org.hyperledger.fabric.shim.ChaincodeStub;
class CommercialPaperContext extends Context {
public CommercialPaperContext(ChaincodeStub stub) {
super(stub);
this.paperList = new PaperList(this);
}
public PaperList paperList;
}

View file

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

View file

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

View file

@ -0,0 +1,61 @@
/*
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();
System.out.println(jsonStr);
return jsonStr.getBytes(UTF_8);
}
/**
* Join the keyParts to make a unififed string
*
* @param (String[]) keyParts
*/
public static String makeKey(String[] keyParts) {
return String.join(":", keyParts);
}
public static String[] splitKey(String key) {
System.out.println("Splittin gkey " + key + " " + java.util.Arrays.asList(key.split(":")));
return key.split(":");
}
}

View file

@ -0,0 +1,10 @@
/*
SPDX-License-Identifier: Apache-2.0
*/
package org.example.ledgerapi;
@FunctionalInterface
public interface StateDeserializer {
State deserialize(byte[] buffer);
}

View file

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

View file

@ -0,0 +1,102 @@
/*
SPDX-License-Identifier: Apache-2.0
*/
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;
/**
* 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());
System.out.println("Data is "+data);
System.out.println("LedgerKey "+ledgerKey.toString());
if (data != null) {
State state = this.deserializer.deserialize(data);
return state;
} else {
return null;
}
}
/**
* Update a state in the list. Puts the new state in world state with
* appropriate composite key. Note that state defines its own key. A state is
* serialized before writing. Logic is very similar to addState() but kept
* separate becuase it is semantically distinct.
*/
@Override
public StateList updateState(State state) {
CompositeKey ledgerKey = this.ctx.getStub().createCompositeKey(this.name, state.getSplitKey());
byte[] data = State.serialize(state);
this.ctx.getStub().putState(ledgerKey.toString(), data);
return this;
}
}

View file

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

View file

@ -0,0 +1,42 @@
/*
SPDX-License-Identifier: Apache-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;
}
}

View file

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

View file

@ -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;
}
/**
@ -116,7 +116,7 @@ class CommercialPaperContract extends Contract {
// 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;
}
}

View file

@ -0,0 +1,39 @@
#!/bin/bash
#
# SPDX-License-Identifier: Apache-2.0
#
function _exit(){
printf "Exiting:%s\n" "$1"
exit -1
}
# Where am I?
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
cd "${DIR}/organization/digibank/configuration/cli"
docker-compose -f docker-compose.yml up -d cliDigiBank
echo "
Install and Instantiate a Smart Contract as 'Magnetocorp'
Run Applications in either langauage (can be different from the Smart Contract)
JavaScript Client Aplications:
To add identity to the wallet: node addToWallet.js
< issue the paper run as Magnetocorp>
To buy the paper : node buy.js
To redeem the paper : node redeem.js
Java Client Applications:
(remember to build the Java first with 'mvn clean package')
< issue the paper run as Magnetocorp>
To buy the paper : node buy.js
To redeem the paper : node redeem.js
"
echo "Suggest that you change to this dir> cd ${DIR}/organization/digibank"

View file

@ -0,0 +1,45 @@
#!/bin/bash
#
# SPDX-License-Identifier: Apache-2.0
function _exit(){
printf "Exiting:%s\n" "$1"
exit -1
}
# Where am I?
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
cd "${DIR}/organization/magnetocorp/configuration/cli"
docker-compose -f docker-compose.yml up -d cliMagnetoCorp
echo "
Install and Instantiate a Smart Contract in either langauge
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')\"
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')\"
Run Applications in either langauage (can be different from the Smart Contract)
JavaScript Client Aplications:
To add identity to the wallet: node addToWallet.js
To issue the paper : node issue.js
Java Client Applications:
(remember to build the Java first with 'mvn')
To add identity to the wallet: java addToWallet
To issue the paper : java issue
"
echo "Suggest that you change to this dir> cd ${DIR}/organization/magnetocorp/"

View file

@ -0,0 +1,29 @@
#!/bin/bash
#
# SPDX-License-Identifier: Apache-2.0
function _exit(){
printf "Exiting:%s\n" "$1"
exit -1
}
# Exit on first error, print all commands.
set -ev
set -o pipefail
# Where am I?
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
cd "${DIR}/../basic-network/"
docker kill cliDigiBank cliMagnetoCorp logspout || true
./teardown.sh || true
./start.sh || _exit "Failed to start Fabric"
# -------------------------------------------------------------------------------
#
# Good to start the applications in other terminals
#
"${DIR}/organization/magnetocorp/configuration/cli/monitordocker.sh" net_basic