Skip to content

Commit

Permalink
feat(fabric-connector): add transact receipt
Browse files Browse the repository at this point in the history
Signed-off-by: jsjs026 <jasonhack518@gmail.com>
  • Loading branch information
jscode017 authored and petermetz committed Oct 5, 2021
1 parent 7ab0c44 commit c6d1b7a
Show file tree
Hide file tree
Showing 8 changed files with 689 additions and 3 deletions.
4 changes: 4 additions & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"Corda",
"Cordapp",
"couchdb",
"data",
"dclm",
"DHTAPI",
"DockerOde",
Expand Down Expand Up @@ -92,7 +93,9 @@
"protobuf",
"protoc",
"protos",
"qscc",
"RUSTC",
"Rwset",
"sbjpubkey",
"Secp",
"shrn",
Expand All @@ -109,6 +112,7 @@
"thream",
"tlsca",
"tlscacerts",
"txid",
"txqueue",
"Uisrs",
"Unmarshal",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,45 @@
},
"components": {
"schemas": {
"TransactReceiptTransactionEndorsement":{
"type":"object",
"properties": {
"mspid":{
"type":"string"
},
"endorserID":{
"type":"string"
},
"signature":{
"type":"string"
}
}
},
"TransactReceiptTransactionCreator":{
"type":"object",
"properties": {
"mspid":{
"type":"string"
},
"creatorID":{
"type":"string"
}
}
},
"TransactReceiptBlockMetaData":{
"type":"object",
"properties": {
"mspid":{
"type":"string"
},
"blockCreatorID":{
"type":"string"
},
"signature":{
"type":"string"
}
}
},
"VaultTransitKey" : {
"type": "object",
"nullable": false,
Expand Down Expand Up @@ -422,7 +461,8 @@
"type": "object",
"required": [
"functionOutput",
"success"
"success",
"transactionId"
],
"properties": {
"functionOutput": {
Expand All @@ -432,9 +472,51 @@
"success": {
"type": "boolean",
"nullable": false
},
"transactionId":{
"type": "string",
"nullable": false
}
}
},
"GetTransactionReceiptResponse": {
"type": "object",
"properties": {
"blockNumber":{
"type":"string"
},
"channelID":{
"type": "string"
},
"transactionCreator":{
"$ref": "#/components/schemas/TransactReceiptTransactionCreator"
},
"transactionEndorsement":{
"type":"array",
"items":{
"$ref": "#/components/schemas/TransactReceiptTransactionEndorsement"
}
},
"blockMetaData":{
"$ref": "#/components/schemas/TransactReceiptBlockMetaData"
},
"chainCodeName":{
"type":"string"
},
"chainCodeVersion":{
"type":"string"
},
"responseStatus":{
"type":"string"
},
"rwsetKey":{
"type":"string"
},
"rwsetWriteData":{
"type": "string"
}
}
},
"DeploymentTargetOrganization": {
"type": "object",
"required": [
Expand Down Expand Up @@ -883,6 +965,45 @@
}
}
},
"/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-fabric/get-transaction-receipt-by-txid": {
"post": {
"x-hyperledger-cactus": {
"http": {
"verbLowerCase": "post",
"path": "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-fabric/get-transaction-receipt-by-txid"
}
},
"operationId": "getTransactionReceiptByTxIDV1",
"summary": "get a transaction receipt by tx id on a Fabric ledger.",
"description": "",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RunTransactionRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GetTransactionReceiptResponse"
}
}
}
},
"404": {
"description": ""
}
}
}
},
"/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-fabric/deploy-contract-go-source": {
"post": {
"operationId": "deployContractGoSourceV1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
import { LoggerProvider, LogLevelDesc } from "@hyperledger/cactus-common";
import { Gateway } from "fabric-network";
import {
GetTransactionReceiptResponse,
TransactReceiptTransactionEndorsement,
TransactReceiptTransactionCreator,
TransactReceiptBlockMetaData,
} from "../generated/openapi/typescript-axios";
import { common } from "fabric-protos";
const { BlockDecoder } = require("fabric-common");
export interface IGetTransactionReceiptByTxIDOptions {
readonly logLevel?: LogLevelDesc;
readonly gateway: Gateway;
readonly channelName: string;
readonly params: string[];
}
export async function getTransactionReceiptByTxID(
req: IGetTransactionReceiptByTxIDOptions,
): Promise<GetTransactionReceiptResponse> {
const fnTag = `getTransactionReceiptForLockContractByTxID`;
const log = LoggerProvider.getOrCreate({
label: fnTag,
level: req.logLevel || "INFO",
});
log.info(`${fnTag}, start getting fabric transact receipt`);
const { gateway } = req;

const contractName = "qscc";
const methodName = "GetBlockByTxID";
if (req.params.length != 2) {
throw new Error(`${fnTag}, should have 2 params`);
}
const network = await gateway.getNetwork(req.channelName);

const contract = network.getContract(contractName);
const out: Buffer = await contract.evaluateTransaction(
methodName,
...req.params,
);
const reqTxID = req.params[1];
const block: common.Block = BlockDecoder.decode(out);
const blockJson = JSON.parse(JSON.stringify(block));

const transactReceipt: GetTransactionReceiptResponse = {};
transactReceipt.blockNumber = blockJson.header.number;
const txIDs = [];
if (!block.data) {
throw new Error(`${fnTag} block.data is null`);
}
const blockData = block.data;
if (!blockData.data) {
throw new Error(`${fnTag} block.data.data is null`);
}
const blockDataArr = blockData.data;
for (let i = 0; i < blockDataArr.length; i++) {
const blockData = JSON.parse(JSON.stringify(blockDataArr[i]));
if (!blockData.payload) {
throw new Error(`${fnTag}, blockData.payload undefine`);
}
if (!blockData.payload.header) continue;
if (!blockData.payload.header.channel_header) continue;

const payloadChannelHeader = blockData.payload.header.channel_header;
if (payloadChannelHeader.tx_id) {
txIDs.push(payloadChannelHeader.tx_id);
if (payloadChannelHeader.tx_id != reqTxID) continue;
transactReceipt.channelID = payloadChannelHeader.channel_id;
if (!blockData.payload.data) continue;
if (!blockData.payload.data.actions) continue;
const payloadDataActions = blockData.payload.data.actions;

if (!payloadDataActions[0].header || !payloadDataActions[0].payload)
continue;
const actionsHeader = payloadDataActions[0].header;
const actionsPayload = payloadDataActions[0].payload;
const creator = actionsHeader.creator;
const creatorMspId = creator.mspid;
const creatorId = String.fromCharCode.apply(null, creator.id_bytes.data);
const transactReceiptCreator: TransactReceiptTransactionCreator = {
mspid: creatorMspId,
creatorID: creatorId,
};
transactReceipt.transactionCreator = transactReceiptCreator;
if (actionsPayload.chaincode_proposal_payload == undefined) continue;
const chainCodeProposal = actionsPayload.chaincode_proposal_payload;
if (
!chainCodeProposal.input ||
!chainCodeProposal.input.chaincode_spec ||
!chainCodeProposal.input.chaincode_spec.chaincode_id
)
continue;
if (
!actionsPayload.action ||
!actionsPayload.action.proposal_response_payload ||
!actionsPayload.action.endorsements
)
continue;
const proposalResponsePayload =
actionsPayload.action.proposal_response_payload;
const actionEndorsements = actionsPayload.action.endorsements;
const endorsements = [];
for (let i = 0; i < actionEndorsements.length; i++) {
const endorser = actionEndorsements[i].endorser;
const mspId = endorser.mspid;
const idBytes = endorser.id_bytes;
const idBytesData = idBytes.data;
const endorserId = String.fromCharCode.apply(null, idBytesData);
const signatureData = actionEndorsements[i].signature.data;
const signature = String.fromCharCode.apply(null, signatureData);
const endorsement: TransactReceiptTransactionEndorsement = {
mspid: mspId,
endorserID: endorserId,
signature: signature,
};
endorsements.push(endorsement);
}
transactReceipt.transactionEndorsement = endorsements;
if (!proposalResponsePayload.extension) continue;

const responseExtension = proposalResponsePayload.extension;
if (!responseExtension.chaincode_id) continue;
const extensionChainCodeID = responseExtension.chaincode_id;
transactReceipt.chainCodeName = extensionChainCodeID;
transactReceipt.chainCodeName = extensionChainCodeID.name;
transactReceipt.chainCodeVersion = extensionChainCodeID.version;
if (
!responseExtension.response ||
!responseExtension.response.payload ||
!responseExtension.response.status
)
continue;
const responseStatus = responseExtension.response.status;
transactReceipt.responseStatus = responseStatus;
if (
!responseExtension.results ||
!responseExtension.results.ns_rwset ||
responseExtension.results.ns_rwset.length < 2
) {
continue;
}
const extensionNsRwset = responseExtension.results.ns_rwset[1];
if (!extensionNsRwset.rwset) continue;

const rwset = extensionNsRwset.rwset;
if (!rwset.writes) continue;
const rwsetWrite = rwset.writes;
if (!rwsetWrite[0].key) continue;
const rwsetKey = rwsetWrite[0].key;
transactReceipt.rwsetKey = rwsetKey;
if (!rwsetWrite[0].value || !rwsetWrite[0].value.data) continue;
const rwSetWriteData = rwsetWrite[0].value.data;
// eslint-disable-next-line prefer-spread
const rwSetWriteDataStr = String.fromCharCode.apply(
String,
rwSetWriteData,
);
transactReceipt.rwsetWriteData = rwSetWriteDataStr;
break;
}
}
if (!block.metadata) {
throw new Error(`${fnTag}, block.metadata undefined`);
}
if (!block.metadata.metadata) {
throw new Error(`${fnTag}, block.metadata.metadata undefined`);
}

const metadata = JSON.parse(JSON.stringify(block.metadata.metadata[0]));
if (!metadata.signatures) {
throw new Error(`${fnTag}, metadata signature undefined`);
}
if (!metadata.signatures[0].signature_header) {
throw new Error(
`${fnTag}, metadata.signatures.signature_header is undefined`,
);
}
const metadataSignatureCreator =
metadata.signatures[0].signature_header.creator;
const metadataMspId = metadataSignatureCreator.mspid;
if (!metadataSignatureCreator.id_bytes) {
throw new Error(`${fnTag}, metadataSignatureCreator.id_bytes`);
}
const metadataCreatorId = String.fromCharCode.apply(
null,
metadataSignatureCreator.id_bytes.data,
);
if (!metadata.signatures[0].signature) {
throw new Error(`${fnTag}, metadata.signatures[0].signature undefined`);
}
const metedataSignature = String.fromCharCode.apply(
null,
metadata.signatures[0].signature.data,
);
const transactionReceiptBlockMetadata: TransactReceiptBlockMetaData = {
mspid: metadataMspId,
blockCreatorID: metadataCreatorId,
signature: metedataSignature,
};
transactReceipt.blockMetaData = transactionReceiptBlockMetadata;

return transactReceipt;
}
Loading

0 comments on commit c6d1b7a

Please sign in to comment.