Fabric auction sample preview

Signed-off-by: NIKHIL E GUPTA <negupta@us.ibm.com>
This commit is contained in:
NIKHIL E GUPTA 2020-08-07 11:32:41 -04:00 committed by NIKHIL E GUPTA
parent 6d196bd9df
commit 93767a001d
19 changed files with 3282 additions and 0 deletions

432
auction/README.md Normal file
View file

@ -0,0 +1,432 @@
## Auction sample
The auction sample demonstrates how Hyperledger Fabric can be used to run an auction where bids kept private from other bidders. Instead of displaying the full bid on the public ledger, only a hash of the bid is revealed while bidding is is open. This prevents potential buyers from reading that were already submitted and changing their bids in response. After the bidding period has ended, participants can reveal their bid. The organizations participating in the auction verify that the bid being revealed matches the hash before the full bid is added to the auction. The auction sample smart contract implements a [Dutch auction](https://en.wikipedia.org/wiki/Dutch_auction) for multiple items of the same type. All items are sold at the price of the lowest winning bid.
A potential seller can use the smart contract to create an auction that sells one or more items. The auction is stoed on the public channel ledger and can be read by all channel members. The auctions created by the smart contract are run in three steps:
1. Each auction is created with the status **open**. While the auction is open, bidders can join the auction by adding a hashed bid. Potential buyers store their bids in the implicit private data collection of their organization. After the bid is created, the bidder can add the hash of the bid to the auction. The bid is added to the auction in two steps because the transaction that creates the bid only needs be endorsed by the the peer of the bidders organization, while a transaction that updates the auction may need to be endorsed by multiple organizations. When the bid is added to the auction, the bidders organization is added to he list of organizations that need to endorse any auction updates.
2. When the bidding period is over, the auction is **closed** to prevent additional bids from being added to the auction. The auction being closed allows bidders to reveal their full bids, as long as they reveal the same bid that they added to the auction in the previous step. Only bids that have been revealed are eligible to win the auction.
3. The auction is **ended** to calculate the winners from the set of revealed bids. All organizations participating in the auction calculate the winning bids and the price that clears the auction. The seller can end the auction only if all organizations endorse the same winners and price.
Before each organization endorses the transaction that ends the auction, the organization queries their private data collection to check no bidder from their organization has created a bid that is higher than the winning price that has not yet been revealed. If there is a winning bid that has not yet been added to the auction, the organization will withhold their endorsement and prevent the auction from being closed. This prevents the seller from ending the auction prematurely, or colluding with buyers to end the auction at an artificially low price?
The sample uses several Fabric features that facilitate privacy and security. Bids are stored in the implicit private data collections to prevent bids from being distributed to other peers in the channel. When bidding is closed, the auction smart contract uses the `GetPrivateDataHash()` API to verify that hash of the bids being stored in private data collections match the hash that was added to the auction and the hash of the revealed bid. State based endorsement is used to add the organization of each bidder to the auction endorsement policy. The smart contract uses the `GetClientIdentity.GetID()` API to ensure that only the potential buyer can read their bid from the private state and only seller can close or end the auction.
This tutorial uses the smart contract to create an auction to sell 100 tickets to an event. Four bidders that belong to two organizations will bid on the tickets.
## Deploy the chaincode
You can run the auction smart contract using the Fabric test network. Open a command terminal and navigate to the test network directory:
```
cd fabric-samples/test-network
```
You can then run the following command to deploy the test network.
```
./network.sh up createChannel -ca
```
Note that we use the `-ca` flag to deploy the network using certificate authorities. We will use the CA to register and enroll our sellers and buyers.
Run the following command to deploy the auction smart contract. We will override the default endorsement policy to allow any channel member to create an auction without requiring an endorsement from another organization.
```
./network.sh deployCC -ccn auction -ccp ../auction/chaincode-go/ -ccep "OR('Org1MSP.peer','Org2MSP.peer')"
```
## Install the application dependencies
We will interact with the auction smart contract through a set of Node.js applications. Change into the `application-javascript` directory:
```
cd fabric-samples/auction/application-javascript
```
Run the following command in the `application-javascript` directory to download the application dependencies:
```
npm install
```
## Register and enroll the application identities
To interact with the network, you will need to enroll the Certificate Authority administrators of Org1 and Org2. You can use the `enrollAdmin.js` program for this task. Run the following command to enroll the Org1 admin:
```
node enrollAdmin.js org1
```
You should see the logs of the admin wallet being created on your local file system. Now run the command to enroll the CA admin of Org2:
```
node enrollAdmin.js org2
```
We can use the CA admins of both organizations to register and enroll the identities the seller that will create the auction and the bidders who will try to purchase the tickets.
Run the following command to register and enroll the seller identity that will create the auction. The seller will belong to Org1.
```
node registerEnrollUser.js org1 seller
```
You should see the logs of the seller wallet being created as well. Run the following commands to register 2 bidders from Org1 and another 2 bidders from Org2:
```
node registerEnrollUser.js org1 bidder1
node registerEnrollUser.js org1 bidder2
node registerEnrollUser.js org2 bidder3
node registerEnrollUser.js org2 bidder4
```
## Create the auction
The seller from Org1 would like to create an auction to sell 100 tickets to an event. Run the following command to use the seller wallet to run the `createAuction.js` program. The application will submit a transaction to the network creating the auction on the channel ledger. The organization and identity name are passed to the application to use the wallet that was created by the`registerEnrollUser.js` application. The seller needs to provide the auctionID, the item to be sold, and the quantity to be sold to create the auction:
```
node createAuction.js org1 seller auction1 tickets 100
```
After the transaction is complete, the `createAuction.js` application will query the auction stored in the public channel ledger:
```
*** Result: Auction: {
"objectType": "auction",
"ID": "tickets",
"seller": "eDUwOTo6Q049c2VsbGVyLE9VPWNsaWVudCtPVT1vcmcxK09VPWRlcGFydG1lbnQxOjpDTj1jYS5vcmcxLmV4YW1wbGUuY29tLE89b3JnMS5leGFtcGxlLmNvbSxMPUR1cmhhbSxTVD1Ob3J0aCBDYXJvbGluYSxDPVVT",
"quantity": 100,
"bidingOrgs": [
"Org1MSP"
],
"privateBids": {},
"revealedBids": {},
"winners": [],
"price": 0,
"status": "open"
}
```
The smart contract uses the `GetClientIdentity().GetID()` API to read identity that creates the auction and defines that identity as the auction `"seller"`. You can see the seller information by decoding the `"seller"` string out of base64 format:
```
echo eDUwOTo6Q049c2VsbGVyLE9VPWNsaWVudCtPVT1vcmcxK09VPWRlcGFydG1lbnQxOjpDTj1jYS5vcmcxLmV4YW1wbGUuY29tLE89b3JnMS5leGFtcGxlLmNvbSxMPUR1cmhhbSxTVD1Ob3J0aCBDYXJvbGluYSxDPVVT | base64 --decode
```
The result is the common name and issuer of the seller's certificate:
```
x509::CN=org1admin,OU=admin,O=Hyperledger,ST=North Carolina,C=US::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=USn
```
## Bid on the auction
We can now use the bidder identities to bid for the auction.
### Bid as bidder1
Bidder1 will enter a bid for 50 tickets for 70 dollars.
```
node bid.js org1 bidder1 auction1 50 80
```
The application will query the bid after it is created:
```
*** Result: Bid: {
"objectType": "bid",
"quantity": 50,
"price": 80,
"org": "Org1MSP",
"buyer": "eDUwOTo6Q049YmlkZGVyMSxPVT1jbGllbnQrT1U9b3JnMStPVT1kZXBhcnRtZW50MTo6Q049Y2Eub3JnMS5leGFtcGxlLmNvbSxPPW9yZzEuZXhhbXBsZS5jb20sTD1EdXJoYW0sU1Q9Tm9ydGggQ2Fyb2xpbmEsQz1VUw=="
}
```
Each bid is stored in the implicit data collection of their respective organizations. You can use the `queryBid.js` program to read a bid that is stored in a peers private data collection. The `"buyer"` identity in the bid is the certificate information from the user that created the bid. Only this identity will be able can query the bid from private state or reveal the bid during the auction.
The `bid.js` application also prints the bidID:
```
*** Result ***SAVE THIS VALUE*** BidID: 68d3de99032700d92b2d753c79d5aff2ca79378b169efb6a70ca3e0ea43acb1b
```
The BidID acts as the unique identifier of the bid. This ID allows you to query the bid and add the bid to the auction. Save the bidID from the query result as an environment variable in your terminal:
```
export BIDDER1_BID_ID=68d3de99032700d92b2d753c79d5aff2ca79378b169efb6a70ca3e0ea43acb1b
```
This value will be different for each transaction, so you will need to use the value returned by your application.
After the bid is created in private state, you can add the bid to the auction. Run the following command to add the bid that was just created to the auction:
```
node addBid.js org1 bidder1 auction1 $BIDDER1_BID_ID
```
The hash of bid will be added to the list private bids in that have been added to `auction1`. Storing the hash in the public auction allows users to accurately reveal the bid after bidding is closed. After the bid is added, the application will query the auction to verify that it was updated:
```
*** Result: Auction: {
"objectType": "auction",
"ID": "tickets",
"seller": "eDUwOTo6Q049c2VsbGVyLE9VPWNsaWVudCtPVT1vcmcxK09VPWRlcGFydG1lbnQxOjpDTj1jYS5vcmcxLmV4YW1wbGUuY29tLE89b3JnMS5leGFtcGxlLmNvbSxMPUR1cmhhbSxTVD1Ob3J0aCBDYXJvbGluYSxDPVVT",
"quantity": 100,
"bidingOrgs": [
"Org1MSP"
],
"privateBids": {
"\u0000bid\u0000auction1\u000068d3de99032700d92b2d753c79d5aff2ca79378b169efb6a70ca3e0ea43acb1b\u0000": {
"org": "Org1MSP",
"hash": "584dbad2269a44afb42bdbc7a7a4c08a7cd50deece1eb3fc38d4e49b9342f270"
}
},
"revealedBids": {},
"winners": [],
"price": 0,
"status": "open"
}
```
### Bid as bidder2
Let's submit another bid. Bidder2 would like to purchase 40 tickets for 50 dollars.
```
node bid.js org1 bidder2 auction1 40 50
```
Save the Bid ID returned by the application:
```
export BIDDER2_BID_ID=77dc57876a1bc5cb798863f07eaab6f041608e55c60900b2cbcf0acc7723e8ec
```
Add bidder2's bid to the auction:
```
node addBid.js org1 bidder2 auction1 $BIDDER2_BID_ID
```
### Bid as bidder3 from Org2
Bidder3 will bid for 40 tickets for 70 dollars:
```
node bid.js org2 bidder3 auction1 30 70
```
Save the Bid ID returned by the application:
```
export BIDDER3_BID_ID=7e2d0c33d0ff1030d855e5fb76f2a4eb30589549b4cb6e581da17d3705cbf77e
```
Add bidder3's bid to the auction:
```
node addBid.js org2 bidder3 auction1 $BIDDER3_BID_ID
```
Because bidder3 belongs to Org2, the last transaction will add Org2 to the list of participating organizations. You can see the Org2 MSP ID has been added to the list of `"biddingOrgs"` in the updated auction returned by the application:
```
*** Result: Auction: {
"objectType": "auction",
"ID": "tickets",
"seller": "eDUwOTo6Q049c2VsbGVyLE9VPWNsaWVudCtPVT1vcmcxK09VPWRlcGFydG1lbnQxOjpDTj1jYS5vcmcxLmV4YW1wbGUuY29tLE89b3JnMS5leGFtcGxlLmNvbSxMPUR1cmhhbSxTVD1Ob3J0aCBDYXJvbGluYSxDPVVT",
"quantity": 100,
"bidingOrgs": [
"Org1MSP",
"Org2MSP"
],
"privateBids": {
"\u0000bid\u0000auction1\u00005eb3b492a693f0063986519053cc50e1a374b94532a9fa0ef2866a1294afa2f7\u0000": {
"org": "Org2MSP",
"hash": "4446c7eb0e2d64165a916ee996348a18716f4c97e632d58d5a8c20eeec5a9238"
},
"\u0000bid\u0000auction1\u000068d3de99032700d92b2d753c79d5aff2ca79378b169efb6a70ca3e0ea43acb1b\u0000": {
"org": "Org1MSP",
"hash": "584dbad2269a44afb42bdbc7a7a4c08a7cd50deece1eb3fc38d4e49b9342f270"
},
"\u0000bid\u0000auction1\u000077dc57876a1bc5cb798863f07eaab6f041608e55c60900b2cbcf0acc7723e8ec\u0000": {
"org": "Org1MSP",
"hash": "bbcd0c7c376e6681a76d8c5482c97f8bdcda55c90c5478100c3aef17815c4fd3"
}
},
"revealedBids": {},
"winners": [],
"price": 0,
"status": "open"
}
```
Now that a bid from Org2 has been added to the auction, any auction updated need to be endorsed by the Org2 peer. The applications will use `"bidingOrgs"` field to specify which organizations need to endorse a transaction that adds a bid to the organization, reveals a bid, or change the bid status before submitting the transaction.
### Bid as bidder4
Bidder4 from Org2 would like to purchase 60 tickets for 60 dollars:
```
node bid.js org2 bidder4 auction1 60 60
```
Save the Bid ID returned by the application:
```
export BIDDER4_BID_ID=083478f1af2ba391a5b8d7c590cfb790aedf11578d64ebc4e5efe793555ff212
```
Add bidder2's bid to the auction:
```
node addBid.js org2 bidder4 auction1 $BIDDER4_BID_ID
```
## Close the auction
Now that 4 bidders have joined the auction, the seller would like to close the auction and allow buyers to reveal their bids. The seller identity that created the auction needs to update the auction:
```
node closeAuction.js org1 seller auction1
```
The application will query the auction so you can verify that the auction status has changed to closed. As a test, you can try to create and add a new bid to the auction. The result will be an endorsement policy failure.
## Reveal bids
After the auction is closed, bidders can try to win the auction by revealing their bids. The transaction to reveal a bid needs to pass four checks:
1. The status of the auction is closed.
2. The transaction needs to be issued by the identity that created the bid.
3. The hash of the revealed bid matches the hash of the bid on the channel ledger. This confirms that the bid is the same as what is stored in the organizations private data collection.
4. The hash of the revealed bid matches the hash that was added to the auction. This confirms that the bid was not altered after the auction was closed.
Use the `revealBid.js` application to reveal the bid of Bidder1:
```
node revealBid.js org1 bidder1 auction1 $BIDDER1_BID_ID
```
The full bid details, including the quantity and price, have beed added to the auction:
```
*** Result: Auction: {
"objectType": "auction",
"ID": "tickets",
"seller": "eDUwOTo6Q049c2VsbGVyLE9VPWNsaWVudCtPVT1vcmcxK09VPWRlcGFydG1lbnQxOjpDTj1jYS5vcmcxLmV4YW1wbGUuY29tLE89b3JnMS5leGFtcGxlLmNvbSxMPUR1cmhhbSxTVD1Ob3J0aCBDYXJvbGluYSxDPVVT",
"quantity": 100,
"bidingOrgs": [
"Org1MSP",
"Org2MSP"
],
"privateBids": {
"\u0000bid\u0000auction1\u00002d0639c7a4ccc139c3b349b3637986748d460a4304c93a025c345ee208b0ebcb\u0000": {
"org": "Org2MSP",
"hash": "d6f661d8b664244ce55065edc2fd95a982221888bb19afdad931b185e187ed4f"
},
"\u0000bid\u0000auction1\u00004886fdaa7edacbc22285cf88c5413ab08e4d17eff4e1681ec1b90a318a8c7253\u0000": {
"org": "Org1MSP",
"hash": "bbcd0c7c376e6681a76d8c5482c97f8bdcda55c90c5478100c3aef17815c4fd3"
},
"\u0000bid\u0000auction1\u00007e2d0c33d0ff1030d855e5fb76f2a4eb30589549b4cb6e581da17d3705cbf77e\u0000": {
"org": "Org2MSP",
"hash": "4446c7eb0e2d64165a916ee996348a18716f4c97e632d58d5a8c20eeec5a9238"
},
"\u0000bid\u0000auction1\u00009b9fbd48a05e0e971efe4f57d28d9f09c976f0b8abed4482dc84d32e2d8dea55\u0000": {
"org": "Org1MSP",
"hash": "584dbad2269a44afb42bdbc7a7a4c08a7cd50deece1eb3fc38d4e49b9342f270"
}
},
"revealedBids": {
"\u0000bid\u0000auction1\u00009b9fbd48a05e0e971efe4f57d28d9f09c976f0b8abed4482dc84d32e2d8dea55\u0000": {
"objectType": "bid",
"quantity": 50,
"price": 80,
"org": "Org1MSP",
"buyer": "eDUwOTo6Q049YmlkZGVyMSxPVT1jbGllbnQrT1U9b3JnMStPVT1kZXBhcnRtZW50MTo6Q049Y2Eub3JnMS5leGFtcGxlLmNvbSxPPW9yZzEuZXhhbXBsZS5jb20sTD1EdXJoYW0sU1Q9Tm9ydGggQ2Fyb2xpbmEsQz1VUw=="
}
},
"winners": [],
"price": 0,
"status": "closed"
}
```
Bidder3 from Org2 will also reveal their bid:
```
node revealBid.js org2 bidder4 auction1 $BIDDER4_BID_ID
```
If the action ended now, the winners of the auction would be Bidder1 and Bidder3 Let's try to end the auction as the seller to see what happens.
```
node endAuction.js org1 seller auction1
```
Instead of ending the auction, the transaction results in an endorsement policy failure. The end of the auction needs to be endorsed by Org2. Before endorsing the transaction, the Org2 peer queries its private data collection to check if any of the bids in its collection would be a potential winner of the auction. If a winning bid has not yet been revealed by its user, the Org2 peer does not endorse the transaction. This protects the bidders from Org2, and prevents the seller from ending the auction prematurely.
In order to end the auction, we need to reveal the bid from bidder3.
```
node revealBid.js org2 bidder3 auction1 $BIDDER3_BID_ID
```
Bidder2 from Org1 would not win the auction in either case, as a sufficient number of higher bids have been already been revealed. As a result, Bidder2 decides not to reveal their bid.
## End the auction
Now that the winning bids have been revealed, we can now end the auction:
```
node endAuction org1 seller auction1
```
The transaction was successfully endorsed by both Org1 and Org2, who both calculated the same price and winners of the auction. Each winning bidder is listed next to the quantity that was allocated to them. The bid from bidder4 clears the auction, and as a result the `"price"` of the ended auction is 60. Because Bidder1 and Bidder3 bid above that price, the first 80 tickets were allocated to them. Bidder4 was allocated the remaining 20 tickets that were left.
```
*** Result: Auction: {
"objectType": "auction",
"ID": "tickets",
"seller": "eDUwOTo6Q049c2VsbGVyLE9VPWNsaWVudCtPVT1vcmcxK09VPWRlcGFydG1lbnQxOjpDTj1jYS5vcmcxLmV4YW1wbGUuY29tLE89b3JnMS5leGFtcGxlLmNvbSxMPUR1cmhhbSxTVD1Ob3J0aCBDYXJvbGluYSxDPVVT",
"quantity": 100,
"bidingOrgs": [
"Org1MSP",
"Org2MSP"
],
"privateBids": {
"\u0000bid\u0000auction1\u00002d0639c7a4ccc139c3b349b3637986748d460a4304c93a025c345ee208b0ebcb\u0000": {
"org": "Org2MSP",
"hash": "d6f661d8b664244ce55065edc2fd95a982221888bb19afdad931b185e187ed4f"
},
"\u0000bid\u0000auction1\u00004886fdaa7edacbc22285cf88c5413ab08e4d17eff4e1681ec1b90a318a8c7253\u0000": {
"org": "Org1MSP",
"hash": "bbcd0c7c376e6681a76d8c5482c97f8bdcda55c90c5478100c3aef17815c4fd3"
},
"\u0000bid\u0000auction1\u00007e2d0c33d0ff1030d855e5fb76f2a4eb30589549b4cb6e581da17d3705cbf77e\u0000": {
"org": "Org2MSP",
"hash": "4446c7eb0e2d64165a916ee996348a18716f4c97e632d58d5a8c20eeec5a9238"
},
"\u0000bid\u0000auction1\u00009b9fbd48a05e0e971efe4f57d28d9f09c976f0b8abed4482dc84d32e2d8dea55\u0000": {
"org": "Org1MSP",
"hash": "584dbad2269a44afb42bdbc7a7a4c08a7cd50deece1eb3fc38d4e49b9342f270"
}
},
"revealedBids": {
"\u0000bid\u0000auction1\u00002d0639c7a4ccc139c3b349b3637986748d460a4304c93a025c345ee208b0ebcb\u0000": {
"objectType": "bid",
"quantity": 60,
"price": 60,
"org": "Org2MSP",
"buyer": "eDUwOTo6Q049YmlkZGVyNCxPVT1jbGllbnQrT1U9b3JnMitPVT1kZXBhcnRtZW50MTo6Q049Y2Eub3JnMi5leGFtcGxlLmNvbSxPPW9yZzIuZXhhbXBsZS5jb20sTD1IdXJzbGV5LFNUPUhhbXBzaGlyZSxDPVVL"
},
"\u0000bid\u0000auction1\u00007e2d0c33d0ff1030d855e5fb76f2a4eb30589549b4cb6e581da17d3705cbf77e\u0000": {
"objectType": "bid",
"quantity": 30,
"price": 70,
"org": "Org2MSP",
"buyer": "eDUwOTo6Q049YmlkZGVyMyxPVT1jbGllbnQrT1U9b3JnMitPVT1kZXBhcnRtZW50MTo6Q049Y2Eub3JnMi5leGFtcGxlLmNvbSxPPW9yZzIuZXhhbXBsZS5jb20sTD1IdXJzbGV5LFNUPUhhbXBzaGlyZSxDPVVL"
},
"\u0000bid\u0000auction1\u00009b9fbd48a05e0e971efe4f57d28d9f09c976f0b8abed4482dc84d32e2d8dea55\u0000": {
"objectType": "bid",
"quantity": 50,
"price": 80,
"org": "Org1MSP",
"buyer": "eDUwOTo6Q049YmlkZGVyMSxPVT1jbGllbnQrT1U9b3JnMStPVT1kZXBhcnRtZW50MTo6Q049Y2Eub3JnMS5leGFtcGxlLmNvbSxPPW9yZzEuZXhhbXBsZS5jb20sTD1EdXJoYW0sU1Q9Tm9ydGggQ2Fyb2xpbmEsQz1VUw=="
}
},
"winners": [
{
"buyer": "eDUwOTo6Q049YmlkZGVyMSxPVT1jbGllbnQrT1U9b3JnMStPVT1kZXBhcnRtZW50MTo6Q049Y2Eub3JnMS5leGFtcGxlLmNvbSxPPW9yZzEuZXhhbXBsZS5jb20sTD1EdXJoYW0sU1Q9Tm9ydGggQ2Fyb2xpbmEsQz1VUw==",
"quantity": 50
},
{
"buyer": "eDUwOTo6Q049YmlkZGVyMyxPVT1jbGllbnQrT1U9b3JnMitPVT1kZXBhcnRtZW50MTo6Q049Y2Eub3JnMi5leGFtcGxlLmNvbSxPPW9yZzIuZXhhbXBsZS5jb20sTD1IdXJzbGV5LFNUPUhhbXBzaGlyZSxDPVVL",
"quantity": 30
},
{
"buyer": "eDUwOTo6Q049YmlkZGVyNCxPVT1jbGllbnQrT1U9b3JnMitPVT1kZXBhcnRtZW50MTo6Q049Y2Eub3JnMi5leGFtcGxlLmNvbSxPPW9yZzIuZXhhbXBsZS5jb20sTD1IdXJzbGV5LFNUPUhhbXBzaGlyZSxDPVVL",
"quantity": 20
}
],
"price": 60,
"status": "ended"
}
```
## Clean up
When your are done using the auction smart contract, you can bring down the network and clean up the environment. In the `auction/application-javascript` directory, run the following command to remove the wallets that were created to use run the applications:
```
rm -rf wallet
```
You can then navigate to the test network directory and bring down the network:
````
cd ../../test-network/
./network.sh down
````

View file

@ -0,0 +1,108 @@
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const { Gateway, Wallets } = require('fabric-network');
const path = require('path');
const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js');
const myChannel = 'mychannel';
const myChaincodeName = 'auction';
function prettyJSONString(inputString) {
if (inputString) {
return JSON.stringify(JSON.parse(inputString), null, 2);
}
else {
return inputString;
}
}
async function addBid(ccp,wallet,user,auctionID,bidID) {
try {
const gateway = new Gateway();
//connect using Discovery enabled
await gateway.connect(ccp,
{ wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } });
const network = await gateway.getNetwork(myChannel);
const contract = network.getContract(myChaincodeName);
console.log('\n--> Evaluate Transaction: query the auction you want to join');
let auctionString = await contract.evaluateTransaction('QueryAuction',auctionID);
var auctionJSON = JSON.parse(auctionString);
let statefulTxn = contract.createTransaction('AddBid');
if (auctionJSON.bidingOrgs.length == 2) {
statefulTxn.setEndorsingOrganizations(auctionJSON.bidingOrgs[0],auctionJSON.bidingOrgs[1]);
} else {
statefulTxn.setEndorsingOrganizations(auctionJSON.bidingOrgs[0]);
}
console.log('\n--> Submit Transaction: add bid to the auction');
await statefulTxn.submit(auctionID,bidID);
console.log('\n--> Evaluate Transaction: query the auction to see that our bid was added');
let result = await contract.evaluateTransaction('QueryAuction',auctionID);
console.log('*** Result: Auction: ' + prettyJSONString(result.toString()));
gateway.disconnect();
} catch (error) {
console.error(`******** FAILED to submit bid: ${error}`);
process.exit(1);
}
}
async function main() {
try {
if (process.argv[2] == undefined || process.argv[3] == undefined
|| process.argv[4] == undefined || process.argv[5] == undefined) {
console.log("Usage: node addBid.js org userID auctionID bidID");
process.exit(1);
}
const org = process.argv[2]
const user = process.argv[3];
const auctionID = process.argv[4];
const bidID = process.argv[5];
if (org == 'Org1' || org == 'org1') {
const orgMSP = 'Org1MSP';
const ccp = buildCCPOrg1();
const walletPath = path.join(__dirname, 'wallet/org1');
const wallet = await buildWallet(Wallets, walletPath);
await addBid(ccp,wallet,user,auctionID,bidID);
}
else if (org == 'Org2' || org == 'org2') {
const orgMSP = 'Org2MSP';
const ccp = buildCCPOrg2();
const walletPath = path.join(__dirname, 'wallet/org2');
const wallet = await buildWallet(Wallets, walletPath);
await addBid(ccp,wallet,user,auctionID,bidID);
}
else {
console.log("Usage: node addBid.js org userID auctionID bidID");
console.log("Org must be Org1 or Org2");
}
} catch (error) {
console.error(`******** FAILED to run the application: ${error}`);
if (error.stack) {
console.error(error.stack);
}
process.exit(1);
}
}
main();

View file

@ -0,0 +1,114 @@
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const { Gateway, Wallets } = require('fabric-network');
const path = require('path');
const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js');
const myChannel = 'mychannel';
const myChaincodeName = 'auction';
function prettyJSONString(inputString) {
if (inputString) {
return JSON.stringify(JSON.parse(inputString), null, 2);
}
else {
return inputString;
}
}
async function bid(ccp,wallet,user,orgMSP,auctionID,quantity,price) {
try {
const gateway = new Gateway();
//connect using Discovery enabled
await gateway.connect(ccp,
{ wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } });
const network = await gateway.getNetwork(myChannel);
const contract = network.getContract(myChaincodeName);
console.log('\n--> Evaluate Transaction: get your client ID');
let buyer = await contract.evaluateTransaction('GetID');
console.log('*** Result: Buyer ID is ' + buyer.toString());
let bidData = { objectType: 'bid', quantity: parseInt(quantity) , price: parseInt(price), org: orgMSP, buyer: buyer.toString()};
let statefulTxn = contract.createTransaction('Bid');
statefulTxn.setEndorsingOrganizations(orgMSP);
let tmapData = Buffer.from(JSON.stringify(bidData));
statefulTxn.setTransient({
bid: tmapData
});
let bidID = statefulTxn.getTransactionId();
console.log('\n--> Submit Transaction: Create the bid that is stored in your organiztions private data collection');
await statefulTxn.submit(auctionID);
console.log('*** Result: committed');
console.log('*** Result ***SAVE THIS VALUE*** BidID: ' + bidID.toString());
console.log('\n--> Evaluate Transaction: read the bid that was just created');
let result = await contract.evaluateTransaction('QueryBid',auctionID,bidID);
console.log('*** Result: Bid: ' + prettyJSONString(result.toString()));
gateway.disconnect();
} catch (error) {
console.error(`******** FAILED to submit bid: ${error}`);
if (error.stack) {
console.error(error.stack);
}
process.exit(1);
}
}
async function main() {
try {
if (process.argv[2] == undefined || process.argv[3] == undefined
|| process.argv[4] == undefined || process.argv[5] == undefined
|| process.argv[6] == undefined) {
console.log("Usage: node bid.js org userID auctionID quantity price");
process.exit(1);
}
const org = process.argv[2]
const user = process.argv[3];
const auctionID = process.argv[4];
const quantity = process.argv[5];
const price = process.argv[6];
if (org == 'Org1' || org == 'org1') {
const orgMSP = 'Org1MSP';
const ccp = buildCCPOrg1();
const walletPath = path.join(__dirname, 'wallet/org1');
const wallet = await buildWallet(Wallets, walletPath);
await bid(ccp,wallet,user,orgMSP,auctionID,quantity,price);
}
else if (org == 'Org2' || org == 'org2') {
const orgMSP = 'Org2MSP';
const ccp = buildCCPOrg2();
const walletPath = path.join(__dirname, 'wallet/org2');
const wallet = await buildWallet(Wallets, walletPath);
await bid(ccp,wallet,user,orgMSP,auctionID,quantity,price);
} else {
console.log("Usage: node bid.js org userID auctionID quantity price");
console.log("Org must be Org1 or Org2");
}
} catch (error) {
console.error(`******** FAILED to run the application: ${error}`);
process.exit(1);
}
}
main();

View file

@ -0,0 +1,109 @@
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const { Gateway, Wallets } = require('fabric-network');
const path = require('path');
const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js');
const myChannel = 'mychannel';
const myChaincodeName = 'auction';
function prettyJSONString(inputString) {
if (inputString) {
return JSON.stringify(JSON.parse(inputString), null, 2);
}
else {
return inputString;
}
}
async function closeAuction(ccp,wallet,user,auctionID) {
try {
const gateway = new Gateway();
//connect using Discovery enabled
await gateway.connect(ccp,
{ wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } });
const network = await gateway.getNetwork(myChannel);
const contract = network.getContract(myChaincodeName);
// Query the auction to get the list of endorsing orgs.
//console.log('\n--> Evaluate Transaction: query the auction you want to join');
let auctionString = await contract.evaluateTransaction('QueryAuction',auctionID);
//console.log('*** Result: Bid: ' + prettyJSONString(auctionString.toString()));
var auctionJSON = JSON.parse(auctionString);
let statefulTxn = contract.createTransaction('CloseAuction');
if (auctionJSON.bidingOrgs.length == 2) {
statefulTxn.setEndorsingOrganizations(auctionJSON.bidingOrgs[0],auctionJSON.bidingOrgs[1]);
} else {
statefulTxn.setEndorsingOrganizations(auctionJSON.bidingOrgs[0]);
}
console.log('\n--> Submit Transaction: close auction');
await statefulTxn.submit(auctionID);
console.log('*** Result: committed');
console.log('\n--> Evaluate Transaction: query the updated auction');
let result = await contract.evaluateTransaction('QueryAuction',auctionID);
console.log('*** Result: Auction: ' + prettyJSONString(result.toString()));
gateway.disconnect();
} catch (error) {
console.error(`******** FAILED to submit bid: ${error}`);
process.exit(1);
}
}
async function main() {
try {
if (process.argv[2] == undefined || process.argv[3] == undefined
|| process.argv[4] == undefined) {
console.log("Usage: node closeAuction.js org userID auctionID");
process.exit(1);
}
const org = process.argv[2]
const user = process.argv[3];
const auctionID = process.argv[4];
if (org == 'Org1' || org == 'org1') {
const orgMSP = 'Org1MSP';
const ccp = buildCCPOrg1();
const walletPath = path.join(__dirname, 'wallet/org1');
const wallet = await buildWallet(Wallets, walletPath);
await closeAuction(ccp,wallet,user,auctionID);
}
else if (org == 'Org2' || org == 'org2') {
const orgMSP = 'Org2MSP';
const ccp = buildCCPOrg2();
const walletPath = path.join(__dirname, 'wallet/org2');
const wallet = await buildWallet(Wallets, walletPath);
await closeAuction(ccp,wallet,user,auctionID);
} else {
console.log("Usage: node closeAuction.js org userID auctionID ");
console.log("Org must be Org1 or Org2");
}
} catch (error) {
console.error(`******** FAILED to run the application: ${error}`);
if (error.stack) {
console.error(error.stack);
}
process.exit(1);
}
}
main();

View file

@ -0,0 +1,95 @@
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const { Gateway, Wallets } = require('fabric-network');
const path = require('path');
const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js');
const myChannel = 'mychannel';
const myChaincodeName = 'auction';
function prettyJSONString(inputString) {
if (inputString) {
return JSON.stringify(JSON.parse(inputString), null, 2);
}
else {
return inputString;
}
}
async function createAuction(ccp,wallet,user,auctionID,item,quantity) {
try {
const gateway = new Gateway();
//connect using Discovery enabled
await gateway.connect(ccp,
{ wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } });
const network = await gateway.getNetwork(myChannel);
const contract = network.getContract(myChaincodeName);
let statefulTxn = contract.createTransaction('CreateAuction');
console.log('\n--> Submit Transaction: Propose a new auction');
await statefulTxn.submit(auctionID,item,parseInt(quantity));
console.log('*** Result: committed');
console.log('\n--> Evaluate Transaction: query the auction that was just created');
let result = await contract.evaluateTransaction('QueryAuction',auctionID);
console.log('*** Result: Auction: ' + prettyJSONString(result.toString()));
gateway.disconnect();
} catch (error) {
console.error(`******** FAILED to submit bid: ${error}`);
}
}
async function main() {
try {
if (process.argv[2] == undefined || process.argv[3] == undefined
|| process.argv[4] == undefined || process.argv[5] == undefined
|| process.argv[6] == undefined) {
console.log("Usage: node createAuction.js org userID auctionID item quantity");
process.exit(1);
}
const org = process.argv[2]
const user = process.argv[3];
const auctionID = process.argv[4];
const item = process.argv[5];
const quantity = process.argv[6];
if (org == 'Org1' || org == 'org1') {
const orgMSP = 'Org1MSP';
const ccp = buildCCPOrg1();
const walletPath = path.join(__dirname, 'wallet/org1');
const wallet = await buildWallet(Wallets, walletPath);
await createAuction(ccp,wallet,user,auctionID,item,quantity);
}
else if (org == 'Org2' || org == 'org2') {
const orgMSP = 'Org2MSP';
const ccp = buildCCPOrg2();
const walletPath = path.join(__dirname, 'wallet/org2');
const wallet = await buildWallet(Wallets, walletPath);
await createAuction(ccp,wallet,user,auctionID,item,quantity);
} else {
console.log("Usage: node createAuction.js org userID auctionID item quantity");
console.log("Org must be Org1 or Org2");
}
} catch (error) {
console.error(`******** FAILED to run the application: ${error}`);
}
}
main();

View file

@ -0,0 +1,109 @@
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const { Gateway, Wallets } = require('fabric-network');
const path = require('path');
const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js');
const myChannel = 'mychannel';
const myChaincodeName = 'auction';
function prettyJSONString(inputString) {
if (inputString) {
return JSON.stringify(JSON.parse(inputString), null, 2);
}
else {
return inputString;
}
}
async function endAuction(ccp,wallet,user,auctionID) {
try {
const gateway = new Gateway();
//connect using Discovery enabled
await gateway.connect(ccp,
{ wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } });
const network = await gateway.getNetwork(myChannel);
const contract = network.getContract(myChaincodeName);
// Query the auction to get the list of endorsing orgs.
//console.log('\n--> Evaluate Transaction: query the auction you want to join');
let auctionString = await contract.evaluateTransaction('QueryAuction',auctionID);
//console.log('*** Result: Bid: ' + prettyJSONString(auctionString.toString()));
var auctionJSON = JSON.parse(auctionString);
let statefulTxn = contract.createTransaction('EndAuction');
if (auctionJSON.bidingOrgs.length == 2) {
statefulTxn.setEndorsingOrganizations(auctionJSON.bidingOrgs[0],auctionJSON.bidingOrgs[1]);
} else {
statefulTxn.setEndorsingOrganizations(auctionJSON.bidingOrgs[0]);
}
console.log('\n--> Submit the transaction to end the auction');
await statefulTxn.submit(auctionID);
console.log('*** Result: committed');
console.log('\n--> Evaluate Transaction: query the updated auction');
let result = await contract.evaluateTransaction('QueryAuction',auctionID);
console.log('*** Result: Auction: ' + prettyJSONString(result.toString()));
gateway.disconnect();
} catch (error) {
console.error(`******** FAILED to submit bid: ${error}`);
process.exit(1);
}
}
async function main() {
try {
if (process.argv[2] == undefined || process.argv[3] == undefined
|| process.argv[4] == undefined) {
console.log("Usage: node endAuction.js org userID auctionID");
process.exit(1);
}
const org = process.argv[2]
const user = process.argv[3];
const auctionID = process.argv[4];
if (org == 'Org1' || org == 'org1') {
const orgMSP = 'Org1MSP';
const ccp = buildCCPOrg1();
const walletPath = path.join(__dirname, 'wallet/org1');
const wallet = await buildWallet(Wallets, walletPath);
await endAuction(ccp,wallet,user,auctionID);
}
else if (org == 'Org2' || org == 'org2') {
const orgMSP = 'Org2MSP';
const ccp = buildCCPOrg2();
const walletPath = path.join(__dirname, 'wallet/org2');
const wallet = await buildWallet(Wallets, walletPath);
await endAuction(ccp,wallet,user,auctionID);
} else {
console.log("Usage: node endAuction.js org userID auctionID");
console.log("Org must be Org1 or Org2");
}
} catch (error) {
console.error(`******** FAILED to run the application: ${error}`);
if (error.stack) {
console.error(error.stack);
}
process.exit(1);
}
}
main();

View file

@ -0,0 +1,76 @@
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const { Wallets } = require('fabric-network');
const FabricCAServices = require('fabric-ca-client');
const path = require('path');
const { buildCAClient, enrollAdmin } = require('../../test-application/javascript/CAUtil.js');
const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js');
const mspOrg1 = 'Org1MSP';
const mspOrg2 = 'Org2MSP';
function prettyJSONString(inputString) {
if (inputString) {
return JSON.stringify(JSON.parse(inputString), null, 2);
}
else {
return inputString;
}
}
async function connectToOrg1CA() {
console.log('\n--> Enrolling the Org1 CA admin');
const ccpOrg1 = buildCCPOrg1();
const caOrg1Client = buildCAClient(FabricCAServices, ccpOrg1, 'ca.org1.example.com');
const walletPathOrg1 = path.join(__dirname, 'wallet/org1');
const walletOrg1 = await buildWallet(Wallets, walletPathOrg1);
await enrollAdmin(caOrg1Client, walletOrg1, mspOrg1);
}
async function connectToOrg2CA() {
console.log('\n--> Enrolling the Org2 CA admin');
const ccpOrg2 = buildCCPOrg2();
const caOrg2Client = buildCAClient(FabricCAServices, ccpOrg2, 'ca.org2.example.com');
const walletPathOrg2 = path.join(__dirname, 'wallet/org2');
const walletOrg2 = await buildWallet(Wallets, walletPathOrg2);
await enrollAdmin(caOrg2Client, walletOrg2, mspOrg2);
}
async function main() {
if (process.argv[2] == undefined) {
console.log("Usage: node enrollAdmin.js Org");
process.exit(1);
}
const org = process.argv[2];
try {
if (org == 'Org1' || org == 'org1') {
await connectToOrg1CA();
}
else if (org == 'Org2' || org == 'org2') {
await connectToOrg2CA();
} else {
console.log("Usage: node registerUser.js org userID");
console.log("Org must be Org1 or Org2");
}
} catch (error) {
console.error(`Error in enrolling admin: ${error}`);
process.exit(1);
}
}
main();

View file

@ -0,0 +1,895 @@
{
"name": "auction",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@grpc/grpc-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.0.3.tgz",
"integrity": "sha512-JKV3f5Bv2TZxK6eJSB9EarsZrnLxrvcFNwI9goq0YRXa3S6NNoCSnI3cG3lkXVIJ03Wng1WXe76kc2JQtRe7AQ==",
"requires": {
"semver": "^6.2.0"
}
},
"@grpc/proto-loader": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.4.tgz",
"integrity": "sha512-HTM4QpI9B2XFkPz7pjwMyMgZchJ93TVkL3kWPW8GDMDKYxsMnmf4w2TNMJK7+KNiYHS5cJrCEAFlF+AwtXWVPA==",
"requires": {
"lodash.camelcase": "^4.3.0",
"protobufjs": "^6.8.6"
}
},
"@protobufjs/aspromise": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
"integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78="
},
"@protobufjs/base64": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
},
"@protobufjs/codegen": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
},
"@protobufjs/eventemitter": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
"integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A="
},
"@protobufjs/fetch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
"integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=",
"requires": {
"@protobufjs/aspromise": "^1.1.1",
"@protobufjs/inquire": "^1.1.0"
}
},
"@protobufjs/float": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
"integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E="
},
"@protobufjs/inquire": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
"integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik="
},
"@protobufjs/path": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
"integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0="
},
"@protobufjs/pool": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
"integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q="
},
"@protobufjs/utf8": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
"integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA="
},
"@types/caseless": {
"version": "0.12.2",
"resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz",
"integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w=="
},
"@types/long": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz",
"integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w=="
},
"@types/node": {
"version": "13.13.21",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.21.tgz",
"integrity": "sha512-tlFWakSzBITITJSxHV4hg4KvrhR/7h3xbJdSFbYJBVzKubrASbnnIFuSgolUh7qKGo/ZeJPKUfbZ0WS6Jp14DQ=="
},
"@types/request": {
"version": "2.48.5",
"resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz",
"integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==",
"requires": {
"@types/caseless": "*",
"@types/node": "*",
"@types/tough-cookie": "*",
"form-data": "^2.5.0"
}
},
"@types/tough-cookie": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz",
"integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A=="
},
"ajv": {
"version": "6.12.5",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz",
"integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==",
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
},
"asn1": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
"requires": {
"safer-buffer": "~2.1.0"
}
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
},
"async": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
"integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
},
"aws4": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz",
"integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA=="
},
"bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
"requires": {
"tweetnacl": "^0.14.3"
}
},
"bn.js": {
"version": "4.11.9",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw=="
},
"brorand": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
"integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8="
},
"browser-request": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/browser-request/-/browser-request-0.3.3.tgz",
"integrity": "sha1-ns5bWsqJopkyJC4Yv5M975h2zBc="
},
"callsite": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
"integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA="
},
"camelcase": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
"integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8="
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
},
"cliui": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
"integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
"requires": {
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1",
"wrap-ansi": "^2.0.0"
}
},
"cloudant-follow": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/cloudant-follow/-/cloudant-follow-0.18.2.tgz",
"integrity": "sha512-qu/AmKxDqJds+UmT77+0NbM7Yab2K3w0qSeJRzsq5dRWJTEJdWeb+XpG4OpKuTE9RKOa/Awn2gR3TTnvNr3TeA==",
"requires": {
"browser-request": "~0.3.0",
"debug": "^4.0.1",
"request": "^2.88.0"
}
},
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
},
"colors": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
"integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs="
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"cycle": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz",
"integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI="
},
"dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
"requires": {
"assert-plus": "^1.0.0"
}
},
"debug": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
"integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
"requires": {
"ms": "2.1.2"
}
},
"decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
"requires": {
"jsbn": "~0.1.0",
"safer-buffer": "^2.1.0"
}
},
"elliptic": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
"integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
"requires": {
"bn.js": "^4.4.0",
"brorand": "^1.0.1",
"hash.js": "^1.0.0",
"hmac-drbg": "^1.0.0",
"inherits": "^2.0.1",
"minimalistic-assert": "^1.0.0",
"minimalistic-crypto-utils": "^1.0.0"
}
},
"errs": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/errs/-/errs-0.3.2.tgz",
"integrity": "sha1-eYCZstvTfKK8dJ5TinwTB9C1BJk="
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
},
"eyes": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz",
"integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A="
},
"fabric-ca-client": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/fabric-ca-client/-/fabric-ca-client-2.2.2.tgz",
"integrity": "sha512-hC762b6kEjot7Z9mBfzZDkloKAQ6rNJiKPg3F9o56XfF10xeJ1wj0p6ULMKgQesSYMmre1g9TcALVdnH1NqS8w==",
"requires": {
"fabric-common": "2.2.2",
"jsrsasign": "^8.0.20",
"url": "^0.11.0",
"winston": "^2.4.0"
}
},
"fabric-common": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/fabric-common/-/fabric-common-2.2.2.tgz",
"integrity": "sha512-OhIvZTTis7tSRzztCzss3+BM6R274ZIM1yFc6VZHqubW7SSAy5qkGyzROSHQEim/6HM5meGgEKS5aHKrLzkMtw==",
"requires": {
"callsite": "^1.0.0",
"elliptic": "^6.5.2",
"fabric-protos": "2.2.2",
"js-sha3": "^0.7.0",
"jsrsasign": "^8.0.20",
"nconf": "^0.10.0",
"pkcs11js": "^1.0.6",
"promise-settle": "^0.3.0",
"sjcl": "1.0.7",
"winston": "^2.4.0",
"yn": "^3.1.0"
}
},
"fabric-network": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/fabric-network/-/fabric-network-2.2.2.tgz",
"integrity": "sha512-zPZ+yrSyHSVzDVS7f9EEMxN9nKOQ7aDg0RX76efevH7PQ7atDogijMnw2EdYnHBcw/t/ATMlMqaIxkKJNBoPjg==",
"requires": {
"fabric-common": "2.2.2",
"fabric-protos": "2.2.2",
"long": "^4.0.0",
"nano": "^8.2.2"
}
},
"fabric-protos": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/fabric-protos/-/fabric-protos-2.2.2.tgz",
"integrity": "sha512-deXDIC4l9opKyu7zqZMXqiszxSOULKP66HmWZ435dgmQZyeo0rzFVO7dCwBZYdAVmz9pE4Ze8/qEU2GQ3suCJg==",
"requires": {
"@grpc/grpc-js": "1.0.3",
"@grpc/proto-loader": "0.5.4",
"protobufjs": "^6.9.0"
}
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
},
"form-data": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
"integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
},
"getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
"requires": {
"assert-plus": "^1.0.0"
}
},
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
},
"har-validator": {
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
"integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
"requires": {
"ajv": "^6.12.3",
"har-schema": "^2.0.0"
}
},
"hash.js": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
"requires": {
"inherits": "^2.0.3",
"minimalistic-assert": "^1.0.1"
}
},
"hmac-drbg": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
"integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
"requires": {
"hash.js": "^1.0.3",
"minimalistic-assert": "^1.0.0",
"minimalistic-crypto-utils": "^1.0.1"
}
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
"requires": {
"assert-plus": "^1.0.0",
"jsprim": "^1.2.2",
"sshpk": "^1.7.0"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"ini": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
},
"invert-kv": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
"integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY="
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"requires": {
"number-is-nan": "^1.0.0"
}
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
"js-sha3": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.7.0.tgz",
"integrity": "sha512-Wpks3yBDm0UcL5qlVhwW9Jr9n9i4FfeWBFOOXP5puDS/SiudJGhw7DPyBqn3487qD4F0lsC0q3zxink37f7zeA=="
},
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
},
"json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
},
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
},
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
},
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.2.3",
"verror": "1.10.0"
}
},
"jsrsasign": {
"version": "8.0.24",
"resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-8.0.24.tgz",
"integrity": "sha512-u45jAyusqUpyGbFc2IbHoeE4rSkoBWQgLe/w99temHenX+GyCz4nflU5sjK7ajU1ffZTezl6le7u43Yjr/lkQg=="
},
"lcid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
"integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
"requires": {
"invert-kv": "^1.0.0"
}
},
"lodash.camelcase": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
"integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
},
"long": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
},
"mime-db": {
"version": "1.44.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg=="
},
"mime-types": {
"version": "2.1.27",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
"requires": {
"mime-db": "1.44.0"
}
},
"minimalistic-assert": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
},
"minimalistic-crypto-utils": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
"integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"nan": {
"version": "2.14.1",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz",
"integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==",
"optional": true
},
"nano": {
"version": "8.2.2",
"resolved": "https://registry.npmjs.org/nano/-/nano-8.2.2.tgz",
"integrity": "sha512-1/rAvpd1J0Os0SazgutWQBx2buAq3KwJpmdIylPDqOwy73iQeAhTSCq3uzbGzvcNNW16Vv/BLXkk+DYcdcH+aw==",
"requires": {
"@types/request": "^2.48.4",
"cloudant-follow": "^0.18.2",
"debug": "^4.1.1",
"errs": "^0.3.2",
"request": "^2.88.0"
}
},
"nconf": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/nconf/-/nconf-0.10.0.tgz",
"integrity": "sha512-fKiXMQrpP7CYWJQzKkPPx9hPgmq+YLDyxcG9N8RpiE9FoCkCbzD0NyW0YhE3xn3Aupe7nnDeIx4PFzYehpHT9Q==",
"requires": {
"async": "^1.4.0",
"ini": "^1.3.0",
"secure-keys": "^1.0.0",
"yargs": "^3.19.0"
}
},
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
},
"oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
},
"os-locale": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
"requires": {
"lcid": "^1.0.0"
}
},
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
"pkcs11js": {
"version": "1.0.22",
"resolved": "https://registry.npmjs.org/pkcs11js/-/pkcs11js-1.0.22.tgz",
"integrity": "sha512-g0gOCCkKSa8YfoQPZFKk8VnbPvK+y3Gfx4O9NplzG6ntUX+1HSu491l8IUouxx45Jm3oEQXdDMtdTKH9t695aQ==",
"optional": true,
"requires": {
"nan": "^2.14.1"
}
},
"promise-settle": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/promise-settle/-/promise-settle-0.3.0.tgz",
"integrity": "sha1-tO/VcqHrdM95T4KM00naQKCOTpY="
},
"protobufjs": {
"version": "6.10.1",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.1.tgz",
"integrity": "sha512-pb8kTchL+1Ceg4lFd5XUpK8PdWacbvV5SK2ULH2ebrYtl4GjJmS24m6CKME67jzV53tbJxHlnNOSqQHbTsR9JQ==",
"requires": {
"@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2",
"@protobufjs/codegen": "^2.0.4",
"@protobufjs/eventemitter": "^1.1.0",
"@protobufjs/fetch": "^1.1.0",
"@protobufjs/float": "^1.0.2",
"@protobufjs/inquire": "^1.1.0",
"@protobufjs/path": "^1.1.2",
"@protobufjs/pool": "^1.1.0",
"@protobufjs/utf8": "^1.1.0",
"@types/long": "^4.0.1",
"@types/node": "^13.7.0",
"long": "^4.0.0"
}
},
"psl": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
"integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
},
"punycode": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
"integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
},
"qs": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
},
"querystring": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
},
"request": {
"version": "2.88.2",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
"requires": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
"caseless": "~0.12.0",
"combined-stream": "~1.0.6",
"extend": "~3.0.2",
"forever-agent": "~0.6.1",
"form-data": "~2.3.2",
"har-validator": "~5.1.3",
"http-signature": "~1.2.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19",
"oauth-sign": "~0.9.0",
"performance-now": "^2.1.0",
"qs": "~6.5.2",
"safe-buffer": "^5.1.2",
"tough-cookie": "~2.5.0",
"tunnel-agent": "^0.6.0",
"uuid": "^3.3.2"
},
"dependencies": {
"form-data": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
}
}
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"secure-keys": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/secure-keys/-/secure-keys-1.0.0.tgz",
"integrity": "sha1-8MgtmKOxOah3aogIBQuCRDEIf8o="
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
},
"sjcl": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.7.tgz",
"integrity": "sha1-MrNlpQ3Ju6JriLo8nfjqNCF9n0U="
},
"sshpk": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
"integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
"requires": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
"bcrypt-pbkdf": "^1.0.0",
"dashdash": "^1.12.0",
"ecc-jsbn": "~0.1.1",
"getpass": "^0.1.1",
"jsbn": "~0.1.0",
"safer-buffer": "^2.0.2",
"tweetnacl": "~0.14.0"
}
},
"stack-trace": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
"integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA="
},
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0"
}
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "^2.0.0"
}
},
"tough-cookie": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
"requires": {
"psl": "^1.1.28",
"punycode": "^2.1.1"
},
"dependencies": {
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
}
}
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"requires": {
"safe-buffer": "^5.0.1"
}
},
"tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
},
"uri-js": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
"integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
"requires": {
"punycode": "^2.1.0"
},
"dependencies": {
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
}
}
},
"url": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
"integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
"requires": {
"punycode": "1.3.2",
"querystring": "0.2.0"
}
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
},
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"requires": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "^1.2.0"
}
},
"window-size": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz",
"integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY="
},
"winston": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/winston/-/winston-2.4.5.tgz",
"integrity": "sha512-TWoamHt5yYvsMarGlGEQE59SbJHqGsZV8/lwC+iCcGeAe0vUaOh+Lv6SYM17ouzC/a/LB1/hz/7sxFBtlu1l4A==",
"requires": {
"async": "~1.0.0",
"colors": "1.0.x",
"cycle": "1.0.x",
"eyes": "0.1.x",
"isstream": "0.1.x",
"stack-trace": "0.0.x"
},
"dependencies": {
"async": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz",
"integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k="
}
}
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
"requires": {
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1"
}
},
"y18n": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
"integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE="
},
"yargs": {
"version": "3.32.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz",
"integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=",
"requires": {
"camelcase": "^2.0.1",
"cliui": "^3.0.3",
"decamelize": "^1.1.1",
"os-locale": "^1.4.0",
"string-width": "^1.0.1",
"window-size": "^0.1.4",
"y18n": "^3.2.0"
}
},
"yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="
}
}
}

View file

@ -0,0 +1,16 @@
{
"name": "auction",
"version": "1.0.0",
"description": "auction application implemented in JavaScript",
"engines": {
"node": ">=12",
"npm": ">=5"
},
"engineStrict": true,
"author": "Hyperledger",
"license": "Apache-2.0",
"dependencies": {
"fabric-ca-client": "^2.2.0",
"fabric-network": "^2.2.0"
}
}

View file

@ -0,0 +1,86 @@
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const { Gateway, Wallets } = require('fabric-network');
const path = require('path');
const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js');
const myChannel = 'mychannel';
const myChaincodeName = 'auction';
function prettyJSONString(inputString) {
if (inputString) {
return JSON.stringify(JSON.parse(inputString), null, 2);
}
else {
return inputString;
}
}
async function queryAuction(ccp,wallet,user,auctionID) {
try {
const gateway = new Gateway();
//connect using Discovery enabled
await gateway.connect(ccp,
{ wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } });
const network = await gateway.getNetwork(myChannel);
const contract = network.getContract(myChaincodeName);
console.log('\n--> Evaluate Transaction: query the auction that was just created');
let result = await contract.evaluateTransaction('QueryAuction',auctionID);
console.log('*** Result: Auction: ' + prettyJSONString(result.toString()));
gateway.disconnect();
} catch (error) {
console.error(`******** FAILED to submit bid: ${error}`);
}
}
async function main() {
try {
if (process.argv[2] == undefined || process.argv[3] == undefined
|| process.argv[4] == undefined) {
console.log("Usage: node queryAuction.js org userID auctionID");
process.exit(1);
}
const org = process.argv[2]
const user = process.argv[3];
const auctionID = process.argv[4];
if (org == 'Org1' || org == 'org1') {
const orgMSP = 'Org1MSP';
const ccp = buildCCPOrg1();
const walletPath = path.join(__dirname, 'wallet/org1');
const wallet = await buildWallet(Wallets, walletPath);
await queryAuction(ccp,wallet,user,auctionID);
}
else if (org == 'Org2' || org == 'org2') {
const orgMSP = 'Org2MSP';
const ccp = buildCCPOrg2();
const walletPath = path.join(__dirname, 'wallet/org2');
const wallet = await buildWallet(Wallets, walletPath);
await queryAuction(ccp,wallet,user,auctionID);
} else {
console.log("Usage: node queryAuction.js org userID auctionID");
console.log("Org must be Org1 or Org2");
}
} catch (error) {
console.error(`******** FAILED to run the application: ${error}`);
}
}
main();

View file

@ -0,0 +1,87 @@
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const { Gateway, Wallets } = require('fabric-network');
const path = require('path');
const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js');
const myChannel = 'mychannel';
const myChaincodeName = 'auction';
function prettyJSONString(inputString) {
if (inputString) {
return JSON.stringify(JSON.parse(inputString), null, 2);
}
else {
return inputString;
}
}
async function queryBid(ccp,wallet,user,auctionID,bidID) {
try {
const gateway = new Gateway();
//connect using Discovery enabled
await gateway.connect(ccp,
{ wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } });
const network = await gateway.getNetwork(myChannel);
const contract = network.getContract(myChaincodeName);
console.log('\n--> Evaluate Transaction: read bid from private data store');
let result = await contract.evaluateTransaction('QueryBid',auctionID,bidID);
console.log('*** Result: Bid: ' + prettyJSONString(result.toString()));
gateway.disconnect();
} catch (error) {
console.error(`******** FAILED to submit bid: ${error}`);
}
}
async function main() {
try {
if (process.argv[2] == undefined || process.argv[3] == undefined
|| process.argv[4] == undefined || process.argv[5] == undefined) {
console.log("Usage: node bid.js org userID auctionID bidID");
process.exit(1);
}
const org = process.argv[2]
const user = process.argv[3];
const auctionID = process.argv[4];
const bidID = process.argv[5];
if (org == 'Org1' || org == 'org1') {
const orgMSP = 'Org1MSP';
const ccp = buildCCPOrg1();
const walletPath = path.join(__dirname, 'wallet/org1');
const wallet = await buildWallet(Wallets, walletPath);
await queryBid(ccp,wallet,user,auctionID,bidID);
}
else if (org == 'Org2' || org == 'org2') {
const orgMSP = 'Org2MSP';
const ccp = buildCCPOrg2();
const walletPath = path.join(__dirname, 'wallet/org2');
const wallet = await buildWallet(Wallets, walletPath);
await queryBid(ccp,wallet,user,auctionID,bidID);
} else {
console.log("Usage: node bid.js org userID auctionID bidID");
console.log("Org must be Org1 or Org2");
}
} catch (error) {
console.error(`******** FAILED to run the application: ${error}`);
}
}
main();

View file

@ -0,0 +1,77 @@
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const { Wallets } = require('fabric-network');
const FabricCAServices = require('fabric-ca-client');
const path = require('path');
const { buildCAClient, registerAndEnrollUser } = require('../../test-application/javascript/CAUtil.js');
const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js');
const mspOrg1 = 'Org1MSP';
const mspOrg2 = 'Org2MSP';
function prettyJSONString(inputString) {
if (inputString) {
return JSON.stringify(JSON.parse(inputString), null, 2);
}
else {
return inputString;
}
}
async function connectToOrg1CA(UserID) {
console.log('\n--> Register and enrolling new user');
const ccpOrg1 = buildCCPOrg1();
const caOrg1Client = buildCAClient(FabricCAServices, ccpOrg1, 'ca.org1.example.com');
const walletPathOrg1 = path.join(__dirname, 'wallet/org1');
const walletOrg1 = await buildWallet(Wallets, walletPathOrg1);
await registerAndEnrollUser(caOrg1Client, walletOrg1, mspOrg1, UserID, 'org1.department1');
}
async function connectToOrg2CA(UserID) {
console.log('\n--> Register and enrolling new user');
const ccpOrg2 = buildCCPOrg2();
const caOrg2Client = buildCAClient(FabricCAServices, ccpOrg2, 'ca.org2.example.com');
const walletPathOrg2 = path.join(__dirname, 'wallet/org2');
const walletOrg2 = await buildWallet(Wallets, walletPathOrg2);
await registerAndEnrollUser(caOrg2Client, walletOrg2, mspOrg2, UserID, 'org2.department1');
}
async function main() {
if (process.argv[2] == undefined && process.argv[3] == undefined) {
console.log("Usage: node registerEnrollUser.js org userID");
process.exit(1);
}
const org = process.argv[2];
const userId = process.argv[3];
try {
if (org == 'Org1' || org == 'org1') {
await connectToOrg1CA(userId);
}
else if (org == 'Org2' || org == 'org2') {
await connectToOrg2CA(userId);
} else {
console.log("Usage: node registerEnrollUser.js org userID");
console.log("Org must be Org1 or Org2");
}
} catch (error) {
console.error(`Error in enrolling admin: ${error}`);
process.exit(1);
}
}
main();

View file

@ -0,0 +1,119 @@
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const { Gateway, Wallets } = require('fabric-network');
const path = require('path');
const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js');
const myChannel = 'mychannel';
const myChaincodeName = 'auction';
function prettyJSONString(inputString) {
if (inputString) {
return JSON.stringify(JSON.parse(inputString), null, 2);
}
else {
return inputString;
}
}
async function addBid(ccp,wallet,user,auctionID,bidID) {
try {
const gateway = new Gateway();
//connect using Discovery enabled
await gateway.connect(ccp,
{ wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } });
const network = await gateway.getNetwork(myChannel);
const contract = network.getContract(myChaincodeName);
console.log('\n--> Evaluate Transaction: read your bid');
let bidString = await contract.evaluateTransaction('QueryBid',auctionID,bidID);
var bidJSON = JSON.parse(bidString);
//console.log('\n--> Evaluate Transaction: query the auction you want to join');
let auctionString = await contract.evaluateTransaction('QueryAuction',auctionID);
// console.log('*** Result: Bid: ' + prettyJSONString(auctionString.toString()));
var auctionJSON = JSON.parse(auctionString);
let bidData = { objectType: 'bid', quantity: parseInt(bidJSON.quantity) , price: parseInt(bidJSON.price), org: bidJSON.org, buyer: bidJSON.buyer};
console.log('*** Result: Bid: ' + JSON.stringify(bidData,null,2));
let statefulTxn = contract.createTransaction('RevealBid');
let tmapData = Buffer.from(JSON.stringify(bidData));
statefulTxn.setTransient({
bid: tmapData
});
if (auctionJSON.bidingOrgs.length == 2) {
statefulTxn.setEndorsingOrganizations(auctionJSON.bidingOrgs[0],auctionJSON.bidingOrgs[1]);
} else {
statefulTxn.setEndorsingOrganizations(auctionJSON.bidingOrgs[0]);
}
await statefulTxn.submit(auctionID,bidID);
console.log('\n--> Evaluate Transaction: query the auction to see that our bid was added');
let result = await contract.evaluateTransaction('QueryAuction',auctionID);
console.log('*** Result: Auction: ' + prettyJSONString(result.toString()));
gateway.disconnect();
} catch (error) {
console.error(`******** FAILED to submit bid: ${error}`);
process.exit(1);
}
}
async function main() {
try {
if (process.argv[2] == undefined || process.argv[3] == undefined
|| process.argv[4] == undefined || process.argv[5] == undefined) {
console.log("Usage: node revealBid.js org userID auctionID bidID");
process.exit(1);
}
const org = process.argv[2]
const user = process.argv[3];
const auctionID = process.argv[4];
const bidID = process.argv[5];
if (org == 'Org1' || org == 'org1') {
const orgMSP = 'Org1MSP';
const ccp = buildCCPOrg1();
const walletPath = path.join(__dirname, 'wallet/org1');
const wallet = await buildWallet(Wallets, walletPath);
await addBid(ccp,wallet,user,auctionID,bidID);
}
else if (org == 'Org2' || org == 'org2') {
const orgMSP = 'Org2MSP';
const ccp = buildCCPOrg2();
const walletPath = path.join(__dirname, 'wallet/org2');
const wallet = await buildWallet(Wallets, walletPath);
await addBid(ccp,wallet,user,auctionID,bidID);
}
else {
console.log("Usage: node revealBid.js org userID auctionID bidID");
console.log("Org must be Org1 or Org2");
}
} catch (error) {
console.error(`******** FAILED to run the application: ${error}`);
if (error.stack) {
console.error(error.stack);
}
process.exit(1);
}
}
main();

View file

@ -0,0 +1,8 @@
module github.com/hyperledger/fabric-samples/auction/chaincode-go
go 1.15
require (
github.com/hyperledger/fabric-chaincode-go v0.0.0-20200728190242-9b3ae92d8664
github.com/hyperledger/fabric-contract-api-go v1.1.0
)

139
auction/chaincode-go/go.sum Normal file
View file

@ -0,0 +1,139 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/DATA-DOG/go-txdb v0.1.3/go.mod h1:DhAhxMXZpUJVGnT+p9IbzJoRKvlArO2pkHjnGX7o0n0=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cucumber/godog v0.8.0/go.mod h1:Cp3tEV1LRAyH/RuCThcxHS/+9ORZ+FMzPva2AZ5Ki+A=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=
github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU=
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4=
github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg=
github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk=
github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212/go.mod h1:N7H3sA7Tx4k/YzFq7U0EPdqJtqvM4Kild0JoCc7C0Dc=
github.com/hyperledger/fabric-chaincode-go v0.0.0-20200728190242-9b3ae92d8664 h1:Pu/9SNpo71SJj5DGehCXOKD9QGQ3MsuWjpsLM9Mkdwg=
github.com/hyperledger/fabric-chaincode-go v0.0.0-20200728190242-9b3ae92d8664/go.mod h1:N7H3sA7Tx4k/YzFq7U0EPdqJtqvM4Kild0JoCc7C0Dc=
github.com/hyperledger/fabric-contract-api-go v1.1.0 h1:K9uucl/6eX3NF0/b+CGIiO1IPm1VYQxBkpnVGJur2S4=
github.com/hyperledger/fabric-contract-api-go v1.1.0/go.mod h1:nHWt0B45fK53owcFpLtAe8DH0Q5P068mnzkNXMPSL7E=
github.com/hyperledger/fabric-protos-go v0.0.0-20190919234611-2a87503ac7c9/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e h1:9PS5iezHk/j7XriSlNuSQILyCOfcZ9wZ3/PiucmSE8E=
github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ=
golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View file

@ -0,0 +1,533 @@
/*
SPDX-License-Identifier: Apache-2.0
*/
package auction
import (
"bytes"
"crypto/sha256"
"encoding/json"
"fmt"
"sort"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
type SmartContract struct {
contractapi.Contract
}
// Auction data
type Auction struct {
Type string `json:"objectType"`
ItemSold string `json:"ID"`
Seller string `json:"seller"`
Quantity int `json:"quantity"`
BiddingOrgs []string `json:"bidingOrgs"`
PrivateBids map[string]BidHash `json:"privateBids"`
RevealedBids map[string]FullBid `json:"revealedBids"`
Winners []Winners `json:"winners"`
Price int `json:"price"`
Status string `json:"status"`
}
// FullBid is the structure of a revealed bid
type FullBid struct {
Type string `json:"objectType"`
Quantity int `json:"quantity"`
Price int `json:"price"`
Org string `json:"org"`
Buyer string `json:"buyer"`
}
// BidHash is the structure of a private bid
type BidHash struct {
Org string `json:"org"`
Hash string `json:"hash"`
}
// Winners stores the winners of the auction
type Winners struct {
Buyer string `json:"buyer"`
Quantity int `json:"quantity"`
}
const bidKeyType = "bid"
// CreateAuction creates on auction on the public channel. The identity that
// submits the transacion becomes the seller of the auction
func (s *SmartContract) CreateAuction(ctx contractapi.TransactionContextInterface, auctionID string, itemsold string, quantity int) error {
// get ID of submitting client
clientID, err := ctx.GetClientIdentity().GetID()
if err != nil {
return fmt.Errorf("failed to get client identity %v", err)
}
// get org of submitting client
clientOrgID, err := ctx.GetClientIdentity().GetMSPID()
if err != nil {
return fmt.Errorf("failed to get client identity %v", err)
}
// Create auction
bidders := make(map[string]BidHash)
revealedBids := make(map[string]FullBid)
auction := Auction{
Type: "auction",
ItemSold: itemsold,
Quantity: quantity,
Price: 0,
Seller: clientID,
BiddingOrgs: []string{clientOrgID},
PrivateBids: bidders,
RevealedBids: revealedBids,
Winners: []Winners{},
Status: "open",
}
auctionBytes, err := json.Marshal(auction)
if err != nil {
return err
}
// put auction into state
err = ctx.GetStub().PutState(auctionID, auctionBytes)
if err != nil {
return fmt.Errorf("failed to put auction in public data: %v", err)
}
// set the seller of the auction as an endorser
err = setAssetStateBasedEndorsement(ctx, auctionID, clientOrgID)
if err != nil {
return fmt.Errorf("failed setting state based endorsement for new organization: %v", err)
}
return nil
}
// Bid is used to add a users bid to the auction. The bid is stored in the private
// data collection on the peer of the bidders organization. A hash of the bid is stored
// in the auction private state. The function returns the transaction ID so that
// users can identify and query their bid
func (s *SmartContract) Bid(ctx contractapi.TransactionContextInterface, auctionID string) (string, error) {
// get bid from transient map
transientMap, err := ctx.GetStub().GetTransient()
if err != nil {
return "", fmt.Errorf("error getting transient: %v", err)
}
BidJSON, ok := transientMap["bid"]
if !ok {
return "", fmt.Errorf("bid key not found in the transient map")
}
// get the implicit collection name using the bidders organization ID
collection, err := getCollectionName(ctx)
if err != nil {
return "", fmt.Errorf("failed to get implicit collection name: %v", err)
}
// the bidder has to target their peer to store the bid
err = verifyClientOrgMatchesPeerOrg(ctx)
if err != nil {
return "", fmt.Errorf("Cannot store bid on this peer, not a member of this org: Error %v", err)
}
// the transaction ID is used as a unique index for the bid
txID := ctx.GetStub().GetTxID()
// create a composite key using the transacition ID
bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID})
if err != nil {
return "", fmt.Errorf("failed to create composite key: %v", err)
}
// put the bid into the organizations implicit data collection
err = ctx.GetStub().PutPrivateData(collection, bidKey, BidJSON)
if err != nil {
return "", fmt.Errorf("failed to input price into collection: %v", err)
}
// return the trannsaction ID so that the uset can identify their bid
return txID, nil
}
// AddBid is used by the bidder to add the hash of that bid stored in private data to the
// auction. Note that this function alters the auction in private state, and needs
// to meet the auction endorsement policy. Transaction ID is used identify the bid
func (s *SmartContract) AddBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) error {
// get the MSP ID of the bidders org
clientOrgID, err := ctx.GetClientIdentity().GetMSPID()
if err != nil {
return fmt.Errorf("failed to get client MSP ID: %v", err)
}
// get the auction from state
auctionBytes, err := ctx.GetStub().GetState(auctionID)
var auctionJSON Auction
if auctionBytes == nil {
return fmt.Errorf("Auction not found: %v", auctionID)
}
err = json.Unmarshal(auctionBytes, &auctionJSON)
if err != nil {
return fmt.Errorf("failed to create auction object JSON: %v", err)
}
// the auction needs to be open for users to add their bid
Status := auctionJSON.Status
if Status != "open" {
return fmt.Errorf("cannot join closed or ended auction")
}
// get the inplicit collection name of bidders org
collection, err := getCollectionName(ctx)
if err != nil {
return fmt.Errorf("failed to get implicit collection name: %v", err)
}
// use the transaction ID passed as a parameter to create composite bid key
bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID})
if err != nil {
return fmt.Errorf("failed to create composite key: %v", err)
}
// get the hash of the bid stored in private data stored on the public ledger
bidHash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey)
if err != nil {
return fmt.Errorf("failed to read bid bash from collection: %v", err)
}
if bidHash == nil {
return fmt.Errorf("bid hash does not exist: %s", bidKey)
}
// store the hash along with the bidders organization
NewHash := BidHash{
Org: clientOrgID,
Hash: fmt.Sprintf("%x", bidHash),
}
bidders := make(map[string]BidHash)
bidders = auctionJSON.PrivateBids
bidders[bidKey] = NewHash
auctionJSON.PrivateBids = bidders
// Add the bid to the list of bidding organizations if it is not already
Orgs := auctionJSON.BiddingOrgs
if !(contains(Orgs, clientOrgID)) {
newOrgs := append(Orgs, clientOrgID)
auctionJSON.BiddingOrgs = newOrgs
err = addAssetStateBasedEndorsement(ctx, auctionID, clientOrgID)
if err != nil {
return fmt.Errorf("failed setting state based endorsement for new organization: %v", err)
}
}
newAuctionBytes, _ := json.Marshal(auctionJSON)
err = ctx.GetStub().PutState(auctionID, newAuctionBytes)
if err != nil {
return fmt.Errorf("failed to update auction: %v", err)
}
return nil
}
// RevealBid is used by a bidder to reveal their bid after the auction is closed
func (s *SmartContract) RevealBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) error {
// get bid from transient map
transientMap, err := ctx.GetStub().GetTransient()
if err != nil {
return fmt.Errorf("error getting transient: %v", err)
}
transientBidJSON, ok := transientMap["bid"]
if !ok {
return fmt.Errorf("bid key not found in the transient map")
}
// get implicit collection name of organization ID
collection, err := getCollectionName(ctx)
if err != nil {
return fmt.Errorf("failed to get implicit collection name: %v", err)
}
// use transaction ID to create composit bid key
bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID})
if err != nil {
return fmt.Errorf("failed to create composite key: %v", err)
}
// get bid hash of bid if private bid on the public ledger
bidHash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey)
if err != nil {
return fmt.Errorf("failed to read bid bash from collection: %v", err)
}
if bidHash == nil {
return fmt.Errorf("bid hash does not exist: %s", bidKey)
}
// get auction from public state
auctionBytes, err := ctx.GetStub().GetState(auctionID)
if err != nil {
return fmt.Errorf("failed to get auction %v: %v", auctionID, err)
}
if auctionBytes == nil {
return fmt.Errorf("Auction interest object %v not found", auctionID)
}
var auctionJSON Auction
err = json.Unmarshal(auctionBytes, &auctionJSON)
if err != nil {
return fmt.Errorf("failed to create interst object JSON: %v", err)
}
// Complete a series of three checks before we add the bid to the auction
// check 1: check that the auction is closed. We cannot reveal an
// bid to an open auction
Status := auctionJSON.Status
if Status != "closed" {
return fmt.Errorf("cannot reveal bid for open or ended auction")
}
// check 2: check that hash of revealed bid matches hash of private bid
// on the public ledger. This checks that the bidder is telling the truth
// about the value of their bid
hash := sha256.New()
hash.Write(transientBidJSON)
calculatedBidJSONHash := hash.Sum(nil)
// verify that the hash of the passed immutable properties matches the on-chain hash
if !bytes.Equal(calculatedBidJSONHash, bidHash) {
return fmt.Errorf("hash %x for bid JSON %s does not match hash in auction: %x",
calculatedBidJSONHash,
transientBidJSON,
bidHash,
)
}
// check 3; check hash of relealed bid matches hash of private bid that was
// added to the earlier bid. This ensures that the bid has not changed since it
// was added ot the auction
bidders := auctionJSON.PrivateBids
privateBidHashString := bidders[bidKey].Hash
onChainBidHashString := fmt.Sprintf("%x", bidHash)
if privateBidHashString != onChainBidHashString {
return fmt.Errorf("hash %s for bid JSON %s does not match hash in auction: %s, bidder must have changed bid",
privateBidHashString,
transientBidJSON,
onChainBidHashString,
)
}
// we can add the bid to the auction if all checks have passed
type transientBidInput struct {
Quantity int `json:"quantity"`
Price int `json:"price"`
Org string `json:"org"`
Buyer string `json:"buyer"`
}
// unmarshal bid imput
var bidInput transientBidInput
err = json.Unmarshal(transientBidJSON, &bidInput)
if err != nil {
return fmt.Errorf("failed to unmarshal JSON: %v", err)
}
// Get ID of submitting client identity
clientID, err := ctx.GetClientIdentity().GetID()
if err != nil {
return fmt.Errorf("failed to get client identity %v", err)
}
// marshal transient paramters and ID and MSPID into bid object
NewBid := FullBid{
Type: bidKeyType,
Quantity: bidInput.Quantity,
Price: bidInput.Price,
Org: bidInput.Org,
Buyer: bidInput.Buyer,
}
// check 4: make sure that the bid is being revealed by the buyer
if bidInput.Buyer != clientID {
return fmt.Errorf("Permission denied, client id %v is not the owner of the bid", clientID)
}
revealedBids := make(map[string]FullBid)
revealedBids = auctionJSON.RevealedBids
revealedBids[bidKey] = NewBid
auctionJSON.RevealedBids = revealedBids
newAuctionBytes, _ := json.Marshal(auctionJSON)
// put auction with bid added back into state
err = ctx.GetStub().PutState(auctionID, newAuctionBytes)
if err != nil {
return fmt.Errorf("failed to update auction: %v", err)
}
return nil
}
// CloseAuction can be used by the seller to close the auction. This prevents
// bids from being added to the auction, and allows users to reveal their bid
func (s *SmartContract) CloseAuction(ctx contractapi.TransactionContextInterface, auctionID string) error {
auctionBytes, err := ctx.GetStub().GetState(auctionID)
if err != nil {
return fmt.Errorf("failed to get auction %v: %v", auctionID, err)
}
if auctionBytes == nil {
return fmt.Errorf("Auction interest object %v not found", auctionID)
}
var auctionJSON Auction
err = json.Unmarshal(auctionBytes, &auctionJSON)
if err != nil {
return fmt.Errorf("failed to create interst object JSON: %v", err)
}
// the auction can only be closed by the seller
// get ID of submitting client
clientID, err := ctx.GetClientIdentity().GetID()
if err != nil {
return fmt.Errorf("failed to get client identity %v", err)
}
Seller := auctionJSON.Seller
if Seller != clientID {
return fmt.Errorf("auction can only be closed by seller: %v", err)
}
Status := auctionJSON.Status
if Status != "open" {
return fmt.Errorf("cannot close auction that is not open")
}
auctionJSON.Status = string("closed")
closedAuction, _ := json.Marshal(auctionJSON)
err = ctx.GetStub().PutState(auctionID, closedAuction)
if err != nil {
return fmt.Errorf("failed to close auction: %v", err)
}
return nil
}
// EndAuction both changes the auction status to closed and calculates the winners
// of the auction
func (s *SmartContract) EndAuction(ctx contractapi.TransactionContextInterface, auctionID string) error {
auctionBytes, err := ctx.GetStub().GetState(auctionID)
if err != nil {
return fmt.Errorf("failed to get auction %v: %v", auctionID, err)
}
if auctionBytes == nil {
return fmt.Errorf("Auction interest object %v not found", auctionID)
}
var auctionJSON Auction
err = json.Unmarshal(auctionBytes, &auctionJSON)
if err != nil {
return fmt.Errorf("failed to create interst object JSON: %v", err)
}
// Check that the auction is being ended by the seller
// get ID of submitting client
clientID, err := ctx.GetClientIdentity().GetID()
if err != nil {
return fmt.Errorf("failed to get client identity %v", err)
}
Seller := auctionJSON.Seller
if Seller != clientID {
return fmt.Errorf("auction can only be ended by seller: %v", err)
}
Status := auctionJSON.Status
if Status != "closed" {
return fmt.Errorf("Can only end a closed auction")
}
// get the list of revealed bids
revealedBidMap := auctionJSON.RevealedBids
if len(auctionJSON.RevealedBids) == 0 {
return fmt.Errorf("No bids have been revealed, cannot end auction: %v", err)
}
// sort the map of revealed bids to make it easier to calculate winners
var Bidders []FullBid
for _, bid := range revealedBidMap {
Bidders = append(Bidders, bid)
}
sort.Slice(Bidders, func(p, q int) bool {
return Bidders[p].Price > Bidders[q].Price
})
i := 0
remainingQuantity := auctionJSON.Quantity
// calculate the winners
for remainingQuantity > 0 {
// create the next winning bid
winner := Winners{
Buyer: Bidders[i].Buyer,
Quantity: Bidders[i].Quantity,
}
// add them to the list of winners and change the winning price
auctionJSON.Winners = append(auctionJSON.Winners, winner)
auctionJSON.Price = Bidders[i].Price
// Calculate the quantity that goes to the winner
// if there is sufficient quantity to give them the full bid
if remainingQuantity > Bidders[i].Quantity {
remainingQuantity = remainingQuantity - Bidders[i].Quantity
// if there is not, give the remainder
} else {
auctionJSON.Winners[i].Quantity = remainingQuantity
remainingQuantity = 0
}
i++
}
// check if there is a winning bid that has yet to be revealed
err = queryAllBids(ctx, auctionJSON.Price, auctionJSON.RevealedBids, auctionJSON.PrivateBids)
if err != nil {
return fmt.Errorf("Cannot close auction: %v", err)
}
auctionJSON.Status = string("ended")
closedAuction, _ := json.Marshal(auctionJSON)
err = ctx.GetStub().PutState(auctionID, closedAuction)
if err != nil {
return fmt.Errorf("failed to close auction: %v", err)
}
return nil
}

View file

@ -0,0 +1,148 @@
/*
SPDX-License-Identifier: Apache-2.0
*/
package auction
import (
"encoding/json"
"fmt"
"github.com/hyperledger/fabric-chaincode-go/shim"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
// QueryAuction allows all members of the channel to read a public auction
func (s *SmartContract) QueryAuction(ctx contractapi.TransactionContextInterface, auctionID string) (*Auction, error) {
auctionJSON, err := ctx.GetStub().GetState(auctionID)
if err != nil {
return nil, fmt.Errorf("failed to get auction object %v: %v", auctionID, err)
}
if auctionJSON == nil {
return nil, fmt.Errorf("auction does not exist")
}
var auction *Auction
err = json.Unmarshal(auctionJSON, &auction)
if err != nil {
return nil, err
}
return auction, nil
}
// QueryBid allows the submitter of the bid to read their bid from public state
func (s *SmartContract) QueryBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) (*FullBid, error) {
err := verifyClientOrgMatchesPeerOrg(ctx)
if err != nil {
return nil, fmt.Errorf("failed to get implicit collection name: %v", err)
}
clientID, err := ctx.GetClientIdentity().GetID()
if err != nil {
return nil, fmt.Errorf("failed to get client identity %v", err)
}
collection, err := getCollectionName(ctx)
if err != nil {
return nil, fmt.Errorf("failed to get implicit collection name: %v", err)
}
bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID})
if err != nil {
return nil, fmt.Errorf("failed to create composite key: %v", err)
}
bidJSON, err := ctx.GetStub().GetPrivateData(collection, bidKey)
if err != nil {
return nil, fmt.Errorf("failed to get bid %v: %v", bidKey, err)
}
if bidJSON == nil {
return nil, fmt.Errorf("bid %v does not exist", bidKey)
}
var bid *FullBid
err = json.Unmarshal(bidJSON, &bid)
if err != nil {
return nil, err
}
// check that the client querying the bid is the bid owner
if bid.Buyer != clientID {
return nil, fmt.Errorf("Permission denied, client id %v is not the owner of the bid", clientID)
}
return bid, nil
}
// GetID is an internal helper function to allow users to get their identity
func (s *SmartContract) GetID(ctx contractapi.TransactionContextInterface) (string, error) {
// Get the MSP ID of submitting client identity
clientID, err := ctx.GetClientIdentity().GetID()
if err != nil {
return "", fmt.Errorf("failed to get verified MSPID: %v", err)
}
return clientID, nil
}
// queryAllBids is an internal function that is used to deterimine if a winning bid has yet to be revealed
func queryAllBids(ctx contractapi.TransactionContextInterface, auctionPrice int, revealedBidders map[string]FullBid, bidders map[string]BidHash) error {
// Get MSP ID of peer org
peerMSPID, err := shim.GetMSPID()
if err != nil {
return fmt.Errorf("failed getting the peer's MSPID: %v", err)
}
var error error
error = nil
for bidKey, privateBid := range bidders {
if _, bidInAuction := revealedBidders[bidKey]; bidInAuction {
//bid is already revealed, no action to take
} else {
collection := "_implicit_org_" + privateBid.Org
if privateBid.Org == peerMSPID {
bidJSON, err := ctx.GetStub().GetPrivateData(collection, bidKey)
if err != nil {
return fmt.Errorf("failed to get bid %v: %v", bidKey, err)
}
if bidJSON == nil {
return fmt.Errorf("bid %v does not exist", bidKey)
}
var bid *FullBid
err = json.Unmarshal(bidJSON, &bid)
if err != nil {
return err
}
if bid.Price > auctionPrice {
error = fmt.Errorf("Cannot close auction, bidder has a higher price: %v", err)
}
} else {
Hash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey)
if err != nil {
return fmt.Errorf("failed to read bid bash from collection: %v", err)
}
if Hash == nil {
return fmt.Errorf("bid hash does not exist: %s", bidKey)
}
}
}
}
return error
}

View file

@ -0,0 +1,108 @@
/*
SPDX-License-Identifier: Apache-2.0
*/
package auction
import (
"fmt"
"github.com/hyperledger/fabric-chaincode-go/pkg/statebased"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
"github.com/hyperledger/fabric-chaincode-go/shim"
)
// setAssetStateBasedEndorsement sets the endorsement policy of a new auction
func setAssetStateBasedEndorsement(ctx contractapi.TransactionContextInterface, auctionID string, orgToEndorse string) error {
endorsementPolicy, err := statebased.NewStateEP(nil)
if err != nil {
return err
}
err = endorsementPolicy.AddOrgs(statebased.RoleTypePeer, orgToEndorse)
if err != nil {
return fmt.Errorf("failed to add org to endorsement policy: %v", err)
}
policy, err := endorsementPolicy.Policy()
if err != nil {
return fmt.Errorf("failed to create endorsement policy bytes from org: %v", err)
}
err = ctx.GetStub().SetStateValidationParameter(auctionID, policy)
if err != nil {
return fmt.Errorf("failed to set validation parameter on auction: %v", err)
}
return nil
}
// addAssetStateBasedEndorsement adds a new organization as an endorser of the auction
func addAssetStateBasedEndorsement(ctx contractapi.TransactionContextInterface, auctionID string, orgToEndorse string) error {
endorsementPolicy, err := ctx.GetStub().GetStateValidationParameter(auctionID)
if err != nil {
return err
}
newEndorsementPolicy, err := statebased.NewStateEP(endorsementPolicy)
if err != nil {
return err
}
err = newEndorsementPolicy.AddOrgs(statebased.RoleTypePeer, orgToEndorse)
if err != nil {
return fmt.Errorf("failed to add org to endorsement policy: %v", err)
}
policy, err := newEndorsementPolicy.Policy()
if err != nil {
return fmt.Errorf("failed to create endorsement policy bytes from org: %v", err)
}
err = ctx.GetStub().SetStateValidationParameter(auctionID, policy)
if err != nil {
return fmt.Errorf("failed to set validation parameter on auction: %v", err)
}
return nil
}
// getCollectionName is an internal helper function to get collection of submitting client identity.
func getCollectionName(ctx contractapi.TransactionContextInterface) (string, error) {
// Get the MSP ID of submitting client identity
clientMSPID, err := ctx.GetClientIdentity().GetMSPID()
if err != nil {
return "", fmt.Errorf("failed to get verified MSPID: %v", err)
}
// Create the collection name
orgCollection := "_implicit_org_" + clientMSPID
return orgCollection, nil
}
// verifyClientOrgMatchesPeerOrg is an internal function used verify client org id and matches peer org id.
func verifyClientOrgMatchesPeerOrg(ctx contractapi.TransactionContextInterface) error {
clientMSPID, err := ctx.GetClientIdentity().GetMSPID()
if err != nil {
return fmt.Errorf("failed getting the client's MSPID: %v", err)
}
peerMSPID, err := shim.GetMSPID()
if err != nil {
return fmt.Errorf("failed getting the peer's MSPID: %v", err)
}
if clientMSPID != peerMSPID {
return fmt.Errorf("client from org %v is not authorized to read or write private data from an org %v peer", clientMSPID, peerMSPID)
}
return nil
}
func contains(sli []string, str string) bool {
for _, a := range sli {
if a == str {
return true
}
}
return false
}

View file

@ -0,0 +1,23 @@
/*
SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"log"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
"github.com/hyperledger/fabric-samples/auction/chaincode-go/smart-contract"
)
func main() {
auctionSmartContract, err := contractapi.NewChaincode(&auction.SmartContract{})
if err != nil {
log.Panicf("Error creating auction chaincode: %v", err)
}
if err := auctionSmartContract.Start(); err != nil {
log.Panicf("Error starting auction chaincode: %v", err)
}
}