@freedomofpress/cometbft 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/commit.d.ts +7 -0
  2. package/dist/commit.js +175 -0
  3. package/dist/commit.js.map +1 -0
  4. package/dist/encoding.d.ts +4 -0
  5. package/dist/encoding.js +31 -0
  6. package/dist/encoding.js.map +1 -0
  7. package/dist/lightclient.d.ts +17 -0
  8. package/dist/lightclient.js +275 -0
  9. package/dist/lightclient.js.map +1 -0
  10. package/dist/proto/cometbft/crypto/v1/keys.d.ts +28 -0
  11. package/dist/proto/cometbft/crypto/v1/keys.js +110 -0
  12. package/dist/proto/cometbft/crypto/v1/keys.js.map +1 -0
  13. package/dist/proto/cometbft/crypto/v1/proof.d.ts +60 -0
  14. package/dist/proto/cometbft/crypto/v1/proof.js +416 -0
  15. package/dist/proto/cometbft/crypto/v1/proof.js.map +1 -0
  16. package/dist/proto/cometbft/types/v1/canonical.d.ts +85 -0
  17. package/dist/proto/cometbft/types/v1/canonical.js +586 -0
  18. package/dist/proto/cometbft/types/v1/canonical.js.map +1 -0
  19. package/dist/proto/cometbft/types/v1/types.d.ts +206 -0
  20. package/dist/proto/cometbft/types/v1/types.js +1794 -0
  21. package/dist/proto/cometbft/types/v1/types.js.map +1 -0
  22. package/dist/proto/cometbft/types/v1/validator.d.ts +64 -0
  23. package/dist/proto/cometbft/types/v1/validator.js +382 -0
  24. package/dist/proto/cometbft/types/v1/validator.js.map +1 -0
  25. package/dist/proto/cometbft/version/v1/types.d.ts +41 -0
  26. package/dist/proto/cometbft/version/v1/types.js +154 -0
  27. package/dist/proto/cometbft/version/v1/types.js.map +1 -0
  28. package/dist/proto/gogoproto/gogo.d.ts +1 -0
  29. package/dist/proto/gogoproto/gogo.js +8 -0
  30. package/dist/proto/gogoproto/gogo.js.map +1 -0
  31. package/dist/proto/google/protobuf/descriptor.d.ts +1228 -0
  32. package/dist/proto/google/protobuf/descriptor.js +5056 -0
  33. package/dist/proto/google/protobuf/descriptor.js.map +1 -0
  34. package/dist/proto/google/protobuf/timestamp.d.ts +128 -0
  35. package/dist/proto/google/protobuf/timestamp.js +83 -0
  36. package/dist/proto/google/protobuf/timestamp.js.map +1 -0
  37. package/dist/tests/commit.test.d.ts +1 -0
  38. package/dist/tests/commit.test.js +219 -0
  39. package/dist/tests/commit.test.js.map +1 -0
  40. package/dist/tests/encoding.test.d.ts +1 -0
  41. package/dist/tests/encoding.test.js +31 -0
  42. package/dist/tests/encoding.test.js.map +1 -0
  43. package/dist/tests/fixtures/commit-12.json +64 -0
  44. package/dist/tests/fixtures/validators-12.json +41 -0
  45. package/dist/tests/fixtures/webcat.json +71 -0
  46. package/dist/tests/lightclient.test.d.ts +1 -0
  47. package/dist/tests/lightclient.test.js +234 -0
  48. package/dist/tests/lightclient.test.js.map +1 -0
  49. package/dist/tests/validators.test.d.ts +1 -0
  50. package/dist/tests/validators.test.js +184 -0
  51. package/dist/tests/validators.test.js.map +1 -0
  52. package/dist/tests/webcat.test.d.ts +1 -0
  53. package/dist/tests/webcat.test.js +52 -0
  54. package/dist/tests/webcat.test.js.map +1 -0
  55. package/dist/types.d.ts +62 -0
  56. package/dist/types.js +2 -0
  57. package/dist/types.js.map +1 -0
  58. package/dist/validators.d.ts +6 -0
  59. package/dist/validators.js +55 -0
  60. package/dist/validators.js.map +1 -0
  61. package/package.json +5 -5
  62. package/src/lightclient.ts +176 -0
  63. package/src/tests/lightclient.test.ts +20 -5
  64. package/src/tests/webcat.test.ts +17 -47
@@ -0,0 +1,234 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { importCommit } from "../commit";
3
+ import { base64ToUint8Array, Uint8ArrayToBase64, Uint8ArrayToHex, } from "../encoding";
4
+ import { verifyCommit } from "../lightclient";
5
+ import { importValidators } from "../validators";
6
+ import commitFixture from "./fixtures/commit-12.json";
7
+ import validatorsFixture from "./fixtures/validators-12.json";
8
+ function clone(x) {
9
+ return JSON.parse(JSON.stringify(x));
10
+ }
11
+ describe("lightclient.verifyCommit", () => {
12
+ it("verifies a valid commit against the validator set", async () => {
13
+ const vResp = validatorsFixture;
14
+ const cResp = commitFixture;
15
+ const { proto: vset, cryptoIndex } = await importValidators(vResp);
16
+ const sh = importCommit(cResp);
17
+ const out = await verifyCommit(sh, vset, cryptoIndex);
18
+ expect(out.quorum).toBe(true);
19
+ expect(out.ok).toBe(true);
20
+ expect(out.signedPower > 0n).toBe(true);
21
+ expect(out.signedPower <= out.totalPower).toBe(true);
22
+ expect(out.headerTime).toBeDefined();
23
+ expect(out.appHash instanceof Uint8Array).toBe(true);
24
+ expect(out.blockIdHash instanceof Uint8Array).toBe(true);
25
+ expect(out.unknownValidators.length).toBe(0);
26
+ expect(out.invalidSignatures.length).toBe(0);
27
+ expect(out.countedSignatures).toBeGreaterThan(0);
28
+ });
29
+ it("throws when commit block_id.hash does not match the header hash", async () => {
30
+ const vResp = validatorsFixture;
31
+ const { proto: vset, cryptoIndex } = await importValidators(vResp);
32
+ const badCommit = clone(commitFixture);
33
+ const h = badCommit.signed_header.commit.block_id.hash;
34
+ badCommit.signed_header.commit.block_id.hash =
35
+ h.slice(0, -2) + (h.slice(-2) === "00" ? "01" : "00");
36
+ const sh = importCommit(badCommit);
37
+ await expect(verifyCommit(sh, vset, cryptoIndex)).rejects.toThrow(/header hash does not match commit blockid hash/i);
38
+ });
39
+ it("throws when app_hash is tampered", async () => {
40
+ const vResp = validatorsFixture;
41
+ const { proto: vset, cryptoIndex } = await importValidators(vResp);
42
+ const badHeader = clone(commitFixture);
43
+ const appHash = badHeader.signed_header.header.app_hash;
44
+ badHeader.signed_header.header.app_hash =
45
+ appHash.slice(0, -2) + (appHash.slice(-2) === "00" ? "01" : "00");
46
+ const sh = importCommit(badHeader);
47
+ await expect(verifyCommit(sh, vset, cryptoIndex)).rejects.toThrow(/header hash does not match commit blockid hash/i);
48
+ });
49
+ it("drops below 2/3 quorum when two votes are ABSENT", async () => {
50
+ const vResp = validatorsFixture;
51
+ const { proto: vset, cryptoIndex } = await importValidators(vResp);
52
+ const lowPower = clone(commitFixture);
53
+ for (let i = 0; i < 2; i++) {
54
+ lowPower.signed_header.commit.signatures[i].block_id_flag = 1;
55
+ lowPower.signed_header.commit.signatures[i].signature = "";
56
+ }
57
+ const sh = importCommit(lowPower);
58
+ const out = await verifyCommit(sh, vset, cryptoIndex);
59
+ expect(out.quorum).toBe(false);
60
+ expect(out.ok).toBe(false);
61
+ expect(out.invalidSignatures.length).toBe(0);
62
+ });
63
+ it("keeps quorum when one signature is corrupted and reports it as invalid", async () => {
64
+ const vResp = validatorsFixture;
65
+ const { proto: vset, cryptoIndex } = await importValidators(vResp);
66
+ const badSigResp = clone(commitFixture);
67
+ const sigB64 = badSigResp.signed_header.commit.signatures[0].signature;
68
+ const sigBytes = base64ToUint8Array(sigB64);
69
+ sigBytes[0] ^= 0x01;
70
+ badSigResp.signed_header.commit.signatures[0].signature =
71
+ Uint8ArrayToBase64(sigBytes);
72
+ const sh = importCommit(badSigResp);
73
+ const out = await verifyCommit(sh, vset, cryptoIndex);
74
+ expect(out.quorum).toBe(true);
75
+ expect(out.invalidSignatures.length).toBe(1);
76
+ expect(out.ok).toBe(true);
77
+ });
78
+ it("adds 0 power when a validator's votingPower is undefined but signature is valid", async () => {
79
+ const vResp = validatorsFixture;
80
+ const { proto: vset, cryptoIndex } = await importValidators(vResp);
81
+ const sh = importCommit(commitFixture);
82
+ const vsetZeroOne = {
83
+ validators: vset.validators.map((vv, i) => i === 0 ? { ...vv, votingPower: undefined } : vv),
84
+ proposer: vset.proposer,
85
+ totalVotingPower: vset.totalVotingPower, // still 4n
86
+ };
87
+ const out = await verifyCommit(sh, vsetZeroOne, cryptoIndex);
88
+ expect(out.countedSignatures).toBe(4);
89
+ expect(out.invalidSignatures.length).toBe(0);
90
+ expect(out.signedPower).toBe(out.totalPower - 1n); // 3n of 4n
91
+ expect(out.quorum).toBe(true);
92
+ expect(out.ok).toBe(true);
93
+ });
94
+ it("throws when SignedHeader is missing header/commit", async () => {
95
+ const vResp = validatorsFixture;
96
+ const { proto: vset, cryptoIndex } = await importValidators(vResp);
97
+ const sh = importCommit(commitFixture);
98
+ delete sh.header;
99
+ await expect(verifyCommit(sh, vset, cryptoIndex)).rejects.toThrow(/SignedHeader missing header\/commit/i);
100
+ });
101
+ it("throws on header/commit height mismatch", async () => {
102
+ const vResp = validatorsFixture;
103
+ const { proto: vset, cryptoIndex } = await importValidators(vResp);
104
+ const sh = importCommit(commitFixture);
105
+ sh.commit.height = 13n;
106
+ await expect(verifyCommit(sh, vset, cryptoIndex)).rejects.toThrow(/height mismatch/i);
107
+ });
108
+ it("throws when validator set is empty", async () => {
109
+ const vResp = validatorsFixture;
110
+ const { proto: vset0, cryptoIndex } = await importValidators(vResp);
111
+ const sh = importCommit(commitFixture);
112
+ const vset = { ...vset0, validators: [] };
113
+ await expect(verifyCommit(sh, vset, cryptoIndex)).rejects.toThrow(/no validators/i);
114
+ });
115
+ it("throws when validator set totalVotingPower is missing (defaults to 0n)", async () => {
116
+ const vResp = validatorsFixture;
117
+ const { proto: vset, cryptoIndex } = await importValidators(vResp);
118
+ const sh = importCommit(commitFixture);
119
+ const vsetMissing = {
120
+ validators: vset.validators,
121
+ proposer: vset.proposer,
122
+ totalVotingPower: undefined, // triggers ?? 0n path
123
+ };
124
+ await expect(verifyCommit(sh, vsetMissing, cryptoIndex)).rejects.toThrow(/total power must be positive/i);
125
+ });
126
+ it("throws when total voting power is non-positive", async () => {
127
+ const vResp = validatorsFixture;
128
+ const { proto: vset0, cryptoIndex } = await importValidators(vResp);
129
+ const sh = importCommit(commitFixture);
130
+ const vset = { ...vset0, totalVotingPower: 0n };
131
+ await expect(verifyCommit(sh, vset, cryptoIndex)).rejects.toThrow(/total power/i);
132
+ });
133
+ it("throws on duplicate validator address in the set", async () => {
134
+ const vResp = validatorsFixture;
135
+ const { proto: vset0, cryptoIndex } = await importValidators(vResp);
136
+ const sh = importCommit(commitFixture);
137
+ const dup = vset0.validators[0];
138
+ const vset = { ...vset0, validators: [...vset0.validators, dup] };
139
+ await expect(verifyCommit(sh, vset, cryptoIndex)).rejects.toThrow(/duplicate validator address/i);
140
+ });
141
+ it("throws when commit BlockID is missing", async () => {
142
+ const vResp = validatorsFixture;
143
+ const { proto: vset, cryptoIndex } = await importValidators(vResp);
144
+ const sh = importCommit(commitFixture);
145
+ sh.commit.blockId = undefined;
146
+ await expect(verifyCommit(sh, vset, cryptoIndex)).rejects.toThrow(/missing blockid/i);
147
+ });
148
+ it("throws when PartSetHeader is missing or malformed", async () => {
149
+ const vResp = validatorsFixture;
150
+ const { proto: vset, cryptoIndex } = await importValidators(vResp);
151
+ const sh1 = importCommit(commitFixture);
152
+ sh1.commit.blockId.partSetHeader = undefined;
153
+ await expect(verifyCommit(sh1, vset, cryptoIndex)).rejects.toThrow(/partsetheader is missing/i);
154
+ const sh2 = importCommit(commitFixture);
155
+ sh2.commit.blockId.partSetHeader.hash = new Uint8Array(0);
156
+ await expect(verifyCommit(sh2, vset, cryptoIndex)).rejects.toThrow(/partsetheader hash is missing/i);
157
+ });
158
+ it("throws when PartSetHeader.total is invalid", async () => {
159
+ const vResp = validatorsFixture;
160
+ const { proto: vset, cryptoIndex } = await importValidators(vResp);
161
+ const sh = importCommit(commitFixture);
162
+ sh.commit.blockId.partSetHeader.total = -1;
163
+ await expect(verifyCommit(sh, vset, cryptoIndex)).rejects.toThrow(/total is invalid/i);
164
+ });
165
+ it("collects unknown validator addresses without counting them", async () => {
166
+ const vResp = validatorsFixture;
167
+ const { proto: vset, cryptoIndex } = await importValidators(vResp);
168
+ const sh = importCommit(commitFixture);
169
+ const u = new Uint8Array(20);
170
+ u.fill(0xff);
171
+ sh.commit.signatures[0].validatorAddress = u;
172
+ const out = await verifyCommit(sh, vset, cryptoIndex);
173
+ expect(out.quorum).toBe(true);
174
+ expect(out.ok).toBe(true);
175
+ expect(out.unknownValidators.length).toBe(1);
176
+ expect(out.invalidSignatures.length).toBe(0);
177
+ expect(out.countedSignatures).toBe(3);
178
+ });
179
+ it("marks a COMMIT with empty signature as invalid and does not count it", async () => {
180
+ const vResp = validatorsFixture;
181
+ const { proto: vset, cryptoIndex } = await importValidators(vResp);
182
+ const sh = importCommit(commitFixture);
183
+ sh.commit.signatures[1].signature = new Uint8Array(0);
184
+ const out = await verifyCommit(sh, vset, cryptoIndex);
185
+ expect(out.invalidSignatures.length).toBe(1);
186
+ expect(out.countedSignatures).toBe(3);
187
+ expect(out.quorum).toBe(true);
188
+ expect(out.ok).toBe(true);
189
+ });
190
+ it("keeps quorum when one verify() call throws (caught) and marks that vote invalid", async () => {
191
+ const vResp = validatorsFixture;
192
+ const { proto: vset, cryptoIndex } = await importValidators(vResp);
193
+ const sh = importCommit(commitFixture);
194
+ const originalVerify = crypto.subtle.verify.bind(crypto.subtle);
195
+ let calls = 0;
196
+ crypto.subtle.verify = (...args) => {
197
+ calls += 1;
198
+ if (calls === 1) {
199
+ return Promise.reject(new Error("forced verify error"));
200
+ }
201
+ return originalVerify(...args);
202
+ };
203
+ try {
204
+ const out = await verifyCommit(sh, vset, cryptoIndex);
205
+ expect(out.quorum).toBe(true);
206
+ expect(out.ok).toBe(true);
207
+ expect(out.invalidSignatures.length).toBe(1);
208
+ expect(out.countedSignatures).toBe(4);
209
+ }
210
+ finally {
211
+ crypto.subtle.verify = originalVerify;
212
+ }
213
+ });
214
+ it("treats a known validator without a crypto key as invalid but still counts the vote attempt", async () => {
215
+ const vResp = validatorsFixture;
216
+ const { proto: vset, cryptoIndex } = await importValidators(vResp);
217
+ const sh = importCommit(commitFixture);
218
+ const addrHex = Uint8ArrayToHex(sh.commit.signatures[0].validatorAddress).toUpperCase();
219
+ cryptoIndex.delete(addrHex);
220
+ const out = await verifyCommit(sh, vset, cryptoIndex);
221
+ expect(out.quorum).toBe(true);
222
+ expect(out.ok).toBe(true);
223
+ expect(out.invalidSignatures.includes(addrHex)).toBe(true);
224
+ expect(out.countedSignatures).toBe(4);
225
+ });
226
+ it("throws when BlockID hash is empty", async () => {
227
+ const vResp = validatorsFixture;
228
+ const { proto: vset, cryptoIndex } = await importValidators(vResp);
229
+ const sh = importCommit(commitFixture);
230
+ sh.commit.blockId.hash = new Uint8Array(0);
231
+ await expect(verifyCommit(sh, vset, cryptoIndex)).rejects.toThrow(/blockid hash is missing/i);
232
+ });
233
+ });
234
+ //# sourceMappingURL=lightclient.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lightclient.test.js","sourceRoot":"","sources":["../../src/tests/lightclient.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,184 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { base64ToUint8Array, Uint8ArrayToBase64, Uint8ArrayToHex, } from "../encoding";
3
+ import { importValidators } from "../validators";
4
+ import validatorsFixture from "./fixtures/validators-12.json";
5
+ /* eslint-disable @typescript-eslint/no-explicit-any */
6
+ async function sha256(u8) {
7
+ const buf = await crypto.subtle.digest("SHA-256", new Uint8Array(u8));
8
+ return new Uint8Array(buf);
9
+ }
10
+ function filledBytes(seed, len = 32) {
11
+ const u = new Uint8Array(len);
12
+ u.fill(seed & 0xff);
13
+ // small variation so different seeds give different keys
14
+ if (len > 0)
15
+ u[0] = (seed * 17) & 0xff;
16
+ if (len > 1)
17
+ u[len - 1] = (seed * 29) & 0xff;
18
+ return u;
19
+ }
20
+ async function makeValidatorEntry(pub, power, opts) {
21
+ const keyType = opts?.keyType ?? "tendermint/PubKeyEd25519";
22
+ const addr = Uint8ArrayToHex((await sha256(pub)).slice(0, 20));
23
+ return {
24
+ address: opts?.lowercaseAddr ? addr : addr.toUpperCase(),
25
+ pub_key: { type: keyType, value: Uint8ArrayToBase64(pub) },
26
+ voting_power: String(power),
27
+ proposer_priority: "0",
28
+ };
29
+ }
30
+ function makeResponse(entries, height = "12", countOverride, totalOverride) {
31
+ const count = countOverride ?? String(entries.length);
32
+ const total = totalOverride ?? String(entries.length);
33
+ return {
34
+ block_height: height,
35
+ validators: entries,
36
+ count,
37
+ total,
38
+ };
39
+ }
40
+ // ---------------------- tests -------------------------
41
+ describe("importValidators (browser crypto)", () => {
42
+ it("happy path: imports full single-page set and sums power", async () => {
43
+ const v1 = await makeValidatorEntry(filledBytes(1), 1);
44
+ const v2 = await makeValidatorEntry(filledBytes(2), 2);
45
+ const v3 = await makeValidatorEntry(filledBytes(3), 3);
46
+ const v4 = await makeValidatorEntry(filledBytes(4), 4);
47
+ const resp = makeResponse([v1, v2, v3, v4], "42");
48
+ const out = await importValidators(resp);
49
+ expect(out.proto.validators).toHaveLength(4);
50
+ expect(out.proto.totalVotingPower).toBe(10n); // 1+2+3+4
51
+ // cryptoIndex should have 4 entries keyed by uppercase hex
52
+ expect(out.cryptoIndex.size).toBe(4);
53
+ for (const [addrHex, key] of out.cryptoIndex.entries()) {
54
+ expect(addrHex).toMatch(/^[0-9A-F]{40}$/);
55
+ expect(key.type).toBe("public");
56
+ expect(key.algorithm.name).toBe("Ed25519");
57
+ expect(key.usages).toEqual(["verify"]);
58
+ expect(key.extractable).toBe(false);
59
+ }
60
+ // proto validators should have bytes + bigint fields
61
+ for (const pv of out.proto.validators) {
62
+ expect(pv.address instanceof Uint8Array).toBe(true);
63
+ expect(pv.address.length).toBe(20);
64
+ expect(typeof pv.votingPower).toBe("bigint");
65
+ expect(pv.votingPower).toBeGreaterThanOrEqual(1n);
66
+ expect(pv.pubKeyType).toBe("ed25519");
67
+ expect(pv.pubKeyBytes instanceof Uint8Array).toBe(true);
68
+ expect(pv.pubKeyBytes.length).toBe(32);
69
+ }
70
+ });
71
+ it("accepts lowercase input addresses but normalizes keys to uppercase in cryptoIndex", async () => {
72
+ const v1 = await makeValidatorEntry(filledBytes(10), 1, {
73
+ lowercaseAddr: true,
74
+ });
75
+ const v2 = await makeValidatorEntry(filledBytes(11), 1, {
76
+ lowercaseAddr: true,
77
+ });
78
+ const resp = makeResponse([v1, v2], "99");
79
+ const out = await importValidators(resp);
80
+ // Derive expected addresses (uppercase) from pubkeys and confirm present in cryptoIndex
81
+ for (const e of resp.validators) {
82
+ const pubRaw = base64ToUint8Array(e.pub_key.value);
83
+ const derived = Uint8ArrayToHex((await sha256(pubRaw)).slice(0, 20)).toUpperCase();
84
+ expect(out.cryptoIndex.has(derived)).toBe(true);
85
+ }
86
+ });
87
+ it("throws when validators array is empty", async () => {
88
+ const resp = {
89
+ jsonrpc: "2.0",
90
+ id: -1,
91
+ result: {
92
+ block_height: "12",
93
+ validators: [], // <-- empty
94
+ count: "0",
95
+ total: "0",
96
+ },
97
+ };
98
+ await expect(importValidators(resp)).rejects.toThrow(/Missing validators/i);
99
+ });
100
+ it("throws on invalid address (wrong length/format)", async () => {
101
+ const pub = filledBytes(1);
102
+ const good = await makeValidatorEntry(pub, 1);
103
+ const bad = { ...good, address: good.address.slice(0, 39) }; // 39 chars
104
+ const resp = makeResponse([bad, good], "7");
105
+ await expect(importValidators(resp)).rejects.toThrow(/address.*40/i);
106
+ });
107
+ it("throws on invalid pub_key object", async () => {
108
+ const v1 = await makeValidatorEntry(filledBytes(1), 1);
109
+ const bad = { ...v1, pub_key: { type: "tendermint/PubKeyEd25519" } }; // missing value
110
+ const resp = makeResponse([bad, v1], "7");
111
+ await expect(importValidators(resp)).rejects.toThrow(/key object is invalid/i);
112
+ });
113
+ it("throws on unsupported pub_key.type", async () => {
114
+ const bad = await makeValidatorEntry(filledBytes(1), 1, {
115
+ keyType: "tendermint/PubKeySecp256k1",
116
+ });
117
+ const v2 = await makeValidatorEntry(filledBytes(2), 1);
118
+ const resp = makeResponse([bad, v2], "7");
119
+ await expect(importValidators(resp)).rejects.toThrow(/unsupported/i);
120
+ });
121
+ it("throws on wrong pubkey length (31 bytes)", async () => {
122
+ const pub31 = filledBytes(5, 31); // 31 bytes
123
+ const vBad = await makeValidatorEntry(pub31, 1);
124
+ const v2 = await makeValidatorEntry(filledBytes(2), 1);
125
+ const resp = makeResponse([vBad, v2], "7");
126
+ await expect(importValidators(resp)).rejects.toThrow();
127
+ });
128
+ it("throws on address/pubkey mismatch", async () => {
129
+ const v1 = await makeValidatorEntry(filledBytes(1), 1);
130
+ const v2 = await makeValidatorEntry(filledBytes(2), 1);
131
+ v2.address = v1.address; // duplicate/mismatch
132
+ const resp = makeResponse([v1, v2], "7");
133
+ await expect(importValidators(resp)).rejects.toThrow(/does not match its public key|mismatch/i);
134
+ });
135
+ it("throws on duplicate address", async () => {
136
+ const pub = filledBytes(9);
137
+ const v1 = await makeValidatorEntry(pub, 1);
138
+ const v2 = await makeValidatorEntry(pub, 1); // same address
139
+ const resp = makeResponse([v1, v2], "7");
140
+ await expect(importValidators(resp)).rejects.toThrow(/Duplicate entry/i);
141
+ });
142
+ it("throws on invalid voting power (non-integer / <1)", async () => {
143
+ const v1 = await makeValidatorEntry(filledBytes(1), 0); // invalid: zero
144
+ const v2 = await makeValidatorEntry(filledBytes(2), 1);
145
+ const resp = makeResponse([v1, v2], "7");
146
+ await expect(importValidators(resp)).rejects.toThrow(/Invalid voting power/i);
147
+ });
148
+ });
149
+ describe("validators fixture:", () => {
150
+ it("derives address as SHA-256(pubkey)[0..20] (uppercased)", async () => {
151
+ const resp = validatorsFixture;
152
+ for (const entry of resp.validators) {
153
+ const pubRaw = base64ToUint8Array(entry.pub_key.value);
154
+ const derived = Uint8ArrayToHex((await sha256(pubRaw)).slice(0, 20)).toUpperCase();
155
+ expect(derived).toBe(entry.address.toUpperCase());
156
+ }
157
+ });
158
+ it("imports Ed25519 keys and fills proto validators correctly", async () => {
159
+ const resp = validatorsFixture;
160
+ const out = await importValidators(resp);
161
+ expect(out.proto.validators).toHaveLength(4);
162
+ expect(out.proto.totalVotingPower).toBe(4n);
163
+ // cryptoIndex: correct WebCrypto attributes
164
+ for (const key of out.cryptoIndex.values()) {
165
+ expect(key.type).toBe("public");
166
+ expect(key.algorithm.name).toBe("Ed25519");
167
+ expect(key.usages).toEqual(["verify"]);
168
+ expect(key.extractable).toBe(false);
169
+ await expect(crypto.subtle.exportKey("raw", key)).rejects.toBeTruthy();
170
+ }
171
+ // proto validators content matches derived bytes
172
+ for (const e of resp.validators) {
173
+ const pubRaw = base64ToUint8Array(e.pub_key.value);
174
+ const sha = await sha256(pubRaw);
175
+ const addr20 = sha.slice(0, 20);
176
+ const match = out.proto.validators.find((pv) => Uint8ArrayToHex(pv.address) === Uint8ArrayToHex(addr20));
177
+ expect(match).toBeTruthy();
178
+ expect(match.pubKeyType).toBe("ed25519");
179
+ expect(Uint8ArrayToHex(match.pubKeyBytes)).toBe(Uint8ArrayToHex(pubRaw));
180
+ expect(match.votingPower).toBe(1n);
181
+ }
182
+ });
183
+ });
184
+ //# sourceMappingURL=validators.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validators.test.js","sourceRoot":"","sources":["../../src/tests/validators.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,52 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { importCommit } from "../commit";
3
+ import { Uint8ArrayToBase64 } from "../encoding";
4
+ import { verifyCommit } from "../lightclient";
5
+ import { importValidators } from "../validators";
6
+ import blockFixture from "./fixtures/webcat.json";
7
+ function clone(x) {
8
+ return JSON.parse(JSON.stringify(x));
9
+ }
10
+ describe("lightclient.verifyCommit", () => {
11
+ it("rejects this fixture when header hash does not match commit block_id.hash", async () => {
12
+ const validators = blockFixture.validator_set;
13
+ const commit = blockFixture;
14
+ const { proto: vset, cryptoIndex } = await importValidators(validators);
15
+ const sh = importCommit(commit);
16
+ await expect(verifyCommit(sh, vset, cryptoIndex)).rejects.toThrow(/header hash does not match commit blockid hash/i);
17
+ });
18
+ it("throws when commit block_id.hash does not match header hash", async () => {
19
+ const validators = blockFixture.validator_set;
20
+ const commit = clone(blockFixture);
21
+ commit.signed_header.commit.block_id.hash =
22
+ "3A1D00CC2A092465E85EA2C24986BEE0105285039DC1873BB6B0CA7F610EC89D";
23
+ const { proto: vset, cryptoIndex } = await importValidators(validators);
24
+ const sh = importCommit(commit);
25
+ await expect(verifyCommit(sh, vset, cryptoIndex)).rejects.toThrow(/header hash does not match commit blockid hash/i);
26
+ });
27
+ it("still rejects on header/commit hash mismatch even when a signature is corrupted", async () => {
28
+ const validators = blockFixture.validator_set;
29
+ const commit = clone(blockFixture);
30
+ commit.signed_header.commit.signatures[0].signature = Uint8ArrayToBase64(new Uint8Array(64));
31
+ const { proto: vset, cryptoIndex } = await importValidators(validators);
32
+ const sh = importCommit(commit);
33
+ await expect(verifyCommit(sh, vset, cryptoIndex)).rejects.toThrow(/header hash does not match commit blockid hash/i);
34
+ });
35
+ it("rejects malformed signature bytes", async () => {
36
+ const validators = blockFixture.validator_set;
37
+ const commit = clone(blockFixture);
38
+ // Truncate the signature (must be 64 bytes for Ed25519)
39
+ commit.signed_header.commit.signatures[0].signature = "AA==";
40
+ await expect(async () => importCommit(commit)).rejects.toThrow(/signature must be 64 bytes/);
41
+ });
42
+ it("still rejects on header/commit hash mismatch even when validator is unknown", async () => {
43
+ const validators = blockFixture.validator_set;
44
+ const commit = clone(blockFixture);
45
+ commit.signed_header.commit.signatures[0].validator_address =
46
+ "0000000000000000000000000000000000000000";
47
+ const { proto: vset, cryptoIndex } = await importValidators(validators);
48
+ const sh = importCommit(commit);
49
+ await expect(verifyCommit(sh, vset, cryptoIndex)).rejects.toThrow(/header hash does not match commit blockid hash/i);
50
+ });
51
+ });
52
+ //# sourceMappingURL=webcat.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webcat.test.js","sourceRoot":"","sources":["../../src/tests/webcat.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ export interface ValidatorJson {
2
+ block_height?: string;
3
+ validators: {
4
+ address: string;
5
+ pub_key: {
6
+ type: string;
7
+ value: string;
8
+ };
9
+ voting_power?: string;
10
+ power?: string;
11
+ proposer_priority?: string;
12
+ }[];
13
+ count: string;
14
+ total: string;
15
+ }
16
+ export interface CommitJson {
17
+ signed_header: {
18
+ header: {
19
+ version: {
20
+ block: string;
21
+ app: string;
22
+ };
23
+ chain_id: string;
24
+ height: string;
25
+ time: string;
26
+ last_block_id: {
27
+ hash: string;
28
+ parts: {
29
+ total: number;
30
+ hash: string;
31
+ };
32
+ };
33
+ last_commit_hash: string;
34
+ data_hash: string;
35
+ validators_hash: string;
36
+ next_validators_hash: string;
37
+ consensus_hash: string;
38
+ app_hash: string;
39
+ last_results_hash: string;
40
+ evidence_hash: string;
41
+ proposer_address: string;
42
+ };
43
+ commit: {
44
+ height: string;
45
+ round: number;
46
+ block_id: {
47
+ hash: string;
48
+ parts: {
49
+ total: number;
50
+ hash: string;
51
+ };
52
+ };
53
+ signatures: {
54
+ block_id_flag: number;
55
+ validator_address: string;
56
+ timestamp: string;
57
+ signature: string;
58
+ }[];
59
+ };
60
+ };
61
+ canonical?: boolean;
62
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ import { ValidatorSet } from "./proto/cometbft/types/v1/validator";
2
+ import type { ValidatorJson } from "./types";
3
+ export declare function importValidators(resp: ValidatorJson): Promise<{
4
+ proto: ValidatorSet;
5
+ cryptoIndex: Map<string, CryptoKey>;
6
+ }>;