Skip to content

Commit

Permalink
fixup
Browse files Browse the repository at this point in the history
  • Loading branch information
eshaan7 committed Nov 4, 2024
1 parent d1d9724 commit 4b7365b
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 19 deletions.
File renamed without changes
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
MicroRollup,
} from "@stackr/sdk";
import express, { Request, Response } from "express";

import { stackrConfig } from "../stackr.config.ts";
import {
leagueMachine,
Expand Down Expand Up @@ -412,4 +413,4 @@ const main = async () => {
});
};

main();
main();
32 changes: 17 additions & 15 deletions src/stackr/state.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { State } from "@stackr/sdk/machine";
import { solidityPacked, solidityPackedKeccak256 } from "ethers";
import { createMT } from "./utils";
import { keccak256, solidityPacked } from "ethers";
import { createMMR, createMT } from "./utils";

type TournamentMeta = {
round: number;
Expand Down Expand Up @@ -73,7 +73,7 @@ export class League extends State<LeagueState> {
)
);

const matchesMMR = createMT(matches, (m) => {
const matchesMMR = createMMR(matches, (m) => {
const teamIds = Object.keys(m.scores).map((k) => parseInt(k));
const scores = teamIds.map((id) => m.scores[id]);
return solidityPacked(
Expand Down Expand Up @@ -102,23 +102,25 @@ export class League extends State<LeagueState> {
);
});

const logsMMR = createMT(logs, (l) =>
const logsMMR = createMMR(logs, (l) =>
solidityPacked(
["uint256", "uint256", "string", "uint256"],
[l.playerId, l.timestamp, l.action, l.matchId || 0]
)
);

const metaHash = solidityPackedKeccak256(
["uint256", "uint256", "uint256", "uint256", "string"],
Object.values(meta).map((v) => {
if (typeof v === "number") {
return v;
}
return Object.entries(v)
.map(([k, v]) => `${k}:${v}`)
.join(",");
})
const metaHash = keccak256(
solidityPacked(
["uint256", "uint256", "uint256", "uint256", "string"],
Object.values(meta).map((v) => {
if (typeof v === "number") {
return v;
}
return Object.entries(v)
.map(([k, v]) => `${k}:${v}`)
.join(",");
})
)
);

const finalMerkleTree = createMT([
Expand All @@ -132,4 +134,4 @@ export class League extends State<LeagueState> {

return finalMerkleTree.rootHash;
}
}
}
120 changes: 117 additions & 3 deletions src/stackr/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
import { keccak256, ZeroHash } from "ethers";
import { MerkleTree } from "merkletreejs";
import {
hexlify,
isHexString,
keccak256,
solidityPackedKeccak256,
ZeroHash,
} from "ethers";
import { MerkleMountainRange, MerkleTree } from "merkletreejs";

export interface MMRResponse {
rootHash: string;
merkleProof: (leaf: string) =>
| {
root: string;
width: number;
index: number;
peakBagging: string[];
siblings: string[];
}
| undefined;
verifyProof: (
leafIndex: number,
leaf: string,
width: number,
peakBagging: string[],
siblings: string[]
) => boolean;
}

export interface MTResponse {
rootHash: string;
Expand All @@ -12,6 +38,94 @@ export interface MTResponse {
verifyProof: (leaf: string, proof: string[]) => boolean;
}

const hashLeafFn = (index: number, dataHash: Buffer): string =>
solidityPackedKeccak256(["uint256", "bytes32"], [index, hexlify(dataHash)]);

const peakBaggingFn = (size: number, peaks: Buffer[]): string =>
solidityPackedKeccak256(
["uint256", "bytes32"],
[
size,
solidityPackedKeccak256(
["uint256", "bytes32[]"],
[size, peaks.map((peak) => hexlify(peak))]
),
]
);

const hashBranchFn = (index: number, left: Buffer, right: Buffer): string =>
solidityPackedKeccak256(
["uint256", "bytes32", "bytes32"],
[index, hexlify(left), hexlify(right)]
);

/**
* 7
* 3 6 10
* 1 2 4 5 8 9 11
* 1 2 3 4 5 6 7
* @param items List of items to be included in the Merkle Mountain Range
* @param serializer Optional function to serialize the items
* @returns `MMRResponse` object
*/
export const createMMR = <ConvertibleItem>(
items: ConvertibleItem[],
serializer?: (item: ConvertibleItem) => string
): MMRResponse => {
const mmr = new MerkleMountainRange(
keccak256,
serializer ? items.map(serializer) : items,
hashLeafFn,
peakBaggingFn,
hashBranchFn
);

const rootHash = mmr.getHexRoot();

return {
rootHash: rootHash === "0x" ? ZeroHash : rootHash,
merkleProof: (leaf: string) => {
const hashes = Object.keys(mmr.data);
const itemIndex = hashes.indexOf(keccak256(leaf));
if (itemIndex === -1) {
// Leaf not found
return undefined;
}
const leafIndex = mmr.getLeafIndex(itemIndex + 1); // indexing in tree starts from 1
const mmrProof = mmr.getMerkleProof(leafIndex);
return {
root: mmr.bufferToHex(mmrProof.root),
width: mmrProof.width,
index: leafIndex,
peakBagging: mmrProof.peakBagging.map((peak) => mmr.bufferToHex(peak)),
siblings: mmrProof.siblings.map((sibling) => mmr.bufferToHex(sibling)),
};
},
verifyProof: (
leafIndex: number,
leaf: string,
width: number,
peaks: string[],
siblings: string[]
): boolean => {
try {
return mmr.verify(
mmr.getRoot(),
width,
leafIndex,
leaf,
peaks.map((peak) => (isHexString(peak) ? mmr.bufferify(peak) : peak)),
siblings.map((sibling) =>
isHexString(sibling) ? mmr.bufferify(sibling) : sibling
)
);
} catch (error) {
return false;
}
},
};
};

/**
* @param items List of items to be included in the Merkle Tree
* @param serializer Optional function to serialize the items
Expand Down Expand Up @@ -54,4 +168,4 @@ export const createMT = <ConvertibleItem>(
}
},
};
};
};

0 comments on commit 4b7365b

Please sign in to comment.