@typeberry/lib 0.5.2 → 0.5.3

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 (61) hide show
  1. package/package.json +2 -2
  2. package/packages/core/collections/blob-dictionary.d.ts.map +1 -1
  3. package/packages/core/collections/blob-dictionary.js +3 -3
  4. package/packages/core/crypto/bandersnatch.d.ts +2 -1
  5. package/packages/core/crypto/bandersnatch.d.ts.map +1 -1
  6. package/packages/core/crypto/bandersnatch.js +9 -2
  7. package/packages/core/crypto/key-derivation.test.js +8 -7
  8. package/packages/core/networking/package.json +1 -1
  9. package/packages/core/pvm-host-calls/bin.js +6 -6
  10. package/packages/core/pvm-host-calls/ecalli-io-tracker.d.ts +32 -0
  11. package/packages/core/pvm-host-calls/ecalli-io-tracker.d.ts.map +1 -0
  12. package/packages/core/pvm-host-calls/ecalli-io-tracker.js +14 -0
  13. package/packages/core/pvm-host-calls/ecalli-trace-logger.d.ts +139 -0
  14. package/packages/core/pvm-host-calls/ecalli-trace-logger.d.ts.map +1 -0
  15. package/packages/core/pvm-host-calls/ecalli-trace-logger.js +209 -0
  16. package/packages/core/pvm-host-calls/ecalli-trace-logger.test.d.ts +2 -0
  17. package/packages/core/pvm-host-calls/ecalli-trace-logger.test.d.ts.map +1 -0
  18. package/packages/core/pvm-host-calls/ecalli-trace-logger.test.js +231 -0
  19. package/packages/core/pvm-host-calls/host-call-memory.d.ts +2 -0
  20. package/packages/core/pvm-host-calls/host-call-memory.d.ts.map +1 -1
  21. package/packages/core/pvm-host-calls/host-call-memory.js +12 -2
  22. package/packages/core/pvm-host-calls/host-call-registers.d.ts +6 -0
  23. package/packages/core/pvm-host-calls/host-call-registers.d.ts.map +1 -1
  24. package/packages/core/pvm-host-calls/host-call-registers.js +24 -0
  25. package/packages/core/pvm-host-calls/host-calls-executor.d.ts +31 -0
  26. package/packages/core/pvm-host-calls/host-calls-executor.d.ts.map +1 -0
  27. package/packages/core/pvm-host-calls/host-calls-executor.js +137 -0
  28. package/packages/core/pvm-host-calls/host-calls.d.ts +20 -26
  29. package/packages/core/pvm-host-calls/host-calls.d.ts.map +1 -1
  30. package/packages/core/pvm-host-calls/host-calls.js +40 -112
  31. package/packages/core/pvm-host-calls/index.d.ts +7 -6
  32. package/packages/core/pvm-host-calls/index.d.ts.map +1 -1
  33. package/packages/core/pvm-host-calls/index.js +7 -6
  34. package/packages/core/pvm-host-calls/{interpreter-instance-manager.d.ts → pvm-instance-manager.d.ts} +3 -3
  35. package/packages/core/pvm-host-calls/pvm-instance-manager.d.ts.map +1 -0
  36. package/packages/core/pvm-host-calls/{interpreter-instance-manager.js → pvm-instance-manager.js} +2 -2
  37. package/packages/core/telemetry/package.json +1 -1
  38. package/packages/jam/node/main-importer.d.ts.map +1 -1
  39. package/packages/jam/node/main-importer.js +3 -1
  40. package/packages/jam/node/package.json +1 -1
  41. package/packages/jam/safrole/bandersnatch-vrf.d.ts +2 -0
  42. package/packages/jam/safrole/bandersnatch-vrf.d.ts.map +1 -1
  43. package/packages/jam/safrole/bandersnatch-vrf.js +11 -0
  44. package/packages/jam/safrole/bandersnatch-vrf.test.js +3 -3
  45. package/packages/jam/safrole/bandersnatch-wasm.d.ts +1 -0
  46. package/packages/jam/safrole/bandersnatch-wasm.d.ts.map +1 -1
  47. package/packages/jam/safrole/bandersnatch-wasm.js +8 -5
  48. package/packages/jam/safrole/safrole-seal.d.ts +1 -3
  49. package/packages/jam/safrole/safrole-seal.d.ts.map +1 -1
  50. package/packages/jam/safrole/safrole-seal.js +14 -25
  51. package/packages/jam/safrole/safrole-seal.test.js +4 -10
  52. package/packages/jam/transition/accumulate/pvm-executor.d.ts.map +1 -1
  53. package/packages/jam/transition/accumulate/pvm-executor.js +2 -2
  54. package/packages/jam/transition/disputes/disputes.d.ts.map +1 -1
  55. package/packages/jam/transition/disputes/disputes.js +5 -4
  56. package/packages/workers/block-authorship/package.json +1 -1
  57. package/packages/workers/importer/package.json +1 -1
  58. package/packages/core/pvm-host-calls/host-calls-manager.d.ts +0 -23
  59. package/packages/core/pvm-host-calls/host-calls-manager.d.ts.map +0 -1
  60. package/packages/core/pvm-host-calls/host-calls-manager.js +0 -44
  61. package/packages/core/pvm-host-calls/interpreter-instance-manager.d.ts.map +0 -1
@@ -1,119 +1,47 @@
1
- import { Status } from "#@typeberry/pvm-interface";
2
- import { assertNever, check, safeAllocUint8Array } from "#@typeberry/utils";
3
- import { PvmExecution, tryAsHostCallIndex } from "./host-call-handler.js";
4
- import { HostCallMemory } from "./host-call-memory.js";
5
- import { HostCallRegisters } from "./host-call-registers.js";
6
- class ReturnValue {
7
- consumedGas;
8
- status;
9
- memorySlice;
10
- constructor(consumedGas, status, memorySlice) {
11
- this.consumedGas = consumedGas;
12
- this.status = status;
13
- this.memorySlice = memorySlice;
14
- check `
15
- ${(status === null && memorySlice !== null) || (status !== null && memorySlice === null)}
16
- 'status' and 'memorySlice' must not both be null or both be non-null — exactly one must be provided
17
- `;
18
- }
19
- static fromStatus(consumedGas, status) {
20
- return new ReturnValue(consumedGas, status, null);
21
- }
22
- static fromMemorySlice(consumedGas, memorySlice) {
23
- return new ReturnValue(consumedGas, null, memorySlice);
24
- }
25
- hasMemorySlice() {
26
- return this.memorySlice instanceof Uint8Array && this.status === null;
27
- }
28
- hasStatus() {
29
- return !this.hasMemorySlice();
30
- }
31
- }
1
+ import { Level, Logger } from "#@typeberry/logger";
2
+ import { tryAsU32 } from "#@typeberry/numbers";
3
+ import { tryAsSmallGas } from "#@typeberry/pvm-interface";
4
+ import { check } from "#@typeberry/utils";
5
+ import { tryAsHostCallIndex, } from "./host-call-handler.js";
6
+ const logger = Logger.new(import.meta.filename, "host-calls-pvm");
7
+ /** Container for all available host calls. */
32
8
  export class HostCalls {
33
- pvmInstanceManager;
34
- hostCalls;
35
- constructor(pvmInstanceManager, hostCalls) {
36
- this.pvmInstanceManager = pvmInstanceManager;
37
- this.hostCalls = hostCalls;
38
- }
39
- getReturnValue(status, pvmInstance) {
40
- const gasConsumed = pvmInstance.gas.used();
41
- if (status === Status.OOG) {
42
- return ReturnValue.fromStatus(gasConsumed, status);
43
- }
44
- if (status === Status.HALT) {
45
- const regs = new HostCallRegisters(pvmInstance.registers.getAllEncoded());
46
- const memory = new HostCallMemory(pvmInstance.memory);
47
- const address = regs.get(7);
48
- // NOTE we are taking the the lower U32 part of the register, hence it's safe.
49
- const length = Number(regs.get(8) & 0xffffffffn);
50
- const result = safeAllocUint8Array(length);
51
- const loadResult = memory.loadInto(result, address);
52
- if (loadResult.isError) {
53
- return ReturnValue.fromMemorySlice(gasConsumed, new Uint8Array());
54
- }
55
- return ReturnValue.fromMemorySlice(gasConsumed, result);
9
+ hostCalls = new Map();
10
+ missing;
11
+ constructor({ missing, handlers = [], }) {
12
+ this.missing = missing;
13
+ for (const handler of handlers) {
14
+ check `${this.hostCalls.get(handler.index) === undefined} Overwriting host call handler at index ${handler.index}`;
15
+ this.hostCalls.set(handler.index, handler);
56
16
  }
57
- return ReturnValue.fromStatus(gasConsumed, Status.PANIC);
58
17
  }
59
- async execute(pvmInstance) {
60
- pvmInstance.runProgram();
61
- for (;;) {
62
- let status = pvmInstance.getStatus();
63
- if (status !== Status.HOST) {
64
- return this.getReturnValue(status, pvmInstance);
65
- }
66
- check `
67
- ${pvmInstance.getExitParam() !== null}
68
- "We know that the exit param is not null, because the status is 'Status.HOST'
69
- `;
70
- const hostCallIndex = pvmInstance.getExitParam() ?? -1;
71
- const gas = pvmInstance.gas;
72
- const regs = new HostCallRegisters(pvmInstance.registers.getAllEncoded());
73
- const memory = new HostCallMemory(pvmInstance.memory);
74
- const index = tryAsHostCallIndex(hostCallIndex);
75
- const hostCall = this.hostCalls.get(index);
76
- const gasBefore = gas.get();
77
- // NOTE: `basicGasCost(regs)` function is for compatibility reasons: pre GP 0.7.2
78
- const basicGasCost = typeof hostCall.basicGasCost === "number" ? hostCall.basicGasCost : hostCall.basicGasCost(regs);
79
- const underflow = gas.sub(basicGasCost);
80
- const pcLog = `[PC: ${pvmInstance.getPC()}]`;
81
- if (underflow) {
82
- this.hostCalls.traceHostCall(`${pcLog} OOG`, index, hostCall, regs, gas.get());
83
- return ReturnValue.fromStatus(gas.used(), Status.OOG);
84
- }
85
- this.hostCalls.traceHostCall(`${pcLog} Invoking`, index, hostCall, regs, gasBefore);
86
- const result = await hostCall.execute(gas, regs, memory);
87
- this.hostCalls.traceHostCall(result === undefined ? `${pcLog} Result` : `${pcLog} Status(${PvmExecution[result]})`, index, hostCall, regs, gas.get());
88
- pvmInstance.registers.setAllEncoded(regs.getEncoded());
89
- if (result === PvmExecution.Halt) {
90
- status = Status.HALT;
91
- return this.getReturnValue(status, pvmInstance);
92
- }
93
- if (result === PvmExecution.Panic) {
94
- status = Status.PANIC;
95
- return this.getReturnValue(status, pvmInstance);
96
- }
97
- if (result === PvmExecution.OOG) {
98
- status = Status.OOG;
99
- return this.getReturnValue(status, pvmInstance);
100
- }
101
- if (result === undefined) {
102
- pvmInstance.runProgram();
103
- status = pvmInstance.getStatus();
104
- continue;
105
- }
106
- assertNever(result);
107
- }
18
+ /** Get a host call by index. */
19
+ get(hostCallIndex) {
20
+ return this.hostCalls.get(hostCallIndex) ?? this.missing;
108
21
  }
109
- async runProgram(program, args, initialPc, initialGas) {
110
- const pvmInstance = await this.pvmInstanceManager.getInstance();
111
- pvmInstance.resetJam(program, args, initialPc, initialGas);
112
- try {
113
- return await this.execute(pvmInstance);
114
- }
115
- finally {
116
- this.pvmInstanceManager.releaseInstance(pvmInstance);
22
+ traceHostCall(context, hostCallIndex, hostCallHandler, registers, gas) {
23
+ if (logger.getLevel() > Level.INSANE) {
24
+ return;
117
25
  }
26
+ const { currentServiceId } = hostCallHandler;
27
+ const requested = hostCallIndex !== hostCallHandler.index ? ` (${hostCallIndex})` : "";
28
+ const name = `${hostCallHandler.constructor.name}:${hostCallHandler.index}`;
29
+ const registerValues = hostCallHandler.tracedRegisters
30
+ .map((idx) => [idx.toString().padStart(2, "0"), registers.get(idx)])
31
+ .filter((v) => v[1] !== 0n)
32
+ .map(([idx, value]) => {
33
+ return `r${idx}=${value} (0x${value.toString(16)})`;
34
+ })
35
+ .join(", ");
36
+ logger.insane `[${currentServiceId}] ${context} ${name}${requested}. Gas: ${gas}. Regs: ${registerValues}.`;
37
+ }
38
+ }
39
+ export class NoopMissing {
40
+ index = tryAsHostCallIndex(2 ** 32 - 1);
41
+ basicGasCost = tryAsSmallGas(0);
42
+ currentServiceId = tryAsU32(0);
43
+ tracedRegisters = [];
44
+ async execute() {
45
+ return;
118
46
  }
119
47
  }
@@ -1,7 +1,8 @@
1
- export { type HostCallHandler, PvmExecution, traceRegisters, tryAsHostCallIndex } from "./host-call-handler.js";
2
- export { HostCallMemory } from "./host-call-memory.js";
3
- export { HostCallRegisters } from "./host-call-registers.js";
4
- export { HostCalls as PvmHostCallExtension } from "./host-calls.js";
5
- export { HostCallsManager as HostCalls } from "./host-calls-manager.js";
6
- export { InterpreterInstanceManager as PvmInstanceManager } from "./interpreter-instance-manager.js";
1
+ export * from "./ecalli-trace-logger.js";
2
+ export * from "./host-call-handler.js";
3
+ export * from "./host-call-memory.js";
4
+ export * from "./host-call-registers.js";
5
+ export * from "./host-calls.js";
6
+ export * from "./host-calls-executor.js";
7
+ export * from "./pvm-instance-manager.js";
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/core/pvm-host-calls/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAChH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,SAAS,IAAI,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,gBAAgB,IAAI,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,0BAA0B,IAAI,kBAAkB,EAAE,MAAM,mCAAmC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/core/pvm-host-calls/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC"}
@@ -1,6 +1,7 @@
1
- export { PvmExecution, traceRegisters, tryAsHostCallIndex } from "./host-call-handler.js";
2
- export { HostCallMemory } from "./host-call-memory.js";
3
- export { HostCallRegisters } from "./host-call-registers.js";
4
- export { HostCalls as PvmHostCallExtension } from "./host-calls.js";
5
- export { HostCallsManager as HostCalls } from "./host-calls-manager.js";
6
- export { InterpreterInstanceManager as PvmInstanceManager } from "./interpreter-instance-manager.js";
1
+ export * from "./ecalli-trace-logger.js";
2
+ export * from "./host-call-handler.js";
3
+ export * from "./host-call-memory.js";
4
+ export * from "./host-call-registers.js";
5
+ export * from "./host-calls.js";
6
+ export * from "./host-calls-executor.js";
7
+ export * from "./pvm-instance-manager.js";
@@ -1,11 +1,11 @@
1
1
  import { PvmBackend } from "#@typeberry/config";
2
2
  import type { IPvmInterpreter } from "#@typeberry/pvm-interface";
3
- export declare class InterpreterInstanceManager {
3
+ export declare class PvmInstanceManager {
4
4
  private readonly instances;
5
5
  private waitingQueue;
6
6
  private constructor();
7
- static new(interpreter: PvmBackend): Promise<InterpreterInstanceManager>;
7
+ static new(interpreter: PvmBackend): Promise<PvmInstanceManager>;
8
8
  getInstance(): Promise<IPvmInterpreter>;
9
9
  releaseInstance(pvm: IPvmInterpreter): void;
10
10
  }
11
- //# sourceMappingURL=interpreter-instance-manager.d.ts.map
11
+ //# sourceMappingURL=pvm-instance-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pvm-instance-manager.d.ts","sourceRoot":"","sources":["../../../../../packages/core/pvm-host-calls/pvm-instance-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAQhE,qBAAa,kBAAkB;IAGT,OAAO,CAAC,QAAQ,CAAC,SAAS;IAF9C,OAAO,CAAC,YAAY,CAAmB;IAEvC,OAAO;WAEM,GAAG,CAAC,WAAW,EAAE,UAAU,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAmBhE,WAAW,IAAI,OAAO,CAAC,eAAe,CAAC;IAU7C,eAAe,CAAC,GAAG,EAAE,eAAe;CAOrC"}
@@ -3,7 +3,7 @@ import { Interpreter } from "#@typeberry/pvm-interpreter";
3
3
  import { AnanasInterpreter } from "#@typeberry/pvm-interpreter-ananas";
4
4
  import { assertNever } from "#@typeberry/utils";
5
5
  // TODO [MaSo] Delete this & also make host calls independent from intepreters.
6
- export class InterpreterInstanceManager {
6
+ export class PvmInstanceManager {
7
7
  instances;
8
8
  waitingQueue = [];
9
9
  constructor(instances) {
@@ -23,7 +23,7 @@ export class InterpreterInstanceManager {
23
23
  default:
24
24
  assertNever(interpreter);
25
25
  }
26
- return new InterpreterInstanceManager(instances);
26
+ return new PvmInstanceManager(instances);
27
27
  }
28
28
  async getInstance() {
29
29
  const instance = this.instances.pop();
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typeberry/telemetry",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "OpenTelemetry initialization utilities for Typeberry",
5
5
  "license": "MPL-2.0",
6
6
  "author": "Fluffy Labs",
@@ -1 +1 @@
1
- {"version":3,"file":"main-importer.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/main-importer.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,MAAM,MAAM,eAAe,GAAG;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC,CAAC;AAEF,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAClC,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,OAAO,CAAC,CA4ElB"}
1
+ {"version":3,"file":"main-importer.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/main-importer.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,MAAM,MAAM,eAAe,GAAG;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC,CAAC;AAEF,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAClC,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,OAAO,CAAC,CA+ElB"}
@@ -1,6 +1,6 @@
1
1
  import { Bytes } from "#@typeberry/bytes";
2
2
  import { PvmBackend } from "#@typeberry/config";
3
- import { initWasm } from "#@typeberry/crypto";
3
+ import { bandersnatch, initWasm } from "#@typeberry/crypto";
4
4
  import { Blake2b, HASH_SIZE } from "#@typeberry/hash";
5
5
  import { createImporter } from "#@typeberry/importer";
6
6
  import { CURRENT_SUITE, CURRENT_VERSION, Result, resultToString } from "#@typeberry/utils";
@@ -10,9 +10,11 @@ import packageJson from "./package.json" with { type: "json" };
10
10
  const zeroHash = Bytes.zero(HASH_SIZE).asOpaque();
11
11
  export async function mainImporter(config, withRelPath, options = {}) {
12
12
  await initWasm();
13
+ const bandesnatchNative = bandersnatch.checkNativeBindings();
13
14
  logger.info `🫐 Typeberry ${packageJson.version}. GP: ${CURRENT_VERSION} (${CURRENT_SUITE})`;
14
15
  logger.info `🎸 Starting importer: ${config.nodeName}.`;
15
16
  logger.info `🖥️ PVM Backend: ${PvmBackend[config.pvmBackend]}.`;
17
+ logger.info `🐇 Bandersnatch ${bandesnatchNative.isOk ? "native 🚀" : `using wasm: ${bandesnatchNative.error}`}`;
16
18
  const chainSpec = getChainSpec(config.node.flavor);
17
19
  const blake2b = await Blake2b.createHasher();
18
20
  const nodeName = config.nodeName;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typeberry/node",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "The main typeberry node.",
5
5
  "main": "index.ts",
6
6
  "dependencies": {
@@ -8,12 +8,14 @@ import { type Opaque, Result } from "#@typeberry/utils";
8
8
  import type { BandernsatchWasm } from "./bandersnatch-wasm.js";
9
9
  declare const FUNCTIONS: {
10
10
  verifySeal: typeof verifySeal;
11
+ verifyHeaderSeals: typeof verifyHeaderSeals;
11
12
  verifyTickets: typeof verifyTickets;
12
13
  getRingCommitment: typeof getRingCommitment;
13
14
  generateSeal: typeof generateSeal;
14
15
  getVrfOutputHash: typeof getVrfOutputHash;
15
16
  };
16
17
  export default FUNCTIONS;
18
+ declare function verifyHeaderSeals(bandersnatch: BandernsatchWasm, authorKey: BandersnatchKey, signature: BandersnatchVrfSignature, payload: BytesBlob, encodedUnsealedHeader: BytesBlob, entropySignature: BandersnatchVrfSignature, entropyPayloadPrefix: BytesBlob): Promise<Result<[EntropyHash, EntropyHash], null>>;
17
19
  declare function verifySeal(bandersnatch: BandernsatchWasm, authorKey: BandersnatchKey, signature: BandersnatchVrfSignature, payload: BytesBlob, encodedUnsealedHeader: BytesBlob): Promise<Result<EntropyHash, null>>;
18
20
  declare function getRingCommitment(bandersnatch: BandernsatchWasm, validators: BandersnatchKey[]): Promise<Result<BandersnatchRingRoot, null>>;
19
21
  declare function verifyTickets(bandersnatch: BandernsatchWasm, numberOfValidators: number, epochRoot: BandersnatchRingRoot, tickets: readonly SignedTicket[], entropy: EntropyHash): Promise<{
@@ -1 +1 @@
1
- {"version":3,"file":"bandersnatch-vrf.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/safrole/bandersnatch-vrf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAS,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACjF,OAAO,EAGL,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC9B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAwB/D,QAAA,MAAM,SAAS;;;;;;CAMd,CAAC;AAKF,eAAe,SAAS,CAAC;AAEzB,iBAAe,UAAU,CACvB,YAAY,EAAE,gBAAgB,EAC9B,SAAS,EAAE,eAAe,EAC1B,SAAS,EAAE,wBAAwB,EACnC,OAAO,EAAE,SAAS,EAClB,qBAAqB,EAAE,SAAS,GAC/B,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAapC;AAED,iBAAS,iBAAiB,CACxB,YAAY,EAAE,gBAAgB,EAC9B,UAAU,EAAE,eAAe,EAAE,GAC5B,OAAO,CAAC,MAAM,CAAC,oBAAoB,EAAE,IAAI,CAAC,CAAC,CAmB7C;AAkBD,iBAAe,aAAa,CAC1B,YAAY,EAAE,gBAAgB,EAC9B,kBAAkB,EAAE,MAAM,EAC1B,SAAS,EAAE,oBAAoB,EAC/B,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,WAAW,CAAA;CAAE,EAAE,CAAC,CAqB3D;AAED,iBAAe,YAAY,CACzB,YAAY,EAAE,gBAAgB,EAC9B,SAAS,EAAE,sBAAsB,EACjC,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,SAAS,GACjB,OAAO,CAAC,MAAM,CAAC,wBAAwB,EAAE,IAAI,CAAC,CAAC,CAQjD;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAC;AAElE,iBAAe,gBAAgB,CAC7B,YAAY,EAAE,gBAAgB,EAC9B,SAAS,EAAE,sBAAsB,EACjC,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,CAQtC"}
1
+ {"version":3,"file":"bandersnatch-vrf.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/safrole/bandersnatch-vrf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAS,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACjF,OAAO,EAGL,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC9B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAwB/D,QAAA,MAAM,SAAS;;;;;;;CAOd,CAAC;AAKF,eAAe,SAAS,CAAC;AAEzB,iBAAe,iBAAiB,CAC9B,YAAY,EAAE,gBAAgB,EAC9B,SAAS,EAAE,eAAe,EAC1B,SAAS,EAAE,wBAAwB,EACnC,OAAO,EAAE,SAAS,EAClB,qBAAqB,EAAE,SAAS,EAChC,gBAAgB,EAAE,wBAAwB,EAC1C,oBAAoB,EAAE,SAAS,GAC9B,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,IAAI,CAAC,CAAC,CAkBnD;AAED,iBAAe,UAAU,CACvB,YAAY,EAAE,gBAAgB,EAC9B,SAAS,EAAE,eAAe,EAC1B,SAAS,EAAE,wBAAwB,EACnC,OAAO,EAAE,SAAS,EAClB,qBAAqB,EAAE,SAAS,GAC/B,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAapC;AAED,iBAAS,iBAAiB,CACxB,YAAY,EAAE,gBAAgB,EAC9B,UAAU,EAAE,eAAe,EAAE,GAC5B,OAAO,CAAC,MAAM,CAAC,oBAAoB,EAAE,IAAI,CAAC,CAAC,CAmB7C;AAkBD,iBAAe,aAAa,CAC1B,YAAY,EAAE,gBAAgB,EAC9B,kBAAkB,EAAE,MAAM,EAC1B,SAAS,EAAE,oBAAoB,EAC/B,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,WAAW,CAAA;CAAE,EAAE,CAAC,CAqB3D;AAED,iBAAe,YAAY,CACzB,YAAY,EAAE,gBAAgB,EAC9B,SAAS,EAAE,sBAAsB,EACjC,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,SAAS,GACjB,OAAO,CAAC,MAAM,CAAC,wBAAwB,EAAE,IAAI,CAAC,CAAC,CAQjD;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAC;AAElE,iBAAe,gBAAgB,CAC7B,YAAY,EAAE,gBAAgB,EAC9B,SAAS,EAAE,sBAAsB,EACjC,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,CAQtC"}
@@ -20,6 +20,7 @@ var ResultValues;
20
20
  const ringCommitmentCache = [];
21
21
  const FUNCTIONS = {
22
22
  verifySeal,
23
+ verifyHeaderSeals,
23
24
  verifyTickets,
24
25
  getRingCommitment,
25
26
  generateSeal,
@@ -29,6 +30,16 @@ const FUNCTIONS = {
29
30
  // Ideally we would just export functions and figure out how to mock
30
31
  // properly in ESM.
31
32
  export default FUNCTIONS;
33
+ async function verifyHeaderSeals(bandersnatch, authorKey, signature, payload, encodedUnsealedHeader, entropySignature, entropyPayloadPrefix) {
34
+ const sealResult = await bandersnatch.verifyHeaderSeals(authorKey.raw, signature.raw, payload.raw, encodedUnsealedHeader.raw, entropySignature.raw, entropyPayloadPrefix.raw);
35
+ if (sealResult[RESULT_INDEX] === ResultValues.Error) {
36
+ return Result.error(null, () => "Bandersnatch VRF seal verification failed");
37
+ }
38
+ return Result.ok([
39
+ Bytes.fromBlob(sealResult.subarray(1, 33), HASH_SIZE).asOpaque(),
40
+ Bytes.fromBlob(sealResult.subarray(33), HASH_SIZE).asOpaque(),
41
+ ]);
42
+ }
32
43
  async function verifySeal(bandersnatch, authorKey, signature, payload, encodedUnsealedHeader) {
33
44
  const sealResult = await bandersnatch.verifySeal(authorKey.raw, signature.raw, payload.raw, encodedUnsealedHeader.raw);
34
45
  if (sealResult[RESULT_INDEX] === ResultValues.Error) {
@@ -27,7 +27,7 @@ describe("Bandersnatch verification", () => {
27
27
  const result = await bandersnatchVrf.getRingCommitment(await bandersnatchWasm, bandersnatchKeys);
28
28
  const expectedCommitment = Bytes.parseBytes("0x8387a131593447e4e1c3d4e220c322e42d33207fa77cd0fedb39fc3491479ca47a2d82295252e278fa3eec78185982ed82ae0c8fd691335e703d663fb5be02b3def15380789320636b2479beab5a03ccb3f0909ffea59d859fcdc7e187e45a8c92e630ae2b14e758ab0960e372172203f4c9a41777dadd529971d7ab9d23ab29fe0e9c85ec450505dde7f5ac038274cf", BANDERSNATCH_RING_ROOT_BYTES);
29
29
  assert.strictEqual(result.isOk, true);
30
- assert.deepStrictEqual(result.ok, expectedCommitment);
30
+ assert.strictEqual(result.ok.toString(), expectedCommitment.toString());
31
31
  });
32
32
  });
33
33
  describe("verifyTickets", () => {
@@ -72,7 +72,7 @@ describe("Bandersnatch verification", () => {
72
72
  ].map((x) => Bytes.parseBytes(x, HASH_SIZE));
73
73
  const result = await bandersnatchVrf.verifyTickets(await bandersnatchWasm, bandersnatchKeys.length, commitment, tickets, entropy);
74
74
  assert.strictEqual(result.every((x) => x.isValid), true);
75
- assert.deepStrictEqual(result.map((x) => x.entropyHash), expectedIds);
75
+ assert.deepStrictEqual(result.map((x) => x.entropyHash.toString()), expectedIds.map((x) => x.toString()));
76
76
  });
77
77
  it("should detect that one signature is incorrect", async () => {
78
78
  const tickets = [
@@ -97,7 +97,7 @@ describe("Bandersnatch verification", () => {
97
97
  ].map((x) => Bytes.parseBytes(x, HASH_SIZE));
98
98
  const result = await bandersnatchVrf.verifyTickets(await bandersnatchWasm, bandersnatchKeys.length, commitment, tickets, entropy);
99
99
  assert.deepStrictEqual(result.map((x) => x.isValid), [false, true, true]);
100
- assert.deepStrictEqual(result.map((x) => x.entropyHash), expectedIds);
100
+ assert.deepStrictEqual(result.map((x) => x.entropyHash.toString()), expectedIds.map((x) => x.toString()));
101
101
  });
102
102
  });
103
103
  describe("verifySeal", () => {
@@ -2,6 +2,7 @@ export declare class BandernsatchWasm {
2
2
  private constructor();
3
3
  static new(): Promise<BandernsatchWasm>;
4
4
  verifySeal(authorKey: Uint8Array, signature: Uint8Array, payload: Uint8Array, auxData: Uint8Array): Promise<Uint8Array<ArrayBufferLike>>;
5
+ verifyHeaderSeals(authorKey: Uint8Array, headerSeal: Uint8Array, headerSealPayload: Uint8Array, unsealedHeader: Uint8Array, entropySeal: Uint8Array, entropyPayloadPrefix: Uint8Array): Promise<Uint8Array<ArrayBufferLike>>;
5
6
  getRingCommitment(keys: Uint8Array): Promise<Uint8Array<ArrayBufferLike>>;
6
7
  batchVerifyTicket(ringSize: number, commitment: Uint8Array, ticketsData: Uint8Array, contextLength: number): Promise<Uint8Array<ArrayBufferLike>>;
7
8
  generateSeal(authorKey: Uint8Array, input: Uint8Array, auxData: Uint8Array): Promise<Uint8Array<ArrayBufferLike>>;
@@ -1 +1 @@
1
- {"version":3,"file":"bandersnatch-wasm.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/safrole/bandersnatch-wasm.ts"],"names":[],"mappings":"AAEA,qBAAa,gBAAgB;IAC3B,OAAO;WAEM,GAAG;IAKV,UAAU,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU;IAIjG,iBAAiB,CAAC,IAAI,EAAE,UAAU;IAIlC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM;IAI1G,YAAY,CAAC,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU;IAI1E,gBAAgB,CAAC,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU;CAGhE"}
1
+ {"version":3,"file":"bandersnatch-wasm.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/safrole/bandersnatch-wasm.ts"],"names":[],"mappings":"AAEA,qBAAa,gBAAgB;IAC3B,OAAO;WAEM,GAAG;IAKV,UAAU,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU;IAIjG,iBAAiB,CACrB,SAAS,EAAE,UAAU,EACrB,UAAU,EAAE,UAAU,EACtB,iBAAiB,EAAE,UAAU,EAC7B,cAAc,EAAE,UAAU,EAC1B,WAAW,EAAE,UAAU,EACvB,oBAAoB,EAAE,UAAU;IAY5B,iBAAiB,CAAC,IAAI,EAAE,UAAU;IAIlC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM;IAI1G,YAAY,CAAC,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU;IAI1E,gBAAgB,CAAC,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU;CAGhE"}
@@ -6,18 +6,21 @@ export class BandernsatchWasm {
6
6
  return new BandernsatchWasm();
7
7
  }
8
8
  async verifySeal(authorKey, signature, payload, auxData) {
9
- return bandersnatchWasm.verify_seal(authorKey, signature, payload, auxData);
9
+ return bandersnatchWasm.verifySeal(authorKey, signature, payload, auxData);
10
+ }
11
+ async verifyHeaderSeals(authorKey, headerSeal, headerSealPayload, unsealedHeader, entropySeal, entropyPayloadPrefix) {
12
+ return bandersnatchWasm.verifyHeaderSeals(authorKey, headerSeal, headerSealPayload, unsealedHeader, entropySeal, entropyPayloadPrefix);
10
13
  }
11
14
  async getRingCommitment(keys) {
12
- return bandersnatchWasm.ring_commitment(keys);
15
+ return bandersnatchWasm.ringCommitment(keys);
13
16
  }
14
17
  async batchVerifyTicket(ringSize, commitment, ticketsData, contextLength) {
15
- return bandersnatchWasm.batch_verify_tickets(ringSize, commitment, ticketsData, contextLength);
18
+ return bandersnatchWasm.batchVerifyTickets(ringSize, commitment, ticketsData, contextLength);
16
19
  }
17
20
  async generateSeal(authorKey, input, auxData) {
18
- return bandersnatchWasm.generate_seal(authorKey, input, auxData);
21
+ return bandersnatchWasm.generateSeal(authorKey, input, auxData);
19
22
  }
20
23
  async getVrfOutputHash(authorKey, input) {
21
- return bandersnatchWasm.vrf_output_hash(authorKey, input);
24
+ return bandersnatchWasm.vrfOutputHash(authorKey, input);
22
25
  }
23
26
  }
@@ -8,8 +8,7 @@ export declare enum SafroleSealError {
8
8
  InvalidValidatorIndex = 0,
9
9
  InvalidValidator = 1,
10
10
  InvalidTicket = 2,
11
- IncorrectSeal = 3,
12
- IncorrectEntropySource = 4
11
+ IncorrectSeal = 3
13
12
  }
14
13
  export type SafroleSealState = Pick<State, "currentValidatorData" | "sealingKeySeries"> & {
15
14
  currentEntropy: EntropyHash;
@@ -22,7 +21,6 @@ export declare class SafroleSeal {
22
21
  * hence the state is passed as an argument for more control.
23
22
  */
24
23
  verifyHeaderSeal(headerView: HeaderView, state: SafroleSealState): Promise<Result<EntropyHash, SafroleSealError>>;
25
- private verifySeal;
26
24
  /** Regular (non-fallback) mode of Safrole. */
27
25
  verifySealWithTicket(tickets: PerEpochBlock<Ticket>, timeSlot: TimeSlot, entropy: EntropyHash, validatorData: ValidatorData, headerView: HeaderView): Promise<Result<EntropyHash, SafroleSealError>>;
28
26
  /** Fallback mode of Safrole. */
@@ -1 +1 @@
1
- {"version":3,"file":"safrole-seal.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/safrole/safrole-seal.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAEhB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAE1D,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACjF,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAE7D,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAG1D,oBAAY,gBAAgB;IAC1B,qBAAqB,IAAI;IACzB,gBAAgB,IAAI;IACpB,aAAa,IAAI;IACjB,aAAa,IAAI;IACjB,sBAAsB,IAAI;CAC3B;AAED,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,EAAE,sBAAsB,GAAG,kBAAkB,CAAC,GAAG;IACxF,cAAc,EAAE,WAAW,CAAC;CAC7B,CAAC;AAIF,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,YAAY;gBAAZ,YAAY,GAAE,OAAO,CAAC,gBAAgB,CAA0B;IAC7F;;;OAGG;IACG,gBAAgB,CACpB,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;YA6BnC,UAAU;IA0BxB,8CAA8C;IACxC,oBAAoB,CACxB,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,EAC9B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,WAAW,EACpB,aAAa,EAAE,aAAa,EAC5B,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;IA4BjD,gCAAgC;IAC1B,kBAAkB,CACtB,IAAI,EAAE,aAAa,CAAC,eAAe,CAAC,EACpC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,aAAa,EACxB,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;CA2BlD"}
1
+ {"version":3,"file":"safrole-seal.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/safrole/safrole-seal.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAEhB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAE1D,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACjF,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAE7D,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAG1D,oBAAY,gBAAgB;IAC1B,qBAAqB,IAAI;IACzB,gBAAgB,IAAI;IACpB,aAAa,IAAI;IACjB,aAAa,IAAI;CAClB;AAED,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,EAAE,sBAAsB,GAAG,kBAAkB,CAAC,GAAG;IACxF,cAAc,EAAE,WAAW,CAAC;CAC7B,CAAC;AAIF,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,YAAY;gBAAZ,YAAY,GAAE,OAAO,CAAC,gBAAgB,CAA0B;IAC7F;;;OAGG;IACG,gBAAgB,CACpB,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;IAuBjD,8CAA8C;IACxC,oBAAoB,CACxB,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,EAC9B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,WAAW,EACpB,aAAa,EAAE,aAAa,EAC5B,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;IAmCjD,gCAAgC;IAC1B,kBAAkB,CACtB,IAAI,EAAE,aAAa,CAAC,eAAe,CAAC,EACpC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,aAAa,EACxB,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;CA8BlD"}
@@ -12,7 +12,6 @@ export var SafroleSealError;
12
12
  SafroleSealError[SafroleSealError["InvalidValidator"] = 1] = "InvalidValidator";
13
13
  SafroleSealError[SafroleSealError["InvalidTicket"] = 2] = "InvalidTicket";
14
14
  SafroleSealError[SafroleSealError["IncorrectSeal"] = 3] = "IncorrectSeal";
15
- SafroleSealError[SafroleSealError["IncorrectEntropySource"] = 4] = "IncorrectEntropySource";
16
15
  })(SafroleSealError || (SafroleSealError = {}));
17
16
  const BANDERSNATCH_ZERO_KEY = Bytes.zero(BANDERSNATCH_KEY_BYTES).asOpaque();
18
17
  export class SafroleSeal {
@@ -25,21 +24,6 @@ export class SafroleSeal {
25
24
  * hence the state is passed as an argument for more control.
26
25
  */
27
26
  async verifyHeaderSeal(headerView, state) {
28
- const sealResult = await this.verifySeal(headerView, state);
29
- if (sealResult.isError) {
30
- return sealResult;
31
- }
32
- // verify entropySource
33
- const payload = BytesBlob.blobFromParts(JAM_ENTROPY, sealResult.ok.raw);
34
- const blockAuthorIndex = headerView.bandersnatchBlockAuthorIndex.materialize();
35
- const blockAuthorKey = state.currentValidatorData.at(blockAuthorIndex)?.bandersnatch;
36
- const entropySourceResult = await bandersnatchVrf.verifySeal(await this.bandersnatch, blockAuthorKey ?? BANDERSNATCH_ZERO_KEY, headerView.entropySource.materialize(), payload, BytesBlob.blobFromNumbers([]));
37
- if (entropySourceResult.isError) {
38
- return Result.error(SafroleSealError.IncorrectEntropySource, () => "Safrole: incorrect entropy source in header seal");
39
- }
40
- return Result.ok(entropySourceResult.ok);
41
- }
42
- async verifySeal(headerView, state) {
43
27
  // we use transitioned keys already
44
28
  const validatorIndex = headerView.bandersnatchBlockAuthorIndex.materialize();
45
29
  const authorKeys = state.currentValidatorData.at(validatorIndex);
@@ -58,17 +42,21 @@ export class SafroleSeal {
58
42
  async verifySealWithTicket(tickets, timeSlot, entropy, validatorData, headerView) {
59
43
  const index = timeSlot % tickets.length;
60
44
  const ticket = tickets.at(index);
61
- const payload = BytesBlob.blobFromParts(JAM_TICKET_SEAL, entropy.raw, new Uint8Array([ticket?.attempt ?? 0]));
62
- // verify seal correctness
45
+ if (ticket === undefined) {
46
+ return Result.error(SafroleSealError.IncorrectSeal, () => "Safrole: missing ticket");
47
+ }
48
+ const payload = BytesBlob.blobFromParts(JAM_TICKET_SEAL, entropy.raw, new Uint8Array([ticket.attempt]));
49
+ // verify seal and entropy source correctness
63
50
  const authorKey = validatorData.bandersnatch;
64
- const result = await bandersnatchVrf.verifySeal(await this.bandersnatch, authorKey ?? BANDERSNATCH_ZERO_KEY, headerView.seal.materialize(), payload, encodeUnsealedHeader(headerView));
51
+ const result = await bandersnatchVrf.verifyHeaderSeals(await this.bandersnatch, authorKey ?? BANDERSNATCH_ZERO_KEY, headerView.seal.materialize(), payload, encodeUnsealedHeader(headerView), headerView.entropySource.materialize(), BytesBlob.blobFrom(JAM_ENTROPY));
65
52
  if (result.isError) {
66
53
  return Result.error(SafroleSealError.IncorrectSeal, () => "Safrole: incorrect seal with ticket");
67
54
  }
68
- if (ticket === undefined || !ticket.id.isEqualTo(result.ok)) {
69
- return Result.error(SafroleSealError.InvalidTicket, () => `Safrole: invalid ticket, expected ${ticket?.id} got ${result.ok}`);
55
+ const [sealOutput, entropyOutput] = result.ok;
56
+ if (!ticket.id.isEqualTo(sealOutput)) {
57
+ return Result.error(SafroleSealError.InvalidTicket, () => `Safrole: invalid ticket, expected ${ticket.id} got ${sealOutput}`);
70
58
  }
71
- return Result.ok(result.ok);
59
+ return Result.ok(entropyOutput);
72
60
  }
73
61
  /** Fallback mode of Safrole. */
74
62
  async verifySealWithKeys(keys, timeSlot, entropy, authorKey, headerView) {
@@ -78,12 +66,13 @@ export class SafroleSeal {
78
66
  if (sealingKey === undefined || !sealingKey.isEqualTo(authorBandersnatchKey)) {
79
67
  return Result.error(SafroleSealError.InvalidValidator, () => `Invalid Validator. Expected: ${sealingKey}, got: ${authorKey.bandersnatch}`);
80
68
  }
81
- // verify seal correctness
69
+ // verify seal and entropy source correctness
82
70
  const payload = BytesBlob.blobFromParts(JAM_FALLBACK_SEAL, entropy.raw);
83
- const result = await bandersnatchVrf.verifySeal(await this.bandersnatch, authorBandersnatchKey, headerView.seal.materialize(), payload, encodeUnsealedHeader(headerView));
71
+ const result = await bandersnatchVrf.verifyHeaderSeals(await this.bandersnatch, authorBandersnatchKey, headerView.seal.materialize(), payload, encodeUnsealedHeader(headerView), headerView.entropySource.materialize(), BytesBlob.blobFrom(JAM_ENTROPY));
84
72
  if (result.isError) {
85
73
  return Result.error(SafroleSealError.IncorrectSeal, () => "Safrole: incorrect seal with keys");
86
74
  }
87
- return Result.ok(result.ok);
75
+ const [_, entropyOutput] = result.ok;
76
+ return Result.ok(entropyOutput);
88
77
  }
89
78
  }
@@ -35,11 +35,8 @@ describe("Safrole Seal verification", () => {
35
35
  sealingKeySeries: SEALING_KEYS,
36
36
  currentEntropy: Bytes.parseBytes("0x405c80c1f6a2d5a0f8dbc56996f04230221100d9500244648f02a795d7850eac", HASH_SIZE).asOpaque(),
37
37
  });
38
- assert.deepStrictEqual(result, {
39
- isError: false,
40
- isOk: true,
41
- ok: Bytes.parseBytes("0xc13af3d0cbdb7174590f34518e3beb05708935ceaee242e7ba11a94ca87bd007", HASH_SIZE).asOpaque(),
42
- });
38
+ assert.strictEqual(result.isOk, true);
39
+ assert.strictEqual(result.ok.toString(), "0xc13af3d0cbdb7174590f34518e3beb05708935ceaee242e7ba11a94ca87bd007");
43
40
  });
44
41
  it("should verify a valid ticket seal and entropySource", async () => {
45
42
  // based on test-vectors/w3f-davxy_070/traces/safrole/00000002.json
@@ -63,11 +60,8 @@ describe("Safrole Seal verification", () => {
63
60
  sealingKeySeries: SEALING_KEYS,
64
61
  currentEntropy: Bytes.parseBytes("0x405c80c1f6a2d5a0f8dbc56996f04230221100d9500244648f02a795d7850eac", HASH_SIZE).asOpaque(),
65
62
  });
66
- assert.deepStrictEqual(result, {
67
- isError: false,
68
- isOk: true,
69
- ok: Bytes.parseBytes("0xc13af3d0cbdb7174590f34518e3beb05708935ceaee242e7ba11a94ca87bd007", HASH_SIZE).asOpaque(),
70
- });
63
+ assert.strictEqual(result.isOk, true);
64
+ assert.strictEqual(result.ok.toString(), "0xc13af3d0cbdb7174590f34518e3beb05708935ceaee242e7ba11a94ca87bd007");
71
65
  });
72
66
  });
73
67
  const TEST_VALIDATOR_KEYS = tryAsPerValidator([
@@ -1 +1 @@
1
- {"version":3,"file":"pvm-executor.d.ts","sourceRoot":"","sources":["../../../../../../packages/jam/transition/accumulate/pvm-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAc,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0DAA0D,CAAC;AAM7F,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,0BAA0B,CAAC;AAkBpD,KAAK,+BAA+B,GAAG;IACrC,YAAY,EAAE,YAAY,CAAC;IAC3B,kBAAkB,EAAE,OAAO,CAAC,mBAAmB,CAAC;IAChD,oBAAoB,EAAE,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC,cAAc,GAAG,OAAO,CAAC,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CACpH,CAAC;AAEF,KAAK,+BAA+B,GAAG;IACrC,YAAY,EAAE,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC,cAAc,GAAG,OAAO,CAAC,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAC3G,kBAAkB,EAAE,OAAO,CAAC,mBAAmB,CAAC;CACjD,CAAC;AASF;;GAEG;AACH,qBAAa,WAAW;IAKpB,OAAO,CAAC,WAAW;IAEnB,OAAO,CAAC,UAAU;IANpB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAuB;IAC3C,OAAO,CAAC,SAAS,CAAY;IAE7B,OAAO;mBAac,cAAc;IAInC,8CAA8C;IAC9C,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAsBzC,6CAA6C;IAC7C,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAazC;;;;;;OAMG;IACG,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG;;;;;;;;;;;;;IAInC,yEAAyE;WAC5D,wBAAwB,CACnC,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,SAAS,EACtB,aAAa,EAAE,+BAA+B,EAC9C,SAAS,EAAE,SAAS,EACpB,GAAG,EAAE,UAAU;IAOjB,0EAA0E;WAC7D,wBAAwB,CACnC,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,SAAS,EACtB,aAAa,EAAE,+BAA+B,EAC9C,GAAG,EAAE,UAAU;CAMlB"}
1
+ {"version":3,"file":"pvm-executor.d.ts","sourceRoot":"","sources":["../../../../../../packages/jam/transition/accumulate/pvm-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAc,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0DAA0D,CAAC;AAM7F,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,0BAA0B,CAAC;AAkBpD,KAAK,+BAA+B,GAAG;IACrC,YAAY,EAAE,YAAY,CAAC;IAC3B,kBAAkB,EAAE,OAAO,CAAC,mBAAmB,CAAC;IAChD,oBAAoB,EAAE,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC,cAAc,GAAG,OAAO,CAAC,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CACpH,CAAC;AAEF,KAAK,+BAA+B,GAAG;IACrC,YAAY,EAAE,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC,cAAc,GAAG,OAAO,CAAC,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAC3G,kBAAkB,EAAE,OAAO,CAAC,mBAAmB,CAAC;CACjD,CAAC;AASF;;GAEG;AACH,qBAAa,WAAW;IAKpB,OAAO,CAAC,WAAW;IAEnB,OAAO,CAAC,UAAU;IANpB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoB;IACxC,OAAO,CAAC,SAAS,CAAY;IAE7B,OAAO;mBAac,cAAc;IAInC,8CAA8C;IAC9C,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAsBzC,6CAA6C;IAC7C,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAazC;;;;;;OAMG;IACG,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG;;;;;;;;;;;;;IAInC,yEAAyE;WAC5D,wBAAwB,CACnC,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,SAAS,EACtB,aAAa,EAAE,+BAA+B,EAC9C,SAAS,EAAE,SAAS,EACpB,GAAG,EAAE,UAAU;IAOjB,0EAA0E;WAC7D,wBAAwB,CACnC,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,SAAS,EACtB,aAAa,EAAE,+BAA+B,EAC9C,GAAG,EAAE,UAAU;CAMlB"}
@@ -1,6 +1,6 @@
1
1
  import { accumulate, general } from "#@typeberry/jam-host-calls";
2
2
  import { tryAsProgramCounter, } from "#@typeberry/jam-host-calls/externalities/refine-externalities.js";
3
- import { HostCalls, PvmHostCallExtension, PvmInstanceManager } from "#@typeberry/pvm-host-calls";
3
+ import { HostCalls, HostCallsExecutor, PvmInstanceManager } from "#@typeberry/pvm-host-calls";
4
4
  const ACCUMULATE_HOST_CALL_CLASSES = [
5
5
  accumulate.Bless,
6
6
  accumulate.Assign,
@@ -38,7 +38,7 @@ export class PvmExecutor {
38
38
  missing: new general.Missing(),
39
39
  handlers: hostCallHandlers,
40
40
  });
41
- this.pvm = new PvmHostCallExtension(pvmInstanceManager, this.hostCalls);
41
+ this.pvm = new HostCallsExecutor(pvmInstanceManager, this.hostCalls);
42
42
  }
43
43
  static async prepareBackend(pvm) {
44
44
  return PvmInstanceManager.new(pvm);
@@ -1 +1 @@
1
- {"version":3,"file":"disputes.d.ts","sourceRoot":"","sources":["../../../../../../packages/jam/transition/disputes/disputes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAGtE,OAAO,EAAkB,OAAO,EAA0B,MAAM,wBAAwB,CAAC;AACzF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAQ/C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAc9E,qBAAa,QAAQ;IAEjB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO;aACR,KAAK,EAAE,aAAa;gBAFnB,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,OAAO,EACjB,KAAK,EAAE,aAAa;IAGtC,OAAO,CAAC,cAAc;IAoDtB,OAAO,CAAC,YAAY;IA8DpB,OAAO,CAAC,cAAc;IA6DtB,OAAO,CAAC,qBAAqB;IAoB7B,OAAO,CAAC,4BAA4B;IAsBpC,OAAO,CAAC,yBAAyB;IAoCjC,OAAO,CAAC,0BAA0B;IA0BlC;;;;OAIG;IACH,OAAO,CAAC,wBAAwB;IAuBhC,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,yBAAyB;IAWjC,OAAO,CAAC,+BAA+B;IAoCvC,OAAO,CAAC,gBAAgB;IAWxB;;OAEG;IACG,UAAU,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CACpD,MAAM,CACJ;QACE,aAAa,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACnC,WAAW,EAAE,mBAAmB,CAAC;KAClC,EACD,iBAAiB,CAClB,CACF;CAwCF"}
1
+ {"version":3,"file":"disputes.d.ts","sourceRoot":"","sources":["../../../../../../packages/jam/transition/disputes/disputes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAGtE,OAAO,EAAkB,OAAO,EAA0B,MAAM,wBAAwB,CAAC;AACzF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAQ/C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAc9E,qBAAa,QAAQ;IAEjB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO;aACR,KAAK,EAAE,aAAa;gBAFnB,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,OAAO,EACjB,KAAK,EAAE,aAAa;IAGtC,OAAO,CAAC,cAAc;IAoDtB,OAAO,CAAC,YAAY;IA8DpB,OAAO,CAAC,cAAc;IA6DtB,OAAO,CAAC,qBAAqB;IAoB7B,OAAO,CAAC,4BAA4B;IAsBpC,OAAO,CAAC,yBAAyB;IAoCjC,OAAO,CAAC,0BAA0B;IA0BlC;;;;OAIG;IACH,OAAO,CAAC,wBAAwB;IAuBhC,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,yBAAyB;IAWjC,OAAO,CAAC,+BAA+B;IAoCvC,OAAO,CAAC,gBAAgB;IAaxB;;OAEG;IACG,UAAU,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CACpD,MAAM,CACJ;QACE,aAAa,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACnC,WAAW,EAAE,mBAAmB,CAAC;KAClC,EACD,iBAAiB,CAClB,CACF;CAwCF"}
@@ -291,10 +291,11 @@ export class Disputes {
291
291
  const punishSetKeys = this.state.disputesRecords.punishSet;
292
292
  const currentValidatorKeys = this.state.currentValidatorData.map((v) => v.ed25519);
293
293
  const previousValidatorKeys = this.state.previousValidatorData.map((v) => v.ed25519);
294
- const allValidatorKeys = currentValidatorKeys
295
- .concat(previousValidatorKeys)
296
- .filter((key) => !punishSetKeys.has(key));
297
- return HashSet.from(allValidatorKeys);
294
+ const allValidatorKeysSet = HashSet.from(currentValidatorKeys.concat(previousValidatorKeys));
295
+ for (const key of punishSetKeys) {
296
+ allValidatorKeysSet.delete(key);
297
+ }
298
+ return allValidatorKeysSet;
298
299
  }
299
300
  /**
300
301
  * Transition the disputes and return a list of offenders.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typeberry/block-authorship",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "A test block generator simulating blocks received over the network.",
5
5
  "main": "index.ts",
6
6
  "dependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typeberry/importer",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "A JAM block importer queue.",
5
5
  "main": "index.ts",
6
6
  "dependencies": {