Fabric SDK New Programming Model Moscow Hyperledger Bootcamp
Fabric SDK: New Programming Model Moscow Hyperledger Bootcamp © 2019 IBM Corporation
The Commercial Paper Example Transaction: Issue Commercial Paper Issuer: IBM Owner: IBM Face value: $1, 000 Maturity date: 2019 -10 -31 Transaction: Move Commercial Paper Issuer: IBM Owner: IBM Face value: $1, 000 Maturity date: 2019 -10 -31 Cash Issuer: Owner: Face value: Fed ACME $900, 000 Cash Issuer: Owner: Face value: Fed IBM $1, 000 Commercial Paper Issuer: IBM Owner: ACME Face value: $1, 000 Maturity date: 2019 -10 -31 Cash Issuer: Owner: Face value: Fed IBM $900, 000 Transaction: Redeem Commercial Paper Issuer: IBM Owner: ACME Face value: $1, 000 Maturity date: 2019 -10 -31 © 2019 IBM Corporation Cash Issuer: Owner: Face value: Fed ACME $1, 000 2
The application programming challenge Applications must know too much: 2. 1 peer invokes chaincode 1. connect to peer A 2. invoke chaincode P 1 3. transaction response L 1 5. ledger update notification 4. update transactions ordered S 1 O 1 2. 2 chaincode generates query or update proposal transaction response 4. 2 peer updates ledger using transaction blocks 4. 1 Transactions sent to peers in blocks WHAT • WHO are the endorsing organizations (Endorsement policy) • WHERE are the endorsing organizations (Peers) • HOW to get transactions validated (Ordering) not HOW Simplify for the developer • Applications should only need to know WHAT system does – not WHO, WHERE or HOW it does it • Allow developers to concentrate on their business logic © 2019 IBM Corporation 3
Simple code flow – invoke and query 1. Create and initialize Client 2. Initiate user security context • Set security context in Client 3. Create channel wrapper(s) from client 4. Invoke transactions • Send proposals to endorsers • Send result transaction to ordering service 5. Query chaincode • Send proposals to endorsers © IBM Corporation, 2016 4
Client creation 1. Create client HFClient client = HFClient. create. New. Instance(); 2. Set default crypto suite for HF client Security. add. Provider(new Bouncy. Castle. Provider()); Crypto. Suite crypto = Crypto. Suite. Factory. get. Crypto. Suite(); client. set. Crypto. Suite(crypto); © IBM Corporation, 2016 5
Setting user security context Loading keys and certificates File private. Key. File = new File(PREFIX + "/keystore/c 75 bd 6911 aca 808941 c 3557 ee 7 c 97 e 90 f 3952 e 379497 dc 55 eb 903 f 31 b 50 abc 83_sk"); File certificate. File = new File(PREFIX + "/signcerts/User 1@org 1. example. com-cert. pem"); String certificate = new String(IOUtils. to. Byte. Array(new File. Input. Stream(certificate. File)), "UTF-8"); Private. Key private. Key = get. Private. Key. From. Bytes(IOUtils. to. Byte. Array(new File. Input. Stream(private. Key. File))); String name = "test. User”; String msp. Id = "Org 1 MSP”; © IBM Corporation, 2016 6
Setting user security context 1. Creating user context User user = new User() { @Override public String get. Name() { return name; }. . . @Override public Enrollment get. Enrollment() { return new Enrollment() { @Override public Private. Key get. Key() { return private. Key; } @Override public String get. Cert() { return certificate; } }; } @Override public String get. Msp. Id() { return msp. Id; } }; 2. Setting user security context client. set. User. Context(user); © IBM Corporation, 2016 7
Getting channel 1. Getting channel instance (should be exist) Channel channel = client. new. Channel("mychannel"); 2. Configuring channel. add. Event. Hub(client. new. Event. Hub("peer 0", "grpc: //localhost: 7053")); channel. add. Peer(client. new. Peer("peer 0", "grpc: //localhost: 7051")); channel. add. Orderer(client. new. Orderer("orderer 0", "grpc: //localhost: 7050")); channel. set. Transaction. Wait. Time(10); channel. initialize(); © IBM Corporation, 2016 8
Invoke transaction 1. Create transaction proposal 2. Configure transaction proposal • Create chaincode. Id • Set function, arguments, etc 3. Send proposal to endorsers, based on policy 4. Get responses 5. Compose transaction from • Original proposal • Endorser signatures in responses 6. Send transaction to ordering service 7. Wait until transaction appear in ledger © IBM Corporation, 2016 9
Order Execute Validate Ordering Service Peer Block Endorser Peer Client Endorser © IBM Corporation, 2016 Peer
Invoke transaction 1. Create proposal Transaction. Proposal. Request proposal. Request = client. new. Transaction. Proposal. Request(); 2. Configure proposal Chaincode. ID chaincode. ID = Chaincode. ID. new. Builder() . set. Name("mycc") . set. Version("1. 0") . build(); 3. Set function, arguments, etc proposal. Request. set. Chaincode. ID(chaincode. ID); proposal. Request. set. Fcn("invoke"); proposal. Request. set. Proposal. Wait. Time(Time. Unit. SECONDS. to. Millis(10)); proposal. Request. set. Args(new String[]{"a", "b", "5"}); 4. Send proposal to endorsers and get responses Collection<Proposal. Response> responses = channel. send. Transaction. Proposal(proposal. Request, peers); © IBM Corporation, 2016 11
Invoke transaction 1. Compose transaction from responses and send to orderers Completable. Future<Block. Event. Transaction. Event> tx. Future = channel. send. Transaction(responses, orderers); 2. Wait until transaction appears in ledger try { tx. Future. get(5000, Time. Unit. MILLISECONDS); } catch(Exception e) { System. out. println("Exception " + e + " during wait"); return; } 3. Transaction result is in the responses for (Proposal. Response resp : responses) { System. out. println("Responce from peer " + resp. get. Peer(). get. Name() + " is " + resp. get. Proposal. Response(). get. Response()); } © IBM Corporation, 2016 12
Query chaincode 1. Create proposal Transaction. Proposal. Request query. AProposal. Request = client. new. Transaction. Proposal. Request(); 2. Configure proposal Chaincode. ID query. Chaincode. ID = Chaincode. ID. new. Builder() . set. Name("mycc") . set. Version("1. 0") . build(); 3. Set function, arguments, etc query. AProposal. Request. set. Chaincode. ID(query. Chaincode. ID); query. AProposal. Request. set. Fcn("query"); query. AProposal. Request. set. Proposal. Wait. Time(Time. Unit. SECONDS. to. Millis(10)); query. AProposal. Request. set. Args(new String[]{"a"}); 4. Send proposal to endorsers and get responses Collection<Proposal. Response> query. AResponses = channel. send. Transaction. Proposal(query. AProposal. Request, peers); for (Proposal. Response resp : query. AResponses) { System. out. println("Responce from peer " + resp. get. Peer(). get. Name() + " is " + resp. get. Proposal. Response(). get. Response()); }© IBM Corporation, 2016 13
New Programming Model • Provide a consistent programming model and set of APIs to meet needs of application developers • Using the vocabulary of the target audience – Networks, Contracts, Transactions • Coherent experience across client application and smart contracts • Maximum functionality with minimum code – High-level APIs, declarative HA strategies – Seamless access to low-level APIs (full spectrum of capabilities) • Consistent across all supported languages – Already delivered in Node (v 1. 4. 0) – Java – Go next © 2019 IBM Corporation 14
High-level and low-level APIs • Existing SDK contains the low-level APIs that interact with Fabric – Client / HFClient class is the entry point • The new programming model provides a high-level API – Built on top of the low-level API • New classes/interfaces – Gateway • Represents a connected identity to the fabric network via a peer or set of peers (HA) • 1 to 1 relationship to underlying Client object – Network • Represents the set of peers associated with a Channel – Contract • Represents a chaincode instance on a channel – Transaction • Enables finer control of transaction parameters (e. g. transient data) – Wallet • Manages the storage of identities © 2019 IBM Corporation 15
Example client application – Java • IBM issues a commercial paper, face value $1 M, redemption date 2019 -10 -31 • IBM sells paper to ACME Inc. for $900, 000 // Create a new file system based wallet for managing identities. Path wallet. Path = Paths. get("wallet"); Wallet wallet = Wallet. create. File. System. Wallet(wallet. Path); // load a CCP Path network. Config. Path = Paths. get(". . ", "paper-network", "connection. json"); // create a gateway, then connect Gateway. Builder builder = Gateway. create. Builder(); builder. identity(wallet, "admin"). network. Config(network. Config. Path); try (Gateway gateway = builder. connect()) { // get the network and contract Network network = gateway. get. Network("market 1234"); Contract contract = network. get. Contract("commercial-paper"); // issue commercial paper String paper = contract. submit. Transaction("issue", "ibm", "1000000", "2019 -10 -31") // then sell paper to acme for $900, 000 contract. submit. Transaction("move", paper, "acme", "900000")) } catch (Exception ex) { ex. print. Stack. Trace(); } © 2019 IBM Corporation 16
Gateway and gateway builder • In common with the Node SDK, a gateway object represents the 'connection' to the Fabric network for a given identity • The gateway gets configured with predefined 'strategies' that specify the behavior of low-level interactions – E. g. what conditions define successful transaction commitment – E. g. how to share out queries amongst available peers • This allows common strategies to be selected declaratively, eliminating boilerplate code • In Java, we adopt the 'builder' design pattern to configure the gateway options Gateway. Builder builder = Gateway. create. Builder(); builder. identity(wallet, "admin"). network. Config(network. Config); builder. commit. Handler(Default. Commit. Handlers. MSPID_SCOPE_ALLFORTX); try (Gateway gateway = builder. connect()) { . . . } © 2019 IBM Corporation 17
Pluggable handlers • Commit event handlers and query handlers are both designed to be pluggable – Allows developers to implement bespoke HA strategies • Default commit handler provides a set of pre-built strategies – choose one: – Listen for all on your org (wait for all responses of all org’s event hubs) – DEFAULT – Listen for any on your org (first response of all org’s event hubs) – Listen for all peers in the channel (minimum one from each org) – Listen for any peers in the channel (first response of all event hubs) • Default query handler strategies: – Stick to a single peer. Move to another one if it stops responding – DEFAULT – Round-robin between available peers within org. © 2019 IBM Corporation 18
Handler SPI • A service provider interface (SPI) is available to allow developers create their own strategies • Typically done by a more 'advanced' fabric developer and implemented using lower-level APIs • Implements a factory method and a handler class • Object lifecycle is managed by the Gateway © 2019 IBM Corporation 19
Identity Management • The Wallet interface is used to manage identities including the storage of credentials – Storage scheme delegated to implementation class – E. g. File. System. Wallet, In. Memory. Wallet • Compatible wallet format between Node. js and Java • Provides management API – import, export, list, delete, update, etc. • Each Gateway instance has one wallet associated with it – Used to select identities stored in that wallet – At any one time only a single identity can be active on that gateway & its network instances – Any contract obtained from that network instance will use the identity assigned to that network © 2019 IBM Corporation 20
Transaction object – for finer control • An object representing a named transaction method can be created in the client app – create. Transaction() method on Contract class Network network = gateway. get. Network("market 1234"); Contract contract = network. get. Contract("commercial-paper"); // issue commercial paper Transaction issue = contract. create. Transaction("issue"); issue. submit("ibm", "1000000", "2019 -10 -31"); • Extra options can be associated with this transaction before it is evaluated or summited to the ledger – E. g. transient data • contract. submit. Transaction('issue', 'ibm', . . . ) is syntactic sugar for the code above © 2019 IBM Corporation 21
Private Data Collections • In the smart contract API, the get. Transient() method is used to access transient (private) data • In the base SDK, this transient data is passed as a property in the transaction request object • In the new programming model, there is a set. Transient() method in the Transaction interface – Passes a Map of name/value pairs to subsequent invocation of submit() & evaluate() • This provides API symmetry between the existing smart contract (shim) API and the application SDK Transaction txn = contract. create. Transaction("move"); Map<String, byte[]> secrets = new Hash. Map<>(); secrets. put("price", "900000". get. Bytes()); txn. set. Transient(secrets); txn. submit("paper 001", "my. Corp"); © 2019 IBM Corporation 22
Chaincode - boilerplate dispatch code • Chaincode invoke() is the single entry point for all interactions with the ledger • The developer thinks in terms of ‘transactions’ – “A ledger contains the current state of a business as a journal of transactions” – Fabric docs – Yet the term ‘transaction’ doesn’t appear in the chaincode stub API • There is a conceptual mismatch between transactions and chaincode ‘invoke’ public Reponse invoke(Chaincode. Stub stub) { String func = stub. get. Function(); List<String> params = stub. get. Parameters(); • The developer has to understand this and write code to bridge the gap – By writing a ‘dispatcher’ – Lookup the transaction name and parameters from the ‘stub’ – Then invoke the appropriate function if(func. equals("issue")) { return issue(stub, params); } else if(func. equals("move")) { return move(stub, params); } else if(func. equals("redeem")) { return redeem(stub, params); } else { return new. Error. Response("unknown txn"); } } • This is a distraction from coding the actual business logic © 2019 IBM Corporation 23
Contracts and transactions • “Contracts are the central documents that govern business transactions. ” @Contract(name="org. papernet. commercialpaper") @Default class Commercial. Paper implements Contract. Interface { • A ‘contract’ is implemented as a class in chaincode public Context create. Context(Chaincode. Stub stub) { return new Commercial. Paper. Context(stub); } • Each transaction proposal from the client will invoke that named transaction function @Transaction public Commercial. Paper issue( Commercial. Paper. Context ctx, String issuer, String value, String date, int face. Value) { // create and return paper • Stub API available from first argument (context) } • The methods in that class will be the transaction functions – – ctx. shim. put. State(key, value) To be abstracted by future ledger API . . . } © 2019 IBM Corporation 24
Networks, Contracts and Transactions Wallet Gateway Identity Client Smart Contract My. Context constructor(stub) Options - commit. Handler – strategy & timeout - query. Handler – single / round robin get. Network(network. Name) Ledger API My. Contract create. Context(stub) Network get. Contract(chaincode. Id [, name]) Contract @Transaction issue(context, arg 1, arg 2) @Transaction redeem(context, arg 1, arg 2) submit. Transaction(name, arg 1, arg 2, …) evaluate. Transaction(name, arg 1, arg 2, …) (query) © 2019 IBM Corporation 25
Mixing high and low level APIs • The Gateway interface has a method get. Client() that returns a reference to the underlying Client object – Client is the entry point to the underlying API – Allows access to low-level Channel, Peer, Orderer, etc. APIs • The Gateway object can also be instantiated from an existing Client object – Allows existing client code to start using the new submit. Transaction() function without rewriting • Existing client code continues to work as is – No breaking changes introduced by the new programming model © 2019 IBM Corporation 26
Documentation © 2019 IBM Corporation 27
Samples • New commercial-paper sample as described in the Fabric docs – https: //github. com/hyperledger/fabric-samples/tree/release-1. 4/commercial-paper • Fab. Car sample updated with Javascript, Typescript and Java implementations using the new programming model. – https: //github. com/hyperledger/fabric-samples/tree/release-1. 4/fabcar/javascript – https: //github. com/hyperledger/fabric-samples/tree/release-1. 4/fabcar/typescript – https: //github. com/hyperledger/fabric-samples/tree/release-1. 4/fabcar/java © 2019 IBM Corporation 28
Summary • Provide a consistent programming model and set of APIs to meet needs of application developers • Using the vocabulary of the target audience – Networks, Contracts, Transactions • Coherent experience across client application and smart contracts • Maximum functionality with minimum code – High-level APIs, declarative HA strategies – Seamless access to low-level APIs (full spectrum of capabilities) • Consistent across all supported languages – Already delivered in Node. JS (v 1. 4. 0) – Java in beta (v 1. 4. x) – Go next © 2019 IBM Corporation 29
Questions ? © IBM Corporation, 2016
Thank you! © IBM Corporation, 2016
- Slides: 31