mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-17 15:35:09 +00:00
[FAB-11951] Interest-rate swap example for SBE
This is an example on how to represent and implement basic interest rate swap handling using fabric. It demonstrates the usage of state-based endorsement. Change-Id: I04e631299d95262e54e1532489766aa20477064c Signed-off-by: Matthias Neugschwandtner <eug@zurich.ibm.com> Signed-off-by: Alessandro Sorniotti <ale.linux@sopit.net> Signed-off-by: David Enyeart <enyeart@us.ibm.com>
This commit is contained in:
parent
9567985d29
commit
5cd277fdc0
7 changed files with 1258 additions and 0 deletions
176
interest_rate_swaps/README.md
Normal file
176
interest_rate_swaps/README.md
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
# Interest-rate swaps
|
||||
|
||||
This is a sample of how interest-rate swaps can be handled on a blockchain using
|
||||
fabric and state-based endorsement. [State-based endorsement](https://hyperledger-fabric.readthedocs.io/en/release-1.3/endorsement-policies.html#key-level-endorsement)
|
||||
is a new feature released in Hyperledger Fabric 1.3.
|
||||
|
||||
An interest-rate swap is a financial swap traded over the counter. It is a
|
||||
contractual agreement between two parties, where two parties (A and B) exchange
|
||||
payments. The amount of individual payments is based on the principal amount of the
|
||||
swap and an interest rate. The interest rates of the two parties differ. In a
|
||||
typical scenario, one payment (A to B) is based on a fixed rate set in the
|
||||
contract. The other payment (B to A) is based on a floating rate. This rate is
|
||||
defined through a reference rate, such as LIBOR from LSE, and an offset to this
|
||||
rate.
|
||||
|
||||
## Network
|
||||
|
||||
We assume organizations of the following roles participate in our network:
|
||||
* Parties that want to exchange payments
|
||||
* Parties that provide reference rates
|
||||
* Auditors that need to audit certain swaps
|
||||
|
||||
The chaincode-level endorsement policy is set to require an endorsement from an
|
||||
auditor as well as an endorsement from any swap participant.
|
||||
|
||||
## Data model
|
||||
We represent a swap on the ledger as a JSON with the following fields:
|
||||
* `StartDate` and `EndDate` of the swap
|
||||
* `PaymentInterval` - the time interval of the payments
|
||||
* `PrincipalAmount` - the principal amount of the swap
|
||||
* `FixedRate` - the fixed rate of the swap
|
||||
* `FloatingRate` - the floating rate of the swap (offset to the reference rate)
|
||||
* `ReferenceRate` - the key name of the KVS pair that holds the reference rate
|
||||
|
||||
The key for the swap is a unique identifier combined with a common prefix `swap`
|
||||
that identifies swap entries in the KVS namespace. Upon creation the key-level
|
||||
endorsement policy for the swap is set to the participants of the swap and,
|
||||
potentially, an auditor.
|
||||
|
||||
We represent the payment information as a single KVS entry per swap with the
|
||||
same unique identifier as the swap itself and a common prefix `payment` for payments.
|
||||
If payments are due, the entry states the amount due. Otherwise, it is "none".
|
||||
A payment information KVS entry has the same key-level endorsement policy
|
||||
set as its corresponding swap entry.
|
||||
|
||||
We represent the reference rates as a KVS entry per rate with an identifier per
|
||||
rate and a common prefix for reference rates. The key-level endorsement policy
|
||||
for a reference rate entry is set to the provider of the corresponding reference
|
||||
rate, such as LSE for LIBOR.
|
||||
The reference rate could also be modeled via a separate chaincode, where the
|
||||
chaincode-level endorsement policies only allows reference rate providers to
|
||||
create keys.
|
||||
|
||||
Taken together, here is an example of the KVS entries involved in a swap:
|
||||
```
|
||||
KEY | VALUE
|
||||
-------------|-----------------------------------------------------
|
||||
swap1 | {StartDate: 2018-10-01, ..., ReferenceRate: "libor"}
|
||||
payment1 | "none"
|
||||
rr_libor | 0.27
|
||||
```
|
||||
In this example, the swap with ID 1 is represented by the `swap1` and `payment1`
|
||||
KVS entries. The reference rate is set to `libor`, which will cause the chaincode
|
||||
to look up the `rr_libor` entry in the KVS to calculate the rate for the
|
||||
floating leg of the swap.
|
||||
|
||||
## Chaincode
|
||||
The interest-rate swap chaincode provides the following API:
|
||||
* `createSwap(swapID, swap_info, partyA, partyB)` - create a new swap with the
|
||||
given identifier and swap parameters among the two parties specified. This
|
||||
function creates the entry for the swap and the corresponding payment. It
|
||||
also sets the key-level endorsement policies for both keys to the participants
|
||||
to the swap. In case the swap's prinicpal amount exceeds a certain threshold,
|
||||
it adds an auditor to the endorsement policy for the keys.
|
||||
* `calculatePayment(swapID)` - calculate the net payment from party A to party
|
||||
B and set the payment entry accordingly. If the payment information is negative,
|
||||
the payment due flows from B to A. The payment information is calculated based
|
||||
on the rates specified in the swap and the principal amount. If the payment
|
||||
key is not "none", this function returns an error, indicating that a prior
|
||||
payment has not been settled yet.
|
||||
* `settlePayment(swapID)` - set the payment entry for the given swap ID to "none".
|
||||
This function is supposed to be invoked after the two parties have settled the
|
||||
payment off-chain.
|
||||
* `setReferenceRate(rrID, value)` - set a given reference rate to a given value.
|
||||
* `Init(auditor, threshold, rrProviders...)` - the chaincode namespace is initialized
|
||||
with a threshold for the principal amount above which a designated auditor
|
||||
needs to be involved as well as a list of reference rate providers and rate IDs.
|
||||
|
||||
## Trust model
|
||||
The state-based endorsement policies used in this sample ensure the following
|
||||
trust model:
|
||||
* All operations related to a specific swap need to be endorsed (at least) by
|
||||
the participants to that swap. This includes both creation of a swap, as well
|
||||
as calculating the payment information and agreeing that the payments have
|
||||
been settled.
|
||||
* Operations related to a reference rate need to be endorsed by the provider of
|
||||
a reference rate.
|
||||
* Under certain circumstances an auditor needs to endorse operations for a swap,
|
||||
e.g., if it exceeds a threshold for the principal amount.
|
||||
|
||||
The chaincode-level endorsement policy requires at least one potential swap
|
||||
participant and an auditor. This endorsement policy sets the trust relationship
|
||||
for creating a swap.
|
||||
|
||||
## Sample network
|
||||
|
||||
The `network` subdirectory contains scripts that will launch a sample network
|
||||
and run a swap transaction flow from creation to settlement.
|
||||
|
||||
### Prerequesites
|
||||
|
||||
The following prerequisites are needed to run this sample:
|
||||
* Fabric docker images. By default the `network/network.sh` script will look for
|
||||
fabric images with the `latest` tag, this can be adapted with the `-i` command
|
||||
line parameter of the script.
|
||||
* A local installation of `configtxgen` and `cryptogen` in the `PATH` environment,
|
||||
or included in `fabric-samples/bin` directory.
|
||||
* Vendoring the chaincode. In the chaincode directory, run `govendor init` and
|
||||
`govendor add +external` to vendor the shim from your local copy of fabric.
|
||||
|
||||
### Bringing up the network
|
||||
|
||||
Simply run `network.sh up` to bring up the network. This will spawn docker
|
||||
containers running a network of 3 "regular" organizations, one auditor
|
||||
organization and one reference rate provider as well as a solo orderer.
|
||||
|
||||
An additional CLI container will run `network/scripts/script.sh` to join the
|
||||
peers to the `irs` channel and deploy the chaincode. In the init parameters it
|
||||
supplies the audit threshold, the auditor organization and the reference rate
|
||||
provider with the corresponding reference rate ID. In the following transactions
|
||||
it sets the reference rate, creates a swap, calculates payment information for
|
||||
the swap and marks them as settled afterwards. We will show the corresponding
|
||||
commands in the following section.
|
||||
|
||||
### Transactions
|
||||
|
||||
The chaincode is instantiated as follows:
|
||||
```
|
||||
peer chaincode instantiate -o irs-orderer:7050 -C irs -n irscc -l golang -v 0 -c '{"Args":["init","auditor","100000","rrprovider","myrr"]}' -P "AND(OR('partya.peer','partyb.peer','partyc.peer'), 'auditor.peer')"
|
||||
```
|
||||
This sets an auditing threshold of 1M, above which the `auditor` organization
|
||||
needs to be involved. It also specifies the `myrr` reference rate provided by
|
||||
the `rrprovider` organization.
|
||||
|
||||
To set a reference rate:
|
||||
```
|
||||
peer chaincode invoke -o irs-orderer:7050 -C irs --waitForEvent -n irscc --peerAddresses irs-rrprovider:7051 -c '{"Args":["setReferenceRate","myrr","3"]}'
|
||||
```
|
||||
Note that the transaction is endorsed by a peer of the organization we have
|
||||
specified as providing this reference rate in the init parameters.
|
||||
|
||||
To create a swap named "myswap":
|
||||
```
|
||||
peer chaincode invoke -o irs-orderer:7050 -C irs --waitForEvent -n irscc --peerAddresses irs-partya:7051 --peerAddresses irs-partyb:7051 --peerAddresses irs-auditor:7051 -c '{"Args":["createSwap","myswap","{\"StartDate\":\"2018-09-27T15:04:05Z\",\"EndDate\":\"2018-09-30T15:04:05Z\",\"PaymentInterval\":365,\"PrincipalAmount\":10000000,\"FixedRate\":4,\"FloatingRate\":5,\"ReferenceRate\":\"myrr\"}", "partya", "partyb"]}'
|
||||
```
|
||||
Note that the transaction is endorsed by both parties that are part of this
|
||||
swap as well as the auditor. Since the principal amount in this case is lower
|
||||
than the audit threshold we set as init parameters, no auditor will be required
|
||||
to endorse changes to the payment info or swap details.
|
||||
|
||||
To calculate payment info for "myswap":
|
||||
```
|
||||
peer chaincode invoke -o irs-orderer:7050 -C irs --waitForEvent -n irscc --peerAddresses irs-partya:7051 --peerAddresses irs-partyb:7051 -c '{"Args":["calculatePayment","myswap"]}'
|
||||
```
|
||||
Note that we target only peers of
|
||||
party A and party B, since the swap is below the auditing threshold.
|
||||
|
||||
To settle payment of "myswap":
|
||||
```
|
||||
peer chaincode invoke -o irs-orderer:7050 -C irs --waitForEvent -n irscc `--peerAddresses irs-partya:7051 --peerAddresses irs-partyb:7051 -c '{"Args":["settlePayment","myswap"]}'
|
||||
```
|
||||
|
||||
As an exercise, try to create a new swap above the auditing threshold and see
|
||||
how validation fails if the auditor is not involved in every operation on the
|
||||
swap. Also try to calculate payment info before settling a prior payment to a
|
||||
swap.
|
||||
313
interest_rate_swaps/chaincode/chaincode.go
Normal file
313
interest_rate_swaps/chaincode/chaincode.go
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
/*
|
||||
Copyright IBM Corp. All Rights Reserved.
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/hyperledger/fabric/core/chaincode/shim"
|
||||
"github.com/hyperledger/fabric/core/chaincode/shim/ext/statebased"
|
||||
pb "github.com/hyperledger/fabric/protos/peer"
|
||||
)
|
||||
|
||||
/* InterestRateSwap represents an interest rate swap on the ledger
|
||||
* The swap is active between its start- and end-date.
|
||||
* At the specified interval, two parties A and B exchange the following payments:
|
||||
* A->B (PrincipalAmount * FixedRateBPS) / 100
|
||||
* B->A (PrincipalAmount * (ReferenceRateBPS + FloatingRateBPS)) / 100
|
||||
* We represent rates as basis points, with one basis point being equal to 1/100th
|
||||
* of 1% (see https://www.investopedia.com/terms/b/basispoint.asp)
|
||||
*/
|
||||
type InterestRateSwap struct {
|
||||
StartDate time.Time
|
||||
EndDate time.Time
|
||||
PaymentInterval time.Duration
|
||||
PrincipalAmount uint64
|
||||
FixedRateBPS uint64
|
||||
FloatingRateBPS uint64
|
||||
ReferenceRate string
|
||||
}
|
||||
|
||||
/*
|
||||
SwapManager is the chaincode that handles interest rate swaps.
|
||||
The chaincode endorsement policy includes an auditing organization.
|
||||
It provides the following functions:
|
||||
-) createSwap: create swap with participants
|
||||
-) calculatePayment: calculate what needs to be paid
|
||||
-) settlePayment: mark payment done
|
||||
-) setReferenceRate: for providers to set the reference rate
|
||||
|
||||
The SwapManager stores three different kinds of information on the ledger:
|
||||
-) the actual swap data ("swap" + ID)
|
||||
-) the payment information ("payment" + ID), if "none", the payment has been settled
|
||||
-) the reference rate ("rr" + ID)
|
||||
*/
|
||||
type SwapManager struct {
|
||||
}
|
||||
|
||||
// Init callback
|
||||
func (cc *SwapManager) Init(stub shim.ChaincodeStubInterface) pb.Response {
|
||||
args := stub.GetArgs()
|
||||
if len(args) < 5 {
|
||||
return shim.Error("Insufficient number of arguments. Expected: <function> <auditor_MSPID> <audit_threshold> <rr_provider1_MSPID> <rr_provider1_rateID> ... <rr_providerN_MSPID> <rr_providerN_rateID>")
|
||||
}
|
||||
// set the limit above which the auditor needs to be involved, require it
|
||||
// to be endorsed by the auditor
|
||||
err := stub.PutState("audit_limit", args[2])
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
auditorEP, err := statebased.NewStateEP(nil)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
err = auditorEP.AddOrgs(statebased.RoleTypePeer, string(args[1]))
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
epBytes, err := auditorEP.Policy()
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
err = stub.SetStateValidationParameter("audit_limit", epBytes)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
|
||||
// create the reference rates, require them to be endorsed by the provider
|
||||
for i := 3; i+1 < len(args); i += 2 {
|
||||
org := string(args[i])
|
||||
rrID := "rr" + string(args[i+1])
|
||||
err = stub.PutState(rrID, []byte("0"))
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
ep, err := statebased.NewStateEP(nil)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
err = ep.AddOrgs(statebased.RoleTypePeer, org)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
epBytes, err = ep.Policy()
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
err = stub.SetStateValidationParameter(rrID, epBytes)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return shim.Success([]byte{})
|
||||
}
|
||||
|
||||
// Invoke dispatcher
|
||||
func (cc *SwapManager) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
|
||||
funcName, _ := stub.GetFunctionAndParameters()
|
||||
if function, ok := functions[funcName]; ok {
|
||||
fmt.Printf("Invoking %s\n", funcName)
|
||||
return function(stub)
|
||||
}
|
||||
return shim.Error(fmt.Sprintf("Unknown function %s", funcName))
|
||||
}
|
||||
|
||||
var functions = map[string]func(stub shim.ChaincodeStubInterface) pb.Response{
|
||||
"createSwap": createSwap,
|
||||
"calculatePayment": calculatePayment,
|
||||
"settlePayment": settlePayment,
|
||||
"setReferenceRate": setReferenceRate,
|
||||
}
|
||||
|
||||
// Create a new swap among participants.
|
||||
// The creation of the swap needs to be endorsed by the chaincode endorsement policy.
|
||||
// Once created, the swap needs to be endorsed by its participants as well as the
|
||||
// auditor in case the principal amount of the swap exceeds the audit threshold.
|
||||
// This is enforced through the state-based endorsement policy that is set in this
|
||||
// function.
|
||||
// Parameters: swap ID, a JSONized InterestRateSwap, MSP ID of participant 1,
|
||||
// MSP ID of participant 2
|
||||
func createSwap(stub shim.ChaincodeStubInterface) pb.Response {
|
||||
_, parameters := stub.GetFunctionAndParameters()
|
||||
if len(parameters) != 4 {
|
||||
return shim.Error("Wrong number of arguments supplied. Expected: <swap_ID> <interest_rate_swap_json> <participant1_MSPID> <participant2_MSPID>")
|
||||
}
|
||||
|
||||
// create the swap
|
||||
swapID := "swap" + string(parameters[0])
|
||||
irsJSON := []byte(parameters[1])
|
||||
var irs InterestRateSwap
|
||||
err := json.Unmarshal(irsJSON, &irs)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
err = stub.PutState(swapID, irsJSON)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
|
||||
// get the auditing threshold
|
||||
auditLimit, err := stub.GetState("audit_limit")
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
threshold, err := strconv.Atoi(string(auditLimit))
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
|
||||
// set endorsers
|
||||
ep, err := statebased.NewStateEP(nil)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
err = ep.AddOrgs(statebased.RoleTypePeer, parameters[2], parameters[3])
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
// if the swap principal amount exceeds the audit threshold set in init, the auditor needs to endorse as well
|
||||
if irs.PrincipalAmount > uint64(threshold) {
|
||||
fmt.Printf("Adding auditor for swap %s with prinicipal amount %v above threshold %v\n", parameters[0], irs.PrincipalAmount, uint64(threshold))
|
||||
err = ep.AddOrgs(statebased.RoleTypePeer, "auditor")
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// set the endorsement policy for the swap
|
||||
epBytes, err := ep.Policy()
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
err = stub.SetStateValidationParameter(swapID, epBytes)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
|
||||
// create and set the key for the payment
|
||||
paymentID := "payment" + string(parameters[0])
|
||||
err = stub.PutState(paymentID, []byte("none"))
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
err = stub.SetStateValidationParameter(paymentID, epBytes)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
|
||||
return shim.Success([]byte{})
|
||||
}
|
||||
|
||||
// Calculate the payment due for a given swap
|
||||
func calculatePayment(stub shim.ChaincodeStubInterface) pb.Response {
|
||||
_, parameters := stub.GetFunctionAndParameters()
|
||||
if len(parameters) != 1 {
|
||||
return shim.Error("Wrong number of arguments supplied. Expected: <swap_ID>")
|
||||
}
|
||||
|
||||
// retrieve swap
|
||||
swapID := "swap" + parameters[0]
|
||||
irsJSON, err := stub.GetState(swapID)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
if irsJSON == nil {
|
||||
return shim.Error(fmt.Sprintf("Swap %s does not exist", parameters[0]))
|
||||
}
|
||||
var irs InterestRateSwap
|
||||
err = json.Unmarshal(irsJSON, &irs)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
|
||||
// check if the previous payment has been settled
|
||||
paymentID := "payment" + parameters[0]
|
||||
paid, err := stub.GetState(paymentID)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
if paid == nil {
|
||||
return shim.Error("Unexpected error: payment entry is nil. This should not happen.")
|
||||
}
|
||||
if string(paid) != "none" {
|
||||
return shim.Error("Previous payment has not been settled yet")
|
||||
}
|
||||
|
||||
// get reference rate
|
||||
referenceRateBytes, err := stub.GetState("rr" + irs.ReferenceRate)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
if referenceRateBytes == nil {
|
||||
return shim.Error(fmt.Sprintf("Reference rate %s not found", irs.ReferenceRate))
|
||||
}
|
||||
referenceRate, err := strconv.Atoi(string(referenceRateBytes))
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
|
||||
// calculate payment
|
||||
p1 := int((irs.PrincipalAmount * irs.FixedRateBPS) / 100)
|
||||
p2 := int((irs.PrincipalAmount * (irs.FloatingRateBPS + uint64(referenceRate))) / 100)
|
||||
payment := strconv.Itoa(p1 - p2)
|
||||
err = stub.PutState(paymentID, []byte(payment))
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
|
||||
return shim.Success([]byte(payment))
|
||||
}
|
||||
|
||||
// Settle the payment for a given swap
|
||||
func settlePayment(stub shim.ChaincodeStubInterface) pb.Response {
|
||||
_, parameters := stub.GetFunctionAndParameters()
|
||||
if len(parameters) != 1 {
|
||||
return shim.Error("Wrong number of arguments supplied. Expected: <swap_ID>")
|
||||
}
|
||||
paymentID := "payment" + parameters[0]
|
||||
paid, err := stub.GetState(paymentID)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
if paid == nil {
|
||||
return shim.Error("Unexpected error: payment entry is nil. This should not happen.")
|
||||
}
|
||||
if string(paid) == "none" {
|
||||
return shim.Error("Payment has already been settled.")
|
||||
}
|
||||
err = stub.PutState(paymentID, []byte("none"))
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
return shim.Success([]byte{})
|
||||
}
|
||||
|
||||
// Set the reference rate for a given rate provider
|
||||
func setReferenceRate(stub shim.ChaincodeStubInterface) pb.Response {
|
||||
_, parameters := stub.GetFunctionAndParameters()
|
||||
if len(parameters) != 2 {
|
||||
return shim.Error("Wrong number of arguments supplied. Expected: <reference_rate_ID> <reference_rate_BPS>")
|
||||
}
|
||||
|
||||
rrID := "rr" + parameters[0]
|
||||
err := stub.PutState(rrID, []byte(parameters[1]))
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
return shim.Success([]byte{})
|
||||
}
|
||||
|
||||
func main() {
|
||||
err := shim.Start(new(SwapManager))
|
||||
if err != nil {
|
||||
fmt.Printf("Error starting IRS chaincode: %s", err)
|
||||
}
|
||||
}
|
||||
192
interest_rate_swaps/network/configtx.yaml
Normal file
192
interest_rate_swaps/network/configtx.yaml
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
# Copyright IBM Corp. All Rights Reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
Organizations:
|
||||
- &orderer
|
||||
Name: orderer
|
||||
ID: orderer
|
||||
MSPDir: crypto-config/ordererOrganizations/example.com/msp
|
||||
Policies:
|
||||
Readers:
|
||||
Type: Signature
|
||||
Rule: OR('orderer.member')
|
||||
Writers:
|
||||
Type: Signature
|
||||
Rule: OR('orderer.member')
|
||||
Admins:
|
||||
Type: Signature
|
||||
Rule: OR('orderer.admin')
|
||||
|
||||
|
||||
- &partya
|
||||
Name: partya
|
||||
ID: partya
|
||||
MSPDir: crypto-config/peerOrganizations/partya.example.com/msp
|
||||
Policies:
|
||||
Readers:
|
||||
Type: Signature
|
||||
Rule: OR('partya.admin', 'partya.peer', 'partya.client')
|
||||
Writers:
|
||||
Type: Signature
|
||||
Rule: OR('partya.admin', 'partya.client')
|
||||
Admins:
|
||||
Type: Signature
|
||||
Rule: OR('partya.admin')
|
||||
AnchorPeers:
|
||||
- Host: irs-partya
|
||||
Port: 7051
|
||||
|
||||
- &partyb
|
||||
Name: partyb
|
||||
ID: partyb
|
||||
MSPDir: crypto-config/peerOrganizations/partyb.example.com/msp
|
||||
Policies:
|
||||
Readers:
|
||||
Type: Signature
|
||||
Rule: OR('partyb.admin', 'partyb.peer', 'partyb.client')
|
||||
Writers:
|
||||
Type: Signature
|
||||
Rule: OR('partyb.admin', 'partyb.client')
|
||||
Admins:
|
||||
Type: Signature
|
||||
Rule: OR('partyb.admin')
|
||||
AnchorPeers:
|
||||
- Host: irs-partyb
|
||||
Port: 7051
|
||||
|
||||
- &partyc
|
||||
Name: partyc
|
||||
ID: partyc
|
||||
MSPDir: crypto-config/peerOrganizations/partyc.example.com/msp
|
||||
Policies:
|
||||
Readers:
|
||||
Type: Signature
|
||||
Rule: OR('partyc.admin', 'partyc.peer', 'partyc.client')
|
||||
Writers:
|
||||
Type: Signature
|
||||
Rule: OR('partyc.admin', 'partyc.client')
|
||||
Admins:
|
||||
Type: Signature
|
||||
Rule: OR('partyc.admin')
|
||||
AnchorPeers:
|
||||
- Host: irs-partyc
|
||||
Port: 7051
|
||||
|
||||
- &auditor
|
||||
Name: auditor
|
||||
ID: auditor
|
||||
MSPDir: crypto-config/peerOrganizations/auditor.example.com/msp
|
||||
Policies:
|
||||
Readers:
|
||||
Type: Signature
|
||||
Rule: OR('auditor.admin', 'auditor.peer', 'auditor.client')
|
||||
Writers:
|
||||
Type: Signature
|
||||
Rule: OR('auditor.admin', 'auditor.client')
|
||||
Admins:
|
||||
Type: Signature
|
||||
Rule: OR('auditor.admin')
|
||||
AnchorPeers:
|
||||
- Host: irs-auditor
|
||||
Port: 7051
|
||||
|
||||
- &rrprovider
|
||||
Name: rrprovider
|
||||
ID: rrprovider
|
||||
MSPDir: crypto-config/peerOrganizations/rrprovider.example.com/msp
|
||||
Policies:
|
||||
Readers:
|
||||
Type: Signature
|
||||
Rule: OR('rrprovider.admin', 'rrprovider.peer', 'rrprovider.client')
|
||||
Writers:
|
||||
Type: Signature
|
||||
Rule: OR('rrprovider.admin', 'rrprovider.client')
|
||||
Admins:
|
||||
Type: Signature
|
||||
Rule: OR('rrprovider.admin')
|
||||
AnchorPeers:
|
||||
- Host: irs-rrprovider
|
||||
Port: 7051
|
||||
|
||||
Channel: &ChannelDefaults
|
||||
Capabilities:
|
||||
V1_3: true
|
||||
Policies:
|
||||
Readers:
|
||||
Type: ImplicitMeta
|
||||
Rule: ANY Readers
|
||||
Writers:
|
||||
Type: ImplicitMeta
|
||||
Rule: ANY Writers
|
||||
Admins:
|
||||
Type: ImplicitMeta
|
||||
Rule: MAJORITY Admins
|
||||
|
||||
Orderer: &OrdererDefaults
|
||||
OrdererType: solo
|
||||
Capabilities:
|
||||
V1_1: true
|
||||
Addresses:
|
||||
- irs-orderer:7050
|
||||
BatchTimeout: 2s
|
||||
BatchSize:
|
||||
MaxMessageCount: 10
|
||||
AbsoluteMaxBytes: 99 MB
|
||||
PreferredMaxBytes: 512 KB
|
||||
Policies:
|
||||
Readers:
|
||||
Type: ImplicitMeta
|
||||
Rule: ANY Readers
|
||||
Writers:
|
||||
Type: ImplicitMeta
|
||||
Rule: ANY Writers
|
||||
Admins:
|
||||
Type: ImplicitMeta
|
||||
Rule: MAJORITY Admins
|
||||
BlockValidation:
|
||||
Type: ImplicitMeta
|
||||
Rule: ANY Writers
|
||||
Organizations:
|
||||
|
||||
Application: &ApplicationDefaults
|
||||
Capabilities:
|
||||
V1_3: true
|
||||
Policies:
|
||||
Readers:
|
||||
Type: ImplicitMeta
|
||||
Rule: ANY Readers
|
||||
Writers:
|
||||
Type: ImplicitMeta
|
||||
Rule: ANY Writers
|
||||
Admins:
|
||||
Type: ImplicitMeta
|
||||
Rule: MAJORITY Admins
|
||||
Organizations:
|
||||
|
||||
Profiles:
|
||||
IRSNetGenesis:
|
||||
<<: *ChannelDefaults
|
||||
Orderer:
|
||||
<<: *OrdererDefaults
|
||||
Organizations:
|
||||
- *orderer
|
||||
Consortiums:
|
||||
SampleConsortium:
|
||||
Organizations:
|
||||
- *partya
|
||||
- *partyb
|
||||
- *partyc
|
||||
- *rrprovider
|
||||
- *auditor
|
||||
IRSChannel:
|
||||
Consortium: SampleConsortium
|
||||
Application:
|
||||
<<: *ApplicationDefaults
|
||||
Organizations:
|
||||
- *partya
|
||||
- *partyb
|
||||
- *partyc
|
||||
- *rrprovider
|
||||
- *auditor
|
||||
51
interest_rate_swaps/network/crypto-config.yaml
Normal file
51
interest_rate_swaps/network/crypto-config.yaml
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# Copyright IBM Corp. All Rights Reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
OrdererOrgs:
|
||||
- Name: orderer
|
||||
Domain: example.com
|
||||
Specs:
|
||||
- Hostname: orderer
|
||||
|
||||
PeerOrgs:
|
||||
- Name: partya
|
||||
Domain: partya.example.com
|
||||
EnableNodeOUs: true
|
||||
Template:
|
||||
Count: 1
|
||||
Users:
|
||||
Count: 1
|
||||
|
||||
- Name: partyb
|
||||
Domain: partyb.example.com
|
||||
EnableNodeOUs: true
|
||||
Template:
|
||||
Count: 1
|
||||
Users:
|
||||
Count: 1
|
||||
|
||||
- Name: partyc
|
||||
Domain: partyc.example.com
|
||||
EnableNodeOUs: true
|
||||
Template:
|
||||
Count: 1
|
||||
Users:
|
||||
Count: 1
|
||||
|
||||
- Name: auditor
|
||||
Domain: auditor.example.com
|
||||
EnableNodeOUs: true
|
||||
Template:
|
||||
Count: 1
|
||||
Users:
|
||||
Count: 1
|
||||
|
||||
- Name: rrprovider
|
||||
Domain: rrprovider.example.com
|
||||
EnableNodeOUs: true
|
||||
Template:
|
||||
Count: 1
|
||||
Users:
|
||||
Count: 1
|
||||
163
interest_rate_swaps/network/docker-compose.yaml
Normal file
163
interest_rate_swaps/network/docker-compose.yaml
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
# Copyright IBM Corp. All Rights Reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
version: '2'
|
||||
|
||||
volumes:
|
||||
orderer.example.com:
|
||||
peer0.partya.example.com:
|
||||
peer0.partyb.example.com:
|
||||
peer0.partyc.example.com:
|
||||
peer0.auditor.example.com:
|
||||
peer0.rrprovider.example.com:
|
||||
|
||||
services:
|
||||
peer-base:
|
||||
image: hyperledger/fabric-peer:$IMAGE_TAG
|
||||
environment:
|
||||
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
|
||||
- FABRIC_LOGGING_SPEC=INFO
|
||||
- CORE_PEER_TLS_ENABLED=false
|
||||
- CORE_PEER_GOSSIP_USELEADERELECTION=true
|
||||
- CORE_PEER_GOSSIP_ORGLEADER=false
|
||||
- CORE_PEER_PROFILE_ENABLED=true
|
||||
- CORE_PEER_ADDRESSAUTODETECT=true
|
||||
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
|
||||
command: peer node start
|
||||
volumes:
|
||||
- /var/run/:/host/var/run/
|
||||
|
||||
orderer:
|
||||
container_name: irs-orderer
|
||||
image: hyperledger/fabric-orderer:$IMAGE_TAG
|
||||
environment:
|
||||
- FABRIC_LOGGING_SPEC=INFO
|
||||
- ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
|
||||
- ORDERER_GENERAL_GENESISMETHOD=file
|
||||
- ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
|
||||
- ORDERER_GENERAL_LOCALMSPID=orderer
|
||||
- ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
|
||||
- ORDERER_GENERAL_TLS_ENABLED=false
|
||||
working_dir: /opt/gopath/src/github.com/hyperledger/fabric
|
||||
command: orderer
|
||||
volumes:
|
||||
- ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
|
||||
- ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp
|
||||
- orderer.example.com:/var/hyperledger/production/orderer
|
||||
ports:
|
||||
- 7050:7050
|
||||
|
||||
|
||||
partya:
|
||||
container_name: irs-partya
|
||||
extends:
|
||||
service: peer-base
|
||||
environment:
|
||||
- CORE_PEER_ID=partya.peer0
|
||||
- CORE_PEER_ADDRESS=irs-partya:7051
|
||||
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=irs-partya:7051
|
||||
- CORE_PEER_LOCALMSPID=partya
|
||||
- CORE_CHAINCODE_LOGGING_SHIM=INFO
|
||||
volumes:
|
||||
- ./crypto-config/peerOrganizations/partya.example.com/peers/peer0.partya.example.com/msp:/etc/hyperledger/fabric/msp
|
||||
- peer0.partya.example.com:/var/hyperledger/production
|
||||
ports:
|
||||
- 7051:7051
|
||||
- 7053:7053
|
||||
|
||||
partyb:
|
||||
container_name: irs-partyb
|
||||
extends:
|
||||
service: peer-base
|
||||
environment:
|
||||
- CORE_PEER_ID=partyb.peer0
|
||||
- CORE_PEER_ADDRESS=irs-partyb:7051
|
||||
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=irs-partyb:7051
|
||||
- CORE_PEER_LOCALMSPID=partyb
|
||||
volumes:
|
||||
- ./crypto-config/peerOrganizations/partyb.example.com/peers/peer0.partyb.example.com/msp:/etc/hyperledger/fabric/msp
|
||||
- peer0.partyb.example.com:/var/hyperledger/production
|
||||
ports:
|
||||
- 8051:7051
|
||||
- 8053:7053
|
||||
|
||||
partyc:
|
||||
container_name: irs-partyc
|
||||
extends:
|
||||
service: peer-base
|
||||
environment:
|
||||
- CORE_PEER_ID=partyc.peer0
|
||||
- CORE_PEER_ADDRESS=irs-partyc:7051
|
||||
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=irs-partyc:7051
|
||||
- CORE_PEER_LOCALMSPID=partyc
|
||||
volumes:
|
||||
- ./crypto-config/peerOrganizations/partyc.example.com/peers/peer0.partyc.example.com/msp:/etc/hyperledger/fabric/msp
|
||||
- peer0.partyc.example.com:/var/hyperledger/production
|
||||
ports:
|
||||
- 9051:7051
|
||||
- 9053:7053
|
||||
|
||||
auditor:
|
||||
container_name: irs-auditor
|
||||
extends:
|
||||
service: peer-base
|
||||
environment:
|
||||
- CORE_PEER_ID=auditor.peer0
|
||||
- CORE_PEER_ADDRESS=irs-auditor:7051
|
||||
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=irs-auditor:7051
|
||||
- CORE_PEER_LOCALMSPID=auditor
|
||||
volumes:
|
||||
- ./crypto-config/peerOrganizations/auditor.example.com/peers/peer0.auditor.example.com/msp:/etc/hyperledger/fabric/msp
|
||||
- peer0.auditor.example.com:/var/hyperledger/production
|
||||
ports:
|
||||
- 10051:7051
|
||||
- 10053:7053
|
||||
|
||||
rrprovider:
|
||||
container_name: irs-rrprovider
|
||||
extends:
|
||||
service: peer-base
|
||||
environment:
|
||||
- CORE_PEER_ID=rrprovider.peer0
|
||||
- CORE_PEER_ADDRESS=irs-rrprovider:7051
|
||||
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=irs-rrprovider:7051
|
||||
- CORE_PEER_LOCALMSPID=rrprovider
|
||||
- CORE_LOGGING_LEVEL=DEBUG
|
||||
volumes:
|
||||
- ./crypto-config/peerOrganizations/rrprovider.example.com/peers/peer0.rrprovider.example.com/msp:/etc/hyperledger/fabric/msp
|
||||
- peer0.rrprovider.example.com:/var/hyperledger/production
|
||||
ports:
|
||||
- 11051:7051
|
||||
- 11053:7053
|
||||
|
||||
cli:
|
||||
container_name: cli
|
||||
image: hyperledger/fabric-tools:$IMAGE_TAG
|
||||
tty: true
|
||||
stdin_open: true
|
||||
environment:
|
||||
- GOPATH=/opt/gopath
|
||||
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
|
||||
- FABRIC_LOGGING_SPEC=INFO
|
||||
- CORE_PEER_ID=cli
|
||||
- CORE_PEER_ADDRESS=irs-partya:7051
|
||||
- CORE_PEER_LOCALMSPID=partya
|
||||
- CORE_PEER_TLS_ENABLED=false
|
||||
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/partya.example.com/users/Admin@partya.example.com/msp
|
||||
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
|
||||
command: /bin/bash
|
||||
volumes:
|
||||
- /var/run/:/host/var/run/
|
||||
- ../chaincode/:/opt/gopath/src/irscc
|
||||
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
|
||||
- ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/
|
||||
- ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
|
||||
depends_on:
|
||||
- orderer
|
||||
- partya
|
||||
- partyb
|
||||
- partyc
|
||||
- auditor
|
||||
- rrprovider
|
||||
240
interest_rate_swaps/network/network.sh
Executable file
240
interest_rate_swaps/network/network.sh
Executable file
|
|
@ -0,0 +1,240 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright IBM Corp All Rights Reserved
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# This script brings up a test network for the interest-rate swap fabric example.
|
||||
# It relies on two tools:
|
||||
# * cryptogen - generates the x509 certificates used to identify and
|
||||
# authenticate the various components in the network.
|
||||
# * configtxgen - generates the requisite configuration artifacts for orderer
|
||||
# bootstrap and channel creation.
|
||||
#
|
||||
# Each tool consumes a configuration yaml file, within which we specify the topology
|
||||
# of our network (cryptogen) and the location of our certificates for various
|
||||
# configuration operations (configtxgen). Once the tools have been successfully run,
|
||||
# we are able to launch our network. More detail on the tools and the structure of
|
||||
# the network will be provided later in this document. For now, let's get going...
|
||||
|
||||
# prepending $PWD/../bin to PATH to ensure we are picking up the correct binaries
|
||||
# this may be commented out to resolve installed version of tools if desired
|
||||
export PATH=${PWD}/../../bin:${PWD}:$PATH
|
||||
export FABRIC_CFG_PATH=${PWD}
|
||||
export VERBOSE=false
|
||||
|
||||
# Print the usage message
|
||||
function printHelp() {
|
||||
echo "Usage: "
|
||||
echo " start_network.sh <mode> [-t <timeout>] [-i <imagetag>] [-v]"
|
||||
echo " <mode> - one of 'up', 'down' or 'generate'"
|
||||
echo " - 'up' - bring up the network with docker-compose up"
|
||||
echo " - 'down' - clear the network with docker-compose down"
|
||||
echo " - 'generate' - generate required certificates and genesis block"
|
||||
echo " -t <timeout> - CLI timeout duration in seconds (defaults to 10)"
|
||||
echo " -i <imagetag> - the tag to be used to launch the network (defaults to \"latest\")"
|
||||
echo " -v - verbose mode"
|
||||
echo
|
||||
echo "Typically, one would first generate the required certificates and "
|
||||
echo "genesis block, then bring up the network."
|
||||
}
|
||||
|
||||
# Obtain CONTAINER_IDS and remove them
|
||||
# TODO Might want to make this optional - could clear other containers
|
||||
function clearContainers() {
|
||||
CONTAINER_IDS=$(docker ps -a | awk '($2 ~ /dev-.*irscc.*/) {print $1}')
|
||||
if [ -z "$CONTAINER_IDS" -o "$CONTAINER_IDS" == " " ]; then
|
||||
echo "---- No containers available for deletion ----"
|
||||
else
|
||||
docker rm -f $CONTAINER_IDS
|
||||
fi
|
||||
}
|
||||
|
||||
# Delete any images that were generated as a part of this setup
|
||||
# specifically the following images are often left behind:
|
||||
# TODO list generated image naming patterns
|
||||
function removeUnwantedImages() {
|
||||
DOCKER_IMAGE_IDS=$(docker images | awk '($1 ~ /dev.*irscc.*/) {print $3}')
|
||||
if [ -z "$DOCKER_IMAGE_IDS" -o "$DOCKER_IMAGE_IDS" == " " ]; then
|
||||
echo "---- No images available for deletion ----"
|
||||
else
|
||||
docker rmi -f $DOCKER_IMAGE_IDS
|
||||
fi
|
||||
}
|
||||
|
||||
# Versions of fabric known not to work with this release of first-network
|
||||
BLACKLISTED_VERSIONS="^1\.0\. ^1\.1\.0-preview ^1\.1\.0-alpha"
|
||||
|
||||
# Do some basic sanity checking to make sure that the appropriate versions of fabric
|
||||
# binaries/images are available. In the future, additional checking for the presence
|
||||
# of go or other items could be added.
|
||||
function checkPrereqs() {
|
||||
# Note, we check configtxlator externally because it does not require a config file, and peer in the
|
||||
# docker image because of FAB-8551 that makes configtxlator return 'development version' in docker
|
||||
LOCAL_VERSION=$(configtxgen -version | sed -ne 's/ Version: //p')
|
||||
DOCKER_IMAGE_VERSION=$(docker run --rm hyperledger/fabric-tools:$IMAGETAG peer version | sed -ne 's/ Version: //p' | head -1)
|
||||
|
||||
echo "LOCAL_VERSION=$LOCAL_VERSION"
|
||||
echo "DOCKER_IMAGE_VERSION=$DOCKER_IMAGE_VERSION"
|
||||
|
||||
if [ "$LOCAL_VERSION" != "$DOCKER_IMAGE_VERSION" ]; then
|
||||
echo "=================== WARNING ==================="
|
||||
echo " Local fabric binaries and docker images are "
|
||||
echo " out of sync. This may cause problems. "
|
||||
echo "==============================================="
|
||||
fi
|
||||
|
||||
for UNSUPPORTED_VERSION in $BLACKLISTED_VERSIONS; do
|
||||
echo "$LOCAL_VERSION" | grep -q $UNSUPPORTED_VERSION
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "ERROR! Local Fabric binary version of $LOCAL_VERSION does not match this newer version of BYFN and is unsupported. Either move to a later version of Fabric or checkout an earlier version of fabric-samples."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$DOCKER_IMAGE_VERSION" | grep -q $UNSUPPORTED_VERSION
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "ERROR! Fabric Docker image version of $DOCKER_IMAGE_VERSION does not match this newer version of BYFN and is unsupported. Either move to a later version of Fabric or checkout an earlier version of fabric-samples."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Generate the needed certificates, the genesis block and start the network.
|
||||
function networkUp() {
|
||||
checkPrereqs
|
||||
# generate artifacts if they don't exist
|
||||
if [ ! -d "crypto-config" ]; then
|
||||
generateCerts
|
||||
generateChannelArtifacts
|
||||
fi
|
||||
IMAGE_TAG=$IMAGETAG docker-compose -f $COMPOSE_FILE up -d orderer partya partyb partyc auditor rrprovider cli 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR !!!! Unable to start network"
|
||||
exit 1
|
||||
fi
|
||||
# now run the end to end script
|
||||
docker exec cli scripts/script.sh
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR !!!! Test failed"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Tear down running network
|
||||
function networkDown() {
|
||||
# stop org3 containers also in addition to org1 and org2, in case we were running sample to add org3
|
||||
docker-compose -f $COMPOSE_FILE down --volumes --remove-orphans
|
||||
|
||||
# Bring down the network, deleting the volumes
|
||||
#Delete any ledger backups
|
||||
docker run -v $PWD:/tmp/first-network --rm hyperledger/fabric-tools:$IMAGETAG rm -Rf /tmp/first-network/ledgers-backup
|
||||
#Cleanup the chaincode containers
|
||||
clearContainers
|
||||
#Cleanup images
|
||||
removeUnwantedImages
|
||||
# remove orderer block and other channel configuration transactions and certs
|
||||
rm -rf channel-artifacts/*.block channel-artifacts/*.tx crypto-config
|
||||
}
|
||||
|
||||
# Generates Org certs using cryptogen tool
|
||||
function generateCerts() {
|
||||
which cryptogen
|
||||
if [ "$?" -ne 0 ]; then
|
||||
echo "cryptogen tool not found. exiting"
|
||||
exit 1
|
||||
fi
|
||||
echo "##### Generate certificates using cryptogen tool #########"
|
||||
|
||||
if [ -d "crypto-config" ]; then
|
||||
rm -Rf crypto-config
|
||||
fi
|
||||
cryptogen generate --config=./crypto-config.yaml
|
||||
res=$?
|
||||
if [ $res -ne 0 ]; then
|
||||
echo "Failed to generate certificates..."
|
||||
exit 1
|
||||
fi
|
||||
echo
|
||||
}
|
||||
|
||||
# Generate orderer genesis block and channel configuration transaction with configtxgen
|
||||
function generateChannelArtifacts() {
|
||||
which configtxgen
|
||||
if [ "$?" -ne 0 ]; then
|
||||
echo "configtxgen tool not found. exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "######### Generating Orderer Genesis block ##############"
|
||||
mkdir channel-artifacts
|
||||
configtxgen -profile IRSNetGenesis -outputBlock ./channel-artifacts/genesis.block
|
||||
res=$?
|
||||
if [ $res -ne 0 ]; then
|
||||
echo "Failed to generate orderer genesis block..."
|
||||
exit 1
|
||||
fi
|
||||
echo
|
||||
echo "### Generating channel configuration transaction 'channel.tx' ###"
|
||||
configtxgen -profile IRSChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
|
||||
res=$?
|
||||
if [ $res -ne 0 ]; then
|
||||
echo "Failed to generate channel configuration transaction..."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Obtain the OS and Architecture string that will be used to select the correct
|
||||
# native binaries for your platform, e.g., darwin-amd64 or linux-amd64
|
||||
OS_ARCH=$(echo "$(uname -s | tr '[:upper:]' '[:lower:]' | sed 's/mingw64_nt.*/windows/')-$(uname -m | sed 's/x86_64/amd64/g')" | awk '{print tolower($0)}')
|
||||
CHANNEL_NAME="irs"
|
||||
COMPOSE_FILE=docker-compose.yaml
|
||||
COMPOSE_PROJECT_NAME=fabric-irs
|
||||
#
|
||||
# default image tag
|
||||
IMAGETAG="latest"
|
||||
# Parse commandline args
|
||||
MODE=$1
|
||||
shift
|
||||
# Determine whether starting, stopping, generating
|
||||
if [ "$MODE" == "up" ]; then
|
||||
EXPMODE="Starting"
|
||||
elif [ "$MODE" == "down" ]; then
|
||||
EXPMODE="Stopping"
|
||||
elif [ "$MODE" == "generate" ]; then
|
||||
EXPMODE="Generating certs and genesis block"
|
||||
else
|
||||
printHelp
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while getopts "t:i:v" opt; do
|
||||
case "$opt" in
|
||||
t)
|
||||
CLI_TIMEOUT=$OPTARG
|
||||
;;
|
||||
i)
|
||||
IMAGETAG=$(go env GOARCH)"-"$OPTARG
|
||||
;;
|
||||
v)
|
||||
VERBOSE=true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
# Announce what was requested
|
||||
echo "${EXPMODE} for channel '${CHANNEL_NAME}'"
|
||||
|
||||
#Create the network using docker compose
|
||||
if [ "${MODE}" == "up" ]; then
|
||||
networkUp
|
||||
elif [ "${MODE}" == "down" ]; then ## Clear the network
|
||||
networkDown
|
||||
elif [ "${MODE}" == "generate" ]; then ## Generate Artifacts
|
||||
generateCerts
|
||||
generateChannelArtifacts
|
||||
else
|
||||
printHelp
|
||||
exit 1
|
||||
fi
|
||||
123
interest_rate_swaps/network/scripts/script.sh
Executable file
123
interest_rate_swaps/network/scripts/script.sh
Executable file
|
|
@ -0,0 +1,123 @@
|
|||
#!/bin/bash
|
||||
|
||||
DELAY="3"
|
||||
TIMEOUT="10"
|
||||
VERBOSE="false"
|
||||
COUNTER=1
|
||||
MAX_RETRY=5
|
||||
|
||||
CC_SRC_PATH="irscc/"
|
||||
|
||||
createChannel() {
|
||||
CORE_PEER_LOCALMSPID=partya
|
||||
CORE_PEER_ADDRESS=irs-partya:7051
|
||||
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/partya.example.com/users/Admin@partya.example.com/msp
|
||||
echo "===================== Creating channel ===================== "
|
||||
peer channel create -o irs-orderer:7050 -c irs -f ./channel-artifacts/channel.tx
|
||||
echo "===================== Channel created ===================== "
|
||||
}
|
||||
|
||||
joinChannel () {
|
||||
for org in partya partyb partyc auditor rrprovider
|
||||
do
|
||||
CORE_PEER_LOCALMSPID=$org
|
||||
CORE_PEER_ADDRESS=irs-$org:7051
|
||||
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/$org.example.com/users/Admin@$org.example.com/msp
|
||||
echo "===================== Org $org joining channel ===================== "
|
||||
peer channel join -b irs.block -o irs-orderer:7050
|
||||
echo "===================== Channel joined ===================== "
|
||||
done
|
||||
}
|
||||
|
||||
installChaincode() {
|
||||
for org in partya partyb partyc auditor rrprovider
|
||||
do
|
||||
CORE_PEER_LOCALMSPID=$org
|
||||
CORE_PEER_ADDRESS=irs-$org:7051
|
||||
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/$org.example.com/users/Admin@$org.example.com/msp
|
||||
echo "===================== Org $org installing chaincode ===================== "
|
||||
peer chaincode install -n irscc -v 0 -l golang -p ${CC_SRC_PATH}
|
||||
echo "===================== Org $org chaincode installed ===================== "
|
||||
done
|
||||
}
|
||||
|
||||
instantiateChaincode() {
|
||||
CORE_PEER_LOCALMSPID=partya
|
||||
CORE_PEER_ADDRESS=irs-partya:7051
|
||||
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/partya.example.com/users/Admin@partya.example.com/msp
|
||||
echo "===================== Instantiating chaincode ===================== "
|
||||
peer chaincode instantiate -o irs-orderer:7050 -C irs -n irscc -l golang -v 0 -c '{"Args":["init","auditor","100000","rrprovider","myrr"]}' -P "AND(OR('partya.peer','partyb.peer','partyc.peer'), 'auditor.peer')"
|
||||
echo "===================== Chaincode instantiated ===================== "
|
||||
}
|
||||
|
||||
setReferenceRate() {
|
||||
CORE_PEER_LOCALMSPID=rrprovider
|
||||
CORE_PEER_ADDRESS=irs-rrprovider:7051
|
||||
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/rrprovider.example.com/users/User1@rrprovider.example.com/msp
|
||||
echo "===================== Invoking chaincode ===================== "
|
||||
peer chaincode invoke -o irs-orderer:7050 -C irs --waitForEvent -n irscc --peerAddresses irs-rrprovider:7051 -c '{"Args":["setReferenceRate","myrr","300"]}'
|
||||
echo "===================== Chaincode invoked ===================== "
|
||||
}
|
||||
|
||||
createSwap() {
|
||||
CORE_PEER_LOCALMSPID=partya
|
||||
CORE_PEER_ADDRESS=irs-partya:7051
|
||||
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/partya.example.com/users/User1@partya.example.com/msp
|
||||
echo "===================== Invoking chaincode ===================== "
|
||||
peer chaincode invoke -o irs-orderer:7050 -C irs --waitForEvent -n irscc --peerAddresses irs-partya:7051 --peerAddresses irs-partyb:7051 --peerAddresses irs-auditor:7051 -c '{"Args":["createSwap","myswap","{\"StartDate\":\"2018-09-27T15:04:05Z\",\"EndDate\":\"2018-09-30T15:04:05Z\",\"PaymentInterval\":395,\"PrincipalAmount\":10,\"FixedRate\":400,\"FloatingRate\":500,\"ReferenceRate\":\"myrr\"}", "partya", "partyb"]}'
|
||||
echo "===================== Chaincode invoked ===================== "
|
||||
}
|
||||
|
||||
calculatePayment() {
|
||||
CORE_PEER_LOCALMSPID=partya
|
||||
CORE_PEER_ADDRESS=irs-partya:7051
|
||||
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/partya.example.com/users/User1@partya.example.com/msp
|
||||
echo "===================== Invoking chaincode ===================== "
|
||||
peer chaincode invoke -o irs-orderer:7050 -C irs --waitForEvent -n irscc --peerAddresses irs-partya:7051 --peerAddresses irs-partyb:7051 -c '{"Args":["calculatePayment","myswap"]}'
|
||||
echo "===================== Chaincode invoked ===================== "
|
||||
}
|
||||
|
||||
settlePayment() {
|
||||
CORE_PEER_LOCALMSPID=partyb
|
||||
CORE_PEER_ADDRESS=irs-partyb:7051
|
||||
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/partyb.example.com/users/User1@partyb.example.com/msp
|
||||
echo "===================== Invoking chaincode ===================== "
|
||||
peer chaincode invoke -o irs-orderer:7050 -C irs --waitForEvent -n irscc --peerAddresses irs-partya:7051 --peerAddresses irs-partyb:7051 -c '{"Args":["settlePayment","myswap"]}'
|
||||
echo "===================== Chaincode invoked ===================== "
|
||||
}
|
||||
|
||||
## Create channel
|
||||
sleep 1
|
||||
echo "Creating channel..."
|
||||
createChannel
|
||||
|
||||
## Join all the peers to the channel
|
||||
echo "Having all peers join the channel..."
|
||||
joinChannel
|
||||
|
||||
## Install chaincode on all peers
|
||||
echo "Installing chaincode..."
|
||||
installChaincode
|
||||
|
||||
# Instantiate chaincode
|
||||
echo "Instantiating chaincode..."
|
||||
instantiateChaincode
|
||||
|
||||
echo "Setting myrr reference rate"
|
||||
sleep 3
|
||||
setReferenceRate
|
||||
|
||||
echo "Creating swap between A and B"
|
||||
createSwap
|
||||
|
||||
echo "Calculate payment information"
|
||||
calculatePayment
|
||||
|
||||
echo "Mark payment settled"
|
||||
settlePayment
|
||||
|
||||
echo
|
||||
echo "========= IRS network sample setup completed =========== "
|
||||
echo
|
||||
|
||||
exit 0
|
||||
Loading…
Reference in a new issue