Invoke Atomic Transaction
/restproxy/api/v2/atomicTransactions
Request
- application/json
object
-
isolationLevel(required):
string
Allowed Values:
[ "serializable", "readCommitted" ]
Isolation Level for the atomic transaction -
lrc:
object atomicTransactionLRCReq
Request body for transaction to be executed as the Last Resource Commit (LRC) transaction
-
prepareTimeout:
integer(int64)
Default Value:
30000
Timeout in ms for the prepare phase of atomic transactions -
role:
string
Which Hyperledger Fabric enrollment should be used
-
sync:
boolean
Default Value:
true
Determines whether the requests waits for a response or return immediately with a global transaction ID. -
transactions(required):
array transactions
Array of individual transactions to process
object
-
ethReq:
object atomicTransactionEthRequest
Request body for Ethereum transaction to be executed
object
-
chainId:
integer
The network ID of the Ethereum network
-
finalityParams:
object finalityParams
-
pendingTimeout(required):
integer
The max time, in seconds, to wait in case the transaction remains in pending state
-
signedReq:
object signedReq
-
unsignedReq:
object unsignedReq
-
url(required):
string
The full URL, along with the protocol and port, representing the network endpoint
object
-
blocksToWait:
integer
Number of blocks to wait for before a transaction is considered final
-
checkFinality:
boolean
Specifies whether transaction finality check is required for the transaction. When true, transaction is rechecked after one of blocksToWait or secondsToWait is satisfied
-
secondsToWait:
integer
Number of seconds to wait before a transaction is considered final
object
-
signedTxHex(required):
string
Signed request string in hex representation
object
-
abi:
string
Smart contract Application Binary Interface (ABI) or method ABI that is called in the smart contract. Required if isContractCall is set to true
-
data:
string
Hex input data to be used along with the transactions; used for smart contract executions
-
ethValue(required):
string
Amount of ETH to transfer from sender to recipient in wei
-
gasFeeCap:
string
Maximum fees users are willing to pay for the transaction
-
gasLimit(required):
integer
The maximum amount of gas units that can be consumed by the transaction
-
gasPrice:
string
Price in wei for each unit of gas used in the transaction
-
gasTipCap:
string
The maximum fees to be included as a tip to the validator
-
isContractCall:
boolean
Default Value:
false
Specifies if the given request is a smart contract call -
methodName:
string
Method name to be called in the smart contract. Required if isContractCall is set to true
-
nonce:
integer
Transaction counter representing the sequence of transactions executed by the account
-
paramKeys:
array paramKeys
List of keys that are to be extracted from the results of the final OBP chaincode transaction and sent to the smart contract via parameters
-
params:
object params
Additional Properties Allowed:
true
Parameters that are required by the method to be called in the smart contract. Required if isContractCall is set to true -
privateKey(required):
string
The hex string representing the private key of the source account
-
toAddress(required):
string
The receiving address when completing ETH transfers, or the contract address when executing smart contracts
-
type:
integer
Select 0 to represent legacy transactions, select 2 (default) to represent EIP-1559 transactions
array
object
true
object
-
args(required):
array args
Arguments for the chaincode
-
chaincode(required):
string
ID of the chaincode to invoke
-
channel(required):
string
ID of the channel to invoke the transaction
-
endorsers:
array endorsers
Endorsers for the chaincode
-
timeout:
integer(int64)
Timeout in ms for the chaincode to invoke
-
transientMap:
object transientMap
Additional Properties Allowed: additionalPropertiesTransientMap for the chaincode
object
Response
- application/json
201 Response
object
-
error:
string
Default Value:
-
result:
object atomicTransactionResults
-
returnCode(required):
string
Allowed Values:
[ "Success", "Failure" ]
object
-
globalStatus:
string
Current status of the atomic transaction
-
globalTxid:
string
Global transaction ID
-
lrc:
object atomicTransactionLRCResults
-
transactions:
array transactions
Details of individual transactions processed
-
txStartTime:
string
Transaction execution start time
object
-
ethResp:
object atomicTransactionEthResponse
-
txStatus:
string
Current status of the LRC transaction
object
-
block:
integer
Block number of the committed transaction
-
error:
string
Error message in case of failures
-
txHex:
string
Hex string representing the transaction executed
object
-
chaincode:
string
ID of the chaincode invoked
-
channel:
string
ID of the channel on which the transaction was invoked
-
commit:
object commit
Details on the commit phase of the transaction
-
prepare:
object prepare
Details on the prepare phase of the transaction
-
rollback:
object rollback
Details on the rollback phase of the transaction
-
txstatus:
string
Current status of the individual transaction
object
-
error:
string
Error message in case the transaction fails
-
txid:
string
Transaction ID for the commit phase
object
-
error:
string
Error message in case the transaction fails
-
txid:
string
Transaction ID for the prepare phase
object
-
error:
string
Error message in case the transaction fails
-
txid:
string
Transaction ID for the rollback phase
202 Response
object
-
error:
string
Default Value:
-
result:
object result
-
returnCode(required):
string
Allowed Values:
[ "Success", "Failure" ]
400 Response
401 Response
403 Response
404 Response
500 Response
Examples
See Make Atomic Updates Across Chaincodes and Channels for an overview of atomic transactions in Oracle Blockchain Platform.
Example of an Atomic Transaction with Two Chaincodes
The following example shows how to invoke an atomic transaction that comprises two chaincode transactions by submitting a POST request on the REST resource using cURL.
curl -v -X POST \ "https://<rest proxy of your blockchain instance>/api/v2/atomicTransactions" \ -H "Authorization: Bearer <OAuth_access_token>" \ -H "accept: application/json" \ -H "Content-Type: application/json" \ --data @<JSON file with the request parameters>
For example,
curl -v -X POST \ "https://myvm.oracle.com:10001/restproxy/api/v2/atomicTransactions" \ -H "Authorization: Bearer mF_9.B5f-4.1JqM" \ -H "accept: application/json" \ -H "Content-Type: application/json" --data @file.json
file.json
are:{
"transactions": [
{"chaincode":"obcs-marbles","args":["transferMarble", "marble1", "tom"],"timeout":0, "channel":"goods"},
{"chaincode":"obcs-example02","args":["invoke", "a", "b", "50"],"timeout":0, "channel":"wallet"}
],
"isolationLevel": "serializable",
"prepareTimeout": 10000,
"sync": true
}
transactions
is an array that contains two chaincode transactions. The first transaction transfers a marble by using the Marbles sample chaincode. The second transaction pays for the marble by using the Balance Transfer sample chaincode.args
specify the chaincode function to be invoked along with its parameters.isolationLevel
with the serializable value indicates that all keys in the read and write set of the transactions are locked between the prepare phase and the commit phase. ThereadCommitted
value for the isolation indicates that keys in the write set of transactions are locked between the prepare phase and the commit phase.timeout
specifies the maximum number of milliseconds for the transaction to timeout during the prepare phase.sync
with a true value indicates that this is a synchronous transaction.
The following example shows the contents of the response body in JSON format for a successful atomic transaction:
{ "returnCode": "Success", "error": "", "result": { "transactions": [ { "channel": "goods", "chaincode": "obcs-marbles", "txstatus": "Committed", "prepare": { "txid": "bb248ef3f948cb107417c3f66ea144910644dee8086a370d44687fd9fe262233" }, "commit": { "txid": "21068846ef85942f9df1ccfd27dcb95d509146c5a0d10c6366642215badcb3b4" }, "rollback": {} }, { "channel": "wallet", "chaincode": "obcs-example02", "txstatus": "Committed", "prepare": { "txid": "08d03d7170e7f696c79da0aa60142bbfdc08b3d92cee0d9423983dd19caf809c" }, "commit": { "txid": "ef9d8a824631f9e671162b81c7d1617080746ef3897b029cfbef1cfd1594d0ab" }, "rollback": {} } ], "globalStatus": "Success", "globalTxid": "21438a99-9fd7-4f96-b0bf-259910a26006", "txStartTime": "2022-08-15T16:16:19.2180799642" } }
In
this case, the value returned for globalStatus
is
Success
, which indicates that all of the transactions that the
atomic transaction comprises were committed successfully.
The following example shows the response for an unsuccessful atomic transaction, where one of the operations encountered an error during the prepare phase. Here, a non-integer value was supplied for a Balance Transfer parameter that requires an integer value. In this case, the transaction that succeeded during the prepare phase is rolled back.
{ "returnCode": "Failure", "error": "blockchain transaction error", "result": { "transactions": [ { "channel": "goods", "chaincode": "obcs-marbles", "txstatus": "Rolledback", "prepare": { "txid": "bb248ef3f948cb107417c3f66ea144910644dee8086a370d44687fd9fe262233" }, "commit": {}, "rollback": { "txid": "21068846ef85942f9df1ccfd27dcb95d509146c5a0d10c6366642215badcb3b4" }, }, { "channel": "wallet", "chaincode": "obcs-example02", "txstatus": "FailedPrepare", "prepare": { "error": "failed to invoke chaincode: Transaction processing for endorser [myvm.oracle.com:20010]: Chaincode status Code: (500) UNKNOWN. Description: Invalid transaction amount, expecting a integer value" }, "commit": {}, "rollback": { "error":"skipping rollback since prepare stage has failed or was skipped" } } ], "globalStatus": "Failure", "globalTxid": "21438a99-9fd7-4f96-b0bf-259910a26006", "txStartTime": "2022-08-15T16:16:19.2180799642" } }
Example of Ethereum Transactions
Ethereum transactions are supported in atomic workflows by using a last resource commit (LRC) optimization, because they cannot be broken down into prepare and commit phases. After all other transactions are in the prepared state, the Ethereum transaction is started. If the Ethereum transaction succeeds, then the other transactions are committed. If the Ethereum transaction fails, then the other transactions are rolled back.
lrc
section, with an atomic
transaction that invokes two other chaincode transactions. The lrc
section includes an ethReq
section, which describes the
transaction, and a finalityParams
section, which determines how
long to wait for transaction
finality.{
"transactions": [
{"chaincode":"bt1","args":["invoke", "a", "b", "7"],"timeout":0, "channel":"ch1"},
{"chaincode":"bt2","args":["invoke", "a", "b", "5"],"timeout":0, "channel":"ch2"}
],
"lrc": {
"ethReq": {
"url": "http://<IP address of Ethereum server>:<port>",
"chainId": 1337,
"unSignedReq": {
"privateKey": "de1fab4e05b476f81d11901a69e58a3000859395eb6bdb222fcb583b8d599b00",
"ethValue": "1000000000000000000",
"gasLimit": 21000,
"toAddress": "0x7336d04f97fdccd0a93462947474c8879a5c6597"
},
"finalityParams": {
"checkFinality": true,
"blocksToWait": 2,
"secondsToWait": 30
}
}
},
"isolationLevel": "serializable",
"prepareTimeout": 10000,
"sync": true
}
url
is the URL of the Ethereum endpoint, including the protocol and port number.chainId
is the network ID of the Ethereum network.unsignedReq
is the unsigned request body, which includes the following parameters:privateKey
: the private key in hexadecimal string format.Foot 1ethValue
: the amount of Ether to transfer, measured in Wei.gasLimit
: the maximum amount of gas that the transaction is allowed to consume.toAddress
: the receiving address for the Ether transfer.
checkFinality
is a Boolean value that specifies whether to check for transaction finality.blocksToWait
is the number of blocks to wait before a transaction is considered final.secondsToWait
is the number of seconds to wait for finality. The maximum wait time is 120 seconds.
txHex
value to look up information
about the block in a block explorer tool such as
Etherscan.{
"returnCode": "Success",
"error": "",
"result": {
"transactions": [
{
"channel": "ch1",
"chaincode": "bt1",
"txstatus": "Committed",
"prepare": {
"txid": "f9c65ac93568b3cb878f3f98a5021c443cf138a6411da22d2154ec6f52299de3"
},
"commit": {
"txid": "b7539349027a0e26eb0522f3066aea721a6bb3bf29d8e821736f73b52357a637"
},
"rollback": {}
},
{
"channel": "ch2",
"chaincode": "bt2",
"txstatus": "Committed",
"prepare": {
"txid": "b96d046ab11437b7dc6d5d584ef5f33968c11f893e3587ebf07aec0484be38e2"
},
"commit": {
"txid": "8f3f1fccfead63a2ce6a76be7c2678791ffc8093997a36c94100faa312f95f17"
},
"rollback": {}
}
],
"lrc": {
"ethResp": {
"block": 19,
"txHex": "0xc5741e0da0e16d9b594cac44d5c3cd70d552d013552265f2d06789a01d3fa81d"
},
"txstatus": "Committed"
},
"globalStatus": "Success",
"globalTxid": "4b9099f4-9528-82cc-357a-7ed5c703d772",
"txStartTime": "2022-09-14T10:56:40.018420392Z"
}
}
unSignedReq
section, the request includes a
signedReq
section.{
"transactions": [
{
"chaincode": "obcs-example02","args": ["invoke","a","b","1"],
"timeout": 0,
"channel": "default",
"endorsers":["http://<IP address of endorser>:<port>"]
}
],
"lrc": {
"ethReq": {
"url": "http://<IP address of Ethereum server>:<port>",
"chainId": 5,
"signedReq": {
"signedTxHex" : "02f8950506841ad2748084476807808401406f409442efb56de8e6a516fff899c9263ef3d21ffd9c298502540be400a4e3456fa90000000000000000000000000000000000000000000000000000000000000001c080a074c985cce323b924e5503592a1301e301c4a3fa4c55234cf60b2782dce81e825a0605b9f61113057e02f614b4d2a52fc5953719aec30743ff4d8b7e2bbf3a206b5"
},
"pendingTimeout": 420,
"finalityParams": {
"checkFinality": true,
"blocksToWait": 10,
"secondsToWait": 20
}
}
},
"isolationLevel": "serializable",
"prepareTimeout": 10000,
"sync": false
}
Where,
in addition to the parameters described previously, unsignedReq
is
the signed request body, which includes the signedTxHex
parameter,
which is the signed request string in hexadecimal format.
{
"returnCode": "Success",
"error": "",
"result": {
"transactions": [
{
"channel": "default",
"chaincode": "obcs-example02",
"txstatus": "Committed",
"prepare": {
"txid": "cb2bb0474bbd1dcb53e8dea68be26f9f3480e60aeeae12977c34fe27a7583f9b"
},
"commit": {
"txid": "915d61e3c1b9b2c9e1a55aa13b3670cb8c2b1b14ea6426b3cad1ff0bb519532f"
},
"rollback": {}
}
],
"lrc": {
"ethResp": {
"block": 8167525,
"txHex": "0x53254e565aedfdac6d63e40d64c967347661dcc64045a673f948b52c6e48ff4c"
},
"txstatus": "Committed"
},
"globalStatus": "Success",
"globalTxid": "3ab9421d-9dfa-40c0-a463-2f9fcb936c42",
"txStartTime": "2022-12-20T06:09:47.040072324Z"
}
}
NFT Transfer From OBP to Ethereum
You can send an NFT from a chaincode deployed in Oracle Blockchain Platform to a smart contract deployed on Ethereum or Polygon blockchain networks. This is done using an extension of an atomic transaction's last resource commit (LRC) transaction request.
burnNFT
method present in ERC1155
and ERC721 Go and TypeScript App Builder-generated chaincodes. This method burns the
NFT from the OBP chaincode and returns the required information from the NFT such as
tokenId
, price
, and
tokenHistory
. Oracle Blockchain Platform then:
- collects the information returned by the
burnNFT
method - extracts the required parameters from it
- creates a transaction (contract call) with the parameters required by the method
- mints the NFT on the smart contract deployed over an Ethereum or Polygon blockchain network by invoking a custom mint method present in the smart contract
- sets all the custom properties required by the NFT such as
tokenPrice
andtokenHistory
on Oracle Blockchain Platform.
Example of a request body for an NFT transfer:
{
"transactions": [
{
"chaincode": "<chaincodeName>",
"args": [
"burnNFT",
"Org1MSP",
"user1",
"1"
],
"timeout": 0,
"channel": "<channelName>"
}
],
"lrc": {
"ethReq": {
"url": "https://eth-sepolia.g.alchemy.com/v2/6Ho4Tv8uQ1hKCoIjfI_2v_xN6gZJWqLP",
"chainId": 11155111,
"unsignedReq": {
"toAddress": "<contractAddress>",
"ethValue": "0",
"methodName": "mintNft",
"isContractCall": true,
"abi":"[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"tokenHistory\",\"type\":\"string\"}],\"name\":\"mintNft\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
"privateKey": "<privateKey>",
"paramKeys": ["tokenId", "tokenUri", "price", "tokenHistory"],
"params": {
"to": "<toAddress>",
"id": "${tokenId}",
"tokenUri": "${tokenUri}",
"price": "${price}",
"tokenHistory": "${tokenHistory}"
},
"gasLimit": 2589190,
"gasTipCap": "250000000",
"gasFeeCap": "250000000"
},
"pendingTimeout": 500,
"finalityParams": {
"checkFinality": false,
"blocksToWait": 3,
"secondsToWait": 30
}
}
},
"isolationLevel": "serializable",
"prepareTimeout": 60000,
"sync": false
}
url
is the URL of the Ethereum endpoint, including the protocol and port number.chainId
is the network ID of the Ethereum network.unsignedReq
is the unsigned request body, which includes the following parameters:toAddress
: the receiving address for the Ether transfer.ethValue
: the amount of Ether to transfer, measured in Wei.methodName
: method name to be called in the smart contract. This example uses a custom mint method present in the smart contract (mintNft
) which mints the NFT on the smart contract deployed over an Ethereum blockchain network.isContractCall
: specifies that the given request is a smart contract call.abi
: an Application Binary Interface allows your smart contract to interact with other applications and smart contracts.privateKey
: the private key in hexadecimal string format.paramKeys
: the keys to be extracted from the results of the final Oracle Blockchain Platform chaincode transaction and sent to the smart contract via parameters.params
: parameters that are required by the method to be called in the smart contract.gasLimit
: the maximum amount of gas that the transaction is allowed to consume.gasTipCap
: the maximum fees to be included as a tip to the validator.gasFeeCap
: the maximum fees you are willing to pay for the transaction.
pendingTimeout
the max time, in seconds, to wait in case the transaction remains in pending state.finalityParams
is the number of blocks to wait before a transaction is considered final.checkFinality
: specifies that transaction finality check is not required for the transaction.blocksToWait
: specifies that it will wait for 3 blocks before a transaction is considered final.secondsToWait
: specifies that it will wait 30 seconds before a transaction is considered final.
Example of the response body for an NFT transfer:
{
"returnCode": "Success",
"error": "",
"result": {
"transactions": [
{
"channel": "default",
"chaincode": "obcs-example02",
"txstatus": "Committed",
"prepare": {
"txid": "b8dda6fe3bf4013c587c96aa1028e57ce3ad71ea59d5d4612d2795ab88046896"
},
"commit": {
"txid": "45f7da042ebedac4faebd458692752e1b934f5f3561fc36255fec6d6ee1d7976"
},
"rollback": {}
}
],
"lrc": {
"ethResp": {
"block": 8167617,
"txHex": "0x99c2da536f751491311a6f671a74e14b3614897b78b0e30d24ba65ff3a370a38"
},
"txstatus": "Committed"
},
"globalStatus": "Success",
"globalTxid": "734e4f32-d2b1-4111-9168-f89f739a16e4",
"txStartTime": "2022-12-20T06:33:24.577427607Z"
}
}
Footnote Legend
Footnote 1: When using the atomicTransaction API to burn Oracle Blockchain Platform tokens and re-mint them on Ethereum or other EVM networks with Oracle Blockchain Platform token history included in their metadata, you should use the unsigned Ethereum request in order to include the token history and other relevant data returned from Oracle Blockchain Platform burn method into Ethereum mint method via specified parameters. In order to use the unsigned Ethereum request, you need to include a private key for your account in the atomicTransaction API payload so that the REST proxy can finalize the request with the parameters specified and sign it before invoking Ethereum RPC API. Your key is protected in transit using TLS (HTTP/S), but exercise caution if your calls are redirected through other external systems (such as proxies) before reaching the Oracle Blockchain Platform REST Proxy endpoint. Once the call reaches the Oracle Blockchain Platform REST Proxy, the private key is used in memory for the sole purpose of signing the Ethereum call request and is discarded after the operation. It is not logged or stored anywhere within the Oracle Blockchain Platform service or Oracle Cloud Infrastructure.Back to Top