Include Oracle Blockchain Platform in Global Distributed Transactions

Your application might need to make updates across the Oracle Blockchain Platform ledger and other repositories such as databases or other blockchain ledgers in an atomic fashion, where either all updates succeed or none do.

To enable atomic updates across multiple databases, developers use global transactions that are coordinated by distributed transaction coordinators such as Oracle WebLogic Server, Oracle Tuxedo, Oracle Transaction Manager for Microservices, JBoss Enterprise Application Platform, IBM WebSphere, and other systems. All of these systems rely on the X/Open XA protocol to orchestrate a two-phase commit process by using standard APIs that are provided by XA Resource Managers (RMs) for each database or other resource. Oracle Blockchain Platform supports two-phase commits and provides its own XA RM library, which external transaction coordinators can use to invoke XA-compliant APIs. These global transactions can also include a single non-XA resource (for example, a non-Oracle blockchain ledger or non-XA compliant database) by using a last resource commit optimization.

The XA specification is part of the X/Open Distributed Transaction Processing architecture, which defines a standard architecture that enables multiple application programs to share resources provided by multiple resource managers. The Java XA interface itself is defined as part of the Java platform. For more information on the Java XA interface, see Interface XAResource in the Java documentation.

Oracle Blockchain Platform provides a library that conforms to the XA specification and implements the standard Java interface for an XA resource manager. The library enables a client-side transaction manager to coordinate global transactions. A global transaction is a single unit of work that might include operations such as database updates and blockchain transactions, all of which must be committed atomically. In other words, all of the operations must succeed to be committed. If any operation that is part of the global transaction fails, then all operations are rolled back. The XA interface relies on the two-phase commit protocol, similar to the protocol supported by the atomic transactions REST endpoints. For more information about atomic transactions in Oracle Blockchain Platform, see Make Atomic Updates Across Chaincodes and Channels.

The XA implementation for Oracle Blockchain Platform is supplied as a Java library, downloadable from the Developer Tools tab on the Application Development pane of the Oracle Blockchain Platform console.

Full details on the library are included in the Javadoc information supplied in the downloadable file. The three key objects supported by the library are OBPXAResource, OBPXADataSource, and OBPXAConnection.
Object Purpose
OBPXAResource This class implements the required APIs for a transaction manager to coordinate with Oracle Blockchain Platform as a resource manager for XA transactions.
OBPXADataSource Use this object to get an instance of the OBPXAConnection and to specify the authentication and authorization credentials.
OBPXAConnection Use this object to get an instance of the OBPXAResource object and to define the blockchain transactions to run as part of an XA transaction.

To use the XA library with Oracle Blockchain Platform, the application must provide credentials for authentication and authorization of the requested operations. The library supports both basic authentication (user/password) and OAuth 2.0 access tokens, which you can configure when you create the OBPXADataSource instance. The two authentication methods are consistent with the authentication methods that you use with the Oracle Blockchain Platform REST proxy. For more information, see Authentication in the REST API documentation.

After you create an OBPXADataSource instance, you can use the obpxaDataSource.getXAConnection() method to get the xaConnection instance. To update authentication when using OAuth 2.0 access tokens, you can use the getXAConnection method, as shown in the following code:
OBPXAConnection xaConnection = obpxaDataSource.getXAConnection(accessToken);      // get an XA connection using an OAuth 2.0 access token
You can also use the getXAConnection method to update basic authentication.
OBPXAConnection xaConnection = obpxaDataSource.getXAConnection(user, password);   // get an XA connection using username and password for basic authentication
To define a blockchain transaction to be run as part of a global XA transaction, you use the following method:
public void createXAInvokeTransaction​(Xid xid, OBPXAInvokeTxRequest invokeTxRequest)
In this method, xid is a global transaction identifier and invokeTxRequest is the blockchain transaction to be run as part of the global XA transaction. To create an XA invoke transaction request, you use the following constructor method:
OBPXAInvokeTxRequest invokeTxRequest = new OBPXAInvokeTxRequest(channel, chaincode, args);
In this constructor method, channel is the channel where the blockchain transaction will run, chaincode is the chaincode to use, and args includes the chaincode function and any arguments to use for the transaction.

The following snippet of code demonstrates creating an OBPXADataSource object, getting the OBPXAConnection instance, and then creating the transaction request and calling the createXAInvokeTransaction method.

OBPXADataSource obpxaDataSource = OBPXADataSource.builder()
                        .withHost(host)
                        .withPort(port)
                        .withBasicAuth(username, password)
                        .withRole(role)
                        .build();
.
.
.
OBPXAConnection obpxaConnection = obpxaDataSource.getXAConnection();

OBPXAInvokeTxRequest invokeTxRequest = new OBPXAInvokeTxRequest(channel, chaincode, args);
invokeTxRequest.setEndorsers(endorsersArray); // optional blockchain transaction request attributes
invokeTxRequest.setTransientMap(transientMap); // optional blockchain transaction request attributes
invokeTxRequest.setTimeout(60000); // optional blockchain transaction request attributes

obpxaConnection.createXAInvokeTransaction​(xid, invokeTxRequest);

Scenario: Explore XA Transactions Using Samples

The following scenario is similar to the one described for atomic transactions: Scenario: Explore Atomic Transactions Using Samples, which uses the Balance Transfer and Marbles samples that are included with Oracle Blockchain Platform.

In this scenario, you install the Balance Transfer and Marbles samples on two different instances of Oracle Blockchain Platform. Each instance then corresponds to an XA data source:

  • XA resource OBP-1, with the Marbles chaincode installed on the goods channel
  • XA resource OBP-2, with the Balance Transfer chaincode installed on the wallet channel

In this scenario, you can use an XA transaction that spans multiple data sources to ensure that the exchange of funds and the marble transfer occur in an atomic manner, where either all operations succeed or none succeed. The following code illustrates this scenario:

OBPXADataSource obpxaDS1 = ... // create an XA data source, supplying details about the OBP-1 instance
OBPXADataSource obpxaDS2 = ... // create an XA data source, supplying details about the OBP-2 instance

// start a global transaction in the client application
// invoke marble transfer on OBP-1
OBPXAConnection obpxaConn1 = (OBPXAConnection) obpxaDS1.getXAConnection();
OBPXAInvokeTxRequest invokeMarbleTransferReq = new OBPXAInvokeTxRequest("goods", "obcs-marbles", new String[]{"transferMarble", "marble1", "tom"});
obpxaConn1.createXAInvokeTransaction​(xid1, invokeMarbleTransferReq);
.
.
.
// invoke fund transfer on OBP-2
OBPXAConnection obpxaConn2 = (OBPXAConnection) obpxaDS2.getXAConnection();
OBPXAInvokeTxRequest invokeBalanceTransferReq = new OBPXAInvokeTxRequest("wallet", "obcs-example02", new String[]{"invoke", "a", "b", "50"});
obpxaConn2.createXAInvokeTransaction​(xid2, invokeBalanceTransferReq);
.
.
.
// end the global transaction in the client application

There is a known issue with the Marbles sample and the default value of the Marble Owner field. For more information, see: Known Issues for Oracle Blockchain Platform.