forked from RafaelAPB/blockchain-integration-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(bungee): updated sketch and added pluguin for fabric
- Loading branch information
eduv09
committed
Mar 4, 2024
1 parent
14ee0c4
commit ab6b402
Showing
20 changed files
with
1,176 additions
and
1,583 deletions.
There are no files selected for viewing
374 changes: 148 additions & 226 deletions
374
packages/cactus-plugin-bungee/src/main/typescript/besu-bungee.ts
Large diffs are not rendered by default.
Oops, something went wrong.
320 changes: 320 additions & 0 deletions
320
packages/cactus-plugin-bungee/src/main/typescript/fabric-bungee.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,320 @@ | ||
/* eslint-disable prefer-const */ | ||
/* eslint-disable @typescript-eslint/no-unused-vars */ | ||
import OAS from "../json/openapi.json"; | ||
|
||
import { Configuration } from "@hyperledger/cactus-core-api"; | ||
|
||
import { | ||
CreateViewRequest, | ||
CreateViewResponse, | ||
} from "./generated/openapi/typescript-axios"; | ||
|
||
import { | ||
DefaultApi as FabricApi, | ||
RunTransactionRequest as FabricRunTransactionRequest, | ||
FabricSigningCredential, | ||
FabricContractInvocationType, | ||
} from "@hyperledger/cactus-plugin-ledger-connector-fabric"; | ||
|
||
import { Utils } from "./utils"; | ||
import { Transaction } from "./view-creation/transaction"; | ||
import { Proof } from "./view-creation/proof"; | ||
import { State } from "./view-creation/state"; | ||
|
||
import { ClientEndpointV1 } from "./web-services/client-endpoint"; | ||
import { IPluginBUNGEEOptions, PluginBUNGEE } from "./plugin-bungee"; | ||
import { StateProof } from "./view-creation/state-proof"; | ||
import { TransactionProof } from "./view-creation/transaction-proof"; | ||
|
||
export interface IPluginBUNGEEFabricOptions extends IPluginBUNGEEOptions { | ||
fabricPath?: string; | ||
fabricSigningCredential?: FabricSigningCredential; | ||
fabricChannelName?: string; | ||
fabricContractName?: string; | ||
fabricAssetID?: string; | ||
fabricAssetSize?: string; | ||
fabricConfig?: Configuration; | ||
fabricApi?: FabricApi; | ||
} | ||
|
||
export class FabricBUNGEE extends PluginBUNGEE { | ||
private ledgerAssetsKey: string[] = []; | ||
|
||
private fabricApi?: FabricApi; | ||
private fabricSigningCredential?: FabricSigningCredential; | ||
private fabricChannelName?: string; | ||
private fabricContractName?: string; | ||
|
||
constructor(public readonly options: IPluginBUNGEEFabricOptions) { | ||
super({ | ||
instanceId: options.instanceId, | ||
participant: options.participant, | ||
keyPair: options.keyPair, | ||
logLevel: options.logLevel, | ||
disableSignalHandlers: options.disableSignalHandlers, | ||
}); | ||
|
||
this.fabricApi = options.fabricApi; | ||
|
||
if (options.fabricPath != undefined) this.defineFabricConnection(options); | ||
} | ||
|
||
public get className(): string { | ||
return PluginBUNGEE.CLASS_NAME; | ||
} | ||
|
||
public getOpenApiSpec(): unknown { | ||
return OAS; | ||
} | ||
|
||
public async shutdown(): Promise<void> { | ||
this.logger.info(`Shutting down ${this.className}...`); | ||
} | ||
|
||
public getPackageName(): string { | ||
return `@hyperledger/cactus-plugin-bungee`; | ||
} | ||
|
||
public async onPluginInit(): Promise<unknown> { | ||
return; | ||
} | ||
|
||
private defineFabricConnection(options: IPluginBUNGEEFabricOptions): void { | ||
this.logger.info(`OPTIONS:: ${options}`); | ||
const fnTag = `${this.className}#defineFabricConnection()`; | ||
|
||
const config = new Configuration({ basePath: options.fabricPath }); | ||
const apiClient = new FabricApi(config); | ||
this.fabricApi = apiClient; | ||
const notEnoughFabricParams: boolean = | ||
options.fabricSigningCredential == undefined || | ||
options.fabricChannelName == undefined || | ||
options.fabricContractName == undefined; | ||
if (notEnoughFabricParams) { | ||
throw new Error( | ||
`${fnTag}, fabric params missing should have: signing credentials, contract name, channel name`, | ||
); | ||
} | ||
this.fabricSigningCredential = options.fabricSigningCredential; | ||
this.fabricChannelName = options.fabricChannelName; | ||
this.fabricContractName = options.fabricContractName; | ||
} | ||
|
||
/** | ||
* | ||
* @abstract Create ledger state. Get all keys, iterate every key and get the respective transactions. For each transaction get the receipt | ||
* */ | ||
public async generateLedgerStates() { | ||
this.logger.info(`Generating ledger snapshot`); | ||
|
||
const assetsKey = await this.getAllAssetsKey(); | ||
this.ledgerAssetsKey = assetsKey.split(","); | ||
|
||
//For each key in ledgerAssetsKey | ||
for (const assetKey of this.ledgerAssetsKey) { | ||
let assetValues: string[] = []; | ||
let txWithTimeS: Transaction[] = []; | ||
|
||
const txs = await this.getAllTxByKey(assetKey); | ||
//For each tx get receipt | ||
for (const tx of txs) { | ||
const endorsements: Proof[] = []; | ||
const receipt = JSON.parse( | ||
await this.fabricGetTxReceiptByTxIDV1(tx.getId()), | ||
); | ||
|
||
// FIXME: double check if required | ||
// Checks if tx was made by participant (capture only transactions made by self) | ||
//if (receipt.transactionCreator.mspid != this.participant) { | ||
// continue; | ||
//} | ||
|
||
assetValues.push(JSON.parse(receipt.rwsetWriteData).Value.toString()); | ||
tx.setStateId(assetKey); | ||
//tx.setPayload(); //FIXME check entries | ||
//tx.setTarget(); | ||
|
||
for (const endorsement of receipt.transactionEndorsement) { | ||
const signature64 = Buffer.from(endorsement.signature).toString( | ||
"base64", | ||
); | ||
tx.addEndorser( | ||
new Proof({ | ||
mspid: endorsement.mspid, | ||
creator: endorsement.endorserID, | ||
signature: signature64, | ||
}), | ||
); | ||
} | ||
//this.logger.info(JSON.stringify(endorsements)); | ||
txWithTimeS.push(tx); | ||
} | ||
const block = await this.fabricGetBlockByTxID( | ||
txs[txs.length - 1].getId(), | ||
); | ||
|
||
const state = new State(assetKey, assetValues, txWithTimeS); | ||
this.ledgerStates.set(assetKey, state); | ||
this.states.push(state); | ||
const stateProof = new StateProof( | ||
state.getValue(), | ||
parseInt(state.getVersion()), | ||
state.getId(), | ||
); | ||
//only adding last block for each state, in the state proof | ||
stateProof.addBlock({ | ||
blockHash: block.hash, | ||
blockCreator: "", | ||
blockSigners: block.signers, | ||
}); | ||
} | ||
|
||
this.ledgerStates.forEach((state: State, keyId: string) => { | ||
console.log(keyId, state); | ||
const assetState = this.ledgerStates.get(keyId); | ||
if (assetState != undefined) { | ||
this.logger.info(assetState); | ||
this.logger.info(JSON.parse(assetState.getStateJson())); | ||
} | ||
}); | ||
} | ||
|
||
async fabricGetBlockByTxID(txId: string): Promise<any> { | ||
const gatewayOptions = { | ||
identity: this.fabricSigningCredential?.keychainRef as string, | ||
wallet: { | ||
keychain: { | ||
keychainId: this.fabricSigningCredential?.keychainId as string, | ||
keychainRef: this.fabricSigningCredential?.keychainRef as string, | ||
}, | ||
}, | ||
}; | ||
const getBlockReq = { | ||
channelName: this.fabricChannelName as string, | ||
gatewayOptions, | ||
query: { | ||
transactionId: txId, | ||
}, | ||
skipDecode: false, | ||
}; | ||
|
||
const getBlockResponse = await this.fabricApi?.getBlockV1(getBlockReq); | ||
|
||
const block = JSON.parse( | ||
JSON.stringify(getBlockResponse?.data), | ||
).decodedBlock; | ||
|
||
const blockSig = block.metadata.metadata[0].signatures; | ||
const sigs = []; | ||
for (const sig of blockSig) { | ||
sigs.push(JSON.stringify(sig)); | ||
} | ||
|
||
return { | ||
hash: Utils.bufArray2HexStr(block.header.data_hash.data), | ||
signers: sigs, | ||
}; | ||
} | ||
|
||
/** | ||
* | ||
* @abstract Returns transaction receipt. | ||
* | ||
* @param transactionId - Transaction id to return the receipt | ||
* */ | ||
async fabricGetTxReceiptByTxIDV1(transactionId: string): Promise<string> { | ||
const receiptLockRes = await this.fabricApi?.getTransactionReceiptByTxIDV1({ | ||
signingCredential: this.fabricSigningCredential, | ||
channelName: this.fabricChannelName, | ||
contractName: "qscc", | ||
invocationType: FabricContractInvocationType.Call, | ||
methodName: "GetBlockByTxID", | ||
params: [this.fabricChannelName, transactionId], | ||
} as FabricRunTransactionRequest); | ||
return JSON.stringify(receiptLockRes?.data); | ||
} | ||
|
||
/** | ||
* | ||
* @abstract Returns all assets key found in the world state. | ||
* */ | ||
async getAllAssetsKey(): Promise<string> { | ||
const response = await this.fabricApi?.runTransactionV1({ | ||
signingCredential: this.fabricSigningCredential, | ||
channelName: this.fabricChannelName, | ||
contractName: this.fabricContractName, | ||
methodName: "GetAllAssetsKey", | ||
invocationType: FabricContractInvocationType.Call, | ||
params: [], | ||
} as FabricRunTransactionRequest); | ||
|
||
if (response != undefined) { | ||
return response.data.functionOutput; | ||
} | ||
|
||
return "response undefined"; | ||
} | ||
|
||
/** | ||
* | ||
* @abstract Returns an array of all transactions for a specific key. | ||
* | ||
* @param key - Key used to get correspondent transactions | ||
* */ | ||
async getAllTxByKey(key: string): Promise<Transaction[]> { | ||
const response = await this.fabricApi?.runTransactionV1({ | ||
signingCredential: this.fabricSigningCredential, | ||
channelName: this.fabricChannelName, | ||
contractName: this.fabricContractName, | ||
methodName: "GetAllTxByKey", | ||
invocationType: FabricContractInvocationType.Call, | ||
params: [key], | ||
} as FabricRunTransactionRequest); | ||
|
||
if (response != undefined) { | ||
return Utils.txsStringToTxs(response.data.functionOutput); | ||
} | ||
|
||
return []; | ||
} | ||
|
||
/** | ||
* | ||
* @abstract Returns all the transactions for a specific key in string format. | ||
* | ||
* @param key - Key (id) used to get correspondent transactions | ||
* */ | ||
async getAllTxByKeyString(key: string): Promise<string> { | ||
const response = await this.fabricApi?.runTransactionV1({ | ||
signingCredential: this.fabricSigningCredential, | ||
channelName: this.fabricChannelName, | ||
contractName: this.fabricContractName, | ||
methodName: "GetAllTxByKey", | ||
invocationType: FabricContractInvocationType.Call, | ||
params: [key], | ||
} as FabricRunTransactionRequest); | ||
|
||
if (response != undefined) { | ||
return response.data.functionOutput; | ||
} | ||
|
||
return ""; | ||
} | ||
|
||
/** | ||
* | ||
* @abstract Save view in json file. | ||
* | ||
* @param fileName - File name or path + file name | ||
* @param data - View in a string format to write inside the json file | ||
* */ | ||
public saveToFile(fileName: string, data: string): void { | ||
const fs = require("fs"); | ||
|
||
fs.writeFileSync(fileName, data, function (err: boolean) { | ||
if (err) { | ||
return console.log("error"); | ||
} | ||
}); | ||
} | ||
} |
Oops, something went wrong.