[FAB-17140] Add go commercial paper contract (#102)

Signed-off-by: Andrew Hurt <andrew.hurt1@ibm.com>
This commit is contained in:
Andrew Hurt 2020-01-24 14:12:30 +00:00 committed by Matthew B White
parent 4fe6a2507e
commit 5b93dd0cc0
38 changed files with 2418 additions and 27 deletions

View file

@ -74,4 +74,14 @@ jobs:
steps:
- template: install-deps.yml
- template: install-fabric.yml
- template: commercialpaper-java.yml
- template: commercialpaper-java.yml
- job: commercialpaper_go
displayName: CommercialPaper (Go)
pool:
vmImage: ubuntu-18.04
dependsOn: []
timeoutInMinutes: 60
steps:
- template: install-deps.yml
- template: install-fabric.yml
- template: commercialpaper-go.yml

50
ci/commercialpaper-go.yml Normal file
View file

@ -0,0 +1,50 @@
#
# SPDX-License-Identifier: Apache-2.0
#
steps:
- script: go test ./...
workingDirectory: commercial-paper/organization/magnetocorp/contract-go
displayName: Go unit test magnetocorp
- script: go test ./...
workingDirectory: commercial-paper/organization/digibank/contract-go
displayName: Go unit test digibank
- script: bash start.sh
workingDirectory: basic-network
displayName: Start Fabric
- script: |
docker-compose -f docker-compose.yml up -d cliMagnetoCorp
docker exec cliMagnetoCorp bash -c 'cd /opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-go && go mod vendor'
docker exec cliMagnetoCorp peer lifecycle chaincode package cp.tar.gz --lang golang --path github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-go --label cp_0
docker exec cliMagnetoCorp peer lifecycle chaincode install cp.tar.gz
export PACKAGE_ID=$(docker exec cliMagnetoCorp peer lifecycle chaincode queryinstalled 2>&1 | awk -F "[, ]+" '/Label: /{print $3}')
docker exec cliMagnetoCorp peer lifecycle chaincode approveformyorg --channelID mychannel --name papercontract -v 0 --package-id $PACKAGE_ID --sequence 1 --signature-policy "AND ('Org1MSP.member')"
docker exec cliMagnetoCorp peer lifecycle chaincode commit -o orderer.example.com:7050 --channelID mychannel --name papercontract -v 0 --sequence 1 --waitForEvent --signature-policy "AND ('Org1MSP.member')"
docker exec cliMagnetoCorp peer chaincode invoke -o orderer.example.com:7050 --channelID mychannel --name papercontract -c '{"Args":["org.papernet.commercialpaper:instantiate"]}' --waitForEvent
workingDirectory: commercial-paper/organization/magnetocorp/configuration/cli
displayName: Setup Commercial Paper contract
- script: retry -- npm install
workingDirectory: commercial-paper/organization/magnetocorp/application
displayName: Install Magnetocorp application
- script: |
set -ex
node addToWallet.js
node issue.js
workingDirectory: commercial-paper/organization/magnetocorp/application
displayName: Magnetocorp issue paper
- script: retry -- npm install
workingDirectory: commercial-paper/organization/digibank/application
displayName: Install Digibank application
- script: |
set -ex
node addToWallet.js
node buy.js
node redeem.js
workingDirectory: commercial-paper/organization/digibank/application
displayName: Digibank issue paper

View file

@ -13,7 +13,7 @@ steps:
- script: |
docker-compose -f docker-compose.yml up -d cliDigiBank
docker exec cliDigiBank peer lifecycle chaincode package cp.tar.gz --lang java --path /opt/gopath/src/github.com/contract-java/build/libs --label cp_0
docker exec cliDigiBank peer lifecycle chaincode package cp.tar.gz --lang java --path /opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/digibank/contract-java/build/libs --label cp_0
docker exec cliDigiBank peer lifecycle chaincode install cp.tar.gz
export PACKAGE_ID=$(docker exec cliDigiBank peer lifecycle chaincode queryinstalled 2>&1 | awk -F "[, ]+" '/Label: /{print $3}')

View file

@ -9,7 +9,7 @@ steps:
- script: |
docker-compose -f docker-compose.yml up -d cliMagnetoCorp
docker exec cliMagnetoCorp peer lifecycle chaincode package cp.tar.gz --lang node --path /opt/gopath/src/github.com/contract --label cp_0
docker exec cliMagnetoCorp peer lifecycle chaincode package cp.tar.gz --lang node --path /opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract --label cp_0
docker exec cliMagnetoCorp peer lifecycle chaincode install cp.tar.gz
export PACKAGE_ID=$(docker exec cliMagnetoCorp peer lifecycle chaincode queryinstalled 2>&1 | awk -F "[, ]+" '/Label: /{print $3}')

View file

@ -68,7 +68,7 @@ This will start a docker container for Fabric CLI commands, and put you in the c
**For a JavaScript Contract:**
```
docker exec cliMagnetoCorp peer lifecycle chaincode package cp.tar.gz --lang node --path /opt/gopath/src/github.com/contract --label cp_0
docker exec cliMagnetoCorp peer lifecycle chaincode package cp.tar.gz --lang node --path /opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract --label cp_0
docker exec cliMagnetoCorp peer lifecycle chaincode install cp.tar.gz
export PACKAGE_ID=$(docker exec cliMagnetoCorp peer lifecycle chaincode queryinstalled 2>&1 | awk -F "[, ]+" '/Label: /{print $3}')
@ -87,13 +87,26 @@ pushd ./organization/magnetocorp/contract-java
popd
docker exec cliMagnetoCorp peer chaincode install -n papercontract -v 0 -p /opt/gopath/src/github.com/contract-java/build/install/papercontract -l java
docker exec cliMagnetoCorp peer chaincode install -n papercontract -v 0 -p /opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-java/build/install/papercontract -l java
docker exec cliMagnetoCorp peer chaincode instantiate -n papercontract -v 0 -l java -c '{"Args":["org.papernet.commercialpaper:instantiate"]}' -C mychannel -P "AND ('Org1MSP.member')"
```
> If you want to try both a Java and JavaScript Contract, then you will need to restart the infrastructure and deploy the other contract.
**For a Go Contract:**
```
docker exec cliMagnetoCorp bash -c 'cd /opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-go && go mod vendor'
docker exec cliMagnetoCorp peer lifecycle chaincode package cp.tar.gz --lang golang --path github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-go --label cp_0
docker exec cliMagnetoCorp peer lifecycle chaincode install cp.tar.gz
export PACKAGE_ID=$(docker exec cliMagnetoCorp peer lifecycle chaincode queryinstalled 2>&1 | awk -F "[, ]+" '/Label: /{print $3}')
docker exec cliMagnetoCorp peer lifecycle chaincode approveformyorg --channelID mychannel --name papercontract -v 0 --package-id $PACKAGE_ID --sequence 1 --signature-policy "AND ('Org1MSP.member')"
docker exec cliMagnetoCorp peer lifecycle chaincode commit -o orderer.example.com:7050 --channelID mychannel --name papercontract -v 0 --sequence 1 --waitForEvent --signature-policy "AND ('Org1MSP.member')"
docker exec cliMagnetoCorp peer chaincode invoke -o orderer.example.com:7050 --channelID mychannel --name papercontract -c '{"Args":["org.papernet.commercialpaper:instantiate"]}' --waitForEvent
```
## Client Applications
Note for Java applications you will need to compile the Java Code using maven. Use this command in each application-java directory

View file

@ -25,7 +25,7 @@ docker ps
# cd "${DIR}/commercial-paper/organization/magnetocorp/configuration/cli"
# docker-compose -f docker-compose.yml up -d cliMagnetoCorp
# docker exec cliMagnetoCorp peer lifecycle chaincode package cp.tar.gz --lang node --path /opt/gopath/src/github.com/contract --label cp_0
# docker exec cliMagnetoCorp peer lifecycle chaincode package cp.tar.gz --lang node --path /opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract --label cp_0
# docker exec cliMagnetoCorp peer lifecycle chaincode install cp.tar.gz
# export PACKAGE_ID=$(docker exec cliMagnetoCorp peer lifecycle chaincode queryinstalled 2>&1 | awk -F "[, ]+" '/Label: /{print $3}')
@ -37,7 +37,7 @@ docker ps
cd "${DIR}/commercial-paper/organization/digibank/configuration/cli"
docker-compose -f docker-compose.yml up -d cliDigiBank
CLI_CONTAINER=cliDigiBank
docker exec ${CLI_CONTAINER} peer lifecycle chaincode package cp.tar.gz --lang java --path /opt/gopath/src/github.com/contract-java/build/libs --label cp_0
docker exec ${CLI_CONTAINER} peer lifecycle chaincode package cp.tar.gz --lang java --path /opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-java/build/libs --label cp_0
docker exec ${CLI_CONTAINER} peer lifecycle chaincode install cp.tar.gz
export PACKAGE_ID=$(docker exec ${CLI_CONTAINER} peer lifecycle chaincode queryinstalled 2>&1 | awk -F "[, ]+" '/Label: /{print $3}')

View file

@ -44,9 +44,9 @@
"integrity": "sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q=="
},
"@types/node": {
"version": "13.1.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.4.tgz",
"integrity": "sha512-Lue/mlp2egZJoHXZr4LndxDAd7i/7SQYhV0EjWfb/a4/OZ6tuVwMCVPiwkU5nsEipxEf7hmkSU7Em5VQ8P5NGA=="
"version": "13.1.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.7.tgz",
"integrity": "sha512-HU0q9GXazqiKwviVxg9SI/+t/nAsGkvLDkIdxz+ObejG2nX6Si00TeLqHMoS+a/1tjH7a8YpKVQwtgHuMQsldg=="
},
"@types/request": {
"version": "2.48.4",
@ -171,9 +171,9 @@
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
},
"aws4": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz",
"integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A=="
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
"integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug=="
},
"balanced-match": {
"version": "1.0.0",

View file

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

View file

@ -28,7 +28,7 @@ services:
command: /bin/bash
volumes:
- /var/run/:/host/var/run/
- ./../../../../organization/digibank:/opt/gopath/src/github.com/
- ./../../../../organization/digibank:/opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/digibank
- ./../../../../../basic-network/crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
networks:
- basic

View file

@ -0,0 +1,139 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package commercialpaper
import (
"encoding/json"
"fmt"
ledgerapi "github.com/hyperledger/fabric-samples/commercial-paper/organization/digibank/contract-go/ledger-api"
)
// State enum for commercial paper state property
type State uint
const (
// ISSUED state for when a paper has been issued
ISSUED State = iota + 1
// TRADING state for when a paper is trading
TRADING
// REDEEMED state for when a paper has been redeemed
REDEEMED
)
func (state State) String() string {
names := []string{"ISSUED", "TRADING", "REDEEMED"}
if state < ISSUED || state > REDEEMED {
return "UNKNOWN"
}
return names[state-1]
}
// CreateCommercialPaperKey creates a key for commercial papers
func CreateCommercialPaperKey(issuer string, paperNumber string) string {
return ledgerapi.MakeKey(issuer, paperNumber)
}
// Used for managing the fact status is private but want it in world state
type commercialPaperAlias CommercialPaper
type jsonCommercialPaper struct {
*commercialPaperAlias
State State `json:"currentState"`
Class string `json:"class"`
Key string `json:"key"`
}
// CommercialPaper defines a commercial paper
type CommercialPaper struct {
PaperNumber string `json:"paperNumber"`
Issuer string `json:"issuer"`
IssueDateTime string `json:"issueDateTime"`
FaceValue int `json:"faceValue"`
MaturityDateTime string `json:"maturityDateTime"`
Owner string `json:"owner"`
state State `metadata:"currentState"`
class string `metadata:"class"`
key string `metadata:"key"`
}
// UnmarshalJSON special handler for managing JSON marshalling
func (cp *CommercialPaper) UnmarshalJSON(data []byte) error {
jcp := jsonCommercialPaper{commercialPaperAlias: (*commercialPaperAlias)(cp)}
err := json.Unmarshal(data, &jcp)
if err != nil {
return err
}
cp.state = jcp.State
return nil
}
// MarshalJSON special handler for managing JSON marshalling
func (cp CommercialPaper) MarshalJSON() ([]byte, error) {
jcp := jsonCommercialPaper{commercialPaperAlias: (*commercialPaperAlias)(&cp), State: cp.state, Class: "org.papernet.commercialpaper", Key: ledgerapi.MakeKey(cp.Issuer, cp.PaperNumber)}
return json.Marshal(&jcp)
}
// GetState returns the state
func (cp *CommercialPaper) GetState() State {
return cp.state
}
// SetIssued returns the state to issued
func (cp *CommercialPaper) SetIssued() {
cp.state = ISSUED
}
// SetTrading sets the state to trading
func (cp *CommercialPaper) SetTrading() {
cp.state = TRADING
}
// SetRedeemed sets the state to redeemed
func (cp *CommercialPaper) SetRedeemed() {
cp.state = REDEEMED
}
// IsIssued returns true if state is issued
func (cp *CommercialPaper) IsIssued() bool {
return cp.state == ISSUED
}
// IsTrading returns true if state is trading
func (cp *CommercialPaper) IsTrading() bool {
return cp.state == TRADING
}
// IsRedeemed returns true if state is redeemed
func (cp *CommercialPaper) IsRedeemed() bool {
return cp.state == REDEEMED
}
// GetSplitKey returns values which should be used to form key
func (cp *CommercialPaper) GetSplitKey() []string {
return []string{cp.Issuer, cp.PaperNumber}
}
// Serialize formats the commercial paper as JSON bytes
func (cp *CommercialPaper) Serialize() ([]byte, error) {
return json.Marshal(cp)
}
// Deserialize formats the commercial paper from JSON bytes
func Deserialize(bytes []byte, cp *CommercialPaper) error {
err := json.Unmarshal(bytes, cp)
if err != nil {
return fmt.Errorf("Error deserializing commercial paper. %s", err.Error())
}
return nil
}

View file

@ -0,0 +1,125 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package commercialpaper
import (
"testing"
ledgerapi "github.com/hyperledger/fabric-samples/commercial-paper/organization/digibank/contract-go/ledger-api"
"github.com/stretchr/testify/assert"
)
func TestString(t *testing.T) {
assert.Equal(t, "ISSUED", ISSUED.String(), "should return string for issued")
assert.Equal(t, "TRADING", TRADING.String(), "should return string for issued")
assert.Equal(t, "REDEEMED", REDEEMED.String(), "should return string for issued")
assert.Equal(t, "UNKNOWN", State(REDEEMED+1).String(), "should return unknown when not one of constants")
}
func TestCreateCommercialPaperKey(t *testing.T) {
assert.Equal(t, ledgerapi.MakeKey("someissuer", "somepaper"), CreateCommercialPaperKey("someissuer", "somepaper"), "should return key comprised of passed values")
}
func TestGetState(t *testing.T) {
cp := new(CommercialPaper)
cp.state = ISSUED
assert.Equal(t, ISSUED, cp.GetState(), "should return set state")
}
func TestSetIssued(t *testing.T) {
cp := new(CommercialPaper)
cp.SetIssued()
assert.Equal(t, ISSUED, cp.state, "should set state to trading")
}
func TestSetTrading(t *testing.T) {
cp := new(CommercialPaper)
cp.SetTrading()
assert.Equal(t, TRADING, cp.state, "should set state to trading")
}
func TestSetRedeemed(t *testing.T) {
cp := new(CommercialPaper)
cp.SetRedeemed()
assert.Equal(t, REDEEMED, cp.state, "should set state to trading")
}
func TestIsIssued(t *testing.T) {
cp := new(CommercialPaper)
cp.SetIssued()
assert.True(t, cp.IsIssued(), "should be true when status set to issued")
cp.SetTrading()
assert.False(t, cp.IsIssued(), "should be false when status not set to issued")
}
func TestIsTrading(t *testing.T) {
cp := new(CommercialPaper)
cp.SetTrading()
assert.True(t, cp.IsTrading(), "should be true when status set to trading")
cp.SetRedeemed()
assert.False(t, cp.IsTrading(), "should be false when status not set to trading")
}
func TestIsRedeemed(t *testing.T) {
cp := new(CommercialPaper)
cp.SetRedeemed()
assert.True(t, cp.IsRedeemed(), "should be true when status set to redeemed")
cp.SetIssued()
assert.False(t, cp.IsRedeemed(), "should be false when status not set to redeemed")
}
func TestGetSplitKey(t *testing.T) {
cp := new(CommercialPaper)
cp.PaperNumber = "somepaper"
cp.Issuer = "someissuer"
assert.Equal(t, []string{"someissuer", "somepaper"}, cp.GetSplitKey(), "should return issuer and paper number as split key")
}
func TestSerialize(t *testing.T) {
cp := new(CommercialPaper)
cp.PaperNumber = "somepaper"
cp.Issuer = "someissuer"
cp.IssueDateTime = "sometime"
cp.FaceValue = 1000
cp.MaturityDateTime = "somelatertime"
cp.Owner = "someowner"
cp.state = TRADING
bytes, err := cp.Serialize()
assert.Nil(t, err, "should not error on serialize")
assert.Equal(t, `{"paperNumber":"somepaper","issuer":"someissuer","issueDateTime":"sometime","faceValue":1000,"maturityDateTime":"somelatertime","owner":"someowner","currentState":2,"class":"org.papernet.commercialpaper","key":"someissuer:somepaper"}`, string(bytes), "should return JSON formatted value")
}
func TestDeserialize(t *testing.T) {
var cp *CommercialPaper
var err error
goodJSON := `{"paperNumber":"somepaper","issuer":"someissuer","issueDateTime":"sometime","faceValue":1000,"maturityDateTime":"somelatertime","owner":"someowner","currentState":2,"class":"org.papernet.commercialpaper","key":"someissuer:somepaper"}`
expectedCp := new(CommercialPaper)
expectedCp.PaperNumber = "somepaper"
expectedCp.Issuer = "someissuer"
expectedCp.IssueDateTime = "sometime"
expectedCp.FaceValue = 1000
expectedCp.MaturityDateTime = "somelatertime"
expectedCp.Owner = "someowner"
expectedCp.state = TRADING
cp = new(CommercialPaper)
err = Deserialize([]byte(goodJSON), cp)
assert.Nil(t, err, "should not return error for deserialize")
assert.Equal(t, expectedCp, cp, "should create expected commercial paper")
badJSON := `{"paperNumber":"somepaper","issuer":"someissuer","issueDateTime":"sometime","faceValue":"NaN","maturityDateTime":"somelatertime","owner":"someowner","currentState":2,"class":"org.papernet.commercialpaper","key":"someissuer:somepaper"}`
cp = new(CommercialPaper)
err = Deserialize([]byte(badJSON), cp)
assert.EqualError(t, err, "Error deserializing commercial paper. json: cannot unmarshal string into Go struct field jsonCommercialPaper.faceValue of type int", "should return error for bad data")
}

View file

@ -0,0 +1,35 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package commercialpaper
import (
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
// TransactionContextInterface an interface to
// describe the minimum required functions for
// a transaction context in the commercial
// paper
type TransactionContextInterface interface {
contractapi.TransactionContextInterface
GetPaperList() ListInterface
}
// TransactionContext implementation of
// TransactionContextInterface for use with
// commercial paper contract
type TransactionContext struct {
contractapi.TransactionContext
paperList *list
}
// GetPaperList return paper list
func (tc *TransactionContext) GetPaperList() ListInterface {
if tc.paperList == nil {
tc.paperList = newList(tc)
}
return tc.paperList
}

View file

@ -0,0 +1,31 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package commercialpaper
import (
"testing"
ledgerapi "github.com/hyperledger/fabric-samples/commercial-paper/organization/digibank/contract-go/ledger-api"
"github.com/stretchr/testify/assert"
)
func TestGetPaperList(t *testing.T) {
var tc *TransactionContext
var expectedPaperList *list
tc = new(TransactionContext)
expectedPaperList = newList(tc)
actualList := tc.GetPaperList().(*list)
assert.Equal(t, expectedPaperList.stateList.(*ledgerapi.StateList).Name, actualList.stateList.(*ledgerapi.StateList).Name, "should configure paper list when one not already configured")
tc = new(TransactionContext)
expectedPaperList = new(list)
expectedStateList := new(ledgerapi.StateList)
expectedStateList.Ctx = tc
expectedStateList.Name = "existing paper list"
expectedPaperList.stateList = expectedStateList
tc.paperList = expectedPaperList
assert.Equal(t, expectedPaperList, tc.GetPaperList(), "should return set paper list when already set")
}

View file

@ -0,0 +1,96 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package commercialpaper
import (
"fmt"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
// Contract chaincode that defines
// the business logic for managing commercial
// paper
type Contract struct {
contractapi.Contract
}
// Instantiate does nothing
func (c *Contract) Instantiate() {
fmt.Println("Instantiated")
}
// Issue creates a new commercial paper and stores it in the world state
func (c *Contract) Issue(ctx TransactionContextInterface, issuer string, paperNumber string, issueDateTime string, maturityDateTime string, faceValue int) (*CommercialPaper, error) {
paper := CommercialPaper{PaperNumber: paperNumber, Issuer: issuer, IssueDateTime: issueDateTime, FaceValue: faceValue, MaturityDateTime: maturityDateTime, Owner: issuer}
paper.SetIssued()
err := ctx.GetPaperList().AddPaper(&paper)
if err != nil {
return nil, err
}
return &paper, nil
}
// Buy updates a commercial paper to be in trading status and sets the new owner
func (c *Contract) Buy(ctx TransactionContextInterface, issuer string, paperNumber string, currentOwner string, newOwner string, price int, purchaseDateTime string) (*CommercialPaper, error) {
paper, err := ctx.GetPaperList().GetPaper(issuer, paperNumber)
if err != nil {
return nil, err
}
if paper.Owner != currentOwner {
return nil, fmt.Errorf("Paper %s:%s is not owned by %s", issuer, paperNumber, currentOwner)
}
if paper.IsIssued() {
paper.SetTrading()
}
if !paper.IsTrading() {
return nil, fmt.Errorf("Paper %s:%s is not trading. Current state = %s", issuer, paperNumber, paper.GetState())
}
paper.Owner = newOwner
err = ctx.GetPaperList().UpdatePaper(paper)
if err != nil {
return nil, err
}
return paper, nil
}
// Redeem updates a commercial paper status to be redeemed
func (c *Contract) Redeem(ctx TransactionContextInterface, issuer string, paperNumber string, redeemingOwner string, redeenDateTime string) (*CommercialPaper, error) {
paper, err := ctx.GetPaperList().GetPaper(issuer, paperNumber)
if err != nil {
return nil, err
}
if paper.Owner != redeemingOwner {
return nil, fmt.Errorf("Paper %s:%s is not owned by %s", issuer, paperNumber, redeemingOwner)
}
if paper.IsRedeemed() {
return nil, fmt.Errorf("Paper %s:%s is already redeemed", issuer, paperNumber)
}
paper.Owner = paper.Issuer
paper.SetRedeemed()
err = ctx.GetPaperList().UpdatePaper(paper)
if err != nil {
return nil, err
}
return paper, nil
}

View file

@ -0,0 +1,185 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package commercialpaper
import (
"errors"
"testing"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
// #########
// HELPERS
// #########
type MockPaperList struct {
mock.Mock
}
func (mpl *MockPaperList) AddPaper(paper *CommercialPaper) error {
args := mpl.Called(paper)
return args.Error(0)
}
func (mpl *MockPaperList) GetPaper(issuer string, papernumber string) (*CommercialPaper, error) {
args := mpl.Called(issuer, papernumber)
return args.Get(0).(*CommercialPaper), args.Error(1)
}
func (mpl *MockPaperList) UpdatePaper(paper *CommercialPaper) error {
args := mpl.Called(paper)
return args.Error(0)
}
type MockTransactionContext struct {
contractapi.TransactionContext
paperList *MockPaperList
}
func (mtc *MockTransactionContext) GetPaperList() ListInterface {
return mtc.paperList
}
func resetPaper(paper *CommercialPaper) {
paper.Owner = "someowner"
paper.SetTrading()
}
// #########
// TESTS
// #########
func TestIssue(t *testing.T) {
var paper *CommercialPaper
var err error
mpl := new(MockPaperList)
ctx := new(MockTransactionContext)
ctx.paperList = mpl
contract := new(Contract)
var sentPaper *CommercialPaper
mpl.On("AddPaper", mock.MatchedBy(func(paper *CommercialPaper) bool { sentPaper = paper; return paper.Issuer == "someissuer" })).Return(nil)
mpl.On("AddPaper", mock.MatchedBy(func(paper *CommercialPaper) bool { sentPaper = paper; return paper.Issuer == "someotherissuer" })).Return(errors.New("AddPaper error"))
expectedPaper := CommercialPaper{PaperNumber: "somepaper", Issuer: "someissuer", IssueDateTime: "someissuedate", FaceValue: 1000, MaturityDateTime: "somematuritydate", Owner: "someissuer", state: 1}
paper, err = contract.Issue(ctx, "someissuer", "somepaper", "someissuedate", "somematuritydate", 1000)
assert.Nil(t, err, "should not error when add paper does not error")
assert.Equal(t, sentPaper, paper, "should send the same paper as it returns to add paper")
assert.Equal(t, expectedPaper, *paper, "should correctly configure paper")
paper, err = contract.Issue(ctx, "someotherissuer", "somepaper", "someissuedate", "somematuritydate", 1000)
assert.EqualError(t, err, "AddPaper error", "should return error when add paper fails")
assert.Nil(t, paper, "should not return paper when fails")
}
func TestBuy(t *testing.T) {
var paper *CommercialPaper
var err error
mpl := new(MockPaperList)
ctx := new(MockTransactionContext)
ctx.paperList = mpl
contract := new(Contract)
wsPaper := new(CommercialPaper)
resetPaper(wsPaper)
var sentPaper *CommercialPaper
var emptyPaper *CommercialPaper
shouldError := false
mpl.On("GetPaper", "someissuer", "somepaper").Return(wsPaper, nil)
mpl.On("GetPaper", "someotherissuer", "someotherpaper").Return(emptyPaper, errors.New("GetPaper error"))
mpl.On("UpdatePaper", mock.MatchedBy(func(paper *CommercialPaper) bool { return shouldError })).Return(errors.New("UpdatePaper error"))
mpl.On("UpdatePaper", mock.MatchedBy(func(paper *CommercialPaper) bool { sentPaper = paper; return !shouldError })).Return(nil)
paper, err = contract.Buy(ctx, "someotherissuer", "someotherpaper", "someowner", "someotherowner", 100, "2019-12-10:10:00")
assert.EqualError(t, err, "GetPaper error", "should return error when GetPaper errors")
assert.Nil(t, paper, "should return nil for paper when GetPaper errors")
paper, err = contract.Buy(ctx, "someissuer", "somepaper", "someotherowner", "someowner", 100, "2019-12-10:10:00")
assert.EqualError(t, err, "Paper someissuer:somepaper is not owned by someotherowner", "should error when sent owner not correct")
assert.Nil(t, paper, "should not return paper for bad owner error")
resetPaper(wsPaper)
wsPaper.SetRedeemed()
paper, err = contract.Buy(ctx, "someissuer", "somepaper", "someowner", "someotherowner", 100, "2019-12-10:10:00")
assert.EqualError(t, err, "Paper someissuer:somepaper is not trading. Current state = REDEEMED")
assert.Nil(t, paper, "should not return paper for bad state error")
resetPaper(wsPaper)
shouldError = true
paper, err = contract.Buy(ctx, "someissuer", "somepaper", "someowner", "someotherowner", 100, "2019-12-10:10:00")
assert.EqualError(t, err, "UpdatePaper error", "should error when update paper fails")
assert.Nil(t, paper, "should not return paper for bad state error")
shouldError = false
resetPaper(wsPaper)
wsPaper.SetIssued()
paper, err = contract.Buy(ctx, "someissuer", "somepaper", "someowner", "someotherowner", 100, "2019-12-10:10:00")
assert.Nil(t, err, "should not error when good paper and owner")
assert.Equal(t, "someotherowner", paper.Owner, "should update the owner of the paper")
assert.True(t, paper.IsTrading(), "should mark issued paper as trading")
assert.Equal(t, sentPaper, paper, "should update same paper as it returns in the world state")
}
func TestRedeem(t *testing.T) {
var paper *CommercialPaper
var err error
mpl := new(MockPaperList)
ctx := new(MockTransactionContext)
ctx.paperList = mpl
contract := new(Contract)
var sentPaper *CommercialPaper
wsPaper := new(CommercialPaper)
resetPaper(wsPaper)
var emptyPaper *CommercialPaper
shouldError := false
mpl.On("GetPaper", "someissuer", "somepaper").Return(wsPaper, nil)
mpl.On("GetPaper", "someotherissuer", "someotherpaper").Return(emptyPaper, errors.New("GetPaper error"))
mpl.On("UpdatePaper", mock.MatchedBy(func(paper *CommercialPaper) bool { return shouldError })).Return(errors.New("UpdatePaper error"))
mpl.On("UpdatePaper", mock.MatchedBy(func(paper *CommercialPaper) bool { sentPaper = paper; return !shouldError })).Return(nil)
paper, err = contract.Redeem(ctx, "someotherissuer", "someotherpaper", "someowner", "2021-12-10:10:00")
assert.EqualError(t, err, "GetPaper error", "should error when GetPaper errors")
assert.Nil(t, paper, "should not return paper when GetPaper errors")
paper, err = contract.Redeem(ctx, "someissuer", "somepaper", "someotherowner", "2021-12-10:10:00")
assert.EqualError(t, err, "Paper someissuer:somepaper is not owned by someotherowner", "should error when paper owned by someone else")
assert.Nil(t, paper, "should not return paper when errors as owned by someone else")
resetPaper(wsPaper)
wsPaper.SetRedeemed()
paper, err = contract.Redeem(ctx, "someissuer", "somepaper", "someowner", "2021-12-10:10:00")
assert.EqualError(t, err, "Paper someissuer:somepaper is already redeemed", "should error when paper already redeemed")
assert.Nil(t, paper, "should not return paper when errors as already redeemed")
shouldError = true
resetPaper(wsPaper)
paper, err = contract.Redeem(ctx, "someissuer", "somepaper", "someowner", "2021-12-10:10:00")
assert.EqualError(t, err, "UpdatePaper error", "should error when update paper errors")
assert.Nil(t, paper, "should not return paper when UpdatePaper errors")
shouldError = false
resetPaper(wsPaper)
paper, err = contract.Redeem(ctx, "someissuer", "somepaper", "someowner", "2021-12-10:10:00")
assert.Nil(t, err, "should not error on good redeem")
assert.True(t, paper.IsRedeemed(), "should return redeemed paper")
assert.Equal(t, sentPaper, paper, "should update same paper as it returns in the world state")
}

View file

@ -0,0 +1,55 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package commercialpaper
import ledgerapi "github.com/hyperledger/fabric-samples/commercial-paper/organization/digibank/contract-go/ledger-api"
// ListInterface defines functionality needed
// to interact with the world state on behalf
// of a commercial paper
type ListInterface interface {
AddPaper(*CommercialPaper) error
GetPaper(string, string) (*CommercialPaper, error)
UpdatePaper(*CommercialPaper) error
}
type list struct {
stateList ledgerapi.StateListInterface
}
func (cpl *list) AddPaper(paper *CommercialPaper) error {
return cpl.stateList.AddState(paper)
}
func (cpl *list) GetPaper(issuer string, paperNumber string) (*CommercialPaper, error) {
cp := new(CommercialPaper)
err := cpl.stateList.GetState(CreateCommercialPaperKey(issuer, paperNumber), cp)
if err != nil {
return nil, err
}
return cp, nil
}
func (cpl *list) UpdatePaper(paper *CommercialPaper) error {
return cpl.stateList.UpdateState(paper)
}
// NewList create a new list from context
func newList(ctx TransactionContextInterface) *list {
stateList := new(ledgerapi.StateList)
stateList.Ctx = ctx
stateList.Name = "org.papernet.commercialpaperlist"
stateList.Deserialize = func(bytes []byte, state ledgerapi.StateInterface) error {
return Deserialize(bytes, state.(*CommercialPaper))
}
list := new(list)
list.stateList = stateList
return list
}

View file

@ -0,0 +1,103 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package commercialpaper
import (
"errors"
"testing"
ledgerapi "github.com/hyperledger/fabric-samples/commercial-paper/organization/digibank/contract-go/ledger-api"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
// #########
// HELPERS
// #########
type MockStateList struct {
mock.Mock
}
func (msl *MockStateList) AddState(state ledgerapi.StateInterface) error {
args := msl.Called(state)
return args.Error(0)
}
func (msl *MockStateList) GetState(key string, state ledgerapi.StateInterface) error {
args := msl.Called(key, state)
state.(*CommercialPaper).PaperNumber = "somepaper"
return args.Error(0)
}
func (msl *MockStateList) UpdateState(state ledgerapi.StateInterface) error {
args := msl.Called(state)
return args.Error(0)
}
// #########
// TESTS
// #########
func TestAddPaper(t *testing.T) {
paper := new(CommercialPaper)
list := new(list)
msl := new(MockStateList)
msl.On("AddState", paper).Return(errors.New("Called add state correctly"))
list.stateList = msl
err := list.AddPaper(paper)
assert.EqualError(t, err, "Called add state correctly", "should call state list add state with paper")
}
func TestGetPaper(t *testing.T) {
var cp *CommercialPaper
var err error
list := new(list)
msl := new(MockStateList)
msl.On("GetState", CreateCommercialPaperKey("someissuer", "somepaper"), mock.MatchedBy(func(state ledgerapi.StateInterface) bool { _, ok := state.(*CommercialPaper); return ok })).Return(nil)
msl.On("GetState", CreateCommercialPaperKey("someotherissuer", "someotherpaper"), mock.MatchedBy(func(state ledgerapi.StateInterface) bool { _, ok := state.(*CommercialPaper); return ok })).Return(errors.New("GetState error"))
list.stateList = msl
cp, err = list.GetPaper("someissuer", "somepaper")
assert.Nil(t, err, "should not error when get state on state list does not error")
assert.Equal(t, cp.PaperNumber, "somepaper", "should use state list GetState to fill commercial paper")
cp, err = list.GetPaper("someotherissuer", "someotherpaper")
assert.EqualError(t, err, "GetState error", "should return error when state list get state errors")
assert.Nil(t, cp, "should not return commercial paper on error")
}
func TestUpdatePaper(t *testing.T) {
paper := new(CommercialPaper)
list := new(list)
msl := new(MockStateList)
msl.On("UpdateState", paper).Return(errors.New("Called update state correctly"))
list.stateList = msl
err := list.UpdatePaper(paper)
assert.EqualError(t, err, "Called update state correctly", "should call state list update state with paper")
}
func TestNewStateList(t *testing.T) {
ctx := new(TransactionContext)
list := newList(ctx)
stateList, ok := list.stateList.(*ledgerapi.StateList)
assert.True(t, ok, "should make statelist of type ledgerapi.StateList")
assert.Equal(t, ctx, stateList.Ctx, "should set the context to passed context")
assert.Equal(t, "org.papernet.commercialpaperlist", stateList.Name, "should set the name for the list")
expectedErr := Deserialize([]byte("bad json"), new(CommercialPaper))
err := stateList.Deserialize([]byte("bad json"), new(CommercialPaper))
assert.EqualError(t, err, expectedErr.Error(), "should call Deserialize when stateList.Deserialize called")
}

View file

@ -0,0 +1,13 @@
module github.com/hyperledger/fabric-samples/commercial-paper/organization/digibank/contract-go
go 1.13
require (
github.com/go-openapi/jsonreference v0.19.3 // indirect
github.com/hyperledger/fabric-contract-api-go v0.0.0-20191118113407-4c6ff12b4f96
github.com/mailru/easyjson v0.7.0 // indirect
github.com/stretchr/testify v1.4.0
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 // indirect
google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 // indirect
google.golang.org/grpc v1.24.0 // indirect
)

View file

@ -0,0 +1,250 @@
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/godog v0.7.13/go.mod h1:z2OZ6a3X0/YAKVqLfVzYBwFt3j6uSt3Xrqa7XTtcQE0=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
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/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/awjh-ibm/fabric-chaincode-go v0.0.0-20190823162523-04390e015b85 h1:I27he/2AiTiQ7b9HNG69Yti+8Z5uRu9LyYI+zHK+3v0=
github.com/awjh-ibm/fabric-chaincode-go v0.0.0-20191101104715-ed6605dbcf4a h1:Og6B6TGwSJ+TANq/nVFldoq2vdFpq6eaz6uJdn4u6mc=
github.com/awjh-ibm/fabric-chaincode-go v0.0.0-20191101104715-ed6605dbcf4a/go.mod h1:EPsP9u9T1bG0HG3fxmh/88ijXC1ivmFpZImQe/XbJ34=
github.com/awjh-ibm/fabric-chaincode-go v0.0.0-20191101150549-e9d05b39373d h1:Wjv4Jb5Ir0ZhauaHFnKqLXrM5dywA0dryw4iOKfOTkk=
github.com/awjh-ibm/fabric-chaincode-go v0.0.0-20191101150549-e9d05b39373d/go.mod h1:EPsP9u9T1bG0HG3fxmh/88ijXC1ivmFpZImQe/XbJ34=
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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
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.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
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/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
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-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
github.com/go-openapi/validate v0.19.4/go.mod h1:BkJ0ZmXui7yB0bJXWSXgLPNTmbLVeX/3D1xn/N9mMUM=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU=
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/envy v1.7.1 h1:OQl5ys5MBea7OGCdvPbBJWRgnhC/fGona6QKfvFeau8=
github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w=
github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
github.com/gobuffalo/logger v1.0.1/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/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
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/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gucumber/gucumber v0.0.0-20180127021336-7d5c79e832a2/go.mod h1:YbdHRK9ViqwGMS0rtRY+1I6faHvVyyurKPIPwifihxI=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hyperledger/fabric-chaincode-go v0.0.0-20191108205148-17c4b2760b56 h1:BUCrT0VEO4ryJ7DAEGccqnEJcdHydx7wIJQ0ZGFEjJM=
github.com/hyperledger/fabric-chaincode-go v0.0.0-20191108205148-17c4b2760b56/go.mod h1:HZK6PKLWrvdD/t0oSLiyaRaUM6fZ7qjJuOlb0zrn0mo=
github.com/hyperledger/fabric-contract-api-go v0.0.0-20191118113407-4c6ff12b4f96 h1:1PaDE2QfQB/5ZnvlrYZNH62xMtKE/9cjwIzy9fjpJmg=
github.com/hyperledger/fabric-contract-api-go v0.0.0-20191118113407-4c6ff12b4f96/go.mod h1:SdJkyS7/oJltu5Ap//5sCEdNlvj+ZzD3TwnJOt3zf4c=
github.com/hyperledger/fabric-protos-go v0.0.0-20190821214336-621b908d5022/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
github.com/hyperledger/fabric-protos-go v0.0.0-20191101064633-9949a658b7e5 h1:2GAVnTeca8eaet9Ked2Usqy7GstZd6JkmsFHiyJI5hY=
github.com/hyperledger/fabric-protos-go v0.0.0-20191101064633-9949a658b7e5/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
github.com/hyperledger/fabric-protos-go v0.0.0-20191114160927-6bee4929a99f h1:t6+iLphkbJrM8i6YB0T/XxvoTlo50FglEf2hMJHxuOo=
github.com/hyperledger/fabric-protos-go v0.0.0-20191114160927-6bee4929a99f/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
github.com/hyperledger/fabric-samples v1.4.4 h1:6CdBpR8M4ajOnXUK4e8cO82/lXQKfAX2L5oTJtzWjLk=
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/karrick/godirwalk v1.13.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
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/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-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
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/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs=
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/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.5.0 h1:Usqs0/lDK/NqTkvrmKSwA/3XkZAs7ZAW/eLeQ2MVBTw=
github.com/rogpeppe/go-internal v1.5.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
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/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
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 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
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 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
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/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/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.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
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=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
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-20190320223903-b7391e95e576/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-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 h1:N66aaryRB3Ax92gH0v3hp1QYZ3zWWCCUR/j8Ifh45Ss=
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/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-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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/sys v0.0.0-20191029155521-f43be2a4598c h1:S/FtSvpNLtFBgjTqcKsRpsa6aVsI6iztaz1bQd9BJwE=
golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c/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-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
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-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191024074452-7defa796fec0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 h1:UXl+Zk3jqqcbEVV7ace5lrt4YdA4tXiz3f/KbmD29Vo=
google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View file

@ -0,0 +1,27 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package ledgerapi
import (
"strings"
)
// SplitKey splits a key on colon
func SplitKey(key string) []string {
return strings.Split(key, ":")
}
// MakeKey joins key parts using colon
func MakeKey(keyParts ...string) string {
return strings.Join(keyParts, ":")
}
// StateInterface interface states must implement
// for use in a list
type StateInterface interface {
// GetSplitKey return components that combine to form the key
GetSplitKey() []string
Serialize() ([]byte, error)
}

View file

@ -0,0 +1,61 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package ledgerapi
import (
"fmt"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
// StateListInterface functions that a state list
// should have
type StateListInterface interface {
AddState(StateInterface) error
GetState(string, StateInterface) error
UpdateState(StateInterface) error
}
// StateList useful for managing putting data in and out
// of the ledger. Implementation of StateListInterface
type StateList struct {
Ctx contractapi.TransactionContextInterface
Name string
Deserialize func([]byte, StateInterface) error
}
// AddState puts state into world state
func (sl *StateList) AddState(state StateInterface) error {
key, _ := sl.Ctx.GetStub().CreateCompositeKey(sl.Name, state.GetSplitKey())
data, err := state.Serialize()
if err != nil {
return err
}
return sl.Ctx.GetStub().PutState(key, data)
}
// GetState returns state from world state. Unmarshalls the JSON
// into passed state. Key is the split key value used in Add/Update
// joined using a colon
func (sl *StateList) GetState(key string, state StateInterface) error {
ledgerKey, _ := sl.Ctx.GetStub().CreateCompositeKey(sl.Name, SplitKey(key))
data, err := sl.Ctx.GetStub().GetState(ledgerKey)
if err != nil {
return err
} else if data == nil {
return fmt.Errorf("No state found for %s", key)
}
return sl.Deserialize(data, state)
}
// UpdateState puts state into world state. Same as AddState but
// separate as semantically different
func (sl *StateList) UpdateState(state StateInterface) error {
return sl.AddState(state)
}

View file

@ -0,0 +1,35 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"fmt"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
"github.com/hyperledger/fabric-samples/commercial-paper/organization/digibank/contract-go/commercial-paper"
)
func main() {
contract := new(commercialpaper.Contract)
contract.TransactionContextHandler = new(commercialpaper.TransactionContext)
contract.Name = "org.papernet.commercialpaper"
contract.Info.Version = "0.0.1"
chaincode, err := contractapi.NewChaincode(contract)
if err != nil {
panic(fmt.Sprintf("Error creating chaincode. %s", err.Error()))
}
chaincode.Info.Title = "CommercialPaperChaincode"
chaincode.Info.Version = "0.0.1"
err = chaincode.Start()
if err != nil {
panic(fmt.Sprintf("Error starting chaincode. %s", err.Error()))
}
}

View file

@ -44,9 +44,9 @@
"integrity": "sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q=="
},
"@types/node": {
"version": "13.1.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.4.tgz",
"integrity": "sha512-Lue/mlp2egZJoHXZr4LndxDAd7i/7SQYhV0EjWfb/a4/OZ6tuVwMCVPiwkU5nsEipxEf7hmkSU7Em5VQ8P5NGA=="
"version": "13.1.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.7.tgz",
"integrity": "sha512-HU0q9GXazqiKwviVxg9SI/+t/nAsGkvLDkIdxz+ObejG2nX6Si00TeLqHMoS+a/1tjH7a8YpKVQwtgHuMQsldg=="
},
"@types/request": {
"version": "2.48.4",
@ -171,9 +171,9 @@
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
},
"aws4": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz",
"integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A=="
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
"integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug=="
},
"balanced-match": {
"version": "1.0.0",

View file

@ -28,7 +28,7 @@ services:
command: /bin/bash
volumes:
- /var/run/:/host/var/run/
- ./../../../../organization/magnetocorp:/opt/gopath/src/github.com/
- ./../../../../organization/magnetocorp:/opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp
- ./../../../../../basic-network/crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
networks:
- basic

View file

@ -0,0 +1,139 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package commercialpaper
import (
"encoding/json"
"fmt"
ledgerapi "github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-go/ledger-api"
)
// State enum for commercial paper state property
type State uint
const (
// ISSUED state for when a paper has been issued
ISSUED State = iota + 1
// TRADING state for when a paper is trading
TRADING
// REDEEMED state for when a paper has been redeemed
REDEEMED
)
func (state State) String() string {
names := []string{"ISSUED", "TRADING", "REDEEMED"}
if state < ISSUED || state > REDEEMED {
return "UNKNOWN"
}
return names[state-1]
}
// CreateCommercialPaperKey creates a key for commercial papers
func CreateCommercialPaperKey(issuer string, paperNumber string) string {
return ledgerapi.MakeKey(issuer, paperNumber)
}
// Used for managing the fact status is private but want it in world state
type commercialPaperAlias CommercialPaper
type jsonCommercialPaper struct {
*commercialPaperAlias
State State `json:"currentState"`
Class string `json:"class"`
Key string `json:"key"`
}
// CommercialPaper defines a commercial paper
type CommercialPaper struct {
PaperNumber string `json:"paperNumber"`
Issuer string `json:"issuer"`
IssueDateTime string `json:"issueDateTime"`
FaceValue int `json:"faceValue"`
MaturityDateTime string `json:"maturityDateTime"`
Owner string `json:"owner"`
state State `metadata:"currentState"`
class string `metadata:"class"`
key string `metadata:"key"`
}
// UnmarshalJSON special handler for managing JSON marshalling
func (cp *CommercialPaper) UnmarshalJSON(data []byte) error {
jcp := jsonCommercialPaper{commercialPaperAlias: (*commercialPaperAlias)(cp)}
err := json.Unmarshal(data, &jcp)
if err != nil {
return err
}
cp.state = jcp.State
return nil
}
// MarshalJSON special handler for managing JSON marshalling
func (cp CommercialPaper) MarshalJSON() ([]byte, error) {
jcp := jsonCommercialPaper{commercialPaperAlias: (*commercialPaperAlias)(&cp), State: cp.state, Class: "org.papernet.commercialpaper", Key: ledgerapi.MakeKey(cp.Issuer, cp.PaperNumber)}
return json.Marshal(&jcp)
}
// GetState returns the state
func (cp *CommercialPaper) GetState() State {
return cp.state
}
// SetIssued returns the state to issued
func (cp *CommercialPaper) SetIssued() {
cp.state = ISSUED
}
// SetTrading sets the state to trading
func (cp *CommercialPaper) SetTrading() {
cp.state = TRADING
}
// SetRedeemed sets the state to redeemed
func (cp *CommercialPaper) SetRedeemed() {
cp.state = REDEEMED
}
// IsIssued returns true if state is issued
func (cp *CommercialPaper) IsIssued() bool {
return cp.state == ISSUED
}
// IsTrading returns true if state is trading
func (cp *CommercialPaper) IsTrading() bool {
return cp.state == TRADING
}
// IsRedeemed returns true if state is redeemed
func (cp *CommercialPaper) IsRedeemed() bool {
return cp.state == REDEEMED
}
// GetSplitKey returns values which should be used to form key
func (cp *CommercialPaper) GetSplitKey() []string {
return []string{cp.Issuer, cp.PaperNumber}
}
// Serialize formats the commercial paper as JSON bytes
func (cp *CommercialPaper) Serialize() ([]byte, error) {
return json.Marshal(cp)
}
// Deserialize formats the commercial paper from JSON bytes
func Deserialize(bytes []byte, cp *CommercialPaper) error {
err := json.Unmarshal(bytes, cp)
if err != nil {
return fmt.Errorf("Error deserializing commercial paper. %s", err.Error())
}
return nil
}

View file

@ -0,0 +1,125 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package commercialpaper
import (
"testing"
ledgerapi "github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-go/ledger-api"
"github.com/stretchr/testify/assert"
)
func TestString(t *testing.T) {
assert.Equal(t, "ISSUED", ISSUED.String(), "should return string for issued")
assert.Equal(t, "TRADING", TRADING.String(), "should return string for issued")
assert.Equal(t, "REDEEMED", REDEEMED.String(), "should return string for issued")
assert.Equal(t, "UNKNOWN", State(REDEEMED+1).String(), "should return unknown when not one of constants")
}
func TestCreateCommercialPaperKey(t *testing.T) {
assert.Equal(t, ledgerapi.MakeKey("someissuer", "somepaper"), CreateCommercialPaperKey("someissuer", "somepaper"), "should return key comprised of passed values")
}
func TestGetState(t *testing.T) {
cp := new(CommercialPaper)
cp.state = ISSUED
assert.Equal(t, ISSUED, cp.GetState(), "should return set state")
}
func TestSetIssued(t *testing.T) {
cp := new(CommercialPaper)
cp.SetIssued()
assert.Equal(t, ISSUED, cp.state, "should set state to trading")
}
func TestSetTrading(t *testing.T) {
cp := new(CommercialPaper)
cp.SetTrading()
assert.Equal(t, TRADING, cp.state, "should set state to trading")
}
func TestSetRedeemed(t *testing.T) {
cp := new(CommercialPaper)
cp.SetRedeemed()
assert.Equal(t, REDEEMED, cp.state, "should set state to trading")
}
func TestIsIssued(t *testing.T) {
cp := new(CommercialPaper)
cp.SetIssued()
assert.True(t, cp.IsIssued(), "should be true when status set to issued")
cp.SetTrading()
assert.False(t, cp.IsIssued(), "should be false when status not set to issued")
}
func TestIsTrading(t *testing.T) {
cp := new(CommercialPaper)
cp.SetTrading()
assert.True(t, cp.IsTrading(), "should be true when status set to trading")
cp.SetRedeemed()
assert.False(t, cp.IsTrading(), "should be false when status not set to trading")
}
func TestIsRedeemed(t *testing.T) {
cp := new(CommercialPaper)
cp.SetRedeemed()
assert.True(t, cp.IsRedeemed(), "should be true when status set to redeemed")
cp.SetIssued()
assert.False(t, cp.IsRedeemed(), "should be false when status not set to redeemed")
}
func TestGetSplitKey(t *testing.T) {
cp := new(CommercialPaper)
cp.PaperNumber = "somepaper"
cp.Issuer = "someissuer"
assert.Equal(t, []string{"someissuer", "somepaper"}, cp.GetSplitKey(), "should return issuer and paper number as split key")
}
func TestSerialize(t *testing.T) {
cp := new(CommercialPaper)
cp.PaperNumber = "somepaper"
cp.Issuer = "someissuer"
cp.IssueDateTime = "sometime"
cp.FaceValue = 1000
cp.MaturityDateTime = "somelatertime"
cp.Owner = "someowner"
cp.state = TRADING
bytes, err := cp.Serialize()
assert.Nil(t, err, "should not error on serialize")
assert.Equal(t, `{"paperNumber":"somepaper","issuer":"someissuer","issueDateTime":"sometime","faceValue":1000,"maturityDateTime":"somelatertime","owner":"someowner","currentState":2,"class":"org.papernet.commercialpaper","key":"someissuer:somepaper"}`, string(bytes), "should return JSON formatted value")
}
func TestDeserialize(t *testing.T) {
var cp *CommercialPaper
var err error
goodJSON := `{"paperNumber":"somepaper","issuer":"someissuer","issueDateTime":"sometime","faceValue":1000,"maturityDateTime":"somelatertime","owner":"someowner","currentState":2,"class":"org.papernet.commercialpaper","key":"someissuer:somepaper"}`
expectedCp := new(CommercialPaper)
expectedCp.PaperNumber = "somepaper"
expectedCp.Issuer = "someissuer"
expectedCp.IssueDateTime = "sometime"
expectedCp.FaceValue = 1000
expectedCp.MaturityDateTime = "somelatertime"
expectedCp.Owner = "someowner"
expectedCp.state = TRADING
cp = new(CommercialPaper)
err = Deserialize([]byte(goodJSON), cp)
assert.Nil(t, err, "should not return error for deserialize")
assert.Equal(t, expectedCp, cp, "should create expected commercial paper")
badJSON := `{"paperNumber":"somepaper","issuer":"someissuer","issueDateTime":"sometime","faceValue":"NaN","maturityDateTime":"somelatertime","owner":"someowner","currentState":2,"class":"org.papernet.commercialpaper","key":"someissuer:somepaper"}`
cp = new(CommercialPaper)
err = Deserialize([]byte(badJSON), cp)
assert.EqualError(t, err, "Error deserializing commercial paper. json: cannot unmarshal string into Go struct field jsonCommercialPaper.faceValue of type int", "should return error for bad data")
}

View file

@ -0,0 +1,35 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package commercialpaper
import (
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
// TransactionContextInterface an interface to
// describe the minimum required functions for
// a transaction context in the commercial
// paper
type TransactionContextInterface interface {
contractapi.TransactionContextInterface
GetPaperList() ListInterface
}
// TransactionContext implementation of
// TransactionContextInterface for use with
// commercial paper contract
type TransactionContext struct {
contractapi.TransactionContext
paperList *list
}
// GetPaperList return paper list
func (tc *TransactionContext) GetPaperList() ListInterface {
if tc.paperList == nil {
tc.paperList = newList(tc)
}
return tc.paperList
}

View file

@ -0,0 +1,31 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package commercialpaper
import (
"testing"
ledgerapi "github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-go/ledger-api"
"github.com/stretchr/testify/assert"
)
func TestGetPaperList(t *testing.T) {
var tc *TransactionContext
var expectedPaperList *list
tc = new(TransactionContext)
expectedPaperList = newList(tc)
actualList := tc.GetPaperList().(*list)
assert.Equal(t, expectedPaperList.stateList.(*ledgerapi.StateList).Name, actualList.stateList.(*ledgerapi.StateList).Name, "should configure paper list when one not already configured")
tc = new(TransactionContext)
expectedPaperList = new(list)
expectedStateList := new(ledgerapi.StateList)
expectedStateList.Ctx = tc
expectedStateList.Name = "existing paper list"
expectedPaperList.stateList = expectedStateList
tc.paperList = expectedPaperList
assert.Equal(t, expectedPaperList, tc.GetPaperList(), "should return set paper list when already set")
}

View file

@ -0,0 +1,96 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package commercialpaper
import (
"fmt"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
// Contract chaincode that defines
// the business logic for managing commercial
// paper
type Contract struct {
contractapi.Contract
}
// Instantiate does nothing
func (c *Contract) Instantiate() {
fmt.Println("Instantiated")
}
// Issue creates a new commercial paper and stores it in the world state
func (c *Contract) Issue(ctx TransactionContextInterface, issuer string, paperNumber string, issueDateTime string, maturityDateTime string, faceValue int) (*CommercialPaper, error) {
paper := CommercialPaper{PaperNumber: paperNumber, Issuer: issuer, IssueDateTime: issueDateTime, FaceValue: faceValue, MaturityDateTime: maturityDateTime, Owner: issuer}
paper.SetIssued()
err := ctx.GetPaperList().AddPaper(&paper)
if err != nil {
return nil, err
}
return &paper, nil
}
// Buy updates a commercial paper to be in trading status and sets the new owner
func (c *Contract) Buy(ctx TransactionContextInterface, issuer string, paperNumber string, currentOwner string, newOwner string, price int, purchaseDateTime string) (*CommercialPaper, error) {
paper, err := ctx.GetPaperList().GetPaper(issuer, paperNumber)
if err != nil {
return nil, err
}
if paper.Owner != currentOwner {
return nil, fmt.Errorf("Paper %s:%s is not owned by %s", issuer, paperNumber, currentOwner)
}
if paper.IsIssued() {
paper.SetTrading()
}
if !paper.IsTrading() {
return nil, fmt.Errorf("Paper %s:%s is not trading. Current state = %s", issuer, paperNumber, paper.GetState())
}
paper.Owner = newOwner
err = ctx.GetPaperList().UpdatePaper(paper)
if err != nil {
return nil, err
}
return paper, nil
}
// Redeem updates a commercial paper status to be redeemed
func (c *Contract) Redeem(ctx TransactionContextInterface, issuer string, paperNumber string, redeemingOwner string, redeenDateTime string) (*CommercialPaper, error) {
paper, err := ctx.GetPaperList().GetPaper(issuer, paperNumber)
if err != nil {
return nil, err
}
if paper.Owner != redeemingOwner {
return nil, fmt.Errorf("Paper %s:%s is not owned by %s", issuer, paperNumber, redeemingOwner)
}
if paper.IsRedeemed() {
return nil, fmt.Errorf("Paper %s:%s is already redeemed", issuer, paperNumber)
}
paper.Owner = paper.Issuer
paper.SetRedeemed()
err = ctx.GetPaperList().UpdatePaper(paper)
if err != nil {
return nil, err
}
return paper, nil
}

View file

@ -0,0 +1,185 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package commercialpaper
import (
"errors"
"testing"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
// #########
// HELPERS
// #########
type MockPaperList struct {
mock.Mock
}
func (mpl *MockPaperList) AddPaper(paper *CommercialPaper) error {
args := mpl.Called(paper)
return args.Error(0)
}
func (mpl *MockPaperList) GetPaper(issuer string, papernumber string) (*CommercialPaper, error) {
args := mpl.Called(issuer, papernumber)
return args.Get(0).(*CommercialPaper), args.Error(1)
}
func (mpl *MockPaperList) UpdatePaper(paper *CommercialPaper) error {
args := mpl.Called(paper)
return args.Error(0)
}
type MockTransactionContext struct {
contractapi.TransactionContext
paperList *MockPaperList
}
func (mtc *MockTransactionContext) GetPaperList() ListInterface {
return mtc.paperList
}
func resetPaper(paper *CommercialPaper) {
paper.Owner = "someowner"
paper.SetTrading()
}
// #########
// TESTS
// #########
func TestIssue(t *testing.T) {
var paper *CommercialPaper
var err error
mpl := new(MockPaperList)
ctx := new(MockTransactionContext)
ctx.paperList = mpl
contract := new(Contract)
var sentPaper *CommercialPaper
mpl.On("AddPaper", mock.MatchedBy(func(paper *CommercialPaper) bool { sentPaper = paper; return paper.Issuer == "someissuer" })).Return(nil)
mpl.On("AddPaper", mock.MatchedBy(func(paper *CommercialPaper) bool { sentPaper = paper; return paper.Issuer == "someotherissuer" })).Return(errors.New("AddPaper error"))
expectedPaper := CommercialPaper{PaperNumber: "somepaper", Issuer: "someissuer", IssueDateTime: "someissuedate", FaceValue: 1000, MaturityDateTime: "somematuritydate", Owner: "someissuer", state: 1}
paper, err = contract.Issue(ctx, "someissuer", "somepaper", "someissuedate", "somematuritydate", 1000)
assert.Nil(t, err, "should not error when add paper does not error")
assert.Equal(t, sentPaper, paper, "should send the same paper as it returns to add paper")
assert.Equal(t, expectedPaper, *paper, "should correctly configure paper")
paper, err = contract.Issue(ctx, "someotherissuer", "somepaper", "someissuedate", "somematuritydate", 1000)
assert.EqualError(t, err, "AddPaper error", "should return error when add paper fails")
assert.Nil(t, paper, "should not return paper when fails")
}
func TestBuy(t *testing.T) {
var paper *CommercialPaper
var err error
mpl := new(MockPaperList)
ctx := new(MockTransactionContext)
ctx.paperList = mpl
contract := new(Contract)
wsPaper := new(CommercialPaper)
resetPaper(wsPaper)
var sentPaper *CommercialPaper
var emptyPaper *CommercialPaper
shouldError := false
mpl.On("GetPaper", "someissuer", "somepaper").Return(wsPaper, nil)
mpl.On("GetPaper", "someotherissuer", "someotherpaper").Return(emptyPaper, errors.New("GetPaper error"))
mpl.On("UpdatePaper", mock.MatchedBy(func(paper *CommercialPaper) bool { return shouldError })).Return(errors.New("UpdatePaper error"))
mpl.On("UpdatePaper", mock.MatchedBy(func(paper *CommercialPaper) bool { sentPaper = paper; return !shouldError })).Return(nil)
paper, err = contract.Buy(ctx, "someotherissuer", "someotherpaper", "someowner", "someotherowner", 100, "2019-12-10:10:00")
assert.EqualError(t, err, "GetPaper error", "should return error when GetPaper errors")
assert.Nil(t, paper, "should return nil for paper when GetPaper errors")
paper, err = contract.Buy(ctx, "someissuer", "somepaper", "someotherowner", "someowner", 100, "2019-12-10:10:00")
assert.EqualError(t, err, "Paper someissuer:somepaper is not owned by someotherowner", "should error when sent owner not correct")
assert.Nil(t, paper, "should not return paper for bad owner error")
resetPaper(wsPaper)
wsPaper.SetRedeemed()
paper, err = contract.Buy(ctx, "someissuer", "somepaper", "someowner", "someotherowner", 100, "2019-12-10:10:00")
assert.EqualError(t, err, "Paper someissuer:somepaper is not trading. Current state = REDEEMED")
assert.Nil(t, paper, "should not return paper for bad state error")
resetPaper(wsPaper)
shouldError = true
paper, err = contract.Buy(ctx, "someissuer", "somepaper", "someowner", "someotherowner", 100, "2019-12-10:10:00")
assert.EqualError(t, err, "UpdatePaper error", "should error when update paper fails")
assert.Nil(t, paper, "should not return paper for bad state error")
shouldError = false
resetPaper(wsPaper)
wsPaper.SetIssued()
paper, err = contract.Buy(ctx, "someissuer", "somepaper", "someowner", "someotherowner", 100, "2019-12-10:10:00")
assert.Nil(t, err, "should not error when good paper and owner")
assert.Equal(t, "someotherowner", paper.Owner, "should update the owner of the paper")
assert.True(t, paper.IsTrading(), "should mark issued paper as trading")
assert.Equal(t, sentPaper, paper, "should update same paper as it returns in the world state")
}
func TestRedeem(t *testing.T) {
var paper *CommercialPaper
var err error
mpl := new(MockPaperList)
ctx := new(MockTransactionContext)
ctx.paperList = mpl
contract := new(Contract)
var sentPaper *CommercialPaper
wsPaper := new(CommercialPaper)
resetPaper(wsPaper)
var emptyPaper *CommercialPaper
shouldError := false
mpl.On("GetPaper", "someissuer", "somepaper").Return(wsPaper, nil)
mpl.On("GetPaper", "someotherissuer", "someotherpaper").Return(emptyPaper, errors.New("GetPaper error"))
mpl.On("UpdatePaper", mock.MatchedBy(func(paper *CommercialPaper) bool { return shouldError })).Return(errors.New("UpdatePaper error"))
mpl.On("UpdatePaper", mock.MatchedBy(func(paper *CommercialPaper) bool { sentPaper = paper; return !shouldError })).Return(nil)
paper, err = contract.Redeem(ctx, "someotherissuer", "someotherpaper", "someowner", "2021-12-10:10:00")
assert.EqualError(t, err, "GetPaper error", "should error when GetPaper errors")
assert.Nil(t, paper, "should not return paper when GetPaper errors")
paper, err = contract.Redeem(ctx, "someissuer", "somepaper", "someotherowner", "2021-12-10:10:00")
assert.EqualError(t, err, "Paper someissuer:somepaper is not owned by someotherowner", "should error when paper owned by someone else")
assert.Nil(t, paper, "should not return paper when errors as owned by someone else")
resetPaper(wsPaper)
wsPaper.SetRedeemed()
paper, err = contract.Redeem(ctx, "someissuer", "somepaper", "someowner", "2021-12-10:10:00")
assert.EqualError(t, err, "Paper someissuer:somepaper is already redeemed", "should error when paper already redeemed")
assert.Nil(t, paper, "should not return paper when errors as already redeemed")
shouldError = true
resetPaper(wsPaper)
paper, err = contract.Redeem(ctx, "someissuer", "somepaper", "someowner", "2021-12-10:10:00")
assert.EqualError(t, err, "UpdatePaper error", "should error when update paper errors")
assert.Nil(t, paper, "should not return paper when UpdatePaper errors")
shouldError = false
resetPaper(wsPaper)
paper, err = contract.Redeem(ctx, "someissuer", "somepaper", "someowner", "2021-12-10:10:00")
assert.Nil(t, err, "should not error on good redeem")
assert.True(t, paper.IsRedeemed(), "should return redeemed paper")
assert.Equal(t, sentPaper, paper, "should update same paper as it returns in the world state")
}

View file

@ -0,0 +1,55 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package commercialpaper
import ledgerapi "github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-go/ledger-api"
// ListInterface defines functionality needed
// to interact with the world state on behalf
// of a commercial paper
type ListInterface interface {
AddPaper(*CommercialPaper) error
GetPaper(string, string) (*CommercialPaper, error)
UpdatePaper(*CommercialPaper) error
}
type list struct {
stateList ledgerapi.StateListInterface
}
func (cpl *list) AddPaper(paper *CommercialPaper) error {
return cpl.stateList.AddState(paper)
}
func (cpl *list) GetPaper(issuer string, paperNumber string) (*CommercialPaper, error) {
cp := new(CommercialPaper)
err := cpl.stateList.GetState(CreateCommercialPaperKey(issuer, paperNumber), cp)
if err != nil {
return nil, err
}
return cp, nil
}
func (cpl *list) UpdatePaper(paper *CommercialPaper) error {
return cpl.stateList.UpdateState(paper)
}
// NewList create a new list from context
func newList(ctx TransactionContextInterface) *list {
stateList := new(ledgerapi.StateList)
stateList.Ctx = ctx
stateList.Name = "org.papernet.commercialpaperlist"
stateList.Deserialize = func(bytes []byte, state ledgerapi.StateInterface) error {
return Deserialize(bytes, state.(*CommercialPaper))
}
list := new(list)
list.stateList = stateList
return list
}

View file

@ -0,0 +1,103 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package commercialpaper
import (
"errors"
"testing"
ledgerapi "github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-go/ledger-api"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
// #########
// HELPERS
// #########
type MockStateList struct {
mock.Mock
}
func (msl *MockStateList) AddState(state ledgerapi.StateInterface) error {
args := msl.Called(state)
return args.Error(0)
}
func (msl *MockStateList) GetState(key string, state ledgerapi.StateInterface) error {
args := msl.Called(key, state)
state.(*CommercialPaper).PaperNumber = "somepaper"
return args.Error(0)
}
func (msl *MockStateList) UpdateState(state ledgerapi.StateInterface) error {
args := msl.Called(state)
return args.Error(0)
}
// #########
// TESTS
// #########
func TestAddPaper(t *testing.T) {
paper := new(CommercialPaper)
list := new(list)
msl := new(MockStateList)
msl.On("AddState", paper).Return(errors.New("Called add state correctly"))
list.stateList = msl
err := list.AddPaper(paper)
assert.EqualError(t, err, "Called add state correctly", "should call state list add state with paper")
}
func TestGetPaper(t *testing.T) {
var cp *CommercialPaper
var err error
list := new(list)
msl := new(MockStateList)
msl.On("GetState", CreateCommercialPaperKey("someissuer", "somepaper"), mock.MatchedBy(func(state ledgerapi.StateInterface) bool { _, ok := state.(*CommercialPaper); return ok })).Return(nil)
msl.On("GetState", CreateCommercialPaperKey("someotherissuer", "someotherpaper"), mock.MatchedBy(func(state ledgerapi.StateInterface) bool { _, ok := state.(*CommercialPaper); return ok })).Return(errors.New("GetState error"))
list.stateList = msl
cp, err = list.GetPaper("someissuer", "somepaper")
assert.Nil(t, err, "should not error when get state on state list does not error")
assert.Equal(t, cp.PaperNumber, "somepaper", "should use state list GetState to fill commercial paper")
cp, err = list.GetPaper("someotherissuer", "someotherpaper")
assert.EqualError(t, err, "GetState error", "should return error when state list get state errors")
assert.Nil(t, cp, "should not return commercial paper on error")
}
func TestUpdatePaper(t *testing.T) {
paper := new(CommercialPaper)
list := new(list)
msl := new(MockStateList)
msl.On("UpdateState", paper).Return(errors.New("Called update state correctly"))
list.stateList = msl
err := list.UpdatePaper(paper)
assert.EqualError(t, err, "Called update state correctly", "should call state list update state with paper")
}
func TestNewStateList(t *testing.T) {
ctx := new(TransactionContext)
list := newList(ctx)
stateList, ok := list.stateList.(*ledgerapi.StateList)
assert.True(t, ok, "should make statelist of type ledgerapi.StateList")
assert.Equal(t, ctx, stateList.Ctx, "should set the context to passed context")
assert.Equal(t, "org.papernet.commercialpaperlist", stateList.Name, "should set the name for the list")
expectedErr := Deserialize([]byte("bad json"), new(CommercialPaper))
err := stateList.Deserialize([]byte("bad json"), new(CommercialPaper))
assert.EqualError(t, err, expectedErr.Error(), "should call Deserialize when stateList.Deserialize called")
}

View file

@ -0,0 +1,13 @@
module github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-go
go 1.13
require (
github.com/go-openapi/jsonreference v0.19.3 // indirect
github.com/hyperledger/fabric-contract-api-go v0.0.0-20191118113407-4c6ff12b4f96
github.com/mailru/easyjson v0.7.0 // indirect
github.com/stretchr/testify v1.4.0
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 // indirect
google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 // indirect
google.golang.org/grpc v1.24.0 // indirect
)

View file

@ -0,0 +1,249 @@
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/godog v0.7.13/go.mod h1:z2OZ6a3X0/YAKVqLfVzYBwFt3j6uSt3Xrqa7XTtcQE0=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
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/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/awjh-ibm/fabric-chaincode-go v0.0.0-20190823162523-04390e015b85 h1:I27he/2AiTiQ7b9HNG69Yti+8Z5uRu9LyYI+zHK+3v0=
github.com/awjh-ibm/fabric-chaincode-go v0.0.0-20191101104715-ed6605dbcf4a h1:Og6B6TGwSJ+TANq/nVFldoq2vdFpq6eaz6uJdn4u6mc=
github.com/awjh-ibm/fabric-chaincode-go v0.0.0-20191101104715-ed6605dbcf4a/go.mod h1:EPsP9u9T1bG0HG3fxmh/88ijXC1ivmFpZImQe/XbJ34=
github.com/awjh-ibm/fabric-chaincode-go v0.0.0-20191101150549-e9d05b39373d h1:Wjv4Jb5Ir0ZhauaHFnKqLXrM5dywA0dryw4iOKfOTkk=
github.com/awjh-ibm/fabric-chaincode-go v0.0.0-20191101150549-e9d05b39373d/go.mod h1:EPsP9u9T1bG0HG3fxmh/88ijXC1ivmFpZImQe/XbJ34=
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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
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.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
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/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
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-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
github.com/go-openapi/validate v0.19.4/go.mod h1:BkJ0ZmXui7yB0bJXWSXgLPNTmbLVeX/3D1xn/N9mMUM=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU=
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/envy v1.7.1 h1:OQl5ys5MBea7OGCdvPbBJWRgnhC/fGona6QKfvFeau8=
github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w=
github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
github.com/gobuffalo/logger v1.0.1/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/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
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/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gucumber/gucumber v0.0.0-20180127021336-7d5c79e832a2/go.mod h1:YbdHRK9ViqwGMS0rtRY+1I6faHvVyyurKPIPwifihxI=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hyperledger/fabric-chaincode-go v0.0.0-20191108205148-17c4b2760b56 h1:BUCrT0VEO4ryJ7DAEGccqnEJcdHydx7wIJQ0ZGFEjJM=
github.com/hyperledger/fabric-chaincode-go v0.0.0-20191108205148-17c4b2760b56/go.mod h1:HZK6PKLWrvdD/t0oSLiyaRaUM6fZ7qjJuOlb0zrn0mo=
github.com/hyperledger/fabric-contract-api-go v0.0.0-20191118113407-4c6ff12b4f96 h1:1PaDE2QfQB/5ZnvlrYZNH62xMtKE/9cjwIzy9fjpJmg=
github.com/hyperledger/fabric-contract-api-go v0.0.0-20191118113407-4c6ff12b4f96/go.mod h1:SdJkyS7/oJltu5Ap//5sCEdNlvj+ZzD3TwnJOt3zf4c=
github.com/hyperledger/fabric-protos-go v0.0.0-20190821214336-621b908d5022/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
github.com/hyperledger/fabric-protos-go v0.0.0-20191101064633-9949a658b7e5 h1:2GAVnTeca8eaet9Ked2Usqy7GstZd6JkmsFHiyJI5hY=
github.com/hyperledger/fabric-protos-go v0.0.0-20191101064633-9949a658b7e5/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
github.com/hyperledger/fabric-protos-go v0.0.0-20191114160927-6bee4929a99f h1:t6+iLphkbJrM8i6YB0T/XxvoTlo50FglEf2hMJHxuOo=
github.com/hyperledger/fabric-protos-go v0.0.0-20191114160927-6bee4929a99f/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/karrick/godirwalk v1.13.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
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/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-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
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/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs=
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/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.5.0 h1:Usqs0/lDK/NqTkvrmKSwA/3XkZAs7ZAW/eLeQ2MVBTw=
github.com/rogpeppe/go-internal v1.5.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
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/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
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 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
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 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
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/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/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.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
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=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
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-20190320223903-b7391e95e576/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-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 h1:N66aaryRB3Ax92gH0v3hp1QYZ3zWWCCUR/j8Ifh45Ss=
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/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-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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/sys v0.0.0-20191029155521-f43be2a4598c h1:S/FtSvpNLtFBgjTqcKsRpsa6aVsI6iztaz1bQd9BJwE=
golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c/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-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
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-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191024074452-7defa796fec0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 h1:UXl+Zk3jqqcbEVV7ace5lrt4YdA4tXiz3f/KbmD29Vo=
google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View file

@ -0,0 +1,27 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package ledgerapi
import (
"strings"
)
// SplitKey splits a key on colon
func SplitKey(key string) []string {
return strings.Split(key, ":")
}
// MakeKey joins key parts using colon
func MakeKey(keyParts ...string) string {
return strings.Join(keyParts, ":")
}
// StateInterface interface states must implement
// for use in a list
type StateInterface interface {
// GetSplitKey return components that combine to form the key
GetSplitKey() []string
Serialize() ([]byte, error)
}

View file

@ -0,0 +1,61 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package ledgerapi
import (
"fmt"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
// StateListInterface functions that a state list
// should have
type StateListInterface interface {
AddState(StateInterface) error
GetState(string, StateInterface) error
UpdateState(StateInterface) error
}
// StateList useful for managing putting data in and out
// of the ledger. Implementation of StateListInterface
type StateList struct {
Ctx contractapi.TransactionContextInterface
Name string
Deserialize func([]byte, StateInterface) error
}
// AddState puts state into world state
func (sl *StateList) AddState(state StateInterface) error {
key, _ := sl.Ctx.GetStub().CreateCompositeKey(sl.Name, state.GetSplitKey())
data, err := state.Serialize()
if err != nil {
return err
}
return sl.Ctx.GetStub().PutState(key, data)
}
// GetState returns state from world state. Unmarshalls the JSON
// into passed state. Key is the split key value used in Add/Update
// joined using a colon
func (sl *StateList) GetState(key string, state StateInterface) error {
ledgerKey, _ := sl.Ctx.GetStub().CreateCompositeKey(sl.Name, SplitKey(key))
data, err := sl.Ctx.GetStub().GetState(ledgerKey)
if err != nil {
return err
} else if data == nil {
return fmt.Errorf("No state found for %s", key)
}
return sl.Deserialize(data, state)
}
// UpdateState puts state into world state. Same as AddState but
// separate as semantically different
func (sl *StateList) UpdateState(state StateInterface) error {
return sl.AddState(state)
}

View file

@ -0,0 +1,35 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"fmt"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
"github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-go/commercial-paper"
)
func main() {
contract := new(commercialpaper.Contract)
contract.TransactionContextHandler = new(commercialpaper.TransactionContext)
contract.Name = "org.papernet.commercialpaper"
contract.Info.Version = "0.0.1"
chaincode, err := contractapi.NewChaincode(contract)
if err != nil {
panic(fmt.Sprintf("Error creating chaincode. %s", err.Error()))
}
chaincode.Info.Title = "CommercialPaperChaincode"
chaincode.Info.Version = "0.0.1"
err = chaincode.Start()
if err != nil {
panic(fmt.Sprintf("Error starting chaincode. %s", err.Error()))
}
}

View file

@ -8,24 +8,34 @@ function _exit(){
}
# Where am I?
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
# DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
cd "${DIR}/organization/magnetocorp/configuration/cli"
docker-compose -f docker-compose.yml up -d cliMagnetoCorp
# cd "${DIR}/organization/magnetocorp/configuration/cli"
# docker-compose -f docker-compose.yml up -d cliMagnetoCorp
echo "
Install and Instantiate a Smart Contract in either langauge
JavaScript Contract:
docker exec cliMagnetoCorp peer chaincode install -n papercontract -v 0 -p /opt/gopath/src/github.com/contract -l node
docker exec cliMagnetoCorp peer chaincode install -n papercontract -v 0 -p /opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract -l node
docker exec cliMagnetoCorp peer chaincode instantiate -n papercontract -v 0 -l node -c '{\"Args\":[\"org.papernet.commercialpaper:instantiate\"]}' -C mychannel -P \"AND ('Org1MSP.member')\"
Java Contract:
docker exec cliMagnetoCorp peer chaincode install -n papercontract -v 0 -p /opt/gopath/src/github.com/contract-java -l java
docker exec cliMagnetoCorp peer chaincode install -n papercontract -v 0 -p /opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-java -l java
docker exec cliMagnetoCorp peer chaincode instantiate -n papercontract -v 0 -l java -c '{\"Args\":[\"org.papernet.commercialpaper:instantiate\"]}' -C mychannel -P \"AND ('Org1MSP.member')\"
Go Contract:
docker exec cliMagnetoCorp bash -c 'cd /opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-go && go mod vendor'
docker exec cliMagnetoCorp peer lifecycle chaincode package cp.tar.gz --lang golang --path github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-go --label cp_0
docker exec cliMagnetoCorp peer lifecycle chaincode install cp.tar.gz
export PACKAGE_ID=\$(docker exec cliMagnetoCorp peer lifecycle chaincode queryinstalled 2>&1 | awk -F \"[, ]+\" '/Label: /{print \$3}')
docker exec cliMagnetoCorp peer lifecycle chaincode approveformyorg --channelID mychannel --name papercontract -v 0 --package-id \$PACKAGE_ID --sequence 1 --signature-policy \"AND ('Org1MSP.member')\"
docker exec cliMagnetoCorp peer lifecycle chaincode commit -o orderer.example.com:7050 --channelID mychannel --name papercontract -v 0 --sequence 1 --waitForEvent --signature-policy \"AND ('Org1MSP.member')\"
docker exec cliMagnetoCorp peer chaincode invoke -o orderer.example.com:7050 --channelID mychannel --name papercontract -c '{\"Args\":[\"org.papernet.commercialpaper:instantiate\"]}' --waitForEvent
Run Applications in either langauage (can be different from the Smart Contract)