Skip to content

Commit

Permalink
feat(bungee): updated sketch and added pluguin for fabric
Browse files Browse the repository at this point in the history
  • Loading branch information
eduv09 committed Mar 4, 2024
1 parent 14ee0c4 commit ab6b402
Show file tree
Hide file tree
Showing 20 changed files with 1,176 additions and 1,583 deletions.
374 changes: 148 additions & 226 deletions packages/cactus-plugin-bungee/src/main/typescript/besu-bungee.ts

Large diffs are not rendered by default.

320 changes: 320 additions & 0 deletions packages/cactus-plugin-bungee/src/main/typescript/fabric-bungee.ts
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");
}
});
}
}
Loading

0 comments on commit ab6b402

Please sign in to comment.