Skip to content

Commit d0a2eff

Browse files
authored
fix(core): make Merkle root hashing deterministic
Build the Merkle DAG root from sorted file paths so identical file hash sets keep a stable root regardless of insertion order.
1 parent 6111c07 commit d0a2eff

2 files changed

Lines changed: 29 additions & 1 deletion

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { FileSynchronizer } from './synchronizer';
2+
3+
type TestableFileSynchronizer = {
4+
buildMerkleDAG(fileHashes: Map<string, string>): {
5+
rootIds: string[];
6+
};
7+
};
8+
9+
describe('FileSynchronizer Merkle DAG', () => {
10+
it('uses stable root ids for identical file hashes inserted in different orders', () => {
11+
const synchronizer = new FileSynchronizer('/tmp/project') as unknown as TestableFileSynchronizer;
12+
const firstOrder = new Map([
13+
['src/a.ts', 'hash-a'],
14+
['src/b.ts', 'hash-b'],
15+
['README.md', 'hash-readme'],
16+
]);
17+
const secondOrder = new Map([
18+
['README.md', 'hash-readme'],
19+
['src/b.ts', 'hash-b'],
20+
['src/a.ts', 'hash-a'],
21+
]);
22+
23+
const firstDag = synchronizer.buildMerkleDAG(firstOrder);
24+
const secondDag = synchronizer.buildMerkleDAG(secondOrder);
25+
26+
expect(firstDag.rootIds).toEqual(secondDag.rootIds);
27+
});
28+
});

packages/core/src/sync/synchronizer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ export class FileSynchronizer {
113113

114114
// Create a root node for the entire directory
115115
let valuesString = "";
116-
keys.forEach(key => {
116+
sortedPaths.forEach(key => {
117117
valuesString += fileHashes.get(key);
118118
});
119119
const rootNodeData = "root:" + valuesString;

0 commit comments

Comments
 (0)