diff --git a/docs/source/developapps/analysis.md b/docs/source/developapps/analysis.md deleted file mode 100644 index fc0ef08cbe2..00000000000 --- a/docs/source/developapps/analysis.md +++ /dev/null @@ -1,226 +0,0 @@ -# Analysis - -**Audience**: Architects, Application and smart contract developers, Business -professionals - -Let's analyze commercial paper in a little more detail. PaperNet participants -such as MagnetoCorp and DigiBank use commercial paper transactions to achieve -their business objectives -- let's examine the structure of a commercial paper -and the transactions that affect it over time. We will also consider which -organizations in PaperNet need to sign off on a transaction based on the trust -relationships among the organizations in the network. Later we'll focus on how -money flows between buyers and sellers; for now, let's focus on the first paper -issued by MagnetoCorp. - -## Commercial paper lifecycle - -A paper 00001 is issued by MagnetoCorp on May 31. Spend a few moments looking at -the first **state** of this paper, with its different properties and values: - -``` -Issuer = MagnetoCorp -Paper = 00001 -Owner = MagnetoCorp -Issue date = 31 May 2020 -Maturity = 30 November 2020 -Face value = 5M USD -Current state = issued -``` - -This paper state is a result of the **issue** transaction and it brings -MagnetoCorp's first commercial paper into existence! Notice how this paper has a -5M USD face value for redemption later in the year. See how the `Issuer` and -`Owner` are the same when paper 00001 is issued. Notice that this paper could be -uniquely identified as `MagnetoCorp00001` -- a composition of the `Issuer` and -`Paper` properties. Finally, see how the property `Current state = issued` -quickly identifies the stage of MagnetoCorp paper 00001 in its lifecycle. - -Shortly after issuance, the paper is bought by DigiBank. Spend a few moments -looking at how the same commercial paper has changed as a result of this **buy** -transaction: - -``` -Issuer = MagnetoCorp -Paper = 00001 -Owner = DigiBank -Issue date = 31 May 2020 -Maturity date = 30 November 2020 -Face value = 5M USD -Current state = trading -``` - -The most significant change is that of `Owner` -- see how the paper initially -owned by `MagnetoCorp` is now owned by `DigiBank`. We could imagine how the -paper might be subsequently sold to BrokerHouse or HedgeMatic, and the -corresponding change to `Owner`. Note how `Current state` allow us to easily -identify that the paper is now `trading`. - -After 6 months, if DigiBank still holds the commercial paper, it can redeem -it with MagnetoCorp: - -``` -Issuer = MagnetoCorp -Paper = 00001 -Owner = MagnetoCorp -Issue date = 31 May 2020 -Maturity date = 30 November 2020 -Face value = 5M USD -Current state = redeemed -``` - -This final **redeem** transaction has ended the commercial paper's lifecycle -- -it can be considered closed. It is often mandatory to keep a record of redeemed -commercial papers, and the `redeemed` state allows us to quickly identify these. -The value of `Owner` of a paper can be used to perform access control on the -**redeem** transaction, by comparing the `Owner` against the identity of the -transaction creator. Fabric supports this through the -[`getCreator()` chaincode API](https://github.com/hyperledger/fabric-chaincode-node/blob/{BRANCH}/fabric-shim/lib/stub.js#L293). -If Go is used as a chaincode language, the [client identity chaincode library](https://github.com/hyperledger/fabric-chaincode-go/blob/{BRANCH}/pkg/cid/README.md) -can be used to retrieve additional attributes of the transaction creator. - -## Transactions - -We've seen that paper 00001's lifecycle is relatively straightforward -- it -moves between `issued`, `trading` and `redeemed` as a result of an **issue**, -**buy**, or **redeem** transaction. - -These three transactions are initiated by MagnetoCorp and DigiBank (twice), and -drive the state changes of paper 00001. Let's have a look at the transactions -that affect this paper in a little more detail: - -### Issue - -Examine the first transaction initiated by MagnetoCorp: - -``` -Txn = issue -Issuer = MagnetoCorp -Paper = 00001 -Issue time = 31 May 2020 09:00:00 EST -Maturity date = 30 November 2020 -Face value = 5M USD -``` - -See how the **issue** transaction has a structure with properties and values. -This transaction structure is different to, but closely matches, the structure -of paper 00001. That's because they are different things -- paper 00001 reflects -a state of PaperNet that is a result of the **issue** transaction. It's the -logic behind the **issue** transaction (which we cannot see) that takes these -properties and creates this paper. Because the transaction **creates** the -paper, it means there's a very close relationship between these structures. - -The only organization that is involved in the **issue** transaction is MagnetoCorp. -Naturally, MagnetoCorp needs to sign off on the transaction. In general, the issuer -of a paper is required to sign off on a transaction that issues a new paper. - -### Buy - -Next, examine the **buy** transaction which transfers ownership of paper 00001 -from MagnetoCorp to DigiBank: - -``` -Txn = buy -Issuer = MagnetoCorp -Paper = 00001 -Current owner = MagnetoCorp -New owner = DigiBank -Purchase time = 31 May 2020 10:00:00 EST -Price = 4.94M USD -``` - -See how the **buy** transaction has fewer properties that end up in this paper. -That's because this transaction only **modifies** this paper. It's only `New -owner = DigiBank` that changes as a result of this transaction; everything else -is the same. That's OK -- the most important thing about the **buy** transaction -is the change of ownership, and indeed in this transaction, there's an -acknowledgement of the current owner of the paper, MagnetoCorp. - -You might ask why the `Purchase time` and `Price` properties are not captured in -paper 00001? This comes back to the difference between the transaction and the -paper. The 4.94 M USD price tag is actually a property of the transaction, -rather than a property of this paper. Spend a little time thinking about -this difference; it is not as obvious as it seems. We're going to see later -that the ledger will record both pieces of information -- the history of all -transactions that affect this paper, as well its latest state. Being clear on -this separation of information is really important. - -It's also worth remembering that paper 00001 may be bought and sold many times. -Although we're skipping ahead a little in our scenario, let's examine what -transactions we **might** see if paper 00001 changes ownership. - -If we have a purchase by BigFund: - -``` -Txn = buy -Issuer = MagnetoCorp -Paper = 00001 -Current owner = DigiBank -New owner = BigFund -Purchase time = 2 June 2020 12:20:00 EST -Price = 4.93M USD -``` -Followed by a subsequent purchase by HedgeMatic: -``` -Txn = buy -Issuer = MagnetoCorp -Paper = 00001 -Current owner = BigFund -New owner = HedgeMatic -Purchase time = 3 June 2020 15:59:00 EST -Price = 4.90M USD -``` - -See how the paper owners changes, and how in our example, the price changes. Can -you think of a reason why the price of MagnetoCorp commercial paper might be -falling? - -Intuitively, a **buy** transaction demands that both the selling as well as the -buying organization need to sign off on such a transaction such that there is -proof of the mutual agreement among the two parties that are part of the deal. - -### Redeem - -The **redeem** transaction for paper 00001 represents the end of its lifecycle. -In our relatively simple example, HedgeMatic initiates the transaction which -transfers the commercial paper back to MagnetoCorp: - -``` -Txn = redeem -Issuer = MagnetoCorp -Paper = 00001 -Current owner = HedgeMatic -Redeem time = 30 Nov 2020 12:00:00 EST -``` - -Again, notice how the **redeem** transaction has very few properties; all of the -changes to paper 00001 can be calculated data by the redeem transaction logic: -the `Issuer` will become the new owner, and the `Current state` will change to -`redeemed`. The `Current owner` property is specified in our example, so that it -can be checked against the current holder of the paper. - -From a trust perspective, the same reasoning of the **buy** transaction also -applies to the **redeem** instruction: both organizations involved in the -transaction are required to sign off on it. - -## The Ledger - -In this topic, we've seen how transactions and the resultant paper states are -the two most important concepts in PaperNet. Indeed, we'll see these two -fundamental elements in any Hyperledger Fabric distributed -[ledger](../ledger/ledger.html) -- a world state, that contains the current -value of all objects, and a blockchain that records the history of all -transactions that resulted in the current world state. - -The required sign-offs on transactions are enforced through rules, which -are evaluated before appending a transaction to the ledger. Only if the -required signatures are present, Fabric will accept a transaction as valid. - -You're now in a great place to translate these ideas into a smart contract. Don't -worry if your programming is a little rusty, we'll provide tips and pointers to -understand the program code. Mastering the commercial paper smart contract is -the first big step towards designing your own application. Or, if you're a -business analyst who's comfortable with a little programming, don't be afraid to -dig a little deeper! - - diff --git a/docs/source/developapps/application.md b/docs/source/developapps/application.md deleted file mode 100644 index 2e9983b9ada..00000000000 --- a/docs/source/developapps/application.md +++ /dev/null @@ -1,359 +0,0 @@ -# Application - -**Audience**: Architects, Application and smart contract developers - -An application can interact with a blockchain network by submitting transactions -to a ledger or querying ledger content. This topic covers the mechanics of how -an application does this; in our scenario, organizations access PaperNet using -applications which invoke **issue**, **buy** and **redeem** transactions -defined in a commercial paper smart contract. Even though MagnetoCorp's -application to issue a commercial paper is basic, it covers all the major points -of understanding. - -In this topic, we're going to cover: - -* [The application flow to invoke a smart contract](#basic-flow) -* [How an application uses a wallet and identity](#wallet) -* [How an application connects using a gateway](#gateway) -* [How to access a particular network](#network-channel) -* [How to construct a transaction request](#construct-request) -* [How to submit a transaction](#submit-transaction) -* [How to process a transaction response](#process-response) - -To help your understanding, we'll make reference to the commercial paper sample -application provided with Hyperledger Fabric. You can [download -it](../install.html) and [run it locally](../tutorial/commercial_paper.html). It -is written in both JavaScript and Java, but the logic is quite language independent, so you'll -easily be able to see what's going on! (The sample will become available for Go as well.) - -## Basic Flow - -An application interacts with a blockchain network using the Fabric SDK. Here's -a simplified diagram of how an application invokes a commercial paper smart -contract: - -![develop.application](./develop.diagram.3.png) *A PaperNet application invokes -the commercial paper smart contract to submit an issue transaction request.* - -An application has to follow six basic steps to submit a transaction: - -* Select an identity from a wallet -* Connect to a gateway -* Access the desired network -* Construct a transaction request for a smart contract -* Submit the transaction to the network -* Process the response - -You're going to see how a typical application performs these six steps using the -Fabric SDK. You'll find the application code in the `issue.js` file. [View -it](https://github.com/hyperledger/fabric-samples/blob/{BRANCH}/commercial-paper/organization/magnetocorp/application/issue.js) -in your browser, or open it in your favourite editor if you've downloaded it. -Spend a few moments looking at the overall structure of the application; even -with comments and spacing, it's only 100 lines of code! - -## Wallet - -Towards the top of `issue.js`, you'll see two Fabric classes are brought -into scope: - -```JavaScript -const { Wallets, Gateway } = require('fabric-network'); -``` - -You can read about the `fabric-network` classes in the -[node SDK documentation](https://hyperledger.github.io/fabric-sdk-node/{BRANCH}/module-fabric-network.html), but for -now, let's see how they are used to connect MagnetoCorp's application to -PaperNet. The application uses the Fabric **Wallet** class as follows: - -```JavaScript -const wallet = await Wallets.newFileSystemWallet('../identity/user/isabella/wallet'); -``` - -See how `wallet` locates a [wallet](./wallet.html) in the local filesystem. The -identity retrieved from the wallet is clearly for a user called Isabella, who is -using the `issue` application. The wallet holds a set of identities -- X.509 -digital certificates -- which can be used to access PaperNet or any other Fabric -network. If you run the tutorial, and look in this directory, you'll see the -identity credentials for Isabella. - -Think of a [wallet](./wallet.html) holding the digital equivalents of your -government ID, driving license or ATM card. The X.509 digital certificates -within it will associate the holder with a organization, thereby entitling them -to rights in a network channel. For example, `Isabella` might be an -administrator in MagnetoCorp, and this could give her more privileges than a -different user -- `Balaji` from DigiBank. Moreover, a smart contract can -retrieve this identity during smart contract processing using the [transaction -context](./transactioncontext.html). - -Note also that wallets don't hold any form of cash or tokens -- they hold -identities. - -## Gateway - -The second key class is a Fabric **Gateway**. Most importantly, a -[gateway](./gateway.html) identifies one or more peers that provide access to a -network -- in our case, PaperNet. See how `issue.js` connects to its gateway: - -```JavaScript -await gateway.connect(connectionProfile, connectionOptions); -``` - -`gateway.connect()` has two important parameters: - - * **connectionProfile**: the file system location of a - [connection profile](./connectionprofile.html) that identifies - a set of peers as a gateway to PaperNet - - * **connectionOptions**: a set of options used to control how `issue.js` - interacts with PaperNet - - -See how the client application uses a gateway to insulate itself from the -network topology, which might change. The gateway takes care of sending the -transaction proposal to the right peer nodes in the network using the -[connection profile](./connectionprofile.html) and [connection -options](./connectionoptions.html). - -Spend a few moments examining the connection -[profile](https://github.com/hyperledger/fabric-samples/blob/{BRANCH}/commercial-paper/organization/magnetocorp/gateway/networkConnection.yaml) -`./gateway/connectionProfile.yaml`. It uses -[YAML](http://yaml.org/spec/1.2/spec.html#Preview), making it easy to read. - -It was loaded and converted into a JSON object: - -```JavaScript -let connectionProfile = yaml.safeLoad(file.readFileSync('./gateway/connectionProfile.yaml', 'utf8')); -``` - -Right now, we're only interested in the `channels:` and `peers:` sections of the -profile: (We've modified the details slightly to better explain what's -happening.) - -```YAML -channels: - papernet: - peers: - peer1.magnetocorp.com: - endorsingPeer: true - eventSource: true - - peer2.digibank.com: - endorsingPeer: true - eventSource: true - -peers: - peer1.magnetocorp.com: - url: grpcs://localhost:7051 - grpcOptions: - ssl-target-name-override: peer1.magnetocorp.com - request-timeout: 120 - tlsCACerts: - path: certificates/magnetocorp/magnetocorp.com-cert.pem - - peer2.digibank.com: - url: grpcs://localhost:8051 - grpcOptions: - ssl-target-name-override: peer1.digibank.com - tlsCACerts: - path: certificates/digibank/digibank.com-cert.pem -``` - -See how `channel:` identifies the `PaperNet:` network channel, and two of its -peers. MagnetoCorp has `peer1.magenetocorp.com` and DigiBank has -`peer2.digibank.com`, and both have the role of endorsing peers. Link to these -peers via the `peers:` key, which contains details about how to connect to them, -including their respective network addresses. - -The connection profile contains a lot of information -- not just peers -- but -network channels, network orderers, organizations, and CAs, so don't worry if -you don't understand all of it! - -Let's now turn our attention to the `connectionOptions` object: - -```JavaScript -let connectionOptions = { - identity: userName, - wallet: wallet, - discovery: { enabled:true, asLocalhost: true } -}; -``` - -See how it specifies that identity, `userName`, and wallet, `wallet`, should be -used to connect to a gateway. These were assigned values earlier in the code. - -There are other [connection options](./connectionoptions.html) which an -application could use to instruct the SDK to act intelligently on its behalf. -For example: - -```JavaScript -let connectionOptions = { - identity: userName, - wallet: wallet, - eventHandlerOptions: { - commitTimeout: 100, - strategy: EventStrategies.MSPID_SCOPE_ANYFORTX - }, -} -``` - -Here, `commitTimeout` tells the SDK to wait 100 seconds to hear whether a -transaction has been committed. And `strategy: -EventStrategies.MSPID_SCOPE_ANYFORTX` specifies that the SDK can notify an -application after a single MagnetoCorp peer has confirmed the transaction, in -contrast to `strategy: EventStrategies.NETWORK_SCOPE_ALLFORTX` which requires -that all peers from MagnetoCorp and DigiBank to confirm the transaction. - -If you'd like to, [read more](./connectionoptions.html) about how connection -options allow applications to specify goal-oriented behaviour without having to -worry about how it is achieved. - -## Network channel - -The peers defined in the gateway `connectionProfile.yaml` provide -`issue.js` with access to PaperNet. Because these peers can be joined to -multiple network channels, the gateway actually provides the application with -access to multiple network channels! - -See how the application selects a particular channel: - -```JavaScript -const network = await gateway.getNetwork('PaperNet'); -``` - -From this point onwards, `network` will provide access to PaperNet. Moreover, -if the application wanted to access another network, `BondNet`, at the same -time, it is easy: - -```JavaScript -const network2 = await gateway.getNetwork('BondNet'); -``` - -Now our application has access to a second network, `BondNet`, simultaneously -with `PaperNet`! - -We can see here a powerful feature of Hyperledger Fabric -- applications can -participate in a **network of networks**, by connecting to multiple gateway -peers, each of which is joined to multiple network channels. Applications will -have different rights in different channels according to their wallet identity -provided in `gateway.connect()`. - -## Construct request - -The application is now ready to **issue** a commercial paper. To do this, it's -going to use `CommercialPaperContract` and again, its fairly straightforward to -access this smart contract: - -```JavaScript -const contract = await network.getContract('papercontract', 'org.papernet.commercialpaper'); -``` - -Note how the application provides a name -- `papercontract` -- and an explicit -contract name: `org.papernet.commercialpaper`! We see how a [contract -name](./contractname.html) picks out one contract from the `papercontract.js` -chaincode file that contains many contracts. In PaperNet, `papercontract.js` was -installed and deployed to the channel with the name `papercontract`, and if you're -interested, read [how](../chaincode_lifecycle.html) to deploy a chaincode containing -multiple smart contracts. - -If our application simultaneously required access to another contract in -PaperNet or BondNet this would be easy: - -```JavaScript -const euroContract = await network.getContract('EuroCommercialPaperContract'); - -const bondContract = await network2.getContract('BondContract'); -``` - -In these examples, note how we didn't use a qualifying contract name -- we have -only one smart contract per file, and `getContract()` will use the first -contract it finds. - -Recall the transaction MagnetoCorp uses to issue its first commercial paper: - -``` -Txn = issue -Issuer = MagnetoCorp -Paper = 00001 -Issue time = 31 May 2020 09:00:00 EST -Maturity date = 30 November 2020 -Face value = 5M USD -``` - -Let's now submit this transaction to PaperNet! - -## Submit transaction - -Submitting a transaction is a single method call to the SDK: - -```JavaScript -const issueResponse = await contract.submitTransaction('issue', 'MagnetoCorp', '00001', '2020-05-31', '2020-11-30', '5000000'); -``` - -See how the `submitTransaction()` parameters match those of the transaction -request. It's these values that will be passed to the `issue()` method in the -smart contract, and used to create a new commercial paper. Recall its -signature: - -```JavaScript -async issue(ctx, issuer, paperNumber, issueDateTime, maturityDateTime, faceValue) {...} -``` - -It might appear that a smart contract receives control shortly after the -application issues `submitTransaction()`, but that's not the case. Under the -covers, the SDK uses the `connectionOptions` and `connectionProfile` details to -send the transaction proposal to the right peers in the network, where it can -get the required endorsements. But the application doesn't need to worry about -any of this -- it just issues `submitTransaction` and the SDK takes care of it -all! - -Note that the `submitTransaction` API includes a process for listening for -transaction commits. Listening for commits is required because without it, -you will not know whether your transaction has successfully been orderered, -validated, and committed to the ledger. - -Let's now turn our attention to how the application handles the response! - -## Process response - -Recall from `papercontract.js` how the **issue** transaction returns a -commercial paper response: - -```JavaScript -return paper.toBuffer(); -``` - -You'll notice a slight quirk -- the new `paper` needs to be converted to a -buffer before it is returned to the application. Notice how `issue.js` uses the -class method `CommercialPaper.fromBuffer()` to rehydrate the response buffer as -a commercial paper: - -```JavaScript -let paper = CommercialPaper.fromBuffer(issueResponse); -``` - -This allows `paper` to be used in a natural way in a descriptive completion -message: - -```JavaScript -console.log(`${paper.issuer} commercial paper : ${paper.paperNumber} successfully issued for value ${paper.faceValue}`); -``` - -See how the same `paper` class has been used in both the application and smart -contract -- if you structure your code like this, it'll really help readability -and reuse. - -As with the transaction proposal, it might appear that the application receives -control soon after the smart contract completes, but that's not the case. Under -the covers, the SDK manages the entire consensus process, and notifies the -application when it is complete according to the `strategy` connectionOption. If -you're interested in what the SDK does under the covers, read the detailed -[transaction flow](../txflow.html). - -That’s it! In this topic you’ve understood how to call a smart contract from a -sample application by examining how MagnetoCorp's application issues a new -commercial paper in PaperNet. Now examine the key ledger and smart contract data -structures are designed by in the [architecture topic](./architecture.html) behind -them. - - diff --git a/docs/source/developapps/architecture.md b/docs/source/developapps/architecture.md deleted file mode 100644 index 50883c74f5f..00000000000 --- a/docs/source/developapps/architecture.md +++ /dev/null @@ -1,184 +0,0 @@ -# Process and Data Design - -**Audience**: Architects, Application and smart contract developers, Business -professionals - -This topic shows you how to design the commercial paper processes and their -related data structures in PaperNet. Our [analysis](./analysis.html) highlighted -that modelling PaperNet using states and transactions provided a precise way to -understand what's happening. We're now going to elaborate on these two strongly -related concepts to help us subsequently design the smart contracts and -applications of PaperNet. - -## Lifecycle - -As we've seen, there are two important concepts that concern us when dealing -with commercial paper; **states** and **transactions**. Indeed, this is true for -_all_ blockchain use cases; there are conceptual objects of value, modeled as -states, whose lifecycle transitions are described by transactions. An effective -analysis of states and transactions is an essential starting point for a -successful implementation. - -We can represent the life cycle of a commercial paper using a state transition -diagram: - -![develop.statetransition](./develop.diagram.4.png) _The state transition -diagram for commercial paper. Commercial papers transition between **issued**, -**trading** and **redeemed** states by means of the **issue**, **buy** and -**redeem** transactions._ - -See how the state diagram describes how commercial papers change over time, and -how specific transactions govern the life cycle transitions. In Hyperledger -Fabric, smart contracts implement transaction logic that transition commercial -papers between their different states. Commercial paper states are actually held -in the ledger world state; so let's take a closer look at them. - -## Ledger state - -Recall the structure of a commercial paper: - -![develop.paperstructure](./develop.diagram.5.png) _A commercial paper can be -represented as a set of properties, each with a value. Typically, some -combination of these properties will provide a unique key for each paper._ - -See how a commercial paper `Paper` property has value `00001`, and the `Face value` property has value `5M USD`. Most importantly, the `Current state` -property indicates whether the commercial paper is `issued`,`trading` or -`redeemed`. In combination, the full set of properties make up the **state** of -a commercial paper. Moreover, the entire collection of these individual -commercial paper states constitutes the ledger -[world state](../ledger/ledger.html#world-state). - -All ledger state share this form; each has a set of properties, each with a -different value. This _multi-property_ aspect of states is a powerful feature -- -it allows us to think of a Fabric state as a vector rather than a simple scalar. -We then represent facts about whole objects as individual states, which -subsequently undergo transitions controlled by transaction logic. A Fabric state -is implemented as a key/value pair, in which the value encodes the object -properties in a format that captures the object's multiple properties, typically -JSON. The [ledger -database](../ledger/ledger.html#ledger-world-state-database-options) can support -advanced query operations against these properties, which is very helpful for -sophisticated object retrieval. - -See how MagnetoCorp's paper `00001` is represented as a state vector that -transitions according to different transaction stimuli: - -![develop.paperstates](./develop.diagram.6.png) _A commercial paper state is -brought into existence and transitions as a result of different transactions. -Hyperledger Fabric states have multiple properties, making them vectors rather -than scalars._ - -Notice how each individual paper starts with the empty state, which is -technically a [`nil`]() state for the -paper, as it doesn't exist! See how paper `00001` is brought into existence by -the **issue** transaction, and how it is subsequently updated as a result of the -**buy** and **redeem** transactions. - -Notice how each state is self-describing; each property has a name and a value. -Although all our commercial papers currently have the same properties, this need -not be the case for all time, as Hyperledger Fabric supports different states -having different properties. This allows the same ledger world state to contain -different forms of the same asset as well as different types of asset. It also -makes it possible to update a state's structure; imagine a new regulation that -requires an additional data field. Flexible state properties support the -fundamental requirement of data evolution over time. - -## State keys - -In most practical applications, a state will have a combination of properties -that uniquely identify it in a given context -- it's **key**. The key for a -PaperNet commercial paper is formed by a concatenation of the `Issuer` and -`paper` properties; so for MagnetoCorp's first paper, it's `MagnetoCorp00001`. - -A state key allows us to uniquely identify a paper; it is created as a result -of the **issue** transaction and subsequently updated by **buy** and **redeem**. -Hyperledger Fabric requires each state in a ledger to have a unique key. - -When a unique key is not available from the available set of properties, an -application-determined unique key is specified as an input to the transaction -that creates the state. This unique key is usually with some form of -[UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier), which -although less readable, is a standard practice. What's important is that every -individual state object in a ledger must have a unique key. - -_Note: You should avoid using U+0000 (nil byte) in keys._ - -## Multiple states - -As we've seen, commercial papers in PaperNet are stored as state vectors in a -ledger. It's a reasonable requirement to be able to query different commercial -papers from the ledger; for example: find all the papers issued by MagnetoCorp, -or: find all the papers issued by MagnetoCorp in the `redeemed` state. - -To make these kinds of search tasks possible, it's helpful to group all related -papers together in a logical list. The PaperNet design incorporates the idea of -a commercial paper list -- a logical container which is updated whenever -commercial papers are issued or otherwise changed. - -### Logical representation - -It's helpful to think of all PaperNet commercial papers being in a single list -of commercial papers: - -![develop.paperlist](./develop.diagram.7.png) _MagnetoCorp's -newly created commercial paper 00004 is added to the list of existing -commercial papers._ - -New papers can be added to the list as a result of an **issue** transaction, and -papers already in the list can be updated with **buy** or **redeem** -transactions. See how the list has a descriptive name: `org.papernet.papers`; -it's a really good idea to use this kind of [DNS -name](https://en.wikipedia.org/wiki/Domain_Name_System) because well-chosen -names will make your blockchain designs intuitive to other people. This idea -applies equally well to smart contract [names](./contractname.html). - -### Physical representation - -While it's correct to think of a single list of papers in PaperNet -- -`org.papernet.papers` -- lists are best implemented as a set of individual -Fabric states, whose composite key associates the state with its list. In this -way, each state's composite key is both unique and supports effective list query. - -![develop.paperphysical](./develop.diagram.8.png) _Representing a list of -PaperNet commercial papers as a set of distinct Hyperledger Fabric states_ - -Notice how each paper in the list is represented by a vector state, with a -unique **composite** key formed by the concatenation of `org.papernet.paper`, -`Issuer` and `Paper` properties. This structure is helpful for two reasons: - -- It allows us to examine any state vector in the ledger to determine which - list it's in, without reference to a separate list. It's analogous to - looking at set of sports fans, and identifying which team they support by - the color of the shirt they are wearing. The sports fans self-declare their - allegiance; we don't need a list of fans. - -- Hyperledger Fabric internally uses a concurrency control - mechanism - to update a ledger, such that keeping papers in separate state vectors vastly - reduces the opportunity for shared-state collisions. Such collisions require - transaction re-submission, complicate application design, and decrease - performance. - -This second point is actually a key take-away for Hyperledger Fabric; the -physical design of state vectors is **very important** to optimum performance -and behaviour. Keep your states separate! - -## Trust relationships - -We have discussed how the different roles in a network, such as issuer, trader -or rating agencies as well as different business interests determine who needs -to sign off on a transaction. In Fabric, these rules are captured by so-called -[**endorsement policies**](endorsementpolicies.html). The rules can be set on -a chaincode granularity, as well as for individual state keys. - -This means that in PaperNet, we can set one rule for the whole namespace that -determines which organizations can issue new papers. Later, rules can be set -and updated for individual papers to capture the trust relationships of buy -and redeem transactions. - -In the next topic, we will show you how to combine these design concepts to -implement the PaperNet commercial paper smart contract, and then an application -in exploits it! - - diff --git a/docs/source/developapps/chaincodenamespace.md b/docs/source/developapps/chaincodenamespace.md deleted file mode 100644 index c1b5a8bb2ab..00000000000 --- a/docs/source/developapps/chaincodenamespace.md +++ /dev/null @@ -1,297 +0,0 @@ -# Chaincode namespace - -**Audience**: Architects, application and smart contract developers, -administrators - -A chaincode namespace allows it to keep its world state separate from other -chaincodes. Specifically, smart contracts in the same chaincode share direct -access to the same world state, whereas smart contracts in different chaincodes -cannot directly access each other's world state. If a smart contract needs to -access another chaincode world state, it can do this by performing a -chaincode-to-chaincode invocation. Finally, a blockchain can contain -transactions which relate to different world states. - -In this topic, we're going to cover: - -* [The importance of namespaces](#motivation) -* [What is a chaincode namespace](#scenario) -* [Channels and namespaces](#channels) -* [How to use chaincode namespaces](#usage) -* [How to access world states across smart contracts](#cross-chaincode-access) -* [Design considerations for chaincode namespaces](#considerations) - -## Motivation - -A namespace is a common concept. We understand that *Park Street, New York* and -*Park Street, Seattle* are different streets even though they have the same -name. The city forms a **namespace** for Park Street, simultaneously providing -freedom and clarity. - -It's the same in a computer system. Namespaces allow different users to program -and operate different parts of a shared system, without getting in each other's -way. Many programming languages have namespaces so that programs can freely -assign unique identifiers, such as variable names, without worrying about other -programs doing the same. We'll see that Hyperledger Fabric uses namespaces to -help smart contracts keep their ledger world state separate from other smart -contracts. - -## Scenario - -Let's examine how the ledger world state organizes facts about business objects -that are important to the organizations in a channel using the diagram below. -Whether these objects are commercial papers, bonds, or vehicle registrations, -and wherever they are in their lifecycle, they are maintained as states within -the ledger world state database. A smart contract manages these business objects -by interacting with the ledger (world state and blockchain), and in most cases -this will involve it querying or updating the ledger world state. - -It's vitally important to understand that the ledger world state is partitioned -according to the chaincode of the smart contract that accesses it, and this -partitioning, or *namespacing* is an important design consideration for -architects, administrators and programmers. - -![chaincodens.scenario](./develop.diagram.50.png) *The ledger world state is -separated into different namespaces according to the chaincode that accesses it. -Within a given channel, smart contracts in the same chaincode share the same -world state, and smart contracts in different chaincodes cannot directly access -each other's world state. Likewise, a blockchain can contain transactions that -relate to different chaincode world states.* - -In our example, we can see four smart contracts defined in two different -chaincodes, each of which is in their own chaincode container. The `euroPaper` -and `yenPaper` smart contracts are defined in the `papers` chaincode. The -situation is similar for the `euroBond` and `yenBond` smart contracts -- they -are defined in the `bonds` chaincode. This design helps application programmers -understand whether they are working with commercial papers or bonds priced in -Euros or Yen, and because the rules for each financial product don't really -change for different currencies, it makes sense to manage their deployment in -the same chaincode. - -The [diagram](#scenario) also shows the consequences of this deployment choice. -The database management system (DBMS) creates different world state databases -for the `papers` and `bonds` chaincodes and the smart contracts contained within -them. `World state A` and `world state B` are each held within distinct -databases; the data are isolated from each other such that a single world state -query (for example) cannot access both world states. The world state is said to -be *namespaced* according to its chaincode. - -See how `world state A` contains two lists of commercial papers `paperListEuro` -and `paperListYen`. The states `PAP11` and `PAP21` are instances of each paper -managed by the `euroPaper` and `yenPaper` smart contracts respectively. Because -they share the same chaincode namespace, their keys (`PAPxyz`) must be unique -within the namespace of the `papers` chaincode, a little like a street name is -unique within a town. Notice how it would be possible to write a smart contract -in the `papers` chaincode that performed an aggregate calculation over all the -commercial papers -- whether priced in Euros or Yen -- because they share the -same namespace. The situation is similar for bonds -- they are held within -`world state B` which maps to a separate `bonds` database, and their keys must -be unique. - -Just as importantly, namespaces mean that `euroPaper` and `yenPaper` cannot -directly access `world state B`, and that `euroBond` and `yenBond` cannot -directly access `world state A`. This isolation is helpful, as commercial papers -and bonds are very distinct financial instruments; they have different -attributes and are subject to different rules. It also means that `papers` and -`bonds` could have the same keys, because they are in different namespaces. This -is helpful; it provides a significant degree of freedom for naming. Use this -freedom to name different business objects meaningfully. - -Most importantly, we can see that a blockchain is associated with the peer -operating in a particular channel, and that it contains transactions that affect -both `world state A` and `world state B`. That's because the blockchain is the -most fundamental data structure contained in a peer. The set of world states can -always be recreated from this blockchain, because they are the cumulative -results of the blockchain's transactions. A world state helps simplify smart -contracts and improve their efficiency, as they usually only require the current -value of a state. Keeping world states separate via namespaces helps smart -contracts isolate their logic from other smart contracts, rather than having to -worry about transactions that correspond to different world states. For example, -a `bonds` contract does not need to worry about `paper` transactions, because it -cannot see their resultant world state. - -It's also worth noticing that the peer, chaincode containers and DBMS all are -logically different processes. The peer and all its chaincode containers are -always in physically separate operating system processes, but the DBMS can be -configured to be embedded or separate, depending on its -[type](../ledger/ledger.html#world-state-database-options). For LevelDB, the -DBMS is wholly contained within the peer, but for CouchDB, it is a separate -operating system process. - -It's important to remember that namespace choices in this example are the result -of a business requirement to share commercial papers in different currencies but -isolate them separate from bonds. Think about how the namespace structure would -be modified to meet a business requirement to keep every financial asset class -separate, or share all commercial papers and bonds? - -## Channels - -If a peer is joined to multiple channels, then a new blockchain is created -and managed for each channel. Moreover, every time a chaincode is deployed to -a new channel, a new world state database is created for it. It means that -the channel also forms a kind of namespace alongside that of the chaincode for -the world state. - -However, the same peer and chaincode container processes can be simultaneously -joined to multiple channels -- unlike blockchains, and world state databases, -these processes do not increase with the number of channels joined. - -For example, if you deployed the `papers` and `bonds` chaincode to a new -channel, there would a totally separate blockchain created, and two new world -state databases created. However, the peer and chaincode containers would not -increase; each would just be connected to multiple channels. - -## Usage - -Let's use our commercial paper [example](#scenario) to show how an application -uses a smart contract with namespaces. It's worth noting that an application -communicates with the peer, and the peer routes the request to the appropriate -chaincode container which then accesses the DBMS. This routing is done by the -peer **core** component shown in the diagram. - -Here's the code for an application that uses both commercial papers and bonds, -priced in Euros and Yen. The code is fairly self-explanatory: - -```javascript -const euroPaper = network.getContract(papers, euroPaper); -paper1 = euroPaper.submit(issue, PAP11); - -const yenPaper = network.getContract(papers, yenPaper); -paper2 = yenPaper.submit(redeem, PAP21); - -const euroBond = network.getContract(bonds, euroBond); -bond1 = euroBond.submit(buy, BON31); - -const yenBond = network.getContract(bonds, yenBond); -bond2 = yenBond.submit(sell, BON41); -``` - -See how the application: - -* Accesses the `euroPaper` and `yenPaper` contracts using the `getContract()` - API specifying the `papers` chaincode. See interaction points **1a** and - **2a**. - -* Accesses the `euroBond` and `yenBond` contracts using the `getContract()` API - specifying the `bonds` chaincode. See interaction points **3a** and **4a**. - -* Submits an `issue` transaction to the network for commercial paper `PAP11` - using the `euroPaper` contract. See interaction point **1a**. This results in - the creation of a commercial paper represented by state `PAP11` in `world - state A`; interaction point **1b**. This operation is captured as a - transaction in the blockchain at interaction point **1c**. - -* Submits a `redeem` transaction to the network for commercial paper `PAP21` - using the `yenPaper` contract. See interaction point **2a**. This results in - the redemption of a commercial paper represented by state `PAP21` in `world - state A`; interaction point **2b**. This operation is captured as a - transaction in the blockchain at interaction point **2c**. - -* Submits a `buy` transaction to the network for bond `BON31` using the - `euroBond` contract. See interaction point **3a**. This results in the - update of a bond represented by state `BON31` in `world state B`; - interaction point **3b**. This operation is captured as a transaction in the - blockchain at interaction point **3c**. - -* Submits a `sell` transaction to the network for bond `BON41` using the - `yenBond` contract. See interaction point **4a**. This results in the update - of a bond represented by state `BON41` in `world state B`; interaction point - **4b**. This operation is captured as a transaction in the blockchain at - interaction point **4c**. - - -See how smart contracts interact with the world state: - -* `euroPaper` and `yenPaper` contracts can directly access `world state A`, but - cannot directly access `world state B`. `World state A` is physically held in - the `papers` database in the database management system (DBMS) corresponding - to the `papers` chaincode. - -* `euroBond` and `yenBond` contracts can directly access `world state B`, but - cannot directly access `world state A`. `World state B` is physically held in - the `bonds` database in the database management system (DBMS) corresponding to - the `bonds` chaincode. - - -See how the blockchain captures transactions for all world states: - -* Interactions **1c** and **2c** correspond to transactions create and update - commercial papers `PAP11` and `PAP21` respectively. These are both contained - within `world state A`. - -* Interactions **3c** and **4c** correspond to transactions both update bonds - `BON31` and `BON41`. These are both contained within `world state B`. - -* If `world state A` or `world state B` were destroyed for any reason, they - could be recreated by replaying all the transactions in the blockchain. - - -## Cross chaincode access - -As we saw in our example [scenario](#scenario), `euroPaper` and `yenPaper` -cannot directly access `world state B`. That's because we have designed our -chaincodes and smart contracts so that these chaincodes and world states are -kept separately from each other. However, let's imagine that `euroPaper` needs -to access `world state B`. - -Why might this happen? Imagine that when a commercial paper was issued, the -smart contract wanted to price the paper according to the current return on -bonds with a similar maturity date. In this case it will be necessary for the -`euroPaper` contract to be able to query the price of bonds in `world state B`. -Look at the following diagram to see how we might structure this interaction. - -![chaincodens.scenario](./develop.diagram.51.png) *How chaincodes and smart -contracts can indirectly access another world state -- via its chaincode.* - -Notice how: - -* the application submits an `issue` transaction in the `euroPaper` smart - contract to issue `PAP11`. See interaction **1a**. - -* the `issue` transaction in the `euroPaper` smart contract calls the `query` - transaction in the `euroBond` smart contract. See interaction point **1b**. - -* the `query`in `euroBond` can retrieve information from `world state B`. See - interaction point **1c**. - -* when control returns to the `issue` transaction, it can use the information in - the response to price the paper and update `world state A` with information. - See interaction point **1d**. - -* the flow of control for issuing commercial paper priced in Yen is the same. - See interaction points **2a**, **2b**, **2c** and **2d**. - -Control is passed between chaincode using the `invokeChaincode()` -[API](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#invokeChaincode__anchor). - -This API passes control from one chaincode to another chaincode. - -Although we have only discussed query transactions in the example, it is -possible to invoke a smart contract which will update the called chaincode's -world state. See the [considerations](#considerations) below. - -## Considerations - -* In general, each chaincode will have a single smart contract in it. - -* Multiple smart contracts should only be deployed in the same chaincode if they - are very closely related. Usually, this is only necessary if they share the - same world state. - -* Chaincode namespaces provide isolation between different world states. In - general it makes sense to isolate unrelated data from each other. Note that - you cannot choose the chaincode namespace; it is assigned by Hyperledger - Fabric, and maps directly to the name of the chaincode. - -* For chaincode to chaincode interactions using the `invokeChaincode()` API, - both chaincodes must be installed on the same peer. - - * For interactions that only require the called chaincode's world state to - be queried, the invocation can be in a different channel to the caller's - chaincode. - - * For interactions that require the called chaincode's world state to be - updated, the invocation must be in the same channel as the caller's - chaincode. - - diff --git a/docs/source/developapps/connectionoptions.md b/docs/source/developapps/connectionoptions.md deleted file mode 100644 index 573de5b3d94..00000000000 --- a/docs/source/developapps/connectionoptions.md +++ /dev/null @@ -1,250 +0,0 @@ -# Connection Options - -**Audience**: Architects, administrators, application and smart contract -developers - -Connection options are used in conjunction with a connection profile to control -*precisely* how a gateway interacts with a network. Using a gateway allows an -application to focus on business logic rather than network topology. - -In this topic, we're going to cover: - -* [Why connection options are important](#scenario) -* [How an application uses connection options](#usage) -* [What each connection option does](#options) -* [When to use a particular connection option](#considerations) - -## Scenario - -A connection option specifies a particular aspect of a gateway's behaviour. -Gateways are important for [many reasons](./gateway.html), the primary being to -allow an application to focus on business logic and smart contracts, while it -manages interactions with the many components of a network. - -![profile.scenario](./develop.diagram.35.png) *The different interaction points -where connection options control behaviour. These options are explained fully in -the text.* - -One example of a connection option might be to specify that the gateway used by -the `issue` application should use identity `Isabella` to submit transactions to -the `papernet` network. Another might be that a gateway should wait for all -three nodes from MagnetoCorp to confirm a transaction has been committed -returning control. Connection options allow applications to specify the precise -behaviour of a gateway's interaction with the network. Without a gateway, -applications need to do a lot more work; gateways save you time, make your -application more readable, and less error prone. - -## Usage - -We'll describe the [full set](#options) of connection options available to an -application in a moment; let's first see how they are specified by the -sample MagnetoCorp `issue` application: - -```javascript -const userName = 'User1@org1.example.com'; -const wallet = new FileSystemWallet('../identity/user/isabella/wallet'); - -const connectionOptions = { - identity: userName, - wallet: wallet, - eventHandlerOptions: { - commitTimeout: 100, - strategy: EventStrategies.MSPID_SCOPE_ANYFORTX - } - }; - -await gateway.connect(connectionProfile, connectionOptions); -``` - -See how the `identity` and `wallet` options are simple properties of the -`connectionOptions` object. They have values `userName` and `wallet` -respectively, which were set earlier in the code. Contrast these options with -the `eventHandlerOptions` option which is an object in its own right. It has -two properties: `commitTimeout: 100` (measured in seconds) and `strategy: -EventStrategies.MSPID_SCOPE_ANYFORTX`. - -See how `connectionOptions` is passed to a gateway as a complement to -`connectionProfile`; the network is identified by the connection profile and -the options specify precisely how the gateway should interact with it. Let's now -look at the available options. - -## Options - -Here's a list of the available options and what they do. - -* `wallet` identifies the wallet that will be used by the gateway on behalf of - the application. See interaction **1**; the wallet is specified by the - application, but it's actually the gateway that retrieves identities from it. - - A wallet must be specified; the most important decision is the - [type](./wallet.html#type) of wallet to use, whether that's file system, - in-memory, HSM or database. - - -* `identity` is the user identity that the application will use from `wallet`. - See interaction **2a**; the user identity is specified by the application and - represents the user of the application, Isabella, **2b**. The identity is - actually retrieved by the gateway. - - In our example, Isabella's identity will be used by different MSPs (**2c**, - **2d**) to identify her as being from MagnetoCorp, and having a particular - role within it. These two facts will correspondingly determine her permission - over resources, such as being able to read and write the ledger, for example. - - A user identity must be specified. As you can see, this identity is - fundamental to the idea that Hyperledger Fabric is a *permissioned* network -- - all actors have an identity, including applications, peers and orderers, which - determines their control over resources. You can read more about this idea in the membership services [topic](../membership/membership.html). - - -* `clientTlsIdentity` is the identity that is retrieved from a wallet (**3a**) - and used for secure communications (**3b**) between the gateway and different - channel components, such as peers and orderers. - - Note that this identity is different to the user identity. Even though - `clientTlsIdentity` is important for secure communications, it is not as - foundational as the user identity because its scope does not extend beyond - secure network communications. - - `clientTlsIdentity` is optional. You are advised to set it in production - environments. You should always use a different `clientTlsIdentity` to - `identity` because these identities have very different meanings and - lifecycles. For example, if your `clientTlsIdentity` was compromised, then so - would your `identity`; it's more secure to keep them separate. - - -* `eventHandlerOptions.commitTimeout` is optional. It specifies, in seconds, the - maximum amount of time the gateway should wait for a transaction to be - committed by any peer (**4a**) before returning control to the application. - The set of peers to use for notification is determined by the - `eventHandlerOptions.strategy` option. If a commitTimeout is not - specified, the gateway will use a timeout of 300 seconds. - - -* `eventHandlerOptions.strategy` is optional. It identifies the set of peers - that a gateway should use to listen for notification that a transaction has - been committed. For example, whether to listen for a single peer, or all - peers, from its organization. It can take one of the following values: - - * `EventStrategies.MSPID_SCOPE_ANYFORTX` Listen for **any** peer within the - user's organization. In our example, see interaction points **4b**; any of - peer 1, peer 2 or peer 3 from MagnetoCorp can notify the gateway. - - * `EventStrategies.MSPID_SCOPE_ALLFORTX` **This is the default value**. Listen - for **all** peers within the user's organization. In our example peer, see - interaction point **4b**. All peers from MagnetoCorp must all have notified - the gateway; peer 1, peer 2 and peer 3. Peers are only counted if they are - known/discovered and available; peers that are stopped or have failed are - not included. - - * `EventStrategies.NETWORK_SCOPE_ANYFORTX` Listen for **any** peer within the - entire network channel. In our example, see interaction points **4b** and - **4c**; any of peer 1-3 from MagnetoCorp or peer 7-9 of DigiBank can notify - the gateway. - - * `EventStrategies.NETWORK_SCOPE_ALLFORTX` Listen for **all** peers within the - entire network channel. In our example, see interaction points **4b** and - **4c**. All peers from MagnetoCorp and DigiBank must notify the gateway; - peers 1-3 and peers 7-9. Peers are only counted if they are known/discovered - and available; peers that are stopped or have failed are not included. - - * <`PluginEventHandlerFunction`> The name of a user-defined event handler. - This allows a user to define their own logic for event handling. See how to - [define](https://hyperledger.github.io/fabric-sdk-node/{BRANCH}/tutorial-transaction-commit-events.html) - a plugin event handler, and examine a [sample - handler](https://github.com/hyperledger/fabric-sdk-node/blob/{BRANCH}/test/integration/network-e2e/sample-transaction-event-handler.js). - - A user-defined event handler is only necessary if you have very specific - event handling requirements; in general, one of the built-in event - strategies will be sufficient. An example of a user-defined event handler - might be to wait for more than half the peers in an organization to confirm - a transaction has been committed. - - If you do specify a user-defined event handler, it does not affect your - application logic; it is quite separate from it. The handler is called by - the SDK during processing; it decides when to call it, and uses its results - to select which peers to use for event notification. The application - receives control when the SDK has finished its processing. - - If a user-defined event handler is not specified then the default values for - `EventStrategies` are used. - - -* `discovery.enabled` is optional and has possible values `true` or `false`. The - default is `true`. It determines whether the gateway uses [service - discovery](../discovery-overview.html) to augment the network topology - specified in the connection profile. See interaction point **6**; peer's - gossip information used by the gateway. - - This value will be overridden by the `INITIALIIZE-WITH-DISCOVERY` environment - variable, which can be set to `true` or `false`. - - -* `discovery.asLocalhost` is optional and has possible values `true` or `false`. - The default is `true`. It determines whether IP addresses found during service - discovery are translated from the docker network to the local host. - - Typically developers will write applications that use docker containers for - their network components such as peers, orderers and CAs, but that do not run - in docker containers themselves. This is why `true` is the default; in - production environments, applications will likely run in docker containers in - the same manner as network components and therefore address translation is not - required. In this case, applications should either explicitly specify `false` - or use the environment variable override. - - This value will be overridden by the `DISCOVERY-AS-LOCALHOST` environment - variable, which can be set to `true` or `false`. - -## Considerations - -The following list of considerations is helpful when deciding how to choose -connection options. - -* `eventHandlerOptions.commitTimeout` and `eventHandlerOptions.strategy` work - together. For example, `commitTimeout: 100` and `strategy: - EventStrategies.MSPID_SCOPE_ANYFORTX` means that the gateway will wait for up - to 100 seconds for *any* peer to confirm a transaction has been committed. In - contrast, specifying `strategy: EventStrategies.NETWORK_SCOPE_ALLFORTX` means - that the gateway will wait up to 100 seconds for *all* peers in *all* - organizations. - - -* The default value of `eventHandlerOptions.strategy: - EventStrategies.MSPID_SCOPE_ALLFORTX` will wait for all peers in the - application's organization to commit the transaction. This is a good default - because applications can be sure that all their peers have an up-to-date copy - of the ledger, minimizing concurrency - issues - - However, as the number of peers in an organization grows, it becomes a little - unnecessary to wait for all peers, in which case using a pluggable event - handler can provide a more efficient strategy. For example the same set of - peers could be used to submit transactions and listen for notifications, on - the safe assumption that consensus will keep all ledgers synchronized. - - -* Service discovery requires `clientTlsIdentity` to be set. That's because the - peers exchanging information with an application need to be confident that - they are exchanging information with entities they trust. If - `clientTlsIdentity` is not set, then `discovery` will not be obeyed, - regardless of whether or not it is set. - - -* Although applications can set connection options when they connect to the - gateway, it can be necessary for these options to be overridden by an - administrator. That's because options relate to network interactions, which - can vary over time. For example, an administrator trying to understand the - effect of using service discovery on network performance. - - A good approach is to define application overrides in a configuration file - which is read by the application when it configures its connection to the - gateway. - - Because the discovery options `enabled` and `asLocalHost` are most frequently - required to be overridden by administrators, the environment variables - `INITIALIIZE-WITH-DISCOVERY` and `DISCOVERY-AS-LOCALHOST` are provided for - convenience. The administrator should set these in the production runtime - environment of the application, which will most likely be a docker container. - - diff --git a/docs/source/developapps/connectionprofile.md b/docs/source/developapps/connectionprofile.md deleted file mode 100644 index 6b73e434ba6..00000000000 --- a/docs/source/developapps/connectionprofile.md +++ /dev/null @@ -1,499 +0,0 @@ -# Connection Profile - -**Audience**: Architects, application and smart contract developers - -A connection profile describes a set of components, including peers, orderers -and certificate authorities in a Hyperledger Fabric blockchain network. It also -contains channel and organization information relating to these components. A -connection profile is primarily used by an application to configure a -[gateway](./gateway.html) that handles all network interactions, allowing it -to focus on business logic. A connection profile is normally created by an -administrator who understands the network topology. - -In this topic, we're going to cover: - -* [Why connection profiles are important](#scenario) -* [How applications use a connection profile](#usage) -* [How to define a connection profile](#structure) - -## Scenario - -A connection profile is used to configure a gateway. Gateways are important for -[many reasons](./gateway.html), the primary being to simplify an application's -interaction with a network channel. - -![profile.scenario](./develop.diagram.30.png) *Two applications, issue and buy, - use gateways 1&2 configured with connection profiles 1&2. Each profile - describes a different subset of MagnetoCorp and DigiBank network components. - Each connection profile must contain sufficient information for a gateway to - interact with the network on behalf of the issue and buy applications. See the - text for a detailed explanation.* - -A connection profile contains a description of a network view, expressed in a -technical syntax, which can either be JSON or YAML. In this topic, we use the -YAML representation, as it's easier for you to read. Static gateways need more -information than dynamic gateways because the latter can use [service -discovery](../discovery-overview.html) to dynamically augment the information in -a connection profile. - -A connection profile should not be an exhaustive description of a network -channel; it just needs to contain enough information sufficient for a gateway -that's using it. In the network above, connection profile 1 needs to contain at -least the endorsing organizations and peers for the `issue` transaction, as well -as identifying the peers that will notify the gateway when the transaction has -been committed to the ledger. - -It's easiest to think of a connection profile as describing a *view* of the -network. It could be a comprehensive view, but that's unrealistic for a few -reasons: - -* Peers, orderers, certificate authorities, channels, and organizations are - added and removed according to demand. - -* Components can start and stop, or fail unexpectedly (e.g. power outage). - -* A gateway doesn't need a view of the whole network, only what's necessary to - successfully handle transaction submission or event notification for example. - -* Service Discovery can augment the information in a connection profile. - Specifically, dynamic gateways can be configured with minimal Fabric topology - information; the rest can be discovered. - -A static connection profile is normally created by an administrator who -understands the network topology in detail. That's because a static profile can -contain quite a lot of information, and an administrator needs to capture this -in the corresponding connection profile. In contrast, dynamic profiles minimize -the amount of definition required and therefore can be a better choice for -developers who want to get going quickly, or administrators who want to create a -more responsive gateway. Connection profiles are created in either the YAML or -JSON format using an editor of choice. - -## Usage - -We'll see how to define a connection profile in a moment; let's first see how it -is used by a sample MagnetoCorp `issue` application: - -```javascript -const yaml = require('js-yaml'); -const { Gateway } = require('fabric-network'); - -const connectionProfile = yaml.safeLoad(fs.readFileSync('../gateway/paperNet.yaml', 'utf8')); - -const gateway = new Gateway(); - -await gateway.connect(connectionProfile, connectionOptions); -``` - -After loading some required classes, see how the `paperNet.yaml` gateway file is -loaded from the file system, converted to a JSON object using the -`yaml.safeLoad()` method, and used to configure a gateway using its `connect()` -method. - -By configuring a gateway with this connection profile, the issue application is -providing the gateway with the relevant network topology it should use to -process transactions. That's because the connection profile contains sufficient -information about the PaperNet channels, organizations, peers, orderers and CAs -to ensure transactions can be successfully processed. - -It's good practice for a connection profile to define more than one peer for any -given organization -- it prevents a single point of failure. This practice also -applies to dynamic gateways; to provide more than one starting point for service -discovery. - -A DigiBank `buy` application would typically configure its gateway with a -similar connection profile, but with some important differences. Some elements -will be the same, such as the channel; some elements will overlap, such as the -endorsing peers. Other elements will be completely different, such as -notification peers or certificate authorities for example. - -The `connectionOptions` passed to a gateway complement the connection profile. -They allow an application to declare how it would like the gateway to use the -connection profile. They are interpreted by the SDK to control interaction -patterns with network components, for example to select which identity to -connect with, or which peers to use for event notifications. Read -[about](./connectionoptions.html) the list of available connection options and -when to use them. - -## Structure - -To help you understand the structure of a connection profile, we're going to -step through an example for the network shown [above](#scenario). Its connection -profile is based on the PaperNet commercial paper sample, and -[stored](https://github.com/hyperledger/fabric-samples/blob/{BRANCH}/commercial-paper/organization/magnetocorp/gateway/networkConnection.yaml) -in the GitHub repository. For convenience, we've reproduced it [below](#sample). -You will find it helpful to display it in another browser window as you now read -about it: - -* Line 9: `name: "papernet.magnetocorp.profile.sample"` - - This is the name of the connection profile. Try to use DNS style names; they - are a very easy way to convey meaning. - - -* Line 16: `x-type: "hlfv1"` - - Users can add their own `x-` properties that are "application-specific" -- - just like with HTTP headers. They are provided primarily for future use. - - -* Line 20: `description: "Sample connection profile for documentation topic"` - - A short description of the connection profile. Try to make this helpful for - the reader who might be seeing this for the first time! - - -* Line 25: `version: "1.0"` - - The schema version for this connection profile. Currently only version 1.0 is - supported, and it is not envisioned that this schema will change frequently. - - -* Line 32: `channels:` - - This is the first really important line. `channels:` identifies that what - follows are *all* the channels that this connection profile describes. However, - it is good practice to keep different channels in different connection - profiles, especially if they are used independently of each other. - - -* Line 36: `papernet:` - - Details of `papernet`, the first channel in this connection profile, will - follow. - - -* Line 41: `orderers:` - - Details of all the orderers for `papernet` follow. You can see in line 45 that - the orderer for this channel is `orderer1.magnetocorp.example.com`. This is - just a logical name; later in the connection profile (lines 134 - 147), there - will be details of how to connect to this orderer. Notice that - `orderer2.digibank.example.com` is not in this list; it makes sense that - applications use their own organization's orderers, rather than those from a - different organization. - - -* Line 49: `peers:` - - Details of all the peers for `papernet` will follow. - - You can see three peers listed from MagnetoCorp: - `peer1.magnetocorp.example.com`, `peer2.magnetocorp.example.com` and - `peer3.magnetocorp.example.com`. It's not necessary to list all the peers in - MagnetoCorp, as has been done here. You can see only one peer listed from - DigiBank: `peer9.digibank.example.com`; including this peer starts to imply - that the endorsement policy requires MagnetoCorp and DigiBank to endorse - transactions, as we'll now confirm. It's good practice to have multiple peers - to avoid single points of failure. - - Underneath each peer you can see four non-exclusive roles: **endorsingPeer**, - **chaincodeQuery**, **ledgerQuery** and **eventSource**. See how `peer1` and - `peer2` can perform all roles as they host `papercontract`. Contrast to - `peer3`, which can only be used for notifications, or ledger queries that - access the blockchain component of the ledger rather than the world state, and - hence do not need to have smart contracts installed. Notice how `peer9` should - not be used for anything other than endorsement, because those roles are - better served by MagnetoCorp peers. - - Again, see how the peers are described according to their logical names and - their roles. Later in the profile, we'll see the physical information for - these peers. - - -* Line 97: `organizations:` - - Details of all the organizations will follow, for all channels. Note that - these organizations are for all channels, even though `papernet` is currently - the only one listed. That's because organizations can be in multiple - channels, and channels can have multiple organizations. Moreover, some - application operations relate to organizations rather than channels. For - example, an application can request notification from one or all peers within - its organization, or all organizations within the network -- using [connection - options](./connectionoptions.html). For this, there needs to be an organization - to peer mapping, and this section provides it. - -* Line 101: `MagnetoCorp:` - - All peers that are considered part of MagnetoCorp are listed: `peer1`, - `peer2` and `peer3`. Likewise for Certificate Authorities. Again, note the - logical name usages, the same as the `channels:` section; physical information - will follow later in the profile. - - -* Line 121: `DigiBank:` - - Only `peer9` is listed as part of DigiBank, and no Certificate Authorities. - That's because these other peers and the DigiBank CA are not relevant for - users of this connection profile. - - -* Line 134: `orderers:` - - The physical information for orderers is now listed. As this connection - profile only mentioned one orderer for `papernet`, you see - `orderer1.magnetocorp.example.com` details listed. These include its IP - address and port, and gRPC options that can override the defaults used when - communicating with the orderer, if necessary. As with `peers:`, for high - availability, specifying more than one orderer is a good idea. - - -* Line 152: `peers:` - - The physical information for all previous peers is now listed. This - connection profile has three peers for MagnetoCorp: `peer1`, `peer2`, and - `peer3`; for DigiBank, a single peer `peer9` has its information listed. For - each peer, as with orderers, their IP address and port is listed, together - with gRPC options that can override the defaults used when communicating with - a particular peer, if necessary. - - -* Line 194: `certificateAuthorities:` - - The physical information for certificate authorities is now listed. The - connection profile has a single CA listed for MagnetoCorp, `ca1-magnetocorp`, - and its physical information follows. As well as IP details, the registrar - information allows this CA to be used for Certificate Signing Requests (CSR). - These are used to request new certificates for locally generated - public/private key pairs. - -Now you've understood a connection profile for MagnetoCorp, you might like to -look at a -[corresponding](https://github.com/hyperledger/fabric-samples/blob/{BRANCH}/commercial-paper/organization/magnetocorp/gateway/networkConnection.yaml) -profile for DigiBank. Locate where the profile is the same as MagnetoCorp's, see -where it's similar, and finally where it's different. Think about why these -differences make sense for DigiBank applications. - -That's everything you need to know about connection profiles. In summary, a -connection profile defines sufficient channels, organizations, peers, orderers -and certificate authorities for an application to configure a gateway. The -gateway allows the application to focus on business logic rather than the -details of the network topology. - -## Sample - -This file is reproduced inline from the GitHub commercial paper -[sample](https://github.com/hyperledger/fabric-samples/blob/{BRANCH}/commercial-paper/organization/magnetocorp/gateway/networkConnection.yaml). - -``` -1: --- -2: # -3: # [Required]. A connection profile contains information about a set of network -4: # components. It is typically used to configure gateway, allowing applications -5: # interact with a network channel without worrying about the underlying -6: # topology. A connection profile is normally created by an administrator who -7: # understands this topology. -8: # -9: name: "papernet.magnetocorp.profile.sample" -10: # -11: # [Optional]. Analogous to HTTP, properties with an "x-" prefix are deemed -12: # "application-specific", and ignored by the gateway. For example, property -13: # "x-type" with value "hlfv1" was originally used to identify a connection -14: # profile for Fabric 1.x rather than 0.x. -15: # -16: x-type: "hlfv1" -17: # -18: # [Required]. A short description of the connection profile -19: # -20: description: "Sample connection profile for documentation topic" -21: # -22: # [Required]. Connection profile schema version. Used by the gateway to -23: # interpret these data. -24: # -25: version: "1.0" -26: # -27: # [Optional]. A logical description of each network channel; its peer and -28: # orderer names and their roles within the channel. The physical details of -29: # these components (e.g. peer IP addresses) will be specified later in the -30: # profile; we focus first on the logical, and then the physical. -31: # -32: channels: -33: # -34: # [Optional]. papernet is the only channel in this connection profile -35: # -36: papernet: -37: # -38: # [Optional]. Channel orderers for PaperNet. Details of how to connect to -39: # them is specified later, under the physical "orderers:" section -40: # -41: orderers: -42: # -43: # [Required]. Orderer logical name -44: # -45: - orderer1.magnetocorp.example.com -46: # -47: # [Optional]. Peers and their roles -48: # -49: peers: -50: # -51: # [Required]. Peer logical name -52: # -53: peer1.magnetocorp.example.com: -54: # -55: # [Optional]. Is this an endorsing peer? (It must have chaincode -56: # installed.) Default: true -57: # -58: endorsingPeer: true -59: # -60: # [Optional]. Is this peer used for query? (It must have chaincode -61: # installed.) Default: true -62: # -63: chaincodeQuery: true -64: # -65: # [Optional]. Is this peer used for non-chaincode queries? All peers -66: # support these types of queries, which include queryBlock(), -67: # queryTransaction(), etc. Default: true -68: # -69: ledgerQuery: true -70: # -71: # [Optional]. Is this peer used as an event hub? All peers can produce -72: # events. Default: true -73: # -74: eventSource: true -75: # -76: peer2.magnetocorp.example.com: -77: endorsingPeer: true -78: chaincodeQuery: true -79: ledgerQuery: true -80: eventSource: true -81: # -82: peer3.magnetocorp.example.com: -83: endorsingPeer: false -84: chaincodeQuery: false -85: ledgerQuery: true -86: eventSource: true -87: # -88: peer9.digibank.example.com: -89: endorsingPeer: true -90: chaincodeQuery: false -91: ledgerQuery: false -92: eventSource: false -93: # -94: # [Required]. List of organizations for all channels. At least one organization -95: # is required. -96: # -97: organizations: -98: # -99: # [Required]. Organizational information for MagnetoCorp -100: # -101: MagnetoCorp: -102: # -103: # [Required]. The MSPID used to identify MagnetoCorp -104: # -105: mspid: MagnetoCorpMSP -106: # -107: # [Required]. The MagnetoCorp peers -108: # -109: peers: -110: - peer1.magnetocorp.example.com -111: - peer2.magnetocorp.example.com -112: - peer3.magnetocorp.example.com -113: # -114: # [Optional]. Fabric-CA Certificate Authorities. -115: # -116: certificateAuthorities: -117: - ca-magnetocorp -118: # -119: # [Optional]. Organizational information for DigiBank -120: # -121: DigiBank: -122: # -123: # [Required]. The MSPID used to identify DigiBank -124: # -125: mspid: DigiBankMSP -126: # -127: # [Required]. The DigiBank peers -128: # -129: peers: -130: - peer9.digibank.example.com -131: # -132: # [Optional]. Orderer physical information, by orderer name -133: # -134: orderers: -135: # -136: # [Required]. Name of MagnetoCorp orderer -137: # -138: orderer1.magnetocorp.example.com: -139: # -140: # [Required]. This orderer's IP address -141: # -142: url: grpc://localhost:7050 -143: # -144: # [Optional]. gRPC connection properties used for communication -145: # -146: grpcOptions: -147: ssl-target-name-override: orderer1.magnetocorp.example.com -148: # -149: # [Required]. Peer physical information, by peer name. At least one peer is -150: # required. -151: # -152: peers: -153: # -154: # [Required]. First MagetoCorp peer physical properties -155: # -156: peer1.magnetocorp.example.com: -157: # -158: # [Required]. Peer's IP address -159: # -160: url: grpc://localhost:7151 -161: # -162: # [Optional]. gRPC connection properties used for communication -163: # -164: grpcOptions: -165: ssl-target-name-override: peer1.magnetocorp.example.com -166: request-timeout: 120001 -167: # -168: # [Optional]. Other MagnetoCorp peers -169: # -170: peer2.magnetocorp.example.com: -171: url: grpc://localhost:7251 -172: grpcOptions: -173: ssl-target-name-override: peer2.magnetocorp.example.com -174: request-timeout: 120001 -175: # -176: peer3.magnetocorp.example.com: -177: url: grpc://localhost:7351 -178: grpcOptions: -179: ssl-target-name-override: peer3.magnetocorp.example.com -180: request-timeout: 120001 -181: # -182: # [Required]. Digibank peer physical properties -183: # -184: peer9.digibank.example.com: -185: url: grpc://localhost:7951 -186: grpcOptions: -187: ssl-target-name-override: peer9.digibank.example.com -188: request-timeout: 120001 -189: # -190: # [Optional]. Fabric-CA Certificate Authority physical information, by name. -191: # This information can be used to (e.g.) enroll new users. Communication is via -192: # REST, hence options relate to HTTP rather than gRPC. -193: # -194: certificateAuthorities: -195: # -196: # [Required]. MagnetoCorp CA -197: # -198: ca1-magnetocorp: -199: # -200: # [Required]. CA IP address -201: # -202: url: http://localhost:7054 -203: # -204: # [Optional]. HTTP connection properties used for communication -205: # -206: httpOptions: -207: verify: false -208: # -209: # [Optional]. Fabric-CA supports Certificate Signing Requests (CSRs). A -210: # registrar is needed to enroll new users. -211: # -212: registrar: -213: - enrollId: admin -214: enrollSecret: adminpw -215: # -216: # [Optional]. The name of the CA. -217: # -218: caName: ca-magnetocorp -``` - - diff --git a/docs/source/developapps/contractname.md b/docs/source/developapps/contractname.md deleted file mode 100644 index 7b62fd334fc..00000000000 --- a/docs/source/developapps/contractname.md +++ /dev/null @@ -1,154 +0,0 @@ -# Contract names - -**Audience**: Architects, application and smart contract developers, -administrators - -A chaincode is a generic container for deploying code to a Hyperledger Fabric -blockchain network. One or more related smart contracts are defined within a -chaincode. Every smart contract has a name that uniquely identifies it within a -chaincode. Applications access a particular smart contract within a chaincode -using its contract name. - -In this topic, we're going to cover: -* [How a chaincode contains multiple smart contracts](#chaincode) -* [How to assign a smart contract name](#name) -* [How to use a smart contract from an application](#application) -* [The default smart contract](#default-contract) - -## Chaincode - -In the [Developing Applications](./developing_applications.html) topic, we can -see how the Fabric SDKs provide high level programming abstractions which help -application and smart contract developers to focus on their business problem, -rather than the low level details of how to interact with a Fabric network. - -Smart contracts are one example of a high level programming abstraction, and it -is possible to define smart contracts within in a chaincode container. When a -chaincode is installed on your peer and deployed to a channel, all the smart -contracts within it are made available to your applications. - -![contract.chaincode](./develop.diagram.20.png) *Multiple smart contracts can be -defined within a chaincode. Each is uniquely identified by their name within a -chaincode.* - -In the diagram [above](#chaincode), chaincode A has three smart contracts -defined within it, whereas chaincode B has four smart contracts. See how the -chaincode name is used to fully qualify a particular smart contract. - -The ledger structure is defined by a set of deployed smart contracts. That's -because the ledger contains facts about the business objects of interest to the -network (such as commercial paper within PaperNet), and these business objects -are moved through their lifecycle (e.g. issue, buy, redeem) by the transaction -functions defined within a smart contract. - -In most cases, a chaincode will only have one smart contract defined within it. -However, it can make sense to keep related smart contracts together in a single -chaincode. For example, commercial papers denominated in different currencies -might have contracts `EuroPaperContract`, `DollarPaperContract`, -`YenPaperContract` which might need to be kept synchronized with each other in -the channel to which they are deployed. - -## Name - -Each smart contract within a chaincode is uniquely identified by its contract -name. A smart contract can explicitly assign this name when the class is -constructed, or let the `Contract` class implicitly assign a default name. - -Examine the `papercontract.js` chaincode -[file](https://github.com/hyperledger/fabric-samples/blob/{BRANCH}/commercial-paper/organization/magnetocorp/contract/lib/papercontract.js#L31): - -```javascript -class CommercialPaperContract extends Contract { - - constructor() { - // Unique name when multiple contracts per chaincode file - super('org.papernet.commercialpaper'); - } -``` - -See how the `CommercialPaperContract` constructor specifies the contract name as -`org.papernet.commercialpaper`. The result is that within the `papercontract` -chaincode, this smart contract is now associated with the contract name -`org.papernet.commercialpaper`. - -If an explicit contract name is not specified, then a default name is assigned --- the name of the class. In our example, the default contract name would be -`CommercialPaperContract`. - -Choose your names carefully. It's not just that each smart contract must have a -unique name; a well-chosen name is illuminating. Specifically, using an explicit -DNS-style naming convention is recommended to help organize clear and meaningful -names; `org.papernet.commercialpaper` conveys that the PaperNet network has -defined a standard commercial paper smart contract. - -Contract names are also helpful to disambiguate different smart contract -transaction functions with the same name in a given chaincode. This happens when -smart contracts are closely related; their transaction names will tend to be the -same. We can see that a transaction is uniquely defined within a channel by the -combination of its chaincode and smart contract name. - -Contract names must be unique within a chaincode file. Some code editors will -detect multiple definitions of the same class name before deployment. Regardless -the chaincode will return an error if multiple classes with the same contract -name are explicitly or implicitly specified. - -## Application - -Once a chaincode has been installed on a peer and deployed to a channel, the -smart contracts in it are accessible to an application: - -```javascript -const network = await gateway.getNetwork(`papernet`); - -const contract = await network.getContract('papercontract', 'org.papernet.commercialpaper'); - -const issueResponse = await contract.submitTransaction('issue', 'MagnetoCorp', '00001', '2020-05-31', '2020-11-30', '5000000'); -``` - -See how the application accesses the smart contract with the -`network.getContract()` method. The `papercontract` chaincode name -`org.papernet.commercialpaper` returns a `contract` reference which can be -used to submit transactions to issue commercial paper with the -`contract.submitTransaction()` API. - -## Default contract - -The first smart contract defined in a chaincode is called the *default* -smart contract. A default is helpful because a chaincode will usually have one -smart contract defined within it; a default allows the application to access -those transactions directly -- without specifying a contract name. - -![default.contract](./develop.diagram.21.png) *A default smart contract is the -first contract defined in a chaincode.* - -In this diagram, `CommercialPaperContract` is the default smart contract. Even -though we have two smart contracts, the default smart contract makes our -[previous](#application) example easier to write: - -```javascript -const network = await gateway.getNetwork(`papernet`); - -const contract = await network.getContract('papercontract'); - -const issueResponse = await contract.submitTransaction('issue', 'MagnetoCorp', '00001', '2020-05-31', '2020-11-30', '5000000'); -``` - -This works because the default smart contract in `papercontract` is -`CommercialPaperContract` and it has an `issue` transaction. Note that the -`issue` transaction in `BondContract` can only be invoked by explicitly -addressing it. Likewise, even though the `cancel` transaction is unique, because -`BondContract` is *not* the default smart contract, it must also be explicitly -addressed. - -In most cases, a chaincode will only contain a single smart contract, so careful -naming of the chaincode can reduce the need for developers to care about -chaincode as a concept. In the example code [above](#default-contract) it feels -like `papercontract` is a smart contract. - -In summary, contract names are a straightforward mechanism to identify -individual smart contracts within a given chaincode. Contract names make it easy -for applications to find a particular smart contract and use it to access the -ledger. - - diff --git a/docs/source/developapps/designelements.rst b/docs/source/developapps/designelements.rst deleted file mode 100644 index 5e546a0d3da..00000000000 --- a/docs/source/developapps/designelements.rst +++ /dev/null @@ -1,20 +0,0 @@ -Application design elements -=========================== - -This section elaborates the key features for client application and smart -contract development found in Hyperledger Fabric. A solid understanding of -the features will help you design and implement efficient and effective -solutions. - -.. toctree:: - :maxdepth: 1 - - contractname.md - chaincodenamespace.md - transactioncontext.md - transactionhandler.md - endorsementpolicies.md - connectionprofile.md - connectionoptions.md - wallet.md - gateway.md diff --git a/docs/source/developapps/develop.diagram.1.png b/docs/source/developapps/develop.diagram.1.png deleted file mode 100644 index a5faa9d2abe..00000000000 Binary files a/docs/source/developapps/develop.diagram.1.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.10.png b/docs/source/developapps/develop.diagram.10.png deleted file mode 100644 index e04dbb7f41a..00000000000 Binary files a/docs/source/developapps/develop.diagram.10.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.11.png b/docs/source/developapps/develop.diagram.11.png deleted file mode 100644 index 300461dd2f6..00000000000 Binary files a/docs/source/developapps/develop.diagram.11.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.12.png b/docs/source/developapps/develop.diagram.12.png deleted file mode 100644 index 0eb104d7d70..00000000000 Binary files a/docs/source/developapps/develop.diagram.12.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.13.png b/docs/source/developapps/develop.diagram.13.png deleted file mode 100644 index 99451ec25ad..00000000000 Binary files a/docs/source/developapps/develop.diagram.13.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.2.png b/docs/source/developapps/develop.diagram.2.png deleted file mode 100644 index 72bd5fb35e7..00000000000 Binary files a/docs/source/developapps/develop.diagram.2.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.20.png b/docs/source/developapps/develop.diagram.20.png deleted file mode 100644 index 33852ca5a60..00000000000 Binary files a/docs/source/developapps/develop.diagram.20.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.21.png b/docs/source/developapps/develop.diagram.21.png deleted file mode 100644 index fa1c4b11559..00000000000 Binary files a/docs/source/developapps/develop.diagram.21.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.25.png b/docs/source/developapps/develop.diagram.25.png deleted file mode 100644 index 90b5e843941..00000000000 Binary files a/docs/source/developapps/develop.diagram.25.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.3.png b/docs/source/developapps/develop.diagram.3.png deleted file mode 100644 index 5e55679b211..00000000000 Binary files a/docs/source/developapps/develop.diagram.3.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.30.png b/docs/source/developapps/develop.diagram.30.png deleted file mode 100644 index 38909a0865f..00000000000 Binary files a/docs/source/developapps/develop.diagram.30.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.35.png b/docs/source/developapps/develop.diagram.35.png deleted file mode 100644 index 1143704f6ad..00000000000 Binary files a/docs/source/developapps/develop.diagram.35.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.4.png b/docs/source/developapps/develop.diagram.4.png deleted file mode 100644 index 9918b4d0111..00000000000 Binary files a/docs/source/developapps/develop.diagram.4.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.40.png b/docs/source/developapps/develop.diagram.40.png deleted file mode 100644 index 71e9d060ae1..00000000000 Binary files a/docs/source/developapps/develop.diagram.40.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.41.png b/docs/source/developapps/develop.diagram.41.png deleted file mode 100644 index 35a06617ea8..00000000000 Binary files a/docs/source/developapps/develop.diagram.41.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.5.png b/docs/source/developapps/develop.diagram.5.png deleted file mode 100644 index 2604b94f042..00000000000 Binary files a/docs/source/developapps/develop.diagram.5.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.50.png b/docs/source/developapps/develop.diagram.50.png deleted file mode 100644 index 9f3309024c5..00000000000 Binary files a/docs/source/developapps/develop.diagram.50.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.51.png b/docs/source/developapps/develop.diagram.51.png deleted file mode 100644 index ceec53b8089..00000000000 Binary files a/docs/source/developapps/develop.diagram.51.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.6.png b/docs/source/developapps/develop.diagram.6.png deleted file mode 100644 index 454535aa522..00000000000 Binary files a/docs/source/developapps/develop.diagram.6.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.7.png b/docs/source/developapps/develop.diagram.7.png deleted file mode 100644 index f7546ed4b7a..00000000000 Binary files a/docs/source/developapps/develop.diagram.7.png and /dev/null differ diff --git a/docs/source/developapps/develop.diagram.8.png b/docs/source/developapps/develop.diagram.8.png deleted file mode 100644 index bcfd04b0762..00000000000 Binary files a/docs/source/developapps/develop.diagram.8.png and /dev/null differ diff --git a/docs/source/developapps/developing_applications.rst b/docs/source/developapps/developing_applications.rst deleted file mode 100644 index d123f8d273a..00000000000 --- a/docs/source/developapps/developing_applications.rst +++ /dev/null @@ -1,44 +0,0 @@ -Developing Applications -======================= - -.. toctree:: - :maxdepth: 1 - :hidden: - - scenario.md - analysis.md - architecture.md - smartcontract.md - application.md - designelements - -This topic covers how to develop a client application and smart contract to -solve a business problem using Hyperledger Fabric. In a real world **Commercial -Paper** scenario, involving multiple organizations, you'll learn about all the -concepts and tasks required to accomplish this goal. We assume that the -blockchain network is already available. - -The topic is designed for multiple audiences: - -* Solution and application architect -* Client application developer -* Smart contract developer -* Business professional - -You can choose to read the topic in order, or you can select individual sections -as appropriate. Individual topic sections are marked according to reader -relevance, so whether you're looking for business or technical information it'll -be clear when a topic is for you. - -The topic follows a typical software development lifecycle. It starts with -business requirements, and then covers all the major technical activities -required to develop an application and smart contract to meet these -requirements. - -If you'd prefer, you can try out the commercial paper scenario immediately, -following an abbreviated explanation, by running the commercial paper `tutorial -<../tutorial/commercial_paper.html>`_. You can return to this topic when you -need fuller explanations of the concepts introduced in the tutorial. - -.. Licensed under Creative Commons Attribution 4.0 International License - https://creativecommons.org/licenses/by/4.0/ diff --git a/docs/source/developapps/diagrams.pptx b/docs/source/developapps/diagrams.pptx deleted file mode 100644 index 4123c80f3af..00000000000 Binary files a/docs/source/developapps/diagrams.pptx and /dev/null differ diff --git a/docs/source/developapps/endorsementpolicies.md b/docs/source/developapps/endorsementpolicies.md deleted file mode 100644 index 634bd59e71b..00000000000 --- a/docs/source/developapps/endorsementpolicies.md +++ /dev/null @@ -1,23 +0,0 @@ -# Endorsement policies - -**Audience**: Architects, Application and smart contract developers - -Endorsement policies define the smallest set of organizations that are required -to endorse a transaction in order for it to be valid. To endorse, an organization's -endorsing peer needs to run the smart contract associated with the transaction -and sign its outcome. When the ordering service sends the transaction to the -committing peers, they will each individually check whether the endorsements in -the transaction fulfill the endorsement policy. If this is not the case, the -transaction is invalidated and it will have no effect on world state. - -Endorsement policies work at two different granularities: they can be set for an -entire namespace, as well as for individual state keys. They are formulated using -basic logic expressions such as `AND` and `OR`. For example, in PaperNet this -could be used as follows: the endorsement policy for a paper that has been sold -from MagnetoCorp to DigiBank could be set to `AND(MagnetoCorp.peer, DigiBank.peer)`, -requiring any changes to this paper to be endorsed by both MagnetoCorp and DigiBank. - - - - diff --git a/docs/source/developapps/gateway.md b/docs/source/developapps/gateway.md deleted file mode 100644 index cfaf8bf3f82..00000000000 --- a/docs/source/developapps/gateway.md +++ /dev/null @@ -1,189 +0,0 @@ -# Gateway - -**Audience**: Architects, application and smart contract developers - -A gateway manages the network interactions on behalf of an application, allowing -it to focus on business logic. Applications connect to a gateway and then all -subsequent interactions are managed using that gateway's configuration. - -In this topic, we're going to cover: - -* [Why gateways are important](#scenario) -* [How applications use a gateway](#connect) -* [How to define a static gateway](#static) -* [How to define a dynamic gateway for service discovery](#dynamic) -* [Using multiple gateways](#multiple-gateways) - -## Scenario - -A Hyperledger Fabric network channel can constantly change. The peer, orderer -and CA components, contributed by the different organizations in the network, -will come and go. Reasons for this include increased or reduced business demand, -and both planned and unplanned outages. A gateway relieves an application of -this burden, allowing it to focus on the business problem it is trying to solve. - -![gateway.scenario](./develop.diagram.25.png) *A MagnetoCorp and DigiBank -applications (issue and buy) delegate their respective network interactions to -their gateways. Each gateway understands the network channel topology comprising -the multiple peers and orderers of two organizations MagnetoCorp and DigiBank, -leaving applications to focus on business logic. Peers can talk to each other -both within and across organizations using the gossip protocol.* - -A gateway can be used by an application in two different ways: - -* **Static**: The gateway configuration is *completely* defined in a [connection - profile](./connectionprofile.html). All the peers, orderers and CAs - available to an application are statically defined in the connection profile - used to configure the gateway. For peers, this includes their role as an - endorsing peer or event notification hub, for example. You can read more about - these roles in the connection profile [topic](./connectionprofile.html). - - The SDK will use this static topology, in conjunction with gateway - [connection options](connectionoptions.html), to manage the transaction - submission and notification processes. The connection profile must contain - enough of the network topology to allow a gateway to interact with the - network on behalf of the application; this includes the network channels, - organizations, orderers, peers and their roles. - - -* **Dynamic**: The gateway configuration is minimally defined in a connection - profile. Typically, one or two peers from the application's organization are - specified, and they use [service discovery](../discovery-overview.html) to - discover the available network topology. This includes peers, orderers, - channels, deployed smart contracts and their endorsement policies. (In - production environments, a gateway configuration should specify at least two - peers for availability.) - - The SDK will use all of the static and discovered topology information, in - conjunction with gateway connection options, to manage the transaction - submission and notification processes. As part of this, it will also - intelligently use the discovered topology; for example, it will *calculate* - the minimum required endorsing peers using the discovered endorsement policy - for the smart contract. - -You might ask yourself whether a static or dynamic gateway is better? The -trade-off is between predictability and responsiveness. Static networks will -always behave the same way, as they perceive the network as unchanging. In this -sense they are predictable -- they will always use the same peers and orderers -if they are available. Dynamic networks are more responsive as they understand -how the network changes -- they can use newly added peers and orderers, which -brings extra resilience and scalability, at potentially some cost in -predictability. In general it's fine to use dynamic networks, and indeed this -the default mode for gateways. - -Note that the *same* connection profile can be used statically or dynamically. -Clearly, if a profile is going to be used statically, it needs to be -comprehensive, whereas dynamic usage requires only sparse population. - -Both styles of gateway are transparent to the application; the application -program design does not change whether static or dynamic gateways are used. This -also means that some applications may use service discovery, while others may -not. In general using dynamic discovery means less definition and more -intelligence by the SDK; it is the default. - -## Connect - -When an application connects to a gateway, two options are provided. These are -used in subsequent SDK processing: - -```javascript - await gateway.connect(connectionProfile, connectionOptions); -``` - -* **Connection profile**: `connectionProfile` is the gateway configuration that - will be used for transaction processing by the SDK, whether statically or - dynamically. It can be specified in YAML or JSON, though it must be converted - to a JSON object when passed to the gateway: - - ```javascript - let connectionProfile = yaml.safeLoad(fs.readFileSync('../gateway/paperNet.yaml', 'utf8')); - ``` - - Read more about [connection profiles](./connectionprofile.html) and how - to configure them. - - -* **Connection options**: `connectionOptions` allow an application to declare - rather than implement desired transaction processing behaviour. Connection - options are interpreted by the SDK to control interaction patterns with - network components, for example to select which identity to connect with, or - which peers to use for event notifications. These options significantly reduce - application complexity without compromising functionality. This is possible - because the SDK has implemented much of the low level logic that would - otherwise be required by applications; connection options control this logic - flow. - - Read about the list of available [connection options](./connectionoptions.html) - and when to use them. - -## Static - -Static gateways define a fixed view of a network. In the MagnetoCorp -[scenario](#scenario), a gateway might identify a single peer from MagnetoCorp, -a single peer from DigiBank, and a MagentoCorp orderer. Alternatively, a gateway -might define *all* peers and orderers from MagnetCorp and DigiBank. In both -cases, a gateway must define a view of the network sufficient to get commercial -paper transactions endorsed and distributed. - -Applications can use a gateway statically by explicitly specifying the connect -option `discovery: { enabled:false }` on the `gateway.connect()` API. -Alternatively, the environment variable setting `FABRIC_SDK_DISCOVERY=false` -will always override the application choice. - -Examine the [connection -profile](https://github.com/hyperledger/fabric-samples/blob/{BRANCH}/commercial-paper/organization/magnetocorp/gateway/networkConnection.yaml) -used by the MagnetoCorp issue application. See how all the peers, orderers and -even CAs are specified in this file, including their roles. - -It's worth bearing in mind that a static gateway represents a view of a network -at a *moment in time*. As networks change, it may be important to reflect this -in a change to the gateway file. Applications will automatically pick up these -changes when they re-load the gateway file. - -## Dynamic - -Dynamic gateways define a small, fixed *starting point* for a network. In the -MagnetoCorp [scenario](#scenario), a dynamic gateway might identify just a -single peer from MagnetoCorp; everything else will be discovered! (To provide -resiliency, it might be better to define two such bootstrap peers.) - -If [service discovery](../discovery-overview.html) is selected by an -application, the topology defined in the gateway file is augmented with that -produced by this process. Service discovery starts with the gateway definition, -and finds all the connected peers and orderers within the MagnetoCorp -organization using the [gossip protocol](../gossip.html). If [anchor -peers](../glossary.html#anchor-peer) have been defined for a channel, then -service discovery will use the gossip protocol across organizations to discover -components within the connected organization. This process will also discover -smart contracts installed on peers and their endorsement policies defined at a -channel level. As with static gateways, the discovered network must be -sufficient to get commercial paper transactions endorsed and distributed. - -Dynamic gateways are the default setting for Fabric applications. They can be -explicitly specified using the connect option `discovery: { enabled:true }` on -the `gateway.connect()` API. Alternatively, the environment variable setting -`FABRIC_SDK_DISCOVERY=true` will always override the application choice. - -A dynamic gateway represents an up-to-date view of a network. As networks -change, service discovery will ensure that the network view is an accurate -reflection of the topology visible to the application. Applications will -automatically pick up these changes; they do not even need to re-load the -gateway file. - -## Multiple gateways - -Finally, it is straightforward for an application to define multiple gateways, -both for the same or different networks. Moreover, applications can use the name -gateway both statically and dynamically. - -It can be helpful to have multiple gateways. Here are a few reasons: - -* Handling requests on behalf of different users. - -* Connecting to different networks simultaneously. - -* Testing a network configuration, by simultaneously comparing its behaviour - with an existing configuration. - - diff --git a/docs/source/developapps/scenario.md b/docs/source/developapps/scenario.md deleted file mode 100644 index 34294673a66..00000000000 --- a/docs/source/developapps/scenario.md +++ /dev/null @@ -1,104 +0,0 @@ -# The scenario - -**Audience**: Architects, Application and smart contract developers, Business -professionals - -In this topic, we're going to describe a business scenario involving six -organizations who use PaperNet, a commercial paper network built on Hyperledger -Fabric, to issue, buy and redeem commercial paper. We're going to use the -scenario to outline requirements for the development of commercial paper -applications and smart contracts used by the participant organizations. - -## What is commercial paper? - -Commercial paper is a commonly used type of unsecured, short-term debt instrument -issued by corporations, typically used for the financing of payroll, accounts -payable and inventories, and meeting other short-term liabilities. Maturities on -commercial paper typically last several days, and rarely range longer than 270 days. -The face value of the commercial paper is the value the issuing corporating would be -paying the redeemer of the paper upon maturity. While buying the paper, the lender -buys it for a price lesser than the face value. The difference between the face value and -the price the lender bought the paper for is the profit made by the lender. - -## PaperNet network - -PaperNet is a commercial paper network that allows suitably authorized -participants to issue, trade, redeem and rate commercial paper. - -![develop.systemscontext](./develop.diagram.1.png) - -*The PaperNet commercial paper network. Six organizations currently use PaperNet -network to issue, buy, sell, redeem and rate commercial paper. MagentoCorp -issues and redeems commercial paper. DigiBank, BigFund, BrokerHouse and -HedgeMatic all trade commercial paper with each other. RateM provides various -measures of risk for commercial paper.* - -Let's see how MagnetoCorp uses PaperNet and commercial paper to help its -business. - -## Introducing the actors - -MagnetoCorp is a well-respected company that makes self-driving electric -vehicles. In early April 2020, MagnetoCorp won a large order to manufacture -10,000 Model D cars for Daintree, a new entrant in the personal transport -market. Although the order represents a significant win for MagnetoCorp, -Daintree will not have to pay for the vehicles until they start to be delivered -on November 1, six months after the deal was formally agreed between MagnetoCorp -and Daintree. - -To manufacture the vehicles, MagnetoCorp will need to hire 1000 workers for at -least 6 months. This puts a short term strain on its finances -- it will require -an extra 5M USD each month to pay these new employees. **Commercial paper** is -designed to help MagnetoCorp overcome its short term financing needs -- to meet -payroll every month based on the expectation that it will be cash rich when -Daintree starts to pay for its new Model D cars. - -At the end of May, MagnetoCorp needs 5M USD to meet payroll for the extra -workers it hired on May 1. To do this, it issues a commercial paper with a face -value of 5M USD with a maturity date 6 months in the future -- when it expects -to see cash flow from Daintree. DigiBank thinks that MagnetoCorp is -creditworthy, and therefore doesn't require much of a premium above the central -bank base rate of 2%, which would value 4.95M USD today at 5M USD in 6 months -time. It therefore purchases the MagnetoCorp 6 month commercial paper for 4.94M -USD -- a slight discount compared to the 4.95M USD it is worth. DigiBank fully -expects that it will be able to redeem 5M USD from MagnetoCorp in 6 months time, -making it a profit of 10K USD for bearing the increased risk associated with -this commercial paper. This extra 10K means it receives a 2.4% return on -investment -- significantly better than the risk free return of 2%. - -At the end of June, when MagnetoCorp issues a new commercial paper for 5M USD to -meet June's payroll, it is purchased by BigFund for 4.94M USD. That's because -the commercial conditions are roughly the same in June as they are in May, -resulting in BigFund valuing MagnetoCorp commercial paper at the same price that -DigiBank did in May. - -Each subsequent month, MagnetoCorp can issue new commercial paper to meet its -payroll obligations, and these may be purchased by DigiBank, or any other -participant in the PaperNet commercial paper network -- BigFund, HedgeMatic or -BrokerHouse. These organizations may pay more or less for the commercial paper -depending on two factors -- the central bank base rate, and the risk associated -with MagnetoCorp. This latter figure depends on a variety of factors such as the -production of Model D cars, and the creditworthiness of MagnetoCorp as assessed -by RateM, a ratings agency. - -The organizations in PaperNet have different roles, MagnetoCorp issues paper, -DigiBank, BigFund, HedgeMatic and BrokerHouse trade paper and RateM rates paper. -Organizations of the same role, such as DigiBank, Bigfund, HedgeMatic and -BrokerHouse are competitors. Organizations of different roles are not -necessarily competitors, yet might still have opposing business interest, for -example MagentoCorp will desire a high rating for its papers to sell them at -a high price, while DigiBank would benefit from a low rating, such that it can -buy them at a low price. As can be seen, even a seemingly simple network such -as PaperNet can have complex trust relationships. A blockchain can help -establish trust among organizations that are competitors or have opposing -business interests that might lead to disputes. Fabric in particular has the -means to capture even fine-grained trust relationships. - -Let's pause the MagnetoCorp story for a moment, and develop the client -applications and smart contracts that PaperNet uses to issue, buy, sell and -redeem commercial paper as well as capture the trust relationships between -the organizations. We'll come back to the role of the rating agency, -RateM, a little later. - - diff --git a/docs/source/developapps/smartcontract.md b/docs/source/developapps/smartcontract.md deleted file mode 100644 index 4257524bea1..00000000000 --- a/docs/source/developapps/smartcontract.md +++ /dev/null @@ -1,720 +0,0 @@ -# Smart Contract Processing - -**Audience**: Architects, Application and smart contract developers - -At the heart of a blockchain network is a smart contract. In PaperNet, the code -in the commercial paper smart contract defines the valid states for commercial -paper, and the transaction logic that transition a paper from one state to -another. In this topic, we're going to show you how to implement a real world -smart contract that governs the process of issuing, buying and redeeming -commercial paper. - -We're going to cover: - -* [What is a smart contract and why it's important](#smart-contract) -* [How to define a smart contract](#contract-class) -* [How to define a transaction](#transaction-definition) -* [How to implement a transaction](#transaction-logic) -* [How to represent a business object in a smart contract](#representing-an-object) -* [How to store and retrieve an object in the ledger](#access-the-ledger) - -If you'd like, you can [download the sample](../install.html) and even [run it -locally](../tutorial/commercial_paper.html). It is written in JavaScript and Java, but -the logic is quite language independent, so you'll easily be able to see what's -going on! (The sample will become available for Go as well.) - -## Smart Contract - -A smart contract defines the different states of a business object and governs -the processes that move the object between these different states. Smart -contracts are important because they allow architects and smart contract -developers to define the key business processes and data that are shared across -the different organizations collaborating in a blockchain network. - -In the PaperNet network, the smart contract is shared by the different network -participants, such as MagnetoCorp and DigiBank. The same version of the smart -contract must be used by all applications connected to the network so that they -jointly implement the same shared business processes and data. - -## Implementation Languages - -There are two runtimes that are supported, the Java Virtual Machine and Node.js. This -gives the opportunity to use one of JavaScript, TypeScript, Java or any other language -that can run on one of these supported runtimes. - -In Java and TypeScript, annotations or decorators are used to provide information about -the smart contract and its structure. This allows for a richer development experience --- -for example, author information or return types can be enforced. Within JavaScript, -conventions must be followed, therefore, there are limitations around what can be -determined automatically. - -Examples here are given in both JavaScript and Java. - -## Contract class - -A copy of the PaperNet commercial paper smart contract is contained in a single -file. View it with your browser, or open it in your favorite editor if you've downloaded it. - - `papercontract.js` - [JavaScript version](https://github.com/hyperledger/fabric-samples/blob/{BRANCH}/commercial-paper/organization/magnetocorp/contract/lib/papercontract.js) - - `CommercialPaperContract.java` - [Java version](https://github.com/hyperledger/fabric-samples/blob/{BRANCH}/commercial-paper/organization/magnetocorp//contract-java/src/main/java/org/example/CommercialPaperContract.java) - - -You may notice from the file path that this is MagnetoCorp's copy of the smart -contract. MagnetoCorp and DigiBank must agree on the version of the smart contract -that they are going to use. For now, it doesn't matter which organization's copy -you use, they are all the same. - -Spend a few moments looking at the overall structure of the smart contract; -notice that it's quite short! Towards the top of the file, you'll see -that there's a definition for the commercial paper smart contract: -
-JavaScript -```JavaScript -class CommercialPaperContract extends Contract {...} -``` -
- -
-Java -```Java -@Contract(...) -@Default -public class CommercialPaperContract implements ContractInterface {...} -``` -
- - -The `CommercialPaperContract` class contains the transaction definitions for commercial paper -- **issue**, **buy** -and **redeem**. It's these transactions that bring commercial papers into -existence and move them through their lifecycle. We'll examine these -[transactions](#transaction-definition) soon, but for now notice for JavaScript, that the -`CommericalPaperContract` extends the Hyperledger Fabric `Contract` -[class](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-contract-api.Contract.html). - -With Java, the class must be decorated with the `@Contract(...)` annotation. This provides the opportunity -to supply additional information about the contract, such as license and author. The `@Default()` annotation -indicates that this contract class is the default contract class. Being able to mark a contract class as the -default contract class is useful in some smart contracts which have multiple contract classes. - -If you are using a TypeScript implementation, there are similar `@Contract(...)` annotations that fulfill the same purpose as in Java. - -For more information on the available annotations, consult the available API documentation: -* [API documentation for Java smart contracts](https://hyperledger.github.io/fabric-chaincode-java/) -* [API documentation for Node.js smart contracts](https://hyperledger.github.io/fabric-chaincode-node/) - -The Fabric contract class is also available for smart contracts written in Go. While we do not discuss the Go contract API in this topic, it uses similar concepts as the API for Java and JavaScript: -* [API documentation for Go smart contracts](https://github.com/hyperledger/fabric-contract-api-go) - -These classes, annotations, and the `Context` class, were brought into scope earlier: - -
-JavaScript -```JavaScript -const { Contract, Context } = require('fabric-contract-api'); -``` -
- -
-Java -```Java -import org.hyperledger.fabric.contract.Context; -import org.hyperledger.fabric.contract.ContractInterface; -import org.hyperledger.fabric.contract.annotation.Contact; -import org.hyperledger.fabric.contract.annotation.Contract; -import org.hyperledger.fabric.contract.annotation.Default; -import org.hyperledger.fabric.contract.annotation.Info; -import org.hyperledger.fabric.contract.annotation.License; -import org.hyperledger.fabric.contract.annotation.Transaction; -``` -
- - -Our commercial paper contract will use built-in features of these classes, such -as automatic method invocation, a -[per-transaction context](./transactioncontext.html), -[transaction handlers](./transactionhandler.html), and class-shared state. - -Notice also how the JavaScript class constructor uses its -[superclass](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super) -to initialize itself with an explicit [contract name](./contractname.html): - -```JavaScript -constructor() { - super('org.papernet.commercialpaper'); -} -``` - -With the Java class, the constructor is blank as the explicit contract name can be specified in the `@Contract()` annotation. If it's absent, then the name of the class is used. - -Most importantly, `org.papernet.commercialpaper` is very descriptive -- this smart -contract is the agreed definition of commercial paper for all PaperNet -organizations. - -Usually there will only be one smart contract per file -- contracts tend to have -different lifecycles, which makes it sensible to separate them. However, in some -cases, multiple smart contracts might provide syntactic help for applications, -e.g. `EuroBond`, `DollarBond`, `YenBond`, but essentially provide the same -function. In such cases, smart contracts and transactions can be disambiguated. - -## Transaction definition - -Within the class, locate the **issue** method. -
-JavaScript -```JavaScript -async issue(ctx, issuer, paperNumber, issueDateTime, maturityDateTime, faceValue) {...} -``` -
- -
-Java -```Java -@Transaction -public CommercialPaper issue(CommercialPaperContext ctx, - String issuer, - String paperNumber, - String issueDateTime, - String maturityDateTime, - int faceValue) {...} -``` -
- -The Java annotation `@Transaction` is used to mark this method as a transaction definition; TypeScript has an equivalent annotation. - -This function is given control whenever this contract is called to `issue` a -commercial paper. Recall how commercial paper 00001 was created with the -following transaction: - -``` -Txn = issue -Issuer = MagnetoCorp -Paper = 00001 -Issue time = 31 May 2020 09:00:00 EST -Maturity date = 30 November 2020 -Face value = 5M USD -``` - -We've changed the variable names for programming style, but see how these -properties map almost directly to the `issue` method variables. - -The `issue` method is automatically given control by the contract whenever an -application makes a request to issue a commercial paper. The transaction -property values are made available to the method via the corresponding -variables. See how an application submits a transaction using the Hyperledger -Fabric SDK in the [application](./application.html) topic, using a sample -application program. - -You might have noticed an extra variable in the **issue** definition -- `ctx`. -It's called the [**transaction context**](./transactioncontext.html), and it's -always first. By default, it maintains both per-contract and per-transaction -information relevant to [transaction logic](#transaction-logic). For example, it -would contain MagnetoCorp's specified transaction identifier, a MagnetoCorp -issuing user's digital certificate, as well as access to the ledger API. - -See how the smart contract extends the default transaction context by -implementing its own `createContext()` method rather than accepting the -default implementation: - -
-JavaScript -```JavaScript -createContext() { - return new CommercialPaperContext() -} -``` -
- -
-Java -```Java -@Override -public Context createContext(ChaincodeStub stub) { - return new CommercialPaperContext(stub); -} -``` -
- - -This extended context adds a custom property `paperList` to the defaults: -
-JavaScript -```JavaScript -class CommercialPaperContext extends Context { - - constructor() { - super(); - // All papers are held in a list of papers - this.paperList = new PaperList(this); -} -``` -
- -
-Java -```Java -class CommercialPaperContext extends Context { - public CommercialPaperContext(ChaincodeStub stub) { - super(stub); - this.paperList = new PaperList(this); - } - public PaperList paperList; -} -``` -
- -We'll soon see how `ctx.paperList` can be subsequently used to help store and -retrieve all PaperNet commercial papers. - -To solidify your understanding of the structure of a smart contract transaction, -locate the **buy** and **redeem** transaction definitions, and see if you can -see how they map to their corresponding commercial paper transactions. - -The **buy** transaction: - -``` -Txn = buy -Issuer = MagnetoCorp -Paper = 00001 -Current owner = MagnetoCorp -New owner = DigiBank -Purchase time = 31 May 2020 10:00:00 EST -Price = 4.94M USD -``` - -
-JavaScript -```JavaScript -async buy(ctx, issuer, paperNumber, currentOwner, newOwner, price, purchaseTime) {...} -``` -
- -
-Java -```Java -@Transaction -public CommercialPaper buy(CommercialPaperContext ctx, - String issuer, - String paperNumber, - String currentOwner, - String newOwner, - int price, - String purchaseDateTime) {...} -``` -
- -The **redeem** transaction: - -``` -Txn = redeem -Issuer = MagnetoCorp -Paper = 00001 -Redeemer = DigiBank -Redeem time = 31 Dec 2020 12:00:00 EST -``` - -
-JavaScript -```JavaScript -async redeem(ctx, issuer, paperNumber, redeemingOwner, redeemDateTime) {...} -``` -
- -
-Java -```Java -@Transaction -public CommercialPaper redeem(CommercialPaperContext ctx, - String issuer, - String paperNumber, - String redeemingOwner, - String redeemDateTime) {...} -``` -
- -In both cases, observe the 1:1 correspondence between the commercial paper -transaction and the smart contract method definition. - -All of the JavaScript functions use the `async` and `await` -[keywords](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) which allow JavaScript functions to be treated as if they were synchronous function calls. - - -## Transaction logic - -Now that you've seen how contracts are structured and transactions are defined, -let's focus on the logic within the smart contract. - -Recall the first **issue** transaction: - -``` -Txn = issue -Issuer = MagnetoCorp -Paper = 00001 -Issue time = 31 May 2020 09:00:00 EST -Maturity date = 30 November 2020 -Face value = 5M USD -``` - -It results in the **issue** method being passed control: -
-JavaScript -```JavaScript -async issue(ctx, issuer, paperNumber, issueDateTime, maturityDateTime, faceValue) { - - // create an instance of the paper - let paper = CommercialPaper.createInstance(issuer, paperNumber, issueDateTime, maturityDateTime, faceValue); - - // Smart contract, rather than paper, moves paper into ISSUED state - paper.setIssued(); - - // Newly issued paper is owned by the issuer - paper.setOwner(issuer); - - // Add the paper to the list of all similar commercial papers in the ledger world state - await ctx.paperList.addPaper(paper); - - // Must return a serialized paper to caller of smart contract - return paper.toBuffer(); -} -``` -
- -
-Java -```Java -@Transaction -public CommercialPaper issue(CommercialPaperContext ctx, - String issuer, - String paperNumber, - String issueDateTime, - String maturityDateTime, - int faceValue) { - - System.out.println(ctx); - - // create an instance of the paper - CommercialPaper paper = CommercialPaper.createInstance(issuer, paperNumber, issueDateTime, maturityDateTime, - faceValue,issuer,""); - - // Smart contract, rather than paper, moves paper into ISSUED state - paper.setIssued(); - - // Newly issued paper is owned by the issuer - paper.setOwner(issuer); - - System.out.println(paper); - // Add the paper to the list of all similar commercial papers in the ledger - // world state - ctx.paperList.addPaper(paper); - - // Must return a serialized paper to caller of smart contract - return paper; -} -``` -
- - -The logic is simple: take the transaction input variables, create a new -commercial paper `paper`, add it to the list of all commercial papers using -`paperList`, and return the new commercial paper (serialized as a buffer) as the -transaction response. - -See how `paperList` is retrieved from the transaction context to provide access -to the list of commercial papers. `issue()`, `buy()` and `redeem()` continually -re-access `ctx.paperList` to keep the list of commercial papers up-to-date. - -The logic for the **buy** transaction is a little more elaborate: -
-JavaScript -```JavaScript -async buy(ctx, issuer, paperNumber, currentOwner, newOwner, price, purchaseDateTime) { - - // Retrieve the current paper using key fields provided - let paperKey = CommercialPaper.makeKey([issuer, paperNumber]); - let paper = await ctx.paperList.getPaper(paperKey); - - // Validate current owner - if (paper.getOwner() !== currentOwner) { - throw new Error('Paper ' + issuer + paperNumber + ' is not owned by ' + currentOwner); - } - - // First buy moves state from ISSUED to TRADING - if (paper.isIssued()) { - paper.setTrading(); - } - - // Check paper is not already REDEEMED - if (paper.isTrading()) { - paper.setOwner(newOwner); - } else { - throw new Error('Paper ' + issuer + paperNumber + ' is not trading. Current state = ' +paper.getCurrentState()); - } - - // Update the paper - await ctx.paperList.updatePaper(paper); - return paper.toBuffer(); -} -``` -
- -
-Java -```Java -@Transaction -public CommercialPaper buy(CommercialPaperContext ctx, - String issuer, - String paperNumber, - String currentOwner, - String newOwner, - int price, - String purchaseDateTime) { - - // Retrieve the current paper using key fields provided - String paperKey = State.makeKey(new String[] { paperNumber }); - CommercialPaper paper = ctx.paperList.getPaper(paperKey); - - // Validate current owner - if (!paper.getOwner().equals(currentOwner)) { - throw new RuntimeException("Paper " + issuer + paperNumber + " is not owned by " + currentOwner); - } - - // First buy moves state from ISSUED to TRADING - if (paper.isIssued()) { - paper.setTrading(); - } - - // Check paper is not already REDEEMED - if (paper.isTrading()) { - paper.setOwner(newOwner); - } else { - throw new RuntimeException( - "Paper " + issuer + paperNumber + " is not trading. Current state = " + paper.getState()); - } - - // Update the paper - ctx.paperList.updatePaper(paper); - return paper; -} -``` -
- -See how the transaction checks `currentOwner` and that `paper` is `TRADING` -before changing the owner with `paper.setOwner(newOwner)`. The basic flow is -simple though -- check some pre-conditions, set the new owner, update the -commercial paper on the ledger, and return the updated commercial paper -(serialized as a buffer) as the transaction response. - -Why don't you see if you can understand the logic for the **redeem** -transaction? - -## Representing an object - -We've seen how to define and implement the **issue**, **buy** and **redeem** -transactions using the `CommercialPaper` and `PaperList` classes. Let's end -this topic by seeing how these classes work. - -Locate the `CommercialPaper` class: - -
-JavaScript -In the -[paper.js file](https://github.com/hyperledger/fabric-samples/blob/{BRANCH}/commercial-paper/organization/magnetocorp/contract/lib/paper.js): - -```JavaScript -class CommercialPaper extends State {...} -``` -
- -
-Java -In the [CommercialPaper.java file](https://github.com/hyperledger/fabric-samples/blob/release-1.4/commercial-paper/organization/magnetocorp/contract-java/src/main/java/org/example/CommercialPaper.java): - - -```Java -@DataType() -public class CommercialPaper extends State {...} -``` -
- - -This class contains the in-memory representation of a commercial paper state. -See how the `createInstance` method initializes a new commercial paper with the -provided parameters: - -
-JavaScript -```JavaScript -static createInstance(issuer, paperNumber, issueDateTime, maturityDateTime, faceValue) { - return new CommercialPaper({ issuer, paperNumber, issueDateTime, maturityDateTime, faceValue }); -} -``` -
- -
-Java -```Java -public static CommercialPaper createInstance(String issuer, String paperNumber, String issueDateTime, - String maturityDateTime, int faceValue, String owner, String state) { - return new CommercialPaper().setIssuer(issuer).setPaperNumber(paperNumber).setMaturityDateTime(maturityDateTime) - .setFaceValue(faceValue).setKey().setIssueDateTime(issueDateTime).setOwner(owner).setState(state); -} -``` -
- -Recall how this class was used by the **issue** transaction: - -
-JavaScript -```JavaScript -let paper = CommercialPaper.createInstance(issuer, paperNumber, issueDateTime, maturityDateTime, faceValue); -``` -
- -
-Java -```Java -CommercialPaper paper = CommercialPaper.createInstance(issuer, paperNumber, issueDateTime, maturityDateTime, - faceValue,issuer,""); -``` -
- -See how every time the issue transaction is called, a new in-memory instance of -a commercial paper is created containing the transaction data. - -A few important points to note: - - * This is an in-memory representation; we'll see - [later](#accessing-the-ledger) how it appears on the ledger. - - - * The `CommercialPaper` class extends the `State` class. `State` is an - application-defined class which creates a common abstraction for a state. - All states have a business object class which they represent, a composite - key, can be serialized and de-serialized, and so on. `State` helps our code - be more legible when we are storing more than one business object type on - the ledger. Examine the `State` class in the `state.js` - [file](https://github.com/hyperledger/fabric-samples/blob/{BRANCH}/commercial-paper/organization/magnetocorp/contract/ledger-api/state.js). - - - * A paper computes its own key when it is created -- this key will be used - when the ledger is accessed. The key is formed from a combination of - `issuer` and `paperNumber`. - - ```JavaScript - constructor(obj) { - super(CommercialPaper.getClass(), [obj.issuer, obj.paperNumber]); - Object.assign(this, obj); - } - ``` - - - * A paper is moved to the `ISSUED` state by the transaction, not by the paper - class. That's because it's the smart contract that governs the lifecycle - state of the paper. For example, an `import` transaction might create a new - set of papers immediately in the `TRADING` state. - -The rest of the `CommercialPaper` class contains simple helper methods: - -```JavaScript -getOwner() { - return this.owner; -} -``` - -Recall how methods like this were used by the smart contract to move the -commercial paper through its lifecycle. For example, in the **redeem** -transaction we saw: - -```JavaScript -if (paper.getOwner() === redeemingOwner) { - paper.setOwner(paper.getIssuer()); - paper.setRedeemed(); -} -``` - -## Access the ledger - -Now locate the `PaperList` class in the `paperlist.js` -[file](https://github.com/hyperledger/fabric-samples/blob/{BRANCH}/commercial-paper/organization/magnetocorp/contract/lib/paperlist.js): - -```JavaScript -class PaperList extends StateList { -``` - -This utility class is used to manage all PaperNet commercial papers in -Hyperledger Fabric state database. The PaperList data structures are described -in more detail in the [architecture topic](./architecture.html). - -Like the `CommercialPaper` class, this class extends an application-defined -`StateList` class which creates a common abstraction for a list of states -- in -this case, all the commercial papers in PaperNet. - -The `addPaper()` method is a simple veneer over the `StateList.addState()` -method: - -```JavaScript -async addPaper(paper) { - return this.addState(paper); -} -``` - -You can see in the `StateList.js` -[file](https://github.com/hyperledger/fabric-samples/blob/{BRANCH}/commercial-paper/organization/magnetocorp/contract/ledger-api/statelist.js) -how the `StateList` class uses the Fabric API `putState()` to write the -commercial paper as state data in the ledger: - -```JavaScript -async addState(state) { - let key = this.ctx.stub.createCompositeKey(this.name, state.getSplitKey()); - let data = State.serialize(state); - await this.ctx.stub.putState(key, data); -} -``` - -Every piece of state data in a ledger requires these two fundamental elements: - - * **Key**: `key` is formed with `createCompositeKey()` using a fixed name and - the key of `state`. The name was assigned when the `PaperList` object was - constructed, and `state.getSplitKey()` determines each state's unique key. - - - * **Data**: `data` is simply the serialized form of the commercial paper - state, created using the `State.serialize()` utility method. The `State` - class serializes and deserializes data using JSON, and the State's business - object class as required, in our case `CommercialPaper`, again set when the - `PaperList` object was constructed. - - -Notice how a `StateList` doesn't store anything about an individual state or the -total list of states -- it delegates all of that to the Fabric state database. -This is an important design pattern -- it reduces the opportunity for [ledger -MVCC collisions](../readwrite.html) in Hyperledger Fabric. - -The StateList `getState()` and `updateState()` methods work in similar ways: - -```JavaScript -async getState(key) { - let ledgerKey = this.ctx.stub.createCompositeKey(this.name, State.splitKey(key)); - let data = await this.ctx.stub.getState(ledgerKey); - let state = State.deserialize(data, this.supportedClasses); - return state; -} -``` - -```JavaScript -async updateState(state) { - let key = this.ctx.stub.createCompositeKey(this.name, state.getSplitKey()); - let data = State.serialize(state); - await this.ctx.stub.putState(key, data); -} -``` - -See how they use the Fabric APIs `putState()`, `getState()` and -`createCompositeKey()` to access the ledger. We'll expand this smart contract -later to list all commercial papers in paperNet -- what might the method look -like to implement this ledger retrieval? - -That's it! In this topic you've understood how to implement the smart contract -for PaperNet. You can move to the next sub topic to see how an application -calls the smart contract using the Fabric SDK. - - diff --git a/docs/source/developapps/transactioncontext.md b/docs/source/developapps/transactioncontext.md deleted file mode 100644 index 4dfaf0636c0..00000000000 --- a/docs/source/developapps/transactioncontext.md +++ /dev/null @@ -1,282 +0,0 @@ -# Transaction context - -**Audience**: Architects, application and smart contract developers - -A transaction context performs two functions. Firstly, it allows a developer to -define and maintain user variables across transaction invocations within a smart -contract. Secondly, it provides access to a wide range of Fabric APIs that allow -smart contract developers to perform operations relating to detailed transaction -processing. These range from querying or updating the ledger, both the immutable -blockchain and the modifiable world state, to retrieving the -transaction-submitting application's digital identity. - -A transaction context is created when a smart contract is deployed to a channel and -made available to every subsequent transaction invocation. A transaction context -helps smart contract developers write programs that are powerful, efficient and -easy to reason about. - -* [Why a transaction context is important](#scenario) -* [How to use a transaction context](#programming) -* [What's in a transaction context](#structure) -* [Using a context `stub`](#stub) -* [Using a context `clientIdentity`](#clientIdentity) - -## Scenario - -In the commercial paper sample, -[papercontract](https://github.com/hyperledger/fabric-samples/blob/{BRANCH}/commercial-paper/organization/magnetocorp/contract/lib/papercontract.js) -initially defines the name of the list of commercial papers for which it's -responsible. Each transaction subsequently refers to this list; the issue -transaction adds new papers to it, the buy transaction changes its owner, and -the redeem transaction marks it as complete. This is a common pattern; when -writing a smart contract it's often helpful to initialize and recall particular -variables in sequential transactions. - -![transaction.scenario](./develop.diagram.40.png) *A smart contract transaction -context allows smart contracts to define and maintain user variables across -transaction invocations. Refer to the text for a detailed explanation.* - -## Programming - -When a smart contract is constructed, a developer can optionally override the -built-in `Context` class `createContext` method to create a custom context: - -```JavaScript -createContext() { - new CommercialPaperContext(); -} -``` - -In our example, the `CommercialPaperContext` is specialized for -`CommercialPaperContract`. See how the custom context, addressed through `this`, -adds the specific variable `PaperList` to itself: - -```JavaScript -CommercialPaperContext extends Context { - constructor () { - this.paperList = new PaperList(this); - } -} -``` - -When the createContext() method returns at point **(1)** in the diagram -[above](#scenario), a custom context `ctx` has been created which contains -`paperList` as one of its variables. - -Subsequently, whenever a smart contract transaction such as issue, buy or redeem -is called, this context will be passed to it. See how at points **(2)**, **(3)** -and **(4)** the same commercial paper context is passed into the transaction -method using the `ctx` variable. - -See how the context is then used at point **(5)**: - -```JavaScript -ctx.paperList.addPaper(...); -ctx.stub.putState(...); -``` - -Notice how `paperList` created in `CommercialPaperContext` is available to the -issue transaction. See how `paperList` is similarly used by the **redeem** and -**buy** transactions; `ctx` makes the smart contracts efficient and easy to -reason about. - -You can also see that there's another element in the context -- `ctx.stub` -- -which was not explicitly added by `CommercialPaperContext`. That's because -`stub` and other variables are part of the built-in context. Let's now examine -the structure of this built-in context, these implicit variables and how to -use them. - -## Structure - -As we've seen from the [example](#programming), a transaction context can -contain any number of user variables such as `paperList`. - -The transaction context also contains two built-in elements that provide access -to a wide range of Fabric functionality ranging from the client application that -submitted the transaction to ledger access. - - * `ctx.stub` is used to access APIs that provide a broad range of transaction - processing operations from `putState()` and `getState()` to access the - ledger, to `getTxID()` to retrieve the current transaction ID. - - * `ctx.clientIdentity` is used to get information about the identity of the - user who submitted the transaction. - -We'll use the following diagram to show you what a smart contract can do using -the `stub` and `clientIdentity` using the APIs available to it: - -![context.apis](./develop.diagram.41.png) *A smart contract can access a -range of functionality in a smart contract via the transaction context `stub` -and `clientIdentity`. Refer to the text for a detailed explanation.* - -## Stub - -The APIs in the stub fall into the following categories: - -* **World state data APIs**. See interaction point **(1)**. These APIs enable - smart contracts to get, put and delete state corresponding to individual - objects from the world state, using their key: - - * [getState()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getState__anchor) - * [putState()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#putState__anchor) - * [deleteState()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#deleteState__anchor) - -
These basic APIs are complemented by query APIs which enable contracts to - retrieve a set of states, rather than an individual state. See interaction - point **(2)**. The set is either defined by a range of key values, using full - or partial keys, or a query according to values in the underlying world state - [database](../ledger/ledger.html#world-state-database-options). For large - queries, the result sets can be paginated to reduce storage requirements: - - * [getStateByRange()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getStateByRange__anchor) - * [getStateByRangeWithPagination()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getStateByRangeWithPagination__anchor) - * [getStateByPartialCompositeKey()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getStateByPartialCompositeKey__anchor) - * [getStateByPartialCompositeKeyWithPagination()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getStateByPartialCompositeKeyWithPagination__anchor) - * [getQueryResult()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getQueryResult__anchor) - * [getQueryResultWithPagination()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getQueryResultWithPagination__anchor) - -* **Private data APIs**. See interaction point **(3)**. These APIs enable smart - contracts to interact with a private data collection. They are analogous to - the APIs for world state interactions, but for private data. There are APIs to - get, put and delete a private data state by its key: - - * [getPrivateData()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getPrivateData__anchor) - * [putPrivateData()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#putPrivateData__anchor) - * [deletePrivateData()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#deletePrivateData__anchor) - -
This set is complemented by set of APIs to query private data **(4)**. - These APIs allow smart contracts to retrieve a set of states from a private - data collection, according to a range of key values, either full or partial - keys, or a query according to values in the underlying world state - [database](../ledger/ledger.html#world-state-database-options). There are - currently no pagination APIs for private data collections. - - * [getPrivateDataByRange()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getPrivateDataByRange__anchor) - * [getPrivateDataByPartialCompositeKey()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getPrivateDataByPartialCompositeKey__anchor) - * [getPrivateDataQueryResult()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getPrivateDataQueryResult__anchor) - -* **Transaction APIs**. See interaction point **(5)**. These APIs are used by a - smart contract to retrieve details about the current transaction proposal - being processed by the smart contract. This includes the transaction - identifier and the time when the transaction proposal was created. - - * [getTxID()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getTxID__anchor) - returns the identifier of the current transaction proposal **(5)**. - * [getTxTimestamp()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getTxTimestamp__anchor) - returns the timestamp when the current transaction proposal was created by - the application **(5)**. - * [getCreator()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getCreator__anchor) - returns the raw identity (X.509 or otherwise) of the creator of - transaction proposal. If this is an X.509 certificate then it is often - more appropriate to use [`ctx.ClientIdentity`](#clientidentity). - * [getSignedProposal()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getSignedProposal__anchor) - returns a signed copy of the current transaction proposal being processed - by the smart contract. - * [getBinding()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getBinding__anchor) - is used to prevent transactions being maliciously or accidentally replayed - using a nonce. (For practical purposes, a nonce is a random number - generated by the client application and incorporated in a cryptographic - hash.) For example, this API could be used by a smart contract at **(1)** - to detect a replay of the transaction **(5)**. - * [getTransient()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getTransient__anchor) - allows a smart contract to access the transient data an application passes - to a smart contract. See interaction points **(9)** and **(10)**. - Transient data is private to the application-smart contract interaction. - It is not recorded on the ledger and is often used in conjunction with - private data collections **(3)**. - -
- -* **Key APIs** are used by smart contracts to manipulate state key in the world - state or a private data collection. See interaction points **2** and **4**. - - The simplest of these APIs allows smart contracts to form and split composite - keys from their individual components. Slightly more advanced are the - `ValidationParameter()` APIs which get and set the state based endorsement - policies for world state **(2)** and private data **(4)**. Finally, - `getHistoryForKey()` retrieves the history for a state by returning the set of - stored values, including the transaction identifiers that performed the state - update, allowing the transactions to be read from the blockchain **(10)**. - - * [createCompositeKey()](https://hyperledger.github.io/fabric-chaincode-node/{BRACNH}/api/fabric-shim.ChaincodeStub.html#createCompositeKey__anchor) - * [splitCompositeKey()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#splitCompositeKey__anchor) - * [setStateValidationParameter()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#setStateValidationParameter__anchor) - * [getStateValidationParameter()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getStateValidationParameter__anchor) - * [getPrivateDataValidationParameter()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getPrivateDataValidationParameter__anchor) - * [setPrivateDataValidationParameter()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#setPrivateDataValidationParameter__anchor) - * [getHistoryForKey()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getHistoryForKey__anchor) - -
- -* **Event APIs** are used to set an event during the processing of a smart contract. - - * [setEvent()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#setEvent__anchor) - - Smart contracts use this API to add an event to a transaction response. - Note that only a single event can be created in a transaction, and must - originate from the outer-most contract when contracts invoke each other via `invokeChaincode`. - See interaction point **(5)**. These events are ultimately recorded on the - blockchain and sent to listening applications at interaction point - **(11)**. - -
- -* **Utility APIs** are a collection of useful APIs that don't easily fit in a - pre-defined category, so we've grouped them together! They include retrieving - the current channel name and passing control to a different chaincode on the - same peer. - - * [getChannelID()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getChannelID__anchor) - - See interaction point **(13)**. A smart contract running on any peer can - use this API to determined on which channel the application invoked the - smart contract. - - * [invokeChaincode()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#invokeChaincode__anchor) - - See interaction point **(14)**. Peer3 owned by MagnetoCorp has multiple - smart contracts installed on it. These smart contracts are able to call - each other using this API. The smart contracts must be collocated; it is - not possible to call a smart contract on a different peer. - -
Some of these utility APIs are only used if you're using low-level - chaincode, rather than smart contracts. These APIs are primarily for the - detailed manipulation of chaincode input; the smart contract `Contract` class - does all of this parameter marshalling automatically for developers. - - * [getFunctionAndParameters()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getFunctionAndParameters__anchor) - * [getStringArgs()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getStringArgs__anchor) - * [getArgs()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html#getArgs__anchor) - -## ClientIdentity - -In most cases, the application submitting a transaction will be using an X.509 -certificate. In the [example](#structure), an X.509 certificate **(6)** issued -by `CA1` **(7)** is being used by `Isabella` **(8)** in her application to sign -the proposal in transaction `t6` **(5)**. - -`ClientIdentity` takes the information returned by `getCreator()` and puts a set -of X.509 utility APIs on top of it to make it easier to use for this common use -case. - -* [getX509Certificate()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ClientIdentity.html#getX509Certificate__anchor) - returns the full X.509 certificate of the transaction submitter, including all - its attributes and their values. See interaction point **(6)**. -* [getAttributeValue()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ClientIdentity.html#getAttributeValue__anchor) - returns the value of a particular X.509 attribute, for example, the - organizational unit `OU`, or distinguished name `DN`. See interaction point - **(6)**. -* [assertAttributeValue()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ClientIdentity.html#assertAttributeValue__anchor) - returns `TRUE` if the specified attribute of the X.509 attribute has a - specified value. See interaction point **(6)**. -* [getID()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ClientIdentity.html#getID__anchor) - returns the unique identity of the transaction submitter, according to their - distinguished name and the issuing CA's distinguished name. The format is - `x509::{subject DN}::{issuer DN}`. See interaction point **(6)**. -* [getMSPID()](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ClientIdentity.html#getMSPID__anchor) - returns the channel MSP of the transaction submitter. This allows a smart - contract to make processing decisions based on the submitter's organizational - identity. See interaction point **(15)** or **(16)**. - - diff --git a/docs/source/developapps/transactionhandler.md b/docs/source/developapps/transactionhandler.md deleted file mode 100644 index cad1cc91c9a..00000000000 --- a/docs/source/developapps/transactionhandler.md +++ /dev/null @@ -1,128 +0,0 @@ -# Transaction handlers - -**Audience**: Architects, Application and smart contract developers - -Transaction handlers allow smart contract developers to define common processing -at key points during the interaction between an application and a smart -contract. Transaction handlers are optional but, if defined, they will receive -control before or after every transaction in a smart contract is invoked. There -is also a specific handler which receives control when a request is made to -invoke a transaction not defined in a smart contract. - -Here's an example of transaction handlers for the [commercial paper smart -contract sample](./smartcontract.html): - -![develop.transactionhandler](./develop.diagram.2.png) - -*Before, After and Unknown transaction handlers. In this example, -`beforeTransaction()` is called before the **issue**, **buy** and **redeem** -transactions. `afterTransaction()` is called after the **issue**, **buy** and -**redeem** transactions. `unknownTransaction()` is only called if a request is -made to invoke a transaction not defined in the smart contract. (The diagram is -simplified by not repeating `beforeTransaction` and `afterTransaction` boxes for -each transaction.)* - -## Types of handler - -There are three types of transaction handlers which cover different aspects -of the interaction between an application and a smart contract: - - * **Before handler**: is called before every smart contract transaction is - invoked. The handler will usually modify the transaction context to be used - by the transaction. The handler has access to the full range of Fabric APIs; - for example, it can issue `getState()` and `putState()`. - - - * **After handler**: is called after every smart contract transaction is - invoked. The handler will usually perform post-processing common to all - transactions, and also has full access to the Fabric APIs. - - - * **Unknown handler**: is called if an attempt is made to invoke a transaction - that is not defined in a smart contract. Typically, the handler will record - the failure for subsequent processing by an administrator. The handler has - full access to the Fabric APIs. - -Defining a transaction handler is optional; a smart contract will perform -correctly without handlers being defined. A smart contract can define at most -one handler of each type. - -## Defining a handler - -Transaction handlers are added to the smart contract as methods with well -defined names. Here's an example which adds a handler of each type: - -```JavaScript -CommercialPaperContract extends Contract { - - ... - - async beforeTransaction(ctx) { - // Write the transaction ID as an informational to the console - console.info(ctx.stub.getTxID()); - }; - - async afterTransaction(ctx, result) { - // This handler interacts with the ledger - ctx.stub.cpList.putState(...); - }; - - async unknownTransaction(ctx) { - // This handler throws an exception - throw new Error('Unknown transaction function'); - }; - -} -``` - -The form of a transaction handler definition is the similar for all handler -types, but notice how the `afterTransaction(ctx, result)` also receives any -result returned by the transaction. The [API -documentation](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-contract-api.Contract.html) -shows you the exact form of these handlers. - -## Handler processing - -Once a handler has been added to the smart contract, it will be invoked during -transaction processing. During processing, the handler receives `ctx`, the -[transaction context](transationcontext.html), performs some processing, and -returns control as it completes. Processing continues as follows: - -* **Before handler**: If the handler completes successfully, the transaction is - called with the updated context. If the handler throws an exception, then the - transaction is not called and the smart contract fails with the exception - error message. - - -* **After handler**: If the handler completes successfully, then the smart - contract completes as determined by the invoked transaction. If the handler - throws an exception, then the transaction fails with the exception error - message. - - -* **Unknown handler**: The handler should complete by throwing an exception with - the required error message. If an **Unknown handler** is not specified, or an - exception is not thrown by it, there is sensible default processing; the smart - contract will fail with an **unknown transaction** error message. - -If the handler requires access to the function and parameters, then it is easy to do this: - -```JavaScript -async beforeTransaction(ctx) { - // Retrieve details of the transaction - let txnDetails = ctx.stub.getFunctionAndParameters(); - - console.info(`Calling function: ${txnDetails.fcn} `); - console.info(util.format(`Function arguments : %j ${stub.getArgs()} ``); -} -``` - -See how this handler uses the utility API `getFunctionAndParameters` via the -[transaction context](./transactioncontext.html#stub). - -## Multiple handlers - -It is only possible to define at most one handler of each type for a smart -contract. If a smart contract needs to invoke multiple functions during before, -after or unknown handling, it should coordinate this from within the appropriate -function. diff --git a/docs/source/developapps/wallet.md b/docs/source/developapps/wallet.md deleted file mode 100644 index 1aa60440df7..00000000000 --- a/docs/source/developapps/wallet.md +++ /dev/null @@ -1,231 +0,0 @@ -# Wallet - -**Audience**: Architects, application and smart contract developers - -A wallet contains a set of user identities. An application run by a user selects -one of these identities when it connects to a channel. Access rights to channel -resources, such as the ledger, are determined using this identity in combination -with an MSP. - -In this topic, we're going to cover: - -* [Why wallets are important](#scenario) -* [How wallets are organized](#structure) -* [Different types of wallet](#types) -* [Wallet operations](#operations) - -## Scenario - -When an application connects to a network channel such as PaperNet, it selects a -user identity to do so, for example `ID1`. The channel MSPs associate `ID1` with -a role within a particular organization, and this role will ultimately determine -the application's rights over channel resources. For example, `ID1` might -identify a user as a member of the MagnetoCorp organization who can read and -write to the ledger, whereas `ID2` might identify an administrator in -MagnetoCorp who can add a new organization to a consortium. - -![wallet.scenario](./develop.diagram.10.png) *Two users, Isabella and Balaji -have wallets containing different identities they can use to connect to -different network channels, PaperNet and BondNet.* - -Consider the example of two users; Isabella from MagnetoCorp and Balaji from -DigiBank. Isabella is going to use App 1 to invoke a smart contract in PaperNet -and a different smart contract in BondNet. Similarly, Balaji is going to use -App 2 to invoke smart contracts, but only in PaperNet. (It's very -[easy](./application.html#construct-request) for applications to access multiple -networks and multiple smart contracts within them.) - -See how: - -* MagnetoCorp uses CA1 to issue identities and DigiBank uses CA2 to issue - identities. These identities are stored in user wallets. - -* Balaji's wallet holds a single identity, `ID4` issued by CA2. Isabella's - wallet has many identities, `ID1`, `ID2` and `ID3`, issued by CA1. Wallets - can hold multiple identities for a single user, and each identity can be - issued by a different CA. - -* Both Isabella and Balaji connect to PaperNet, and its MSPs determine that - Isabella is a member of the MagnetoCorp organization, and Balaji is a member - of the DigiBank organization, because of the respective CAs that issued their - identities. (It is - [possible](../membership/membership.html#mapping-msps-to-organizations) for an - organization to use multiple CAs, and for a single CA to support multiple - organizations.) - -* Isabella can use `ID1` to connect to both PaperNet and BondNet. In both cases, - when Isabella uses this identity, she is recognized as a member of - MangetoCorp. - -* Isabella can use `ID2` to connect to BondNet, in which case she is identified - as an administrator of MagnetoCorp. This gives Isabella two very different - privileges: `ID1` identifies her as a simple member of MagnetoCorp who can - read and write to the BondNet ledger, whereas `ID2` identities her as a - MagnetoCorp administrator who can add a new organization to BondNet. - -* Balaji cannot connect to BondNet with `ID4`. If he tried to connect, `ID4` - would not be recognized as belonging to DigiBank because CA2 is not known to - BondNet's MSP. - -## Types - -There are different types of wallets according to where they store their -identities: - -![wallet.types](./develop.diagram.12.png) *The three different types of wallet storage: -File system, In-memory and CouchDB.* - -* **File system**: This is the most common place to store wallets; file systems - are pervasive, easy to understand, and can be network mounted. They are a good - default choice for wallets. - -* **In-memory**: A wallet in application storage. Use this type of wallet when - your application is running in a constrained environment without access to a - file system; typically a web browser. It's worth remembering that this type of - wallet is volatile; identities will be lost after the application ends - normally or crashes. - -* **CouchDB**: A wallet stored in CouchDB. This is the rarest form of wallet - storage, but for those users who want to use the database back-up and restore - mechanisms, CouchDB wallets can provide a useful option to simplify disaster - recovery. - -Use factory functions provided by the `Wallets` -[class](https://hyperledger.github.io/fabric-sdk-node/{BRANCH}/module-fabric-network.Wallets.html) -to create wallets. - -### Hardware Security Module - -A Hardware Security Module (HSM) is an ultra-secure, tamper-proof device that -stores digital identity information, particularly private keys. HSMs can be -locally attached to your computer or network accessible. Most HSMs provide the -ability to perform on-board encryption with private keys, such that the private -keys never leave the HSM. - -An HSM can be used with any of the wallet types. In this case the certificate -for an identity will be stored in the wallet and the private key will be stored -in the HSM. - -To enable the use of HSM-managed identities, an `IdentityProvider` must be -configured with the HSM connection information and registered with the wallet. -For further details, refer to the [Using wallets to manage identities](https://hyperledger.github.io/fabric-sdk-node/{BRANCH}/tutorial-wallet.html) tutorial. - -## Structure - -A single wallet can hold multiple identities, each issued by a particular -Certificate Authority. Each identity has a standard structure comprising a -descriptive label, an X.509 certificate containing a public key, a private key, -and some Fabric-specific metadata. Different [wallet types](#types) map this -structure appropriately to their storage mechanism. - -![wallet.structure](./develop.diagram.11.png) *A Fabric wallet can hold multiple -identities with certificates issued by a different Certificate Authority. -Identities comprise certificate, private key and Fabric metadata.* - -There's a couple of key class methods that make it easy to manage wallets and -identities: - -```JavaScript -const identity: X509Identity = { - credentials: { - certificate: certificatePEM, - privateKey: privateKeyPEM, - }, - mspId: 'Org1MSP', - type: 'X.509', -}; -await wallet.put(identityLabel, identity); -``` - -See how an `identity` is created that has metadata `Org1MSP`, a `certificate` and -a `privateKey`. See how `wallet.put()` adds this identity to the wallet with a -particular `identityLabel`. - -The `Gateway` class only requires the `mspId` and `type` metadata to be set for -an identity -- `Org1MSP` and `X.509` in the above example. It *currently* uses the -MSP ID value to identify particular peers from a [connection profile](./connectionprofile.html), -for example when a specific notification [strategy](./connectionoptions.html) is -requested. In the DigiBank gateway file `networkConnection.yaml`, see how -`Org1MSP` notifications will be associated with `peer0.org1.example.com`: - -```yaml -organizations: - Org1: - mspid: Org1MSP - - peers: - - peer0.org1.example.com -``` - -You really don't need to worry about the internal structure of the different -wallet types, but if you're interested, navigate to a user identity folder in -the commercial paper sample: - -``` -magnetocorp/identity/user/isabella/ - wallet/ - User1@org1.example.com.id -``` - -You can examine these files, but as discussed, it's easier to use the SDK to -manipulate these data. - -## Operations - -The different wallet types all implement a common -[Wallet](https://hyperledger.github.io/fabric-sdk-node/{BRANCH}/module-fabric-network.Wallet.html) -interface which provides a standard set of APIs to manage identities. It means -that applications can be made independent of the underlying wallet storage -mechanism; for example, File system and HSM wallets are handled in a very -similar way. - -![wallet.operations](./develop.diagram.13.png) *Wallets follow a -lifecycle: they can be created or opened, and identities can be read, added and -deleted.* - -An application can use a wallet according to a simple lifecycle. Wallets can be -opened or created, and subsequently identities can be added, updated, read and -deleted. Spend a little time on the different `Wallet` methods in the -[JSDoc](https://hyperledger.github.io/fabric-sdk-node/{BRANCH}/module-fabric-network.Wallet.html) -to see how they work; the commercial paper tutorial provides a nice example in -`addToWallet.js`: - -```JavaScript -const wallet = await Wallets.newFileSystemWallet('../identity/user/isabella/wallet'); - -const cert = fs.readFileSync(path.join(credPath, '.../User1@org1.example.com-cert.pem')).toString(); -const key = fs.readFileSync(path.join(credPath, '.../_sk')).toString(); - -const identityLabel = 'User1@org1.example.com'; -const identity = { - credentials: { - certificate: cert, - privateKey: key, - }, - mspId: 'Org1MSP', - type: 'X.509', -}; - -await wallet.put(identityLabel, identity); -``` - -Notice how: - -* When the program is first run, a wallet is created on the local file system at - `.../isabella/wallet`. - -* a certificate `cert` and private `key` are loaded from the file system. - -* a new X.509 identity is created with `cert`, `key` and `Org1MSP`. - -* the new identity is added to the wallet with `wallet.put()` with a label - `User1@org1.example.com`. - -That's everything you need to know about wallets. You've seen how they hold -identities that are used by applications on behalf of users to access Fabric -network resources. There are different types of wallets available depending on -your application and security needs, and a simple set of APIs to help -applications manage wallets and the identities within them. - - diff --git a/docs/source/index.rst b/docs/source/index.rst index f901505f7ae..fb42b1006e8 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -20,7 +20,6 @@ modularity and versatility for a broad set of industry use cases. key_concepts getting_started getting_started_run_fabric - developapps/developing_applications tutorials deployment_guide_overview ops_guide diff --git a/docs/source/test_network.md b/docs/source/test_network.md index 2602b4dc20e..7862dd57e34 100644 --- a/docs/source/test_network.md +++ b/docs/source/test_network.md @@ -386,10 +386,6 @@ local machine, you can use the tutorials to start developing your own solution: - Visit the [Running a Fabric Application](write_first_app.html) tutorial to learn how to use the APIs provided by the Fabric SDKs to invoke smart contracts from your client applications. -- If you are ready to deploy a more complicated smart contract to the network, follow -the [commercial paper tutorial](tutorial/commercial_paper.html) to explore a -use case in which two organizations use a blockchain network to trade commercial -paper. You can find the complete list of Fabric tutorials on the [tutorials](tutorials.html) page. diff --git a/docs/source/tutorial/commercial_paper.diagram.1.png b/docs/source/tutorial/commercial_paper.diagram.1.png deleted file mode 100644 index 3d08dca913f..00000000000 Binary files a/docs/source/tutorial/commercial_paper.diagram.1.png and /dev/null differ diff --git a/docs/source/tutorial/commercial_paper.diagram.10.png b/docs/source/tutorial/commercial_paper.diagram.10.png deleted file mode 100644 index 7091311c768..00000000000 Binary files a/docs/source/tutorial/commercial_paper.diagram.10.png and /dev/null differ diff --git a/docs/source/tutorial/commercial_paper.diagram.11.png b/docs/source/tutorial/commercial_paper.diagram.11.png deleted file mode 100644 index 07bdf85c5d7..00000000000 Binary files a/docs/source/tutorial/commercial_paper.diagram.11.png and /dev/null differ diff --git a/docs/source/tutorial/commercial_paper.diagram.12.png b/docs/source/tutorial/commercial_paper.diagram.12.png deleted file mode 100644 index b75d1018dbb..00000000000 Binary files a/docs/source/tutorial/commercial_paper.diagram.12.png and /dev/null differ diff --git a/docs/source/tutorial/commercial_paper.diagram.2.png b/docs/source/tutorial/commercial_paper.diagram.2.png deleted file mode 100644 index 41a6b2346dd..00000000000 Binary files a/docs/source/tutorial/commercial_paper.diagram.2.png and /dev/null differ diff --git a/docs/source/tutorial/commercial_paper.diagram.3.png b/docs/source/tutorial/commercial_paper.diagram.3.png deleted file mode 100644 index 18d7b1c97a7..00000000000 Binary files a/docs/source/tutorial/commercial_paper.diagram.3.png and /dev/null differ diff --git a/docs/source/tutorial/commercial_paper.diagram.4.png b/docs/source/tutorial/commercial_paper.diagram.4.png deleted file mode 100644 index 07a8667d2c6..00000000000 Binary files a/docs/source/tutorial/commercial_paper.diagram.4.png and /dev/null differ diff --git a/docs/source/tutorial/commercial_paper.diagram.5.png b/docs/source/tutorial/commercial_paper.diagram.5.png deleted file mode 100644 index 4be9ffa7e1a..00000000000 Binary files a/docs/source/tutorial/commercial_paper.diagram.5.png and /dev/null differ diff --git a/docs/source/tutorial/commercial_paper.diagram.6.png b/docs/source/tutorial/commercial_paper.diagram.6.png deleted file mode 100644 index ee8123c6dbf..00000000000 Binary files a/docs/source/tutorial/commercial_paper.diagram.6.png and /dev/null differ diff --git a/docs/source/tutorial/commercial_paper.diagram.7.png b/docs/source/tutorial/commercial_paper.diagram.7.png deleted file mode 100644 index 457eaa7e0be..00000000000 Binary files a/docs/source/tutorial/commercial_paper.diagram.7.png and /dev/null differ diff --git a/docs/source/tutorial/commercial_paper.diagram.8.png b/docs/source/tutorial/commercial_paper.diagram.8.png deleted file mode 100644 index a518f0af479..00000000000 Binary files a/docs/source/tutorial/commercial_paper.diagram.8.png and /dev/null differ diff --git a/docs/source/tutorial/commercial_paper.diagram.commit.png b/docs/source/tutorial/commercial_paper.diagram.commit.png deleted file mode 100644 index 7e36d95c716..00000000000 Binary files a/docs/source/tutorial/commercial_paper.diagram.commit.png and /dev/null differ diff --git a/docs/source/tutorial/commercial_paper.diagram.install.png b/docs/source/tutorial/commercial_paper.diagram.install.png deleted file mode 100644 index baf99fc2564..00000000000 Binary files a/docs/source/tutorial/commercial_paper.diagram.install.png and /dev/null differ diff --git a/docs/source/tutorial/commercial_paper.diagram.testnet.png b/docs/source/tutorial/commercial_paper.diagram.testnet.png deleted file mode 100644 index a2c21361b9a..00000000000 Binary files a/docs/source/tutorial/commercial_paper.diagram.testnet.png and /dev/null differ diff --git a/docs/source/tutorial/commercial_paper.md b/docs/source/tutorial/commercial_paper.md deleted file mode 100644 index 19c4f333ded..00000000000 --- a/docs/source/tutorial/commercial_paper.md +++ /dev/null @@ -1,1041 +0,0 @@ -# Commercial paper tutorial - -**Audience:** Architects, application and smart contract developers, -administrators - -This tutorial will show you how to install and use a commercial paper sample -application and smart contract. It is a task-oriented topic, so it emphasizes -procedures above concepts. When you’d like to understand the concepts in more -detail, you can read the -[Developing Applications](../developapps/developing_applications.html) topic. - -![commercialpaper.tutorial](./commercial_paper.diagram.1.png) *In this tutorial -two organizations, MagnetoCorp and DigiBank, trade commercial paper with each -other using PaperNet, a Hyperledger Fabric blockchain network.* - -Once you've set up the test network, you'll act as Isabella, an employee of -MagnetoCorp, who will issue a commercial paper on its behalf. You'll then switch -roles to take the role of Balaji, an employee of DigiBank, who will buy this -commercial paper, hold it for a period of time, and then redeem it with -MagnetoCorp for a small profit. - -You'll act as a developer, end user, and administrator, each in different -organizations, performing the following steps designed to help you understand -what it's like to collaborate as two different organizations working -independently, but according to mutually agreed rules in a Hyperledger Fabric -network. - -* [Set up machine](#prerequisites) and [download samples](#download-samples) -* [Create the network](#create-the-network) -* [Examine the commercial paper smart contract](#examine-the-commercial-paper-smart-contract) -* [Deploy the smart contract to the channel](#deploy-the-smart-contract-to-the-channel) - by approving the chaincode definition as MagnetoCorp and Digibank. -* Understand the structure of a MagnetoCorp [application](#application-structure), - including its [dependencies](#application-dependencies) -* Configure and use a [wallet and identities](#wallet) -* Run a MagnetoCorp application to [issue a commercial paper](#issue-application) -* Understand how DigiBank uses the smart contract in their [applications](#digibank-applications) -* As Digibank, run applications that - [buy](#buy-application) and [redeem](#redeem-application) commercial paper - -This tutorial has been tested on MacOS and Ubuntu, and should work on other -Linux distributions. - -## Prerequisites - -Before you start, you must install some prerequisite technology required by the -tutorial. We've kept these to a minimum so that you can get going quickly. - -You **must** have the following technologies installed: - - * [**Node**](https://github.com/hyperledger/fabric-sdk-node#build-and-test) - The Node.js SDK README contains the up to date list of prerequisites. - -You **will** find it helpful to install the following technologies: - - * A source code editor, such as - [**Visual Studio Code**](https://code.visualstudio.com/) version 1.28, or - higher. VS Code will help you develop and test your application and smart - contract. Install VS Code [here](https://code.visualstudio.com/Download). - - Many excellent code editors are available including - [Atom](https://atom.io/), [Sublime Text](http://www.sublimetext.com/) and - [Brackets](http://www.sublimetext.com/). - -You **may** find it helpful to install the following technologies as you become -more experienced with application and smart contract development. There's no -requirement to install these when you first run the tutorial: - - * [**Node Version Manager**](https://github.com/creationix/nvm). NVM helps you - easily switch between different versions of node -- it can be really helpful - if you're working on multiple projects at the same time. Install NVM - [here](https://github.com/creationix/nvm#installation). - -## Download samples - -The commercial paper tutorial is one of the samples in the `fabric-samples` -repository. Before you begin this tutorial, ensure that you have followed the -instructions to install the required software in the [Getting Started](../getting_started.html) section. -When you are finished, you will have cloned the `fabric-samples` repository that -contains the tutorial scripts, smart contract, and application files. - - -![commercialpaper.download](./commercial_paper.diagram.2.png) *Download the -`fabric-samples` GitHub repository to your local machine.* - -After downloading, feel free to examine the directory structure of `fabric-samples`: - -``` -$ cd fabric-samples -$ ls - -CODEOWNERS SECURITY.md first-network -CODE_OF_CONDUCT.md chaincode high-throughput -CONTRIBUTING.md chaincode-docker-devmode interest_rate_swaps -LICENSE ci off_chain_data -MAINTAINERS.md commercial-paper test-network -README.md fabcar -``` - -Notice the `commercial-paper` directory -- that's where our sample is located! - -You've now completed the first stage of the tutorial! As you proceed, you'll -open multiple command windows for different users and components. For example: - -* To show peer, orderer and CA log output from your network. -* To approve the chaincode as an administrator from MagnetoCorp and as an - administrator from DigiBank. -* To run applications on behalf of Isabella and Balaji, who will use the smart - contract to trade commercial paper with each other. - -We'll make it clear when you should run a command from particular command -window; for example: - -``` -(isabella)$ ls -``` - -indicates that you should run the `ls` command from Isabella's window. - -## Create the network - -This tutorial will deploy a smart contract using the Fabric test network. -The test network consists of two peer organizations and one ordering organization. -The two peer organizations operate one peer each, while the ordering organization -operates a single node Raft ordering service. We will also use the test network -to create a single channel named `mychannel` that both peer organizations -will be members of. - -![commercialpaper.network](./commercial_paper.diagram.testnet.png) -*The Fabric test network is comprised of two peer organizations, Org1 and Org2, -and one ordering organization. Each component runs as a Docker container.* - -Each organization runs their own Certificate Authority. The two peers, the -[state databases](../ledger/ledger.html#world-state-database-options), the ordering service node, -and each organization CA each run in their own Docker container. In production -environments, organizations typically use existing CAs that are shared with other -systems; they're not dedicated to the Fabric network. - -The two organizations of the test network allow us to interact with a blockchain -ledger as two organizations that operate separate peers. In this tutorial, -we will operate Org1 of the test network as DigiBank and Org2 as MagnetoCorp. - -You can start the test network and create the channel with a script provided in -the commercial paper directory. Change to the `commercial-paper` directory in -the `fabric-samples`: -``` -cd fabric-samples/commercial-paper -``` -Then use the script to start the test network: -``` -./network-starter.sh -``` - -While the script is running, you will see logs of the test network being deployed. -When the script is complete, you can use the `docker ps` command to see the -Fabric nodes running on your local machine: -``` -$ docker ps - -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -a86f50ca1907 hyperledger/fabric-peer:latest "peer node start" About a minute ago Up About a minute 7051/tcp, 0.0.0.0:9051->9051/tcp peer0.org2.example.com -77d0fcaee61b hyperledger/fabric-peer:latest "peer node start" About a minute ago Up About a minute 0.0.0.0:7051->7051/tcp peer0.org1.example.com -7eb5f64bfe5f hyperledger/fabric-couchdb "tini -- /docker-ent…" About a minute ago Up About a minute 4369/tcp, 9100/tcp, 0.0.0.0:5984->5984/tcp couchdb0 -2438df719f57 hyperledger/fabric-couchdb "tini -- /docker-ent…" About a minute ago Up About a minute 4369/tcp, 9100/tcp, 0.0.0.0:7984->5984/tcp couchdb1 -03373d116c5a hyperledger/fabric-orderer:latest "orderer" About a minute ago Up About a minute 0.0.0.0:7050->7050/tcp orderer.example.com -6b4d87f65909 hyperledger/fabric-ca:latest "sh -c 'fabric-ca-se…" About a minute ago Up About a minute 7054/tcp, 0.0.0.0:8054->8054/tcp ca_org2 -7b01f5454832 hyperledger/fabric-ca:latest "sh -c 'fabric-ca-se…" About a minute ago Up About a minute 7054/tcp, 0.0.0.0:9054->9054/tcp ca_orderer -87aef6062f23 hyperledger/fabric-ca:latest "sh -c 'fabric-ca-se…" About a minute ago Up About a minute 0.0.0.0:7054->7054/tcp ca_org1 -``` - -See if you can map these containers to the nodes of the test network (you may -need to horizontally scroll to locate the information): -* The Org1 peer, `peer0.org1.example.com`, is running in container `a86f50ca1907` -* The Org2 peer, `peer0.org2.example.com`, is running in container `77d0fcaee61b` -* The CouchDB database for the Org1 peer, `couchdb0`, is running in container `7eb5f64bfe5f` -* The CouchDB database for the Org2 peer, `couchdb1`, is running in container `2438df719f57` -* The Ordering node, `orderer.example.com`, is running in container `03373d116c5a` -* The Org1 CA, `ca_org1`, is running in container `87aef6062f23` -* The Org2 CA, `ca_org2`, is running in container `6b4d87f65909` -* The Ordering Org CA, `ca_orderer`, is running in container `7b01f5454832` - -These containers all form a [Docker network](https://docs.docker.com/network/) -called `fabric_test`. You can view the network with the `docker network` command: - -``` -$ docker network inspect fabric_test - - [ - { - "Name": "fabric_test", - "Id": "f4c9712139311004b8f7acc14e9f90170c5dcfd8cdd06303c7b074624b44dc9f", - "Created": "2020-04-28T22:45:38.525016Z", - "Containers": { - "03373d116c5abf2ca94f6f00df98bb74f89037f511d6490de4a217ed8b6fbcd0": { - "Name": "orderer.example.com", - "EndpointID": "0eed871a2aaf9a5dbcf7896aa3c0f53cc61f57b3417d36c56747033fd9f81972", - "MacAddress": "02:42:c0:a8:70:05", - "IPv4Address": "192.168.112.5/20", - "IPv6Address": "" - }, - "2438df719f57a597de592cfc76db30013adfdcfa0cec5b375f6b7259f67baff8": { - "Name": "couchdb1", - "EndpointID": "52527fb450a7c80ea509cb571d18e2196a95c630d0f41913de8ed5abbd68993d", - "MacAddress": "02:42:c0:a8:70:06", - "IPv4Address": "192.168.112.6/20", - "IPv6Address": "" - }, - "6b4d87f65909afd335d7acfe6d79308d6e4b27441b25a829379516e4c7335b88": { - "Name": "ca_org2", - "EndpointID": "1cc322a995880d76e1dd1f37ddf9c43f86997156124d4ecbb0eba9f833218407", - "MacAddress": "02:42:c0:a8:70:04", - "IPv4Address": "192.168.112.4/20", - "IPv6Address": "" - }, - "77d0fcaee61b8fff43d33331073ab9ce36561a90370b9ef3f77c663c8434e642": { - "Name": "peer0.org1.example.com", - "EndpointID": "05d0d34569eee412e28313ba7ee06875a68408257dc47e64c0f4f5ef4a9dc491", - "MacAddress": "02:42:c0:a8:70:08", - "IPv4Address": "192.168.112.8/20", - "IPv6Address": "" - }, - "7b01f5454832984fcd9650f05b4affce97319f661710705e6381dfb76cd99fdb": { - "Name": "ca_orderer", - "EndpointID": "057390288a424f49d6e9d6f788049b1e18aa28bccd56d860b2be8ceb8173ef74", - "MacAddress": "02:42:c0:a8:70:02", - "IPv4Address": "192.168.112.2/20", - "IPv6Address": "" - }, - "7eb5f64bfe5f20701aae8a6660815c4e3a81c3834b71f9e59a62fb99bed1afc7": { - "Name": "couchdb0", - "EndpointID": "bfe740be15ec9dab7baf3806964e6b1f0b67032ce1b7ae26ac7844a1b422ddc4", - "MacAddress": "02:42:c0:a8:70:07", - "IPv4Address": "192.168.112.7/20", - "IPv6Address": "" - }, - "87aef6062f2324889074cda80fec8fe014d844e10085827f380a91eea4ccdd74": { - "Name": "ca_org1", - "EndpointID": "a740090d33ca94dd7c6aaf14a79e1cb35109b549ee291c80195beccc901b16b7", - "MacAddress": "02:42:c0:a8:70:03", - "IPv4Address": "192.168.112.3/20", - "IPv6Address": "" - }, - "a86f50ca19079f59552e8674932edd02f7f9af93ded14db3b4c404fd6b1abe9c": { - "Name": "peer0.org2.example.com", - "EndpointID": "6e56772b4783b1879a06f86901786fed1c307966b72475ce4631405ba8bca79a", - "MacAddress": "02:42:c0:a8:70:09", - "IPv4Address": "192.168.112.9/20", - "IPv6Address": "" - } - }, - "Options": {}, - "Labels": {} - } - ] -``` - -See how the eight containers use different IP addresses, while being part of a -single Docker network. (We've abbreviated the output for clarity.) - -Because we are operating the test network as DigiBank and MagnetoCorp, -`peer0.org1.example.com` will belong to the DigiBank organization while -`peer0.org2.example.com` will be operated by MagnetoCorp. Now that the test -network is up and running, we can refer to our network as PaperNet from this point -forward. - -To recap: you've downloaded the Hyperledger Fabric samples repository from -GitHub and you've got a Fabric network running on your local machine. Let's now -start to play the role of MagnetoCorp, who wishes to issue and trade commercial paper. - -## Monitor the network as MagnetoCorp - -The commercial paper tutorial allows you to act as two organizations by -providing two separate folders for DigiBank and MagnetoCorp. The two folders -contain the smart contracts and application files for each organization. Because -the two organizations have different roles in the trading of the commercial paper, -the application files are different for each organization. Open a new window in -the `fabric-samples` repository and use the following command to change into -the MagnetoCorp directory: -``` -cd commercial-paper/organization/magnetocorp -``` -The first thing we are going to do as MagnetoCorp is monitor the components -of PaperNet. An administrator can view the aggregated output from a set -of Docker containers using the `logspout` [tool](https://github.com/gliderlabs/logspout#logspout). -The tool collects the different output streams into one place, making it easy -to see what's happening from a single window. This can be really helpful for -administrators when installing smart contracts or for developers when invoking -smart contracts, for example. - -In the MagnetoCorp directory, run the following command to run the -`monitordocker.sh` script and start the `logspout` tool for the containers -associated with PaperNet running on `fabric_test`: -``` -(magnetocorp admin)$ ./configuration/cli/monitordocker.sh fabric_test -... -latest: Pulling from gliderlabs/logspout -4fe2ade4980c: Pull complete -decca452f519: Pull complete -(...) -Starting monitoring on all containers on the network fabric_test -b7f3586e5d0233de5a454df369b8eadab0613886fc9877529587345fc01a3582 -``` - -Note that you can pass a port number to the above command if the default port in `monitordocker.sh` is already in use. -``` -(magnetocorp admin)$ ./monitordocker.sh fabric_test -``` - -This window will now show output from the Docker containers for the remainder of the -tutorial, so go ahead and open another command window. The next thing we will do is -examine the smart contract that MagnetoCorp will use to issue to the commercial -paper. - -## Examine the commercial paper smart contract - -`issue`, `buy` and `redeem` are the three functions at the heart of the commercial -paper smart contract. It is used by applications to submit transactions which -correspondingly issue, buy and redeem commercial paper on the ledger. Our next -task is to examine this smart contract. - -Open a new terminal in the `fabric-samples` directory and change into the -MagnetoCorp folder to act as the MagnetoCorp developer. -``` -cd commercial-paper/organization/magnetocorp -``` -You can then view the smart contract in the `contract` directory using your chosen -editor (VS Code in this tutorial): -``` -(magnetocorp developer)$ code contract -``` - -In the `lib` directory of the folder, you'll see `papercontract.js` file -- this -contains the commercial paper smart contract! - -![commercialpaper.vscode1](./commercial_paper.vscode.papercontract.png) *An -example code editor displaying the commercial paper smart contract in `papercontract.js`* - -`papercontract.js` is a JavaScript program designed to run in the Node.js -environment. Note the following key program lines: - -* `const { Contract, Context } = require('fabric-contract-api');` - - This statement brings into scope two key Hyperledger Fabric classes that will - be used extensively by the smart contract -- `Contract` and `Context`. You - can learn more about these classes in the - [`fabric-shim` JSDOCS](https://hyperledger.github.io/fabric-chaincode-node/). - - -* `class CommercialPaperContract extends Contract {` - - This defines the smart contract class `CommercialPaperContract` based on the - built-in Fabric `Contract` class. The methods which implement the key - transactions to `issue`, `buy` and `redeem` commercial paper are defined - within this class. - - -* `async issue(ctx, issuer, paperNumber, issueDateTime, maturityDateTime...) {` - - This method defines the commercial paper `issue` transaction for PaperNet. The - parameters that are passed to this method will be used to create the new - commercial paper. - - Locate and examine the `buy` and `redeem` transactions within the smart - contract. - - -* `let paper = CommercialPaper.createInstance(issuer, paperNumber, issueDateTime...);` - - Within the `issue` transaction, this statement creates a new commercial paper - in memory using the `CommercialPaper` class with the supplied transaction - inputs. Examine the `buy` and `redeem` transactions to see how they similarly - use this class. - - -* `await ctx.paperList.addPaper(paper);` - - This statement adds the new commercial paper to the ledger using - `ctx.paperList`, an instance of a `PaperList` class that was created when the - smart contract context `CommercialPaperContext` was initialized. Again, - examine the `buy` and `redeem` methods to see how they use this class. - - -* `return paper;` - - This statement returns a binary buffer as response from the `issue` - transaction for processing by the caller of the smart contract. - - -Feel free to examine other files in the `contract` directory to understand how -the smart contract works, and read in detail how `papercontract.js` is -designed in the [smart contract processing](../developapps/smartcontract.html) -topic. - -## Deploy the smart contract to the channel - -Before `papercontract` can be invoked by applications, it must be installed onto -the appropriate peer nodes of the test network and then defined on the channel -using the [Fabric chaincode lifecycle](../chaincode_lifecycle.html#chaincode-lifecycle). The Fabric chaincode -lifecycle allows multiple organizations to agree to the parameters of a chaincode -before the chaincode is deployed to a channel. As a result, we need to install -and approve the chaincode as administrators of both MagnetoCorp and DigiBank. - -![commercialpaper.install](./commercial_paper.diagram.install.png) *A MagnetoCorp -administrator installs a copy of the `papercontract` onto a MagnetoCorp peer.* - -Smart contracts are the focus of application development, and are contained -within a Hyperledger Fabric artifact called [chaincode](../chaincode4ade.html). One -or more smart contracts can be defined within a single chaincode, and installing -a chaincode will allow them to be consumed by the different organizations in -PaperNet. It means that only administrators need to worry about chaincode; -everyone else can think in terms of smart contracts. - -### Install and approve the smart contract as MagnetoCorp - -We will first install and approve the smart contract as the MagnetoCorp admin. Make -sure that you are operating from the `magnetocorp` folder, or navigate back to that -folder using the following command: -``` -cd commercial-paper/organization/magnetocorp -``` - -A MagnetoCorp administrator can interact with PaperNet using the `peer` CLI. However, -the administrator needs to set certain environment variables in their command -window to use the correct set of `peer` binaries, send commands to the address -of the MagnetoCorp peer, and sign requests with the correct cryptographic material. - -You can use a script provided by the sample to set the environment variables in -your command window. Run the following command in the `magnetocorp` directory: -``` -source magnetocorp.sh -``` - -You will see the full list of environment variables printed in your window. We -can now use this command window to interact with PaperNet as the MagnetoCorp -administrator. - -The first step is to install the `papercontract` smart contract. The smart -contract can be packaged into a chaincode using the -`peer lifecycle chaincode package` command. In the MagnetoCorp administrator's -command window, run the following command to create the chaincode package: -``` -(magnetocorp admin)$ peer lifecycle chaincode package cp.tar.gz --lang node --path ./contract --label cp_0 -``` -The MagnetoCorp admin can now install the chaincode on the MagnetoCorp peer using -the `peer lifecycle chaincode install` command: -``` -(magnetocorp admin)$ peer lifecycle chaincode install cp.tar.gz -``` -When the chaincode package is installed, you will see messages similar to the following -printed in your terminal: -``` -2020-01-30 18:32:33.762 EST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response: -2020-01-30 18:32:33.762 EST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: cp_0:ffda93e26b183e231b7e9d5051e1ee7ca47fbf24f00a8376ec54120b1a2a335c -``` -Because the MagnetoCorp admin has set `CORE_PEER_ADDRESS=localhost:9051` to -target its commands to `peer0.org2.example.com`, the `INFO 001 Installed remotely...` -indicates that `papercontract` has been successfully installed on this peer. - -After we install the smart contract, we need to approve the chaincode definition -for `papercontract` as MagnetoCorp. The first step is to find the packageID of -the chaincode we installed on our peer. We can query the packageID using the -`peer lifecycle chaincode queryinstalled` command: -``` -peer lifecycle chaincode queryinstalled -``` - -The command will return the same package identifier as the install command. You -should see output similar to the following: -``` -Installed chaincodes on peer: -Package ID: cp_0:ffda93e26b183e231b7e9d5051e1ee7ca47fbf24f00a8376ec54120b1a2a335c, Label: cp_0 -``` - -We will need the package ID in the next step, so we will save it as an environment -variable. The package ID may not be the same for all users, so you need to -complete this step using the package ID returned from your command window. -``` -export PACKAGE_ID=cp_0:ffda93e26b183e231b7e9d5051e1ee7ca47fbf24f00a8376ec54120b1a2a335c -``` - -The admin can now approve the chaincode definition for MagnetoCorp using the -`peer lifecycle chaincode approveformyorg` command: -``` -(magnetocorp admin)$ peer lifecycle chaincode approveformyorg --orderer localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name papercontract -v 0 --package-id $PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA -``` - -One of the most important chaincode parameters that channel members need to -agree to using the chaincode definition is the chaincode [endorsement policy](../endorsement-policies.html). -The endorsement policy describes the set of organizations that must endorse -(execute and sign) a transaction before it can be determined to be valid. By -approving the `papercontract` chaincode without the ``--policy`` flag, the -MagnetoCorp admin agrees to using the channel's default `Endorsement` policy, -which in the case of the `mychannel` test channel requires a -majority of organizations on the channel to endorse a transaction. All transactions, -whether valid or invalid, will be recorded on the [ledger blockchain](../ledger/ledger.html#blockchain), -but only valid transactions will update the [world state](../ledger/ledger.html#world-state). - -### Install and approve the smart contract as DigiBank - -Based on the `mychannel` `LifecycleEndorsement` policy, the Fabric Chaincode lifecycle -will require a majority of organizations on the channel to agree to the chaincode -definition before the chaincode can be committed to the channel. -This implies that we need to approve the `papernet` chaincode as both MagnetoCorp -and DigiBank to get the required majority of 2 out of 2. Open a new terminal -window in the `fabric-samples` and navigate to the folder that contains the -DigiBank smart contract and application files: -``` -(digibank admin)$ cd commercial-paper/organization/digibank/ -``` -Use the script in the DigiBank folder to set the environment variables that will -allow you to act as the DigiBank admin: -``` -source digibank.sh -``` - -We can now install and approve `papercontract` as the DigiBank. Run the following -command to package the chaincode: -``` -(digibank admin)$ peer lifecycle chaincode package cp.tar.gz --lang node --path ./contract --label cp_0 -``` -The admin can now install the chaincode on the DigiBank peer: -``` -(digibank admin)$ peer lifecycle chaincode install cp.tar.gz -``` -We then need to query and save the packageID of the chaincode that was just -installed: -``` -(digibank admin)$ peer lifecycle chaincode queryinstalled -``` -Save the package ID as an environment variable. Complete this step using the -package ID returned from your console. -``` -export PACKAGE_ID=cp_0:ffda93e26b183e231b7e9d5051e1ee7ca47fbf24f00a8376ec54120b1a2a335c -``` - -The Digibank admin can now approve the chaincode definition of `papercontract`: -``` -(digibank admin)$ peer lifecycle chaincode approveformyorg --orderer localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name papercontract -v 0 --package-id $PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA -``` - -### Commit the chaincode definition to the channel - -Now that DigiBank and MagnetoCorp have both approved the `papernet` chaincode, we -have the majority we need (2 out of 2) to commit the chaincode definition to the -channel. Once the chaincode is successfully defined on the channel, the -`CommercialPaper` smart contract inside the `papercontract` chaincode can be -invoked by client applications on the channel. Since either organization can -commit the chaincode to the channel, we will continue operating as the -DigiBank admin: - -![commercialpaper.commit](./commercial_paper.diagram.commit.png) *After the DigiBank administrator commits the definition of the `papercontract` chaincode to the channel, a new Docker chaincode container will be created to run `papercontract` on both PaperNet peers* - -The DigiBank administrator uses the `peer lifecycle chaincode commit` command -to commit the chaincode definition of `papercontract` to `mychannel`: -``` -(digibank admin)$ peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --peerAddresses localhost:7051 --tlsRootCertFiles ${PEER0_ORG1_CA} --peerAddresses localhost:9051 --tlsRootCertFiles ${PEER0_ORG2_CA} --channelID mychannel --name papercontract -v 0 --sequence 1 --tls --cafile $ORDERER_CA --waitForEvent -``` -The chaincode container will start after the chaincode definition has been -committed to the channel. You can use the `docker ps` command to see -`papercontract` container starting on both peers. - -``` -(digibank admin)$ docker ps - -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -d4ba9dc9c55f dev-peer0.org1.example.com-cp_0-ebef35e7f1f25eea1dcc6fcad5019477cd7f434c6a5dcaf4e81744e282903535-05cf67c20543ee1c24cf7dfe74abce99785374db15b3bc1de2da372700c25608 "docker-entrypoint.s…" 30 seconds ago Up 28 seconds dev-peer0.org1.example.com-cp_0-ebef35e7f1f25eea1dcc6fcad5019477cd7f434c6a5dcaf4e81744e282903535 -a944c0f8b6d6 dev-peer0.org2.example.com-cp_0-1487670371e56d107b5e980ce7f66172c89251ab21d484c7f988c02912ddeaec-1a147b6fd2a8bd2ae12db824fad8d08a811c30cc70bc5b6bc49a2cbebc2e71ee "docker-entrypoint.s…" 31 seconds ago Up 28 seconds dev-peer0.org2.example.com-cp_0-1487670371e56d107b5e980ce7f66172c89251ab21d484c7f988c02912ddeaec -``` - -Notice that the containers are named to indicate the peer that started it, and -the fact that it's running `papercontract` version `0`. - -Now that we have deployed the `papercontract` chaincode to the channel, we can -use the MagnetoCorp application to issue the commercial paper. Let's take a -moment to examine the application structure. - -## Application structure - -The smart contract contained in `papercontract` is called by MagnetoCorp's -application `issue.js`. Isabella uses this application to submit a transaction -to the ledger which issues commercial paper `00001`. Let's quickly examine how -the `issue` application works. - -![commercialpaper.application](./commercial_paper.diagram.8.png) *A gateway -allows an application to focus on transaction generation, submission and -response. It coordinates transaction proposal, ordering and notification -processing between the different network components.* - -Because the `issue` application submits transactions on behalf of Isabella, it -starts by retrieving Isabella's X.509 certificate from her -[wallet](../developapps/wallet.html), which might be stored on the local file -system or a Hardware Security Module -[HSM](https://en.wikipedia.org/wiki/Hardware_security_module). The `issue` -application is then able to utilize the gateway to submit transactions on the -channel. The Hyperledger Fabric SDK provides a -[gateway](../developapps/gateway.html) abstraction so that applications can -focus on application logic while delegating network interaction to the -gateway. Gateways and wallets make it straightforward to write Hyperledger -Fabric applications. - -So let's examine the `issue` application that Isabella is going to use. Open a -separate terminal window for her, and in `fabric-samples` locate the MagnetoCorp -`/application` folder: - -``` -(isabella)$ cd commercial-paper/organization/magnetocorp/application/ -(isabella)$ ls - -addToWallet.js enrollUser.js issue.js package.json -``` - -`addToWallet.js` is the program that Isabella is going to use to load her -identity into her wallet, and `issue.js` will use this identity to create -commercial paper `00001` on behalf of MagnetoCorp by invoking `papercontract`. - -Change to the directory that contains MagnetoCorp's copy of the application -`issue.js`, and use your code editor to examine it: - -``` -(isabella)$ cd commercial-paper/organization/magnetocorp/application -(isabella)$ code issue.js -``` - -Examine this directory; it contains the issue application and all its -dependencies. - -![commercialpaper.vscode2](./commercial_paper.vscode.issue.png) *A code editor -displaying the contents of the commercial paper application directory.* - -Note the following key program lines in `issue.js`: - -* `const { Wallets, Gateway } = require('fabric-network');` - - This statement brings two key Hyperledger Fabric SDK classes into scope -- - `Wallet` and `Gateway`. - - -* `const wallet = await Wallets.newFileSystemWallet('../identity/user/isabella/wallet');` - - This statement identifies that the application will use `isabella` wallet when - it connects to the blockchain network channel. Because Isabella's X.509 certificate - is in the local file system, the application creates a new `FileSystemWallet`. The - application will select a particular identity within `isabella` wallet. - - -* `await gateway.connect(connectionProfile, connectionOptions);` - - This line of code connects to the network using the gateway identified by - `connectionProfile`, using the identity referred to in `ConnectionOptions`. - - See how `../gateway/networkConnection.yaml` and `User1@org1.example.com` are - used for these values respectively. - - -* `const network = await gateway.getNetwork('mychannel');` - - This connects the application to the network channel `mychannel`, where the - `papercontract` was previously deployed. - - -* `const contract = await network.getContract('papercontract');` - - This statement gives the application access to the `papercontract` chaincode. - Once an application has issued getContract, it can submit to any smart contract - transaction implemented within the chaincode. - -* `const issueResponse = await contract.submitTransaction('issue', 'MagnetoCorp', '00001', ...);` - - This line of code submits the a transaction to the network using the `issue` - transaction defined within the smart contract. `MagnetoCorp`, `00001`... are - the values to be used by the `issue` transaction to create a new commercial - paper. - -* `let paper = CommercialPaper.fromBuffer(issueResponse);` - - This statement processes the response from the `issue` transaction. The - response needs to deserialized from a buffer into `paper`, a `CommercialPaper` - object which can interpreted correctly by the application. - - -Feel free to examine other files in the `/application` directory to understand -how `issue.js` works, and read in detail how it is implemented in the -application [topic](../developapps/application.html). - -## Application dependencies - -The `issue.js` application is written in JavaScript and designed to run in the -Node.js environment that acts as a client to the PaperNet network. -As is common practice, MagnetoCorp's application is built on many -external node packages --- to improve quality and speed of development. Consider -how `issue.js` includes the `js-yaml` -[package](https://www.npmjs.com/package/js-yaml) to process the YAML gateway -connection profile, or the `fabric-network` -[package](https://www.npmjs.com/package/fabric-network) to access the `Gateway` -and `Wallet` classes: - -```JavaScript -const yaml = require('js-yaml'); -const { Wallets, Gateway } = require('fabric-network'); -``` - -These packages have to be downloaded from [npm](https://www.npmjs.com/) to the -local file system using the `npm install` command. By convention, packages must -be installed into an application-relative `/node_modules` directory for use at -runtime. - -Open the `package.json` file to see how `issue.js` identifies the packages to -download and their exact versions by examining the "dependencies" section of the file. - -**npm** versioning is very powerful; you can read more about it -[here](https://docs.npmjs.com/getting-started/semantic-versioning). - -Let's install these packages with the `npm install` command -- this may take up -to a minute to complete: - -``` -(isabella)$ cd commercial-paper/organization/magnetocorp/application/ -(isabella)$ npm install - -( ) extract:lodash: sill extract ansi-styles@3.2.1 -(...) -added 738 packages in 46.701s -``` - -See how this command has updated the directory: - -``` -(isabella)$ ls - -enrollUser.js node_modules package.json -issue.js package-lock.json -``` - -Examine the `node_modules` directory to see the packages that have been -installed. There are lots, because `js-yaml` and `fabric-network` are themselves -built on other npm packages! Helpfully, the `package-lock.json` -[file](https://docs.npmjs.com/files/package-lock.json) identifies the exact -versions installed, which can prove invaluable if you want to exactly reproduce -environments; to test, diagnose problems or deliver proven applications for -example. - -## Wallet - -Isabella is almost ready to run `issue.js` to issue MagnetoCorp commercial paper -`00001`; there's just one remaining task to perform! As `issue.js` acts on -behalf of Isabella, and therefore MagnetoCorp, it will use identity from her -[wallet](../developapps/wallet.html) that reflects these facts. We now need to -perform this one-time activity of generating the appropriate X.509 credentials -to her wallet. - -The MagnetoCorp Certificate Authority running on PaperNet, `ca_org2`, has an -application user that was registered when the network was deployed. Isabella -can use the identity name and secret to generate the X.509 cryptographic material -for the `issue.js` application. The process of using a CA to generate client side -cryptographic material is referred to as **enrollment**. In a real word scenario, -a network operator would provide the name and secret of a client identity that -was registered with the CA to an application developer. The developer would then -use the credentials to enroll their application and interact with the network. - -The `enrollUser.js` program uses the `fabric-ca-client` class to generate a private -and public key pair, and then issues a **Certificate Signing Request** to the CA. -If the identiy name and secret submitted by Isabella match the credentials -registered with the CA, the CA will issue and sign a certificate that encodes the -public key, establishing that Isabella belongs to MagnetoCorp. When the signing -request is complete, `enrollUser.js` stores the private key and signing certificate -in Isabella's wallet. You can examine the `enrollUser.js` file to learn more about -how the Node SDK uses the `fabric-ca-client` class to complete these tasks. - -In Isabella's terminal window, run the `enrollUser.js` program to add identity -information to her wallet: - -``` -(isabella)$ node enrollUser.js - -Wallet path: /Users/nikhilgupta/fabric-samples/commercial-paper/organization/magnetocorp/identity/user/isabella/wallet -Successfully enrolled client user "isabella" and imported it into the wallet -``` - -We can now turn our focus to the result of this program --- the contents of the -wallet which will be used to submit transactions to PaperNet: - -``` -(isabella)$ ls ../identity/user/isabella/wallet/ - -isabella.id -``` - -Isabella can store multiple identities in her wallet, though in our example, she -only uses one. The `wallet` folder contains an `isabella.id` file that provides -the information that Isabella needs to connect to the network. Other identities -used by Isabella would have their own file. You can open this file to see the -identity information that `issue.js` will use on behalf of Isabella inside a JSON -file. The output has been formatted for clarity. -``` -(isabella)$ cat ../identity/user/isabella/wallet/* - -{ - "credentials": { - "certificate": "-----BEGIN CERTIFICATE-----\nMIICKTCCAdCgAwIBAgIQWKwvLG+sqeO3LwwQK6avZDAKBggqhkjOPQQDAjBzMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMi5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eu\nb3JnMi5leGFtcGxlLmNvbTAeFw0yMDAyMDQxOTA5MDBaFw0zMDAyMDExOTA5MDBa\nMGwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T\nYW4gRnJhbmNpc2NvMQ8wDQYDVQQLEwZjbGllbnQxHzAdBgNVBAMMFlVzZXIxQG9y\nZzIuZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT4TnTblx0k\ngfqX+NN7F76Me33VTq3K2NUWZRreoJzq6bAuvdDR+iFvVPKXbdORnVvRSATcXsYl\nt20yU7n/53dbo00wSzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADArBgNV\nHSMEJDAigCDOCdm4irsZFU3D6Hak4+84QRg1N43iwg8w1V6DRhgLyDAKBggqhkjO\nPQQDAgNHADBEAiBhzKix1KJcbUy9ey5ulWHRUMbqdVCNHe/mRtUdaJagIgIgYpbZ\nXf0CSiTXIWOJIsswN4Jp+ZxkJfFVmXndqKqz+VM=\n-----END CERTIFICATE-----\n", - "privateKey": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQggs55vQg2oXi8gNi8\nNidE8Fy5zenohArDq3FGJD8cKU2hRANCAAT4TnTblx0kgfqX+NN7F76Me33VTq3K\n2NUWZRreoJzq6bAuvdDR+iFvVPKXbdORnVvRSATcXsYlt20yU7n/53db\n-----END PRIVATE KEY-----\n" - }, - "mspId": "Org2MSP", - "type": "X.509", - "version": 1 -} -``` - -In the file you can notice the following: - -* a `"privateKey":` used to sign transactions on Isabella's behalf, but not - distributed outside of her immediate control. - -* a `"certificate":` which contains Isabella's public key and other X.509 - attributes added by the Certificate Authority at certificate creation. This - certificate is distributed to the network so that different actors at different - times can cryptographically verify information created by Isabella's private key. - -You can Learn more about certificates [here](../identity/identity.html#digital-certificates). In practice, the -certificate file also contains some Fabric-specific metadata such as -Isabella's organization and role -- read more in the [wallet](../developapps/wallet.html) topic. - -## Issue application - -Isabella can now use `issue.js` to submit a transaction that will issue -MagnetoCorp commercial paper `00001`: - -``` -(isabella)$ node issue.js - -Connect to Fabric gateway. -Use network channel: mychannel. -Use org.papernet.commercialpaper smart contract. -Submit commercial paper issue transaction. -Process issue transaction response.{"class":"org.papernet.commercialpaper","key":"\"MagnetoCorp\":\"00001\"","currentState":1,"issuer":"MagnetoCorp","paperNumber":"00001","issueDateTime":"2020-05-31","maturityDateTime":"2020-11-30","faceValue":"5000000","owner":"MagnetoCorp"} -MagnetoCorp commercial paper : 00001 successfully issued for value 5000000 -Transaction complete. -Disconnect from Fabric gateway. -Issue program complete. -``` - -The `node` command initializes a Node.js environment, and runs `issue.js`. We -can see from the program output that MagnetoCorp commercial paper 00001 was -issued with a face value of 5M USD. - -As you've seen, to achieve this, the application invokes the `issue` transaction -defined in the `CommercialPaper` smart contract within `papercontract.js`. -The smart contract interacts with the ledger via the -Fabric APIs, most notably `putState()` and `getState()`, to represent the new -commercial paper as a vector state within the world state. We'll see how this -vector state is subsequently manipulated by the `buy` and `redeem` transactions -also defined within the smart contract. - -All the time, the underlying Fabric SDK handles the transaction endorsement, -ordering and notification process, making the application's logic -straightforward; the SDK uses a [gateway](../developapps/gateway.html) to -abstract away network details and -[connectionOptions](../developapps/connectionoptions.html) to declare more advanced -processing strategies such as transaction retry. - -Let's now follow the lifecycle of MagnetoCorp 00001 by switching our emphasis -to an employee of DigiBank, Balaji, who will buy the commercial paper using a -DigiBank application. - -## Digibank applications - -Balaji uses DigiBank's `buy` application to submit a transaction to the ledger -which transfers ownership of commercial paper `00001` from MagnetoCorp to -DigiBank. The `CommercialPaper` smart contract is the same as that used by -MagnetoCorp's application, however the transaction is different this time -- -it's `buy` rather than `issue`. Let's examine how DigiBank's application works. - -Open a separate terminal window for Balaji. In `fabric-samples`, change to the -DigiBank application directory that contains the application, `buy.js`, and open -it with your editor: - -``` -(balaji)$ cd commercial-paper/organization/digibank/application/ -(balaji)$ code buy.js -``` - -As you can see, this directory contains both the `buy` and `redeem` applications -that will be used by Balaji. - - -![commercialpaper.vscode3](./commercial_paper.diagram.12.png) *DigiBank's -commercial paper directory containing the `buy.js` and `redeem.js` -applications.* - -DigiBank's `buy.js` application is very similar in structure to MagnetoCorp's -`issue.js` with two important differences: - - - * **Identity**: the user is a DigiBank user `Balaji` rather than MagnetoCorp's - `Isabella` - - ```JavaScript - const wallet = await Wallets.newFileSystemWallet('../identity/user/balaji/wallet'); - ``` - - See how the application uses the `balaji` wallet when it connects to the - PaperNet network channel. `buy.js` selects a particular identity within - `balaji` wallet. - - - * **Transaction**: the invoked transaction is `buy` rather than `issue` - - ```JavaScript - const buyResponse = await contract.submitTransaction('buy', 'MagnetoCorp', '00001', ...); - ``` - - A `buy` transaction is submitted with the values `MagnetoCorp`, `00001`, ..., - that are used by the `CommercialPaper` smart contract class to transfer - ownership of commercial paper `00001` to DigiBank. - -Feel free to examine other files in the `application` directory to understand -how the application works, and read in detail how `buy.js` is implemented in -the application [topic](../developapps/application.html). - -## Run as DigiBank - -The DigiBank applications which buy and redeem commercial paper have a very -similar structure to MagnetoCorp's issue application. Therefore, let’s install -their dependencies and set up Balaji's wallet so that he can use these -applications to buy and redeem commercial paper. - -Like MagnetoCorp, Digibank must the install the required application packages -using the ``npm install`` command, and again, this make take a short time to -complete. - -In the DigiBank administrator window, install the application dependencies: - -``` -(digibank admin)$ cd commercial-paper/organization/digibank/application/ -(digibank admin)$ npm install - -( ) extract:lodash: sill extract ansi-styles@3.2.1 -(...) -added 738 packages in 46.701s -``` - -In Balaji's command window, run the `enrollUser.js` program to generate a -certificate and private key and them to his wallet: -``` -(balaji)$ node enrollUser.js - -Wallet path: /Users/nikhilgupta/fabric-samples/commercial-paper/organization/digibank/identity/user/balaji/wallet -Successfully enrolled client user "balaji" and imported it into the wallet -``` - -The `addToWallet.js` program has added identity information for `balaji`, to his -wallet, which will be used by `buy.js` and `redeem.js` to submit transactions to -`PaperNet`. - -Like Isabella, Balaji can store multiple identities in his wallet, though in our -example, he only uses one. His corresponding id file at -`digibank/identity/user/balaji/wallet/balaji.id` is very similar Isabella's --- -feel free to examine it. - -## Buy application - -Balaji can now use `buy.js` to submit a transaction that will transfer ownership -of MagnetoCorp commercial paper 00001 to DigiBank. - -Run the `buy` application in Balaji's window: - -``` -(balaji)$ node buy.js - -Connect to Fabric gateway. -Use network channel: mychannel. -Use org.papernet.commercialpaper smart contract. -Submit commercial paper buy transaction. -Process buy transaction response. -MagnetoCorp commercial paper : 00001 successfully purchased by DigiBank -Transaction complete. -Disconnect from Fabric gateway. -Buy program complete. -``` - -You can see the program output that MagnetoCorp commercial paper 00001 was -successfully purchased by Balaji on behalf of DigiBank. `buy.js` invoked the -`buy` transaction defined in the `CommercialPaper` smart contract which updated -commercial paper `00001` within the world state using the `putState()` and -`getState()` Fabric APIs. As you've seen, the application logic to buy and issue -commercial paper is very similar, as is the smart contract logic. - -## Redeem application - -The final transaction in the lifecycle of commercial paper 00001 is for -DigiBank to redeem it with MagnetoCorp. Balaji uses `redeem.js` to submit a -transaction to perform the redeem logic within the smart contract. - -Run the `redeem` transaction in Balaji's window: - -``` -(balaji)$ node redeem.js - -Connect to Fabric gateway. -Use network channel: mychannel. -Use org.papernet.commercialpaper smart contract. -Submit commercial paper redeem transaction. -Process redeem transaction response. -MagnetoCorp commercial paper : 00001 successfully redeemed with MagnetoCorp -Transaction complete. -Disconnect from Fabric gateway. -Redeem program complete. -``` - -Again, see how the commercial paper 00001 was successfully redeemed when -`redeem.js` invoked the `redeem` transaction defined in `CommercialPaper`. -Again, it updated commercial paper `00001` within the world state to reflect -that the ownership returned to MagnetoCorp, the issuer of the paper. - -## Clean up - -When you are finished using the Commercial Paper tutorial, you can use a script -to clean up your environment. Use a command window to navigate back to the root -directory of the commercial paper sample: -``` -cd fabric-samples/commercial-paper -``` -You can then bring down the network with the following command: -``` -./network-clean.sh -``` -This command will bring down the peers, CouchDB containers, and ordering node of the network, in addition to the logspout tool. It will also remove the identities that we created for Isabella and Balaji. Note that all of the data on the ledger will be lost. If you want to go through the tutorial again, you will start from a clean initial state. - -## Further reading - -To understand how applications and smart contracts shown in this tutorial work -in more detail, you'll find it helpful to read -[Developing Applications](../developapps/developing_applications.html). This -topic will give you a fuller explanation of the commercial paper scenario, the -PaperNet business network, its actors, and how the applications and smart -contracts they use work in detail. - -Also feel free to use this sample to start creating your own applications and -smart contracts! - - diff --git a/docs/source/tutorial/commercial_paper.vscode.issue.png b/docs/source/tutorial/commercial_paper.vscode.issue.png deleted file mode 100644 index a534c300e30..00000000000 Binary files a/docs/source/tutorial/commercial_paper.vscode.issue.png and /dev/null differ diff --git a/docs/source/tutorial/commercial_paper.vscode.papercontract.png b/docs/source/tutorial/commercial_paper.vscode.papercontract.png deleted file mode 100644 index bcffa4fe03e..00000000000 Binary files a/docs/source/tutorial/commercial_paper.vscode.papercontract.png and /dev/null differ diff --git a/docs/source/tutorials.rst b/docs/source/tutorials.rst index db88894beb2..29b53f4fccd 100644 --- a/docs/source/tutorials.rst +++ b/docs/source/tutorials.rst @@ -36,7 +36,6 @@ Finally, we provide an introduction to how to write a basic smart contract, test_network deploy_chaincode.md write_first_app - tutorial/commercial_paper private_data_tutorial secured_asset_transfer/secured_private_asset_transfer_tutorial.md couchdb_tutorial