Skip to content

Commit

Permalink
chore: added merkle root summary to tendermint-bsync
Browse files Browse the repository at this point in the history
  • Loading branch information
troykessler committed Jun 14, 2024
1 parent 28ce140 commit 2e2c531
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 15 deletions.
1 change: 1 addition & 0 deletions integrations/tendermint-bsync/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
},
"dependencies": {
"@kyvejs/protocol": "1.1.7",
"@kyvejs/sdk": "1.2.0",
"axios": "^0.27.2"
},
"devDependencies": {
Expand Down
10 changes: 8 additions & 2 deletions integrations/tendermint-bsync/src/runtime.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { DataItem, IRuntime, Validator, VOTE } from '@kyvejs/protocol';
import { name, version } from '../package.json';
import axios from 'axios';
import { createHashesFromTendermintBundle } from './utils/merkle';
import { generateMerkleRoot } from '@kyvejs/sdk';

// TendermintBSync config
interface IConfig {
Expand Down Expand Up @@ -82,8 +84,12 @@ export default class TendermintBSync implements IRuntime {
}

async summarizeDataBundle(_: Validator, bundle: DataItem[]): Promise<string> {
// use latest block height as bundle summary
return bundle.at(-1)?.value?.header?.height ?? '';
const hashes: Uint8Array[] = createHashesFromTendermintBundle(bundle);
const merkleRoot: Uint8Array = generateMerkleRoot(hashes);

return JSON.stringify({
merkle_root: Buffer.from(merkleRoot).toString('hex'),
});
}

async nextKey(_: Validator, key: string): Promise<string> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
import * as crypto from '@cosmjs/crypto';
import { dataItemToSha256, generateMerkleRoot } from "@kyvejs/sdk";
import { dataItemToSha256, generateMerkleRoot } from '@kyvejs/sdk';

// Creates an Array of hashes from an array of data items (bundle).
// The hash of a data item consists of the Merkle root from the block and the block
// results (only two leafs) and the key of the data item. This allows the
// Trustless API to serve block and block results independently.
export function createHashesFromTendermintBundle(bundle: any[]): Uint8Array[] {
return bundle.map(dataItem => {
const blockHashes: Uint8Array[] = [dataItemToSha256(dataItem.value?.block), dataItemToSha256(dataItem.value?.block_results)];
return bundle.map((dataItem) => {
const blockHashes: Uint8Array[] = [
dataItemToSha256(dataItem.value?.block),
dataItemToSha256(dataItem.value?.block_results),
];

const merkleRoot: Uint8Array = generateMerkleRoot(blockHashes);

return tendermintDataItemToSha256(dataItem.key, merkleRoot)
})
return tendermintDataItemToSha256(dataItem.key, merkleRoot);
});
}

function tendermintDataItemToSha256(key: string, merkleRoot: Uint8Array): Uint8Array {
function tendermintDataItemToSha256(
key: string,
merkleRoot: Uint8Array
): Uint8Array {
const keyBytes = crypto.sha256(Buffer.from(key, 'utf-8'));

const combined = Buffer.concat([keyBytes, merkleRoot]);

return crypto.sha256(combined);
}
}
11 changes: 5 additions & 6 deletions integrations/tendermint/src/runtime.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { DataItem, IRuntime, Validator, VOTE } from "@kyvejs/protocol";
import { DataItem, IRuntime, Validator, VOTE } from '@kyvejs/protocol';
import { name, version } from '../package.json';
import axios from 'axios';
import Ajv from 'ajv';
import block_schema from './schemas/block.json';
import block_results_schema from './schemas/block_result.json';
import { createHashesFromTendermintBundle } from "../utils/merkle";
import { generateMerkleRoot } from "@kyvejs/sdk";
import { createHashesFromTendermintBundle } from './utils/merkle';
import { generateMerkleRoot } from '@kyvejs/sdk';

const ajv = new Ajv();

Expand Down Expand Up @@ -239,12 +239,11 @@ export default class Tendermint implements IRuntime {

async summarizeDataBundle(_: Validator, bundle: DataItem[]): Promise<string> {
const hashes: Uint8Array[] = createHashesFromTendermintBundle(bundle);

const merkleRoot: Uint8Array = generateMerkleRoot(hashes);

return JSON.stringify({
"merkle_root": Buffer.from(merkleRoot).toString("hex")
})
merkle_root: Buffer.from(merkleRoot).toString('hex'),
});
}

async nextKey(_: Validator, key: string): Promise<string> {
Expand Down
30 changes: 30 additions & 0 deletions integrations/tendermint/src/utils/merkle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as crypto from '@cosmjs/crypto';
import { dataItemToSha256, generateMerkleRoot } from '@kyvejs/sdk';

// Creates an Array of hashes from an array of data items (bundle).
// The hash of a data item consists of the Merkle root from the block and the block
// results (only two leafs) and the key of the data item. This allows the
// Trustless API to serve block and block results independently.
export function createHashesFromTendermintBundle(bundle: any[]): Uint8Array[] {
return bundle.map((dataItem) => {
const blockHashes: Uint8Array[] = [
dataItemToSha256(dataItem.value?.block),
dataItemToSha256(dataItem.value?.block_results),
];

const merkleRoot: Uint8Array = generateMerkleRoot(blockHashes);

return tendermintDataItemToSha256(dataItem.key, merkleRoot);
});
}

function tendermintDataItemToSha256(
key: string,
merkleRoot: Uint8Array
): Uint8Array {
const keyBytes = crypto.sha256(Buffer.from(key, 'utf-8'));

const combined = Buffer.concat([keyBytes, merkleRoot]);

return crypto.sha256(combined);
}

0 comments on commit 2e2c531

Please sign in to comment.