Skip to content

Commit

Permalink
feat(bungee): Refactoring bungee plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
eduv09 authored and eduv09 committed Mar 6, 2024
1 parent 1fb18d2 commit 0386796
Show file tree
Hide file tree
Showing 25 changed files with 6,352 additions and 827 deletions.
8 changes: 6 additions & 2 deletions packages/cactus-plugin-bungee/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,11 @@
"@hyperledger/cactus-plugin-object-store-ipfs": "2.0.0-alpha.2",
"@hyperledger/cactus-test-tooling": "2.0.0-alpha.2",
"axios": "1.6.0",
"key-encoder": "2.0.3",
"typescript-optional": "2.0.1",
"uuid": "9.0.1"
"uuid": "9.0.1",
"web3": "1.6.1",
"web3-core": "1.6.1"
},
"devDependencies": {
"@types/body-parser": "1.19.4",
Expand All @@ -75,7 +78,8 @@
"@types/tape": "4.13.4",
"@types/uuid": "9.0.6",
"express": "4.18.2",
"fabric-network": "2.2.20"
"fabric-network": "2.2.20",
"socket.io": "4.5.4"
},
"engines": {
"node": ">=18",
Expand Down
241 changes: 241 additions & 0 deletions packages/cactus-plugin-bungee/src/main/typescript/besu-bungee.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
import { Configuration } from "@hyperledger/cactus-core-api";
import {
DefaultApi as BesuApi,
EthContractInvocationType,
EvmBlock,
EvmLog,
GetBlockV1Request,
GetPastLogsV1Request,
GetTransactionV1Request,
InvokeContractV1Request,
Web3SigningCredential,
} from "@hyperledger/cactus-plugin-ledger-connector-besu";
import { State } from "./view-creation/state";
import Web3 from "web3";
import { Transaction } from "./view-creation/transaction";
import { Proof } from "./view-creation/proof";
import { IPluginBUNGEEOptions, PluginBUNGEE } from "./plugin-bungee";
import { StateProof } from "./view-creation/state-proof";
import { TransactionProof } from "./view-creation/transaction-proof";
/*
enum Consensus {
qbft = "QBFT",
ibft = "IBFT",
clique = "CLIQUE",
pow = "PoW",
}*/
export interface IKeyPair {
publicKey: Uint8Array;
privateKey: Uint8Array;
}

export interface IPluginBUNGEEBesuOptions extends IPluginBUNGEEOptions {
besuPath?: string;
besuSigningCredential?: Web3SigningCredential;
bungeeContractAddress?: string;
besuContractName?: string;
keychainId?: string;
//besuConfig?: Configuration;
besuApi?: BesuApi;
}

export class BesuBUNGEE extends PluginBUNGEE {
public besuApi?: BesuApi;
public besuSigningCredential?: Web3SigningCredential;
public besuChannelName?: string;
public besuContractName?: string;
public besuAssetID?: string;
public besuAssetSize?: string;
private bungeeContractAddress?: string;
private keychainId?: string;

constructor(public readonly options: IPluginBUNGEEBesuOptions) {
super({
instanceId: options.instanceId,
participant: options.participant,
keyPair: options.keyPair,
logLevel: options.logLevel,
disableSignalHandlers: options.disableSignalHandlers,
});
this.besuApi = options.besuApi;
if (options.besuPath != undefined) this.defineBesuConnection(options);
}

private defineBesuConnection(options: IPluginBUNGEEBesuOptions): void {
this.logger.info(`OPTIONS:: ${options}`);
const fnTag = `${this.className}#defineFabricConnection()`;

const config = new Configuration({ basePath: options.besuPath });
const apiClient = new BesuApi(config);
this.besuApi = apiClient;
const notEnoughBesuParams: boolean =
options.besuSigningCredential == undefined ||
options.besuContractName == undefined ||
options.bungeeContractAddress == undefined ||
options.keychainId == undefined;
if (notEnoughBesuParams) {
throw new Error(
`${fnTag}, besu params missing should have: signing credentials, contract name`,
);
}
this.besuSigningCredential = options.besuSigningCredential;
this.bungeeContractAddress = options.bungeeContractAddress;
this.besuContractName = options.besuContractName;
this.keychainId = options.keychainId;
}

public async generateLedgerStates() {
this.logger.debug(`Generating ledger snapshot`);

const assetsKey = (await this.getAllAssetsKey()) as string[];
this.logger.debug("Current assets detected to capture: " + assetsKey);
for (const assetKey of assetsKey) {
const { transactions, values, blocks } =
await this.getAllInfoByKey(assetKey);

//=========
// query last value, or get all from logs?
/*const value = await this.besuApi?.invokeContractV1({
contractName: this.besuContractName,
keychainId: this.keychainId,
invocationType: EthContractInvocationType.Call,
methodName: "getAsset",
params: [assetKey],
signingCredential: this.besuSigningCredential,
gas: 1000000,
} as InvokeContractV1Request);*/
//=========

const state = new State(assetKey, values, transactions);

const stateProof = new StateProof(
state.getValue(),
parseInt(state.getVersion()),
state.getId(),
);
const blocksHash: string[] = [];
for (const block of blocks.values()) {
if (blocksHash.indexOf(block.hash as string) !== -1) {
continue;
}
blocksHash.push(block.hash as string);
stateProof.addBlock({
blockHash: block.hash as string,
blockCreator: block.miner as string,
blockSigners: [], // FIXME: query blocksigners (blockchain specific)
});
}
state.setStateProof([]);
this.ledgerStates.set(assetKey, state);
this.states.push(state);
}
}

async getAllAssetsKey(): Promise<string | string[]> {
const parameters = {
contractName: this.besuContractName,
keychainId: this.keychainId,
invocationType: EthContractInvocationType.Call,
methodName: "getAllAssetsIDs",
params: [],
signingCredential: this.besuSigningCredential,
gas: 1000000,
};
const response = await this.besuApi?.invokeContractV1(
parameters as InvokeContractV1Request,
);
if (response != undefined) {
return response.data.callOutput;
}

return "response undefined";
}

async getAllInfoByKey(key: string): Promise<{
transactions: Transaction[];
values: string[];
blocks: Map<string, EvmBlock>;
}> {
const req = {
address: this.bungeeContractAddress,
topics: [[null], [Web3.utils.keccak256(key)]],
};
const response = await this.besuApi?.getPastLogsV1(
req as GetPastLogsV1Request,
);
if (response == undefined) {
return {
transactions: [],
values: [],
blocks: new Map<string, EvmBlock>(),
};
}
const decoded = response.data.logs as EvmLog[];
const transactions: Transaction[] = [];
const blocks: Map<string, EvmBlock> = new Map<string, EvmBlock>();
const values: string[] = [];
this.logger.debug("Getting transaction logs for asset: " + key);

for (const log of decoded) {
const txTx = await this.besuApi?.getTransactionV1({
transactionHash: log.transactionHash,
} as GetTransactionV1Request);

const txBlock = await this.besuApi?.getBlockV1({
blockHashOrBlockNumber: log.blockHash,
} as GetBlockV1Request);
if (txTx == undefined || txBlock == undefined) {
this.logger.debug(
"some error occurred fetching transaction or block info in ",
);
return {
transactions: [],
values: [],
blocks: new Map<string, EvmBlock>(),
};
}
this.logger.debug(
"Transaction: " +
log.transactionHash +
"\nData: " +
JSON.stringify(this.splitDataIntoChunks(log.data)) +
"\n =========== \n",
);
const proof = new Proof({
creator: txTx.data.transaction.from as string, //no proof for bungee
});
const transaction: Transaction = new Transaction(
log.transactionHash,
txBlock.data.block.timestamp,
new TransactionProof(proof),
);
transaction.setStateId(key);
transaction.setTarget(this.bungeeContractAddress as string);
transaction.setPayload(
txTx.data.transaction.input ? txTx.data.transaction.input : "",
); //FIXME: payload = transaction input ?
transactions.push(transaction);
values.push(JSON.stringify(this.splitDataIntoChunks(log.data))); //FIXME: dont split, save as it is

blocks.set(transaction.getId(), txBlock.data.block);
}

return { transactions: transactions, values: values, blocks: blocks };
}

// for debug only
splitDataIntoChunks(data: string) {
const size = (data.length - 2) / 3;
//this.logger.debug("size = " + size);
const chunks = [];

chunks.push("0x" + data.substring(26, 2 + size));
chunks.push(data.substring(2 + size, 2 + size * 2));
chunks.push(data.substring(2 + size * 2, data.length));
return {
creator: chunks[0],
isLock: parseInt(chunks[1], 16) !== 0,
size: parseInt(chunks[2], 16),
};
}
}
Loading

0 comments on commit 0386796

Please sign in to comment.