1 of 18

Fabric Sample improvements

fabric-samples has grown organically over time, without any overall plan or target objectives.

This presentation proposes a set of Objectives to revamp fabric-samples, that is, make it easier to understand Fabric capabilities and application patterns through a logical series of samples and associated tutorials.

Objective 1: Rational suite of asset transfer samples to teach Fabric core concepts - IN PROGRESS

Objective 2: Easy to understand sample that demonstrates ‘secured asset transfer’ - DONE

Objective 3: Improve/Simplify Commercial Paper sample

Objective 4: New samples - token, auction, supply chain, decentralized identity

Objective 5: Improve chaincode API documentation

Objective 6: Identify Fabric improvement areas

1

2 of 18

Objective 1: Rational suite of asset transfer samples to teach Fabric core concepts

Replace overlapping sacc/fabcar/marble asset samples with a series of samples demonstrating a core concepts

  • Each sample in the series is based on a generic ‘asset’ and consistent verbs, e.g. CreateAsset’, ‘TransferAsset’.
  • Each sample and associated tutorial has a specific learning objective

Proposed sample series:

  • Basic asset transfer - for newbies (replaces sacc/fabcar/abstore)
  • Ledger queries - composite key queries in a tran, CouchDB queries and indexes (refactoring of marbles02)
  • Private data - private data concepts (refactoring of marbles02_private)
  • Secured agreement - see Objective 2 (owner auth, SBE, implicit collections, multi-party agreement, provenance verification)

Each sample can be driven by CLI or sample application.

Start with one chaincode language, port Basic asset transfer to each chaincode language.

The sample applications will similarly demonstrate a series of good applications patterns, e.g.:

  • service discovery gets endorsers for the first three samples
  • for the secured agreement asset transfer sample, application targets a specific org, service discovery gets peers of the target org
  • transient data used for privacy
  • event handling (monitor for transaction validation and chaincode events)
  • show different Gateway submission completion event strategies
  • show connection setup and use

2

3 of 18

Objective 1 (continued): Asset transfer samples

3

Asset transfer - basic

Asset transfer - ledger queries

Asset transfer - private data

Asset transfer - secured

Location in fabric-samples

fabric-samples/

asset-transfer-basic

fabric-samples/

asset-transfer-ledger-queries

fabric-samples/

asset-transfer-privatet-data

fabric-samples/

asset-transfer-secured-agreement

Associated tutorial

Test Network (existing)

Chaincode deployment (existing)

Write your first application (existing)

Write your first chaincode (refactor of Chaincode for Developers)

CouchDB tutorial (existing)

Private data tutorial (existing)

Secured asset transfer (new)

Replaces old sample

abstore

fabcar

sacc

marbles02

marbles02_private

CreateAsset(), TransferAsset()

Advanced ledger APIs

- Composite key queries in a tran

- CouchDB queries and indexes

simple queries

simple queries

simple queries

Owner auth

ownership based on client id

ownership based on client’s org MSPID

Private data

explicit collections

implicit collections

State-based endorsement

Multi-party agreement

4 of 18

Objective 1 (continued): Asset transfer samples - CRUD Functions

4

Asset transfer - basic

Tiffany/Dereck

(based on Fabcar)

Asset transfer - ledger queries

Tiffany

(based on marbles02)

Asset transfer - private data

Nik

(based on marbles02_private)

Asset transfer - secured

Nik/Dave → Tiffany/Dereck

(new transfer chaincode)

Asset properties

Public:

ID

color

size

owner

appraisedValue

Public:

ObjectType

ID

color

size

owner

appraisedValue

Private collection 1:

ObjectType

ID

color

size

owner

Private collection2:

ObjectType

ID

appraisedValue

Public

ObjectType

ID

owner

Owner’s private Implicit collection:

ObjectType

ID

color

size

owner

InitLedger()

InitLedger() creates a few assets

(init not enforced to keep cc simple)

InitLedger() creates a few assets

(init not enforced to keep cc simple)

No init.

Remove Init-required from tutorial

No init.

CreateAsset()

CreateCar() → CreateAsset()

initMarble() → CreateAsset()

Also create color index for queries

initMarble() → CreateAsset()

  • Note - color~name index can be removed since it is not used (cant do queries in transactions with private data, since not all orgs can validate the query)

IssueAsset() → CreateAsset()

  • Create public and private data.
  • Set state-based endorsement

ReadAsset()

QueryCar() → ReadAsset()

readMarble() → ReadAsset()

readMarble() → ReadAsset()

readMarblePrivateDetails() → GetAssetPrivateDetails()

getMarbleHash() → GetAssetHash()

GetAsset() - public → ReadAsset()

GetAssetPrivateProperties() - prvt

UpdateAsset()

na → UpdateAsset()

not needed (support transfer only)

not needed (support transfer only)

not needed (support transfer and description update only)

DeleteAsset()

na → DeleteAsset()

delete() → DeleteAsset()

delete() → DeleteAsset()

Not needed

AssetExists()

AssetExists()

AssetExists()

AssetExists()

AssetExists()

TransferAsset()

ChangeCarOwner() → TransferAsset()

Pass new owner name

No auth check

transferMarble() → TransferAsset()

Pass new owner name

No auth check

transferMarble() → TransferAsset()

Pass new owner client id

Verify current owner against client id

AgreeToSell() / AgreeToBuy()

GetAssetSalesPrice() / GetAssetBidPrice()

TransferAsset():

  • Pass new org mspid
  • Verify current owner against client mspid
  • Verify asset
  • Verify buyer and seller price agreement

5 of 18

Objective 1 (continued): Asset transfer samples - Query Functions

5

Asset transfer - basic

Tiffany/Dereck

(based on Fabcar)

Asset transfer - ledger queries

Tiffany

(based on marbles02)

Asset transfer - private data

Nik

(based on marbles02_private)

Asset transfer - secured

Nik/Dave → Tiffany/Dereck

(new transfer chaincode)

GetAllAssets()

Simple range query (no start/end keys)

QueryAllCars() → GetAllAssets()

No pagination

No pagination

Range query on simple key

GetAssetsByRange()

GetAssetsByRangeWithPagination()

  • Pagination driven by application (pageSize and bookmark)

GetAssetsByRange()

No pagination supported

Range query on composite key

transferAssetByColor()

  • Existing, used in a transaction

QueryAssetSaleAgreements()

QueryAssetBuyAgreements()

CouchDB JSON queries and indexes

QueryAssetsByOwner()

QueryAssets()

QueryAssetsWithPaginiation()

  • Pagination driven by application (pageSize and bookmark)

QueryAssetsByOwner()

QueryAssets()

GetHistoryForAsset()

getHistoryForMarble() → GetAssetHistory()

GetAssetHistory()

6 of 18

Objective 2: Easy to understand sample that demonstrates ‘secured asset transfer’

Secured asset transfer sample that demonstrates

  • Implicit private data collections used to indicate transaction agreement
  • Asset ownership and transfer authorization based on client’s org identity
  • State based endorsement to ensure owning client’s org executes the chaincode
  • Private data passed via transient data field
  • Multi-party transaction agreement
  • Verification of asset and provenance

Driveable via CLI and SDK.

Since Commercial Paper is already too complex (per Objective 3), use a simple asset transfer to demonstrate the concepts.

Chaincode and Tutorial Merged:

6

7 of 18

Objective 3: Improve/Simplify Commercial Paper sample

The Commercial Paper business scenario, documentation, and sample take several hours to read and digest due to the length, it is therefore not a good starting point for Fabric beginners.

Additionally, the following feedback has been provided:

Business scenario confusion - feedback from a new user

  • I am fairly new to the concept of Commercial Paper, so take this with a grain of salt, please. Also, I just happened to learn a little more about bonds over the weekend and it make me think about Commercial Paper.
  • My understanding is Commercial Paper is like a Commercial Bond, so essentially a fixed term loan made from an investor to the company borrowing the money. This borrowing of money is called issuing a commercial paper. So a company needs money and issues a commercial paper for the amount they need. The investor purchases the commercial paper, i.e, the investor agrees to lend the company a certain amount of money in return for interest and full payment at the end of the term of the loan.
  • Par value and Face Value are both essentially the same thing, at least in principle: They are the amount of money loaned by an investor to the borrower.
  • In this case MagnetoCorp is the issuer of the Commercial Paper (i.e they are borrowing the money) and DigiBank is the purchaser of the commercial Paper (i.e., they are lending the money.
  • Normally, the principal amount of the loan is paid back at some specified future date, in this case its 6 months (May 31 to Nov 30??).
  • While the Interest payments are made to the investor at regular intervals during the term of the loan, typically the way we specify the interest for Commercial Paper is by discounting the Face Value/Par Value of the Loan.
  • So a 2% Annual Interest (the standard rate offered by the Central Bank) on a 5Mil Loan would be 100K. Since this is a 6 month loan, we get 50K in interest. So the loan is for 5 Mil, and comes with 50K in interest, and so we say its valued at 4.95 Mil. I think in reality the purchaser is still lending the full face Value, this is just how we specify the interest on the loan, so instead of saying 5 Mil at 2% interest, we say 4.95 Mil value.
  • Because it’s a commercial paper and supposedly MagnetoCorp is less trustworthy than a Central Bank, they would have to pay a slightly higher interest of 2.4%, ie 120K per year, ie 60k for 6 months, i.e its valued at 4.94 Mil
  • I Think we need to do a brief primar on Commercial Paper in the beginning for non Financial Domain users, if we decide to keep the tutorial

State management

  • At the end of the day, Commercial paper does a simple GetState() and PutState() similar to Fabcar.
  • However, there is a concept of a paper list that confuses things.
  • This misleads the user into thinking that there is a list of papers in memory.
  • Furthermore, to understand what is really going on, you have to drill through multiple layers of indirection, making it more of a software engineering education rather than Fabric education - paperList.addPaper() --> StateList.addState() --> this.ctx.stub.putState()
  • Compared with Fabcar, the logic in Commercial Paper is 3 times as complex to achieve the same simple result.

Ownership check

  • There is an existing check on 'owner' field, however it only checks against a string that the client passes in.
  • Ownership should be based on a client identity (org MSPID or client id), and only the current owner should be authorized to transfer an asset.
  • Therefore, instead of 'Buy paper', the verb should be 'Sell paper' or even better ‘Transfer paper’, since in this sample the agreement takes place out of band.
  • The scenario is perfectly set up to do a real ownership check given the description of the identities and the availability of ctx.clientIdentity. Not doing a real ownership check is a missed opportunity to demonstrate a core concept.

Converge to a single chaincode

  • There is no need to manage separate chaincodes for Digibank and MagnetoCorp.

7

8 of 18

Objective 4: New samples

Potential samples

  • tokens
    • UTXO
    • Account-based
  • auction
  • supply chain
  • decentralized identity

8

9 of 18

Token chaincode samples

Demonstrate how to model fungible tokens in chaincode

Basic sample for account-based model and UTXO model

  • Demonstrate that both models can support the same basic functions
    • Mint() - assume one org plays a central bank role and can create tokens
    • Transfer()
    • BalanceOf()
  • Ownership based on x509 user enrollment cert
  • Use default endorsement policy (majority)

9

10 of 18

Token chaincode sample - Account-based (ERC-20 model)

Transfer(recipient string, num_tokens int)

  • Purpose: Transfer tokens to recipient
  • Validate sufficient funds available in caller’s account
  • Reduce caller’s account balance
  • Increase recipient’s account balance

Account records

  • Each state key represents an account/owner with a token balance
  • Key is based on account id / owner id (could be org-level or user-level)

Mint(recipient string, num_tokens int)

  • Purpose: Create new tokens
  • Validate that caller is minter
  • Add tokens to recipient’s balance (create account if needed)

BalanceOf(owner string)

  • Purpose: Get balance of an account
  • Simple account query

Advanced acount-based sample options

  • State-based endorsement, e.g. sender and recipient must both endorse
  • Full set of ERC-20 operations, e.g. add 3rd party operations for approve(), transferFrom(), allowance()

10

org1user1

10000

key

value

org1user1

10000

org1user1

8000

org2user1

2000

Scenario:

- Mint 10000 tokens to org1

- Transfer 2000 tokens to org2

11 of 18

Token chaincode sample - UTXO

Transfer(input_keys []string, outputs []utxo)

  • Purpose: Transfer tokens to recipients
  • Validate that caller owns all inputs
  • Validate that input values equals output values
  • Delete (spend) input utxo keys
  • Create output utxo keys assigned to recipient(s)

UTXO Records

  • Each state record represents an unspent number of tokens and an owner (could be org-level or user-level)
  • Key is based on transaction id that created the utxo, and output index within the transaction

Mint(outputs []utxo)

  • Purpose: Create new UTXOs containing new tokens
  • Validate that caller is minter
  • Create output utxo keys assigned to recipient(s)

11

BalanceOf(owner string)

  • Query to return all UTXOs owned by a user
  • Can be easily queried if the UTXO records are defined using composite key starting with owner:

txid1:1

10000

org1user1

txid1:1

10000

org1user1

txid2:1

8000

org1user1

txid2:2

2000

org2user1

inputs

outputs

outputs

inputs

none

txid1:1

10000

org1user1

key

value

org1user1:txid1:1

10000

delete/spend inputs

Scenario:

- Mint 10000 tokens to org1

- Transfer 2000 tokens to org2

12 of 18

Token chaincode samples - more advanced options

Advanced sample options (applies to account-based and UTXO)

  • Use of anonymous addresses and Identity Mixer MSP for anonymous users, rather than using known x509 owners
    • User manages addresses in their wallet, and must sign over address to spend tokens
    • Similar to bitcoin (UTXO) and ethereum (account-based), but with permissioned users

  • Custom VSCC so that every peer validates (executes) every transaction, rather than simply validating endorsement policy
    • Essentially, utilize a post-order execution trust model, rather than an endorsement trust model
    • Similar in concept to having every org endorse, but more efficient

12

13 of 18

Objective 5: Improve chaincode API documentation

The chaincode API documentation is difficult to find and difficult to understand.

Some APIs are not described at all, e.g. how to use state-based endorsement APIs in node chaincode

Add a ‘cheatsheet’ in Fabric docs

  • Summarize each chaincode API
  • For each API, provide link to Go, Node.js, Java reference docs that each have code snippets
  • Similar in concept to Ethereum https://reference.auditless.com/cheatsheet/
  • Similar to other cloud API docs that have a tiny example snippet per language

Note - this is not part of ‘samples’ per se, rather it should be a fundamental and easy-to-find part of the base chaincode/SDK documentation.

13

14 of 18

Objective 6: Identify Fabric improvement areas

What is difficult to do in Fabric that needs to be improved?

  • Add GetImplicitCollectionName(mspid string) API to chaincode stub to hide the internal collection name.
  • FAB-17916 - Add support for CouchDB indexes on implicit private data collections
  • Simplify collection and composite key namespacing, e.g. something similar to proposed Ledger API
  • FAB-18067 - Service discovery support for implicit collections
  • FAB-7593 - Local collections - when sharing private data, local collections would eliminate the need to copy the same key into multiple collections.

Application SDK improvements

  • Gateway event strategy for specific orgs of interest
  • FABN-1601 - Service discovery to target specific orgs
  • FABN-1571 - Consider peer heights when determing endorsing peers
  • FABN-1598 - Check if endorsement respones match before submitting to ordering

14

15 of 18

Backup/Other (somewhat outdated)

15

16 of 18

Hyperledger Fabric chaincode/data patterns

Patterns will be turned into sample code.

16

Pattern

Description

Example use cases

Transaction flow

Fabric features/APIs

Secured asset transfer

(aka non-fungible token)

Private transfer of an asset between two organizations without publicly sharing data

  • Commercial paper advanced (simplified)
  • Marbles

Two organizations agree on the transfer of an asset from one organization to the other for a certain price.

The details of the agreement are stored by each organization in their respective private data collections.

The asset transfer is only endorsed by the two organizations.

More details:

https://ibm.box.com/s/ctpitnlioumrmoqvus73k74pfbhqoijx

  • Implicit data collections
  • State based endorsement
  • Transient data
  • Key based ACLs (e.g. asset ownership)

Auction

Bidders submit private bids, then reveal bids

Can be bolted on the front of asset transfer sample (perhaps two chaincodes that work together).

Bidders submit private bids to their private data collection.

Auction closes.

Bidders reveal bids.

Highest revealed bid wins.

Implicit data collections

Audit

Supply chain

Reconciliation

17 of 18

Hyperledger Fabric client application patterns

  • Patterns will be turned into sample code.

17

Pattern

Description

Example uses cases

Customers

Transaction flow

Fabric features/APIs

Event listeners

Listen to smart contract events, listen for commit events

setEvent api in chaincodes, addContractListener() in sdks

Service discovery - find endorsers

Used when application can get ‘any’ endorser

Service discovery - find peers of org

Used when application needs to target a specific org, e.g. when state-based endorsement is used.

Event strategy

Which set of peers to listen for submission completion (your org vs all orgs)

Gateway setup

Connection setup and use

18 of 18

Work item plan

18

asset-transfer-basic - port to all chaincode and application languages

  • chaincode-go - Dereck DONE
  • chaincode-javascript - Dereck DONE, Unit tests - Pancham DONE
  • chaincode-typescript - Dereck DONE
  • chaincode-java - Arturo DONE
  • chaincode-external - Dereck/Arnaud DONE

  • application-go - Dereck DONE - Fixed
  • application-javascript - Dereck/Sijo DONE
  • application-typescript - Rijul DONE
  • application-java - Arturo DONE

  • Tutorial switchover - Test Network, CC Deploy - Chris Gabriel DONE
  • Tutorial switchover - Write Your First Application - Chris Gabriel DONE (Java CC?)
  • Tutorial switchover - Chaincode for Developers - Chris Gabriel DONE
  • Tutorial switchover - Channel update (Adding an org) - Tiffany DONE
  • CI for each language - Brett Logan DONE

asset-transfer-ledger-queries

  • chaincode-go - Tiffany DONE
  • chaincode-javascript - Arturo DONE
  • application-java Arturo DONE
  • application-javascript Bret DONE
  • Tutorial switchover - CouchDB tutorial - Tiffany DONE

asset-transfer-private-data

  • chaincode-go - Nik Gupta, Sijo DONE
  • chaincode-java - Sijo DONE - add CI test
  • application-javascript - Sijo DONE
  • Tutorial switchover - Chris and Nik - DONE - backport to 2.2

asset-transfer-sbe

  • chaincode-typescript - Guarav DONE
  • chaincode-java - Guarav DONE
  • application-javascript - Bret DONE
  • improve readme - Nik DONE
  • more advanced SBE sample - Guarav DONE

asset-transfer-secured-agreement (pvt+sbe+acl)

  • chaincode-go - Nik/Dave/Tiffany - DONE
  • application-javascript - Bret DONE
  • Convert Readme to doc tutorial - Tiffany DONE

asset-transfer-events (javascript) Bret DONE

  • chaincode-java Sijo DONE - add CI test

asset-transfer-abac Nik DONE

  • replaces old abac chaincode sample

Misc tasks

Test network

  • Deploy any chaincode instead of hardcoding Fabcar - Bret DONE
  • Deploy any chaincode with pvt data collection definition - Nik DONE
  • Always pass path to deployCC - update tutorials then test network - Julian DONE
  • Improve iterative development experience for user chaincodes - Sijo/Dave
  • Use channel participation API instead of system channel - Julian

Improve Commercial Paper sample - Paul DONE

  • Rob to merge some of the Developing Applications content into the Asset Transfer tutorials

Retire replaced/outdated samples - Dave

  • replace all references to fabcar - Tiffany DONE
  • update off chain data to asset transfer basic - Nik DONE (check couchdb issue)
  • retire - sacc, marbles02, marbles02_private
  • keep for now - fabcar, interest_rate_swaps

Improve chaincode reference docs - Matthew

Improve SDK reference docs - Bret

Other potential samples

Auction (simple) Nik and Arnaud - DONE

Auction (dutch) Nik PR

Token ERC-20 (Go) - Dave/Julian DONE

Token ERC-20 (Javascript) Yuki DONE

Token UTXO - Dave DONE (add 2nd recipient to tutorial)

Token ERC-721 - chaincode-javascript - Yuki PR

Token anonymous payment addresses and Identity Mixer extensions - Guarav

Identity deep-dive and SoftHSM tutorial - Bret

Peerless orgs - Client orgs using a namespace within a peer org implicit private data collection

Delivery versus payment (using tokens)

Supply chain sample - Chris

Decentralized Identity sample - Kamlesh/Sanket