Skip to content

Commit

Permalink
feat(bungee-hermes): add BUNGEE package
Browse files Browse the repository at this point in the history
BUNGEE is an implementation of a view generator https://dl.acm.org/doi/10.1145/3643689

Authored-by: Eduardo Vasques <[email protected]>
Co-authored-by: Rafael Belchior <[email protected]>
Signed-off-by: Rafael Belchior <[email protected]>
  • Loading branch information
RafaelAPB committed Nov 15, 2024
1 parent 4424bf9 commit 4781fb1
Show file tree
Hide file tree
Showing 20 changed files with 167 additions and 38 deletions.
2 changes: 1 addition & 1 deletion packages/cactus-plugin-bungee-hermes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,4 +226,4 @@ We welcome contributions to Hyperledger Cactus in many forms, and there’s alwa
Please review [CONTRIBUTING.md](https://github.com/hyperledger/cactus/blob/main/CONTRIBUTING.md "CONTRIBUTING.md") to get started.

## License
This distribution is published under the Apache License Version 2.0 found in the [LICENSE ](https://github.com/hyperledger/cactus/blob/main/LICENSE "LICENSE ")file.
This distribution is published under the Apache License Version 2.0 found in the [LICENSE ](https://github.com/hyperledger/cactus/blob/main/LICENSE "LICENSE ")file.
1 change: 1 addition & 0 deletions packages/cactus-plugin-bungee-hermes/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"http-errors-enhanced-cjs": "2.0.1",
"key-encoder": "2.0.3",
"merkletreejs": "0.3.11",
"safe-stable-stringify": "2.5.0",
"typescript-optional": "2.0.1",
"uuid": "10.0.0",
"web3": "1.6.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
"PrivacyPolicyOpts": {
"description": "identifier of the policy used to process a view",
"type": "string",
"enum": ["pruneState"],
"x-enum-varnames": ["PruneState"]
"enum": ["pruneState", "singleTransaction"],
"x-enum-varnames": ["PruneState", "SingleTransaction"]
},
"MergePolicyOpts": {
"description": "identifier of the policy used to merge views (can be none)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
"PrivacyPolicyOpts": {
"description": "identifier of the policy used to process a view",
"type": "string",
"enum": ["pruneState"],
"x-enum-varnames": ["PruneState"]
"enum": ["pruneState", "singleTransaction"],
"x-enum-varnames": ["PruneState", "SingleTransaction"]
},
"MergePolicyOpts": {
"description": "identifier of the policy used to merge views (can be none)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ export interface MergeViewsResponse {
*/

export const PrivacyPolicyOpts = {
PruneState: 'pruneState'
PruneState: 'pruneState',
SingleTransaction: 'singleTransaction'
} as const;

export type PrivacyPolicyOpts = typeof PrivacyPolicyOpts[keyof typeof PrivacyPolicyOpts];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
LoggerProvider,
Secp256k1Keys,
} from "@hyperledger/cactus-common";
import { stringify as safeStableStringify } from "safe-stable-stringify";

import { v4 as uuidV4 } from "uuid";
import {
ICactusPlugin,
Expand Down Expand Up @@ -231,8 +233,8 @@ export class PluginBungeeHermes implements ICactusPlugin, IPluginWebService {
view.setCreator(this.pubKeyBungee);
view.setKey(uuidV4());
return {
view: JSON.stringify(view),
signature: this.sign(JSON.stringify(view)),
view: safeStableStringify(view),
signature: this.sign(safeStableStringify(view)),
};
}
onMergeViews(request: MergeViewsRequest): MergeViewsResponse {
Expand Down Expand Up @@ -267,7 +269,7 @@ export class PluginBungeeHermes implements ICactusPlugin, IPluginWebService {
request.policyArguments ? request.policyArguments : [],
);
return {
integratedView: JSON.stringify(integratedView),
integratedView: safeStableStringify(integratedView),
signature: integratedView.signature,
};
}
Expand All @@ -287,7 +289,7 @@ export class PluginBungeeHermes implements ICactusPlugin, IPluginWebService {
this.logger.info("Generating view for request: ", request);
const response = this.generateView(snapshot, ti, tf, request.viewID);
return {
view: JSON.stringify(response.view),
view: safeStableStringify(response.view),
signature: response.signature,
};
}
Expand All @@ -308,7 +310,7 @@ export class PluginBungeeHermes implements ICactusPlugin, IPluginWebService {
const view = new View(this.pubKeyBungee, tI, tF, snapshot, id);
snapshot.pruneStates(tI, tF);

const signature = this.sign(JSON.stringify(view));
const signature = this.sign(safeStableStringify(view));

return { view: view, signature: signature };
}
Expand Down Expand Up @@ -414,7 +416,7 @@ export class PluginBungeeHermes implements ICactusPlugin, IPluginWebService {
integratedView: integratedView,
//The paper specs suggest the integratedView should be jointly signed by all participants.
//That process is left to be addressed in the future
signature: this.sign(JSON.stringify(integratedView)),
signature: this.sign(safeStableStringify(integratedView)),
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { IPluginFactoryOptions } from "@hyperledger/cactus-core-api";
import { PluginFactoryBungeeHermes } from "./plugin-factory-bungee-hermes";

export { isMergePolicyValueArray } from "./view-merging/merge-policies";
export { isPrivacyPolicyValueArray } from "./view-creation/privacy-policies";

export {
PluginBungeeHermes,
IPluginBungeeHermesOptions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
Logger,
LoggerProvider,
} from "@hyperledger/cactus-common";
import { stringify as safeStableStringify } from "safe-stable-stringify";

import {
DefaultApi as BesuApi,
EthContractInvocationType,
Expand Down Expand Up @@ -170,7 +172,7 @@ export class StrategyBesu implements ObtainLedgerStrategy {
"Transaction: " +
log.transactionHash +
"\nData: " +
JSON.stringify(log.data) +
safeStableStringify(log.data) +
"\n =========== \n",
);
const proof = new Proof({
Expand All @@ -185,7 +187,7 @@ export class StrategyBesu implements ObtainLedgerStrategy {
transaction.setTarget(networkDetails.contractAddress as string);
transaction.setPayload(txTx.input ? txTx.input : ""); //FIXME: payload = transaction input ?
transactions.push(transaction);
values.push(JSON.stringify(log.data));
values.push(safeStableStringify(log.data));

blocks.set(transaction.getId(), txBlock);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
LoggerProvider,
Checks,
} from "@hyperledger/cactus-common";
import { stringify as safeStableStringify } from "safe-stable-stringify";

import {
Web3SigningCredential,
DefaultApi as EthereumApi,
Expand Down Expand Up @@ -214,7 +216,7 @@ export class StrategyEthereum implements ObtainLedgerStrategy {
"Transaction: " +
log.transactionHash +
"\nData: " +
JSON.stringify(log.data) +
safeStableStringify(log.data) +
"\n =========== \n",
);
const proof = new Proof({
Expand All @@ -229,7 +231,7 @@ export class StrategyEthereum implements ObtainLedgerStrategy {
transaction.setTarget(networkDetails.contractAddress as string);
transaction.setPayload(txTx.data.input ? txTx.data.input : ""); //FIXME: payload = transaction input ?
transactions.push(transaction);
values.push(JSON.stringify(log.data));
values.push(safeStableStringify(log.data));

blocks.set(transaction.getId(), txBlock.data);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
Logger,
LoggerProvider,
} from "@hyperledger/cactus-common";
import { stringify as safeStableStringify } from "safe-stable-stringify";
import { Transaction } from "../view-creation/transaction";
import { State } from "../view-creation/state";
import { StateProof } from "../view-creation/state-proof";
Expand Down Expand Up @@ -101,7 +102,11 @@ export class StrategyFabric implements ObtainLedgerStrategy {
mspid: receipt.transactionCreator.mspid,
}),
);
assetValues.push(JSON.parse(receipt.rwsetWriteData).Value.toString());
if (!receipt.rwsetWriteData) {
assetValues.push("");
} else {
assetValues.push(JSON.parse(receipt.rwsetWriteData).Value.toString());
}
tx.setStateId(assetKey);
tx.setTarget(receipt.channelID + ": " + receipt.chainCodeName);

Expand Down Expand Up @@ -135,10 +140,11 @@ export class StrategyFabric implements ObtainLedgerStrategy {
//only adding last block for each state, in the state proof
stateProof.addBlock({
blockHash: block.hash,
blockCreator: JSON.stringify({
mspid: last_receipt.blockMetaData.mspid,
id: last_receipt.blockMetaData.blockCreatorID,
}),
blockCreator:
safeStableStringify({
mspid: last_receipt.blockMetaData.mspid,
id: last_receipt.blockMetaData.blockCreatorID,
}) ?? "",
blockSigners: block.signers,
});

Expand Down Expand Up @@ -170,7 +176,7 @@ export class StrategyFabric implements ObtainLedgerStrategy {
if (!response) {
throw new InternalServerError(`${fn} response is falsy`);
}
const receiptLockRes = JSON.stringify(response);
const receiptLockRes = safeStableStringify(response);
if (!receiptLockRes) {
throw new InternalServerError(`${fn} receiptLockRes is falsy`);
}
Expand Down Expand Up @@ -199,7 +205,7 @@ export class StrategyFabric implements ObtainLedgerStrategy {
throw new InternalServerError(`${fn} response.data is falsy`);
}

const receiptLockRes = JSON.stringify(data);
const receiptLockRes = safeStableStringify(data);
if (!receiptLockRes) {
throw new InternalServerError(`${fn} receiptLockRes is falsy`);
}
Expand Down Expand Up @@ -275,7 +281,7 @@ export class StrategyFabric implements ObtainLedgerStrategy {
);
}

const block = JSON.parse(JSON.stringify(block_data)).decodedBlock;
const block = JSON.parse(safeStableStringify(block_data)).decodedBlock;

const blockSig = block.metadata.metadata[0].signatures;
const sigs = [];
Expand All @@ -289,7 +295,7 @@ export class StrategyFabric implements ObtainLedgerStrategy {
},
signature: Buffer.from(sig.signature.data).toString("hex"),
};
sigs.push(JSON.stringify(decoded));
sigs.push(safeStableStringify(decoded));
}
return {
hash: Buffer.from(block.header.data_hash.data).toString("hex"),
Expand Down Expand Up @@ -440,7 +446,7 @@ export class StrategyFabric implements ObtainLedgerStrategy {
ts,
new TransactionProof(new Proof({ creator: "" }), txId), //transaction proof details are set in function 'generateLedgerStates'
);
transaction.setPayload(JSON.stringify(tx.value));
transaction.setPayload(safeStableStringify(tx.value) ?? "");
transactions.push(transaction);
}
return transactions.reverse();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,35 @@ export interface IPrivacyPolicyValue {
policy: PrivacyPolicyOpts;
policyHash: string;
}

// Type guard for PrivacyPolicyOpts
export function isPrivacyPolicyOpts(
value: unknown,
): value is PrivacyPolicyOpts {
return (
typeof value === "string" &&
Object.values(PrivacyPolicyOpts).includes(value as PrivacyPolicyOpts)
);
}

// Type guard for IPrivacyPolicyValue
export function isPrivacyPolicyValue(obj: unknown): obj is IPrivacyPolicyValue {
return (
typeof obj === "object" &&
obj !== null &&
"policy" in obj && // Ensure 'policy' key exists
isPrivacyPolicyOpts((obj as Record<string, unknown>).policy) && // Check if policy is a valid PrivacyPolicyOpts value
typeof (obj as Record<string, unknown>).policyHash === "string" // Ensure 'policyHash' is a string
);
}

// Type guard for an array of IPrivacyPolicyValue
export function isPrivacyPolicyValueArray(
input: unknown,
): input is Array<IPrivacyPolicyValue> {
return Array.isArray(input) && input.every(isPrivacyPolicyValue);
}

export class PrivacyPolicies {
constructor() {}

Expand All @@ -18,11 +47,24 @@ export class PrivacyPolicies {
return view;
}

public singleTransaction(
view: View,
stateId: string,
transactionId: string,
): View {
const snapshot = view.getSnapshot();
snapshot.filterTransaction(stateId, transactionId);
return view;
}

public getPrivacyPolicy(opts: PrivacyPolicyOpts): IPrivacyPolicy | undefined {
switch (opts) {
case PrivacyPolicyOpts.PruneState:
return this.pruneState;
break;
case PrivacyPolicyOpts.SingleTransaction:
return this.singleTransaction;
break;
default:
return undefined;
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Proof is a general purpose type, used to represent signatures of diverse elements.
// Proof may be used, for example in Fabric, to represent an transaction endorsement
// Or simply the signature of a transaction upon is creation (in Besu)
import { stringify as safeStableStringify } from "safe-stable-stringify";

export class Proof {
// The term creator refers to the ID of the entity who created the signature
// For example endorserID in Fabric (when Proof represents an endorsement)
Expand Down Expand Up @@ -36,7 +38,7 @@ export class Proof {
mspid: this.mspid,
signature: this.signature,
};
return JSON.stringify(proof);
return safeStableStringify(proof);
}

public getCreator(): string {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { State } from "./state";
import { stringify as safeStableStringify } from "safe-stable-stringify";

export class Snapshot {
private id: string;
Expand Down Expand Up @@ -76,14 +77,30 @@ export class Snapshot {
this.stateBins = stateBins;
}

public selectStates(states: string[]): void {
const stateBins: State[] = [];
for (const state of this.stateBins) {
if (states.includes(state.getId())) {
stateBins.push(state);
}
}
this.stateBins = stateBins;
}

public filterTransaction(stateId: string, transaction: string): void {
this.selectStates([stateId]);
const state = this.stateBins[0];
state.selectTransactions([transaction]);
}

public getSnapshotJson(): string {
const snapshotJson = {
id: this.id,
participant: this.participant,
stateBins: this.stateBins,
};

return JSON.stringify(snapshotJson);
return safeStableStringify(snapshotJson);
}

public removeState(stateId: string) {
Expand Down
Loading

0 comments on commit 4781fb1

Please sign in to comment.