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.

Scenario

In the commercial paper sample, papercontract 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 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:

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:

CommercialPaperContext extends Context {
    constructor () {
        this.paperList = new PaperList(this);
    }
}

When the createContext() method returns at point (1) in the diagram above, 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):

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, 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.

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 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:


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. 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)


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. 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)


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)


ClientIdentity

In most cases, the application submitting a transaction will be using an X.509 certificate. In the example, 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.