@typeberry/lib 0.5.2 → 0.5.3-c402c56
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.
- package/package.json +2 -2
- package/packages/core/collections/blob-dictionary.d.ts.map +1 -1
- package/packages/core/collections/blob-dictionary.js +3 -3
- package/packages/core/crypto/bandersnatch.d.ts +2 -1
- package/packages/core/crypto/bandersnatch.d.ts.map +1 -1
- package/packages/core/crypto/bandersnatch.js +9 -2
- package/packages/core/crypto/key-derivation.test.js +8 -7
- package/packages/core/networking/package.json +1 -1
- package/packages/core/pvm-host-calls/bin.js +6 -6
- package/packages/core/pvm-host-calls/ecalli-io-tracker.d.ts +32 -0
- package/packages/core/pvm-host-calls/ecalli-io-tracker.d.ts.map +1 -0
- package/packages/core/pvm-host-calls/ecalli-io-tracker.js +14 -0
- package/packages/core/pvm-host-calls/ecalli-trace-logger.d.ts +139 -0
- package/packages/core/pvm-host-calls/ecalli-trace-logger.d.ts.map +1 -0
- package/packages/core/pvm-host-calls/ecalli-trace-logger.js +209 -0
- package/packages/core/pvm-host-calls/ecalli-trace-logger.test.d.ts +2 -0
- package/packages/core/pvm-host-calls/ecalli-trace-logger.test.d.ts.map +1 -0
- package/packages/core/pvm-host-calls/ecalli-trace-logger.test.js +231 -0
- package/packages/core/pvm-host-calls/host-call-memory.d.ts +2 -0
- package/packages/core/pvm-host-calls/host-call-memory.d.ts.map +1 -1
- package/packages/core/pvm-host-calls/host-call-memory.js +12 -2
- package/packages/core/pvm-host-calls/host-call-registers.d.ts +6 -0
- package/packages/core/pvm-host-calls/host-call-registers.d.ts.map +1 -1
- package/packages/core/pvm-host-calls/host-call-registers.js +24 -0
- package/packages/core/pvm-host-calls/host-calls-executor.d.ts +31 -0
- package/packages/core/pvm-host-calls/host-calls-executor.d.ts.map +1 -0
- package/packages/core/pvm-host-calls/host-calls-executor.js +137 -0
- package/packages/core/pvm-host-calls/host-calls.d.ts +20 -26
- package/packages/core/pvm-host-calls/host-calls.d.ts.map +1 -1
- package/packages/core/pvm-host-calls/host-calls.js +40 -112
- package/packages/core/pvm-host-calls/index.d.ts +7 -6
- package/packages/core/pvm-host-calls/index.d.ts.map +1 -1
- package/packages/core/pvm-host-calls/index.js +7 -6
- package/packages/core/pvm-host-calls/{interpreter-instance-manager.d.ts → pvm-instance-manager.d.ts} +3 -3
- package/packages/core/pvm-host-calls/pvm-instance-manager.d.ts.map +1 -0
- package/packages/core/pvm-host-calls/{interpreter-instance-manager.js → pvm-instance-manager.js} +2 -2
- package/packages/core/telemetry/package.json +1 -1
- package/packages/jam/node/main-importer.d.ts.map +1 -1
- package/packages/jam/node/main-importer.js +3 -1
- package/packages/jam/node/package.json +1 -1
- package/packages/jam/safrole/bandersnatch-vrf.d.ts +2 -0
- package/packages/jam/safrole/bandersnatch-vrf.d.ts.map +1 -1
- package/packages/jam/safrole/bandersnatch-vrf.js +11 -0
- package/packages/jam/safrole/bandersnatch-vrf.test.js +3 -3
- package/packages/jam/safrole/bandersnatch-wasm.d.ts +1 -0
- package/packages/jam/safrole/bandersnatch-wasm.d.ts.map +1 -1
- package/packages/jam/safrole/bandersnatch-wasm.js +8 -5
- package/packages/jam/safrole/safrole-seal.d.ts +1 -3
- package/packages/jam/safrole/safrole-seal.d.ts.map +1 -1
- package/packages/jam/safrole/safrole-seal.js +14 -25
- package/packages/jam/safrole/safrole-seal.test.js +4 -10
- package/packages/jam/transition/accumulate/pvm-executor.d.ts.map +1 -1
- package/packages/jam/transition/accumulate/pvm-executor.js +2 -2
- package/packages/jam/transition/disputes/disputes.d.ts.map +1 -1
- package/packages/jam/transition/disputes/disputes.js +5 -4
- package/packages/workers/block-authorship/package.json +1 -1
- package/packages/workers/importer/package.json +1 -1
- package/packages/core/pvm-host-calls/host-calls-manager.d.ts +0 -23
- package/packages/core/pvm-host-calls/host-calls-manager.d.ts.map +0 -1
- package/packages/core/pvm-host-calls/host-calls-manager.js +0 -44
- package/packages/core/pvm-host-calls/interpreter-instance-manager.d.ts.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typeberry/lib",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3-c402c56",
|
|
4
4
|
"description": "Typeberry Library",
|
|
5
5
|
"main": "./bin/lib/index.js",
|
|
6
6
|
"types": "./bin/lib/index.d.ts",
|
|
@@ -258,7 +258,7 @@
|
|
|
258
258
|
"#@typeberry/state-vectors/*": "./packages/jam/state-vectors/*"
|
|
259
259
|
},
|
|
260
260
|
"dependencies": {
|
|
261
|
-
"@fluffylabs/anan-as": "^1.1.
|
|
261
|
+
"@fluffylabs/anan-as": "^1.1.5",
|
|
262
262
|
"@noble/ed25519": "2.2.3",
|
|
263
263
|
"@typeberry/native": "0.0.4-4c0cd28",
|
|
264
264
|
"hash-wasm": "4.12.0"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blob-dictionary.d.ts","sourceRoot":"","sources":["../../../../../packages/core/collections/blob-dictionary.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"blob-dictionary.d.ts","sourceRoot":"","sources":["../../../../../packages/core/collections/blob-dictionary.ts"],"names":[],"mappings":"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"}
|
|
@@ -172,14 +172,14 @@ export class BlobDictionary extends WithDebug {
|
|
|
172
172
|
const pathChunksGenerator = key.chunks(CHUNK_SIZE);
|
|
173
173
|
let depth = 0;
|
|
174
174
|
while (node !== undefined) {
|
|
175
|
-
const maybePathChunk = pathChunksGenerator.next().value;
|
|
176
175
|
if (node.children instanceof ListChildren) {
|
|
177
|
-
const subkey = BytesBlob.blobFrom(key.raw.subarray(depth * CHUNK_SIZE));
|
|
176
|
+
const subkey = depth === 0 ? key : BytesBlob.blobFrom(key.raw.subarray(depth * CHUNK_SIZE));
|
|
178
177
|
const child = node.children.find(subkey);
|
|
179
178
|
if (child !== null) {
|
|
180
179
|
return child.value;
|
|
181
180
|
}
|
|
182
181
|
}
|
|
182
|
+
const maybePathChunk = pathChunksGenerator.next().value;
|
|
183
183
|
if (maybePathChunk === undefined) {
|
|
184
184
|
return node.getLeaf()?.value;
|
|
185
185
|
}
|
|
@@ -363,7 +363,7 @@ export class ListChildren {
|
|
|
363
363
|
children = [];
|
|
364
364
|
constructor() { }
|
|
365
365
|
find(key) {
|
|
366
|
-
const result = this.children.find((item) => item[0].isEqualTo(key));
|
|
366
|
+
const result = this.children.find((item) => item[0] === key || item[0].isEqualTo(key));
|
|
367
367
|
if (result !== undefined) {
|
|
368
368
|
return result[1];
|
|
369
369
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Bytes } from "#@typeberry/bytes";
|
|
2
|
-
import { type Opaque } from "#@typeberry/utils";
|
|
2
|
+
import { OK, type Opaque, Result } from "#@typeberry/utils";
|
|
3
3
|
/** Bandersnatch public key size. */
|
|
4
4
|
export declare const BANDERSNATCH_KEY_BYTES = 32;
|
|
5
5
|
export type BANDERSNATCH_KEY_BYTES = typeof BANDERSNATCH_KEY_BYTES;
|
|
@@ -47,4 +47,5 @@ export type BandersnatchProof = Opaque<Bytes<BANDERSNATCH_PROOF_BYTES>, "Banders
|
|
|
47
47
|
export type BlsKey = Opaque<Bytes<BLS_KEY_BYTES>, "BlsKey">;
|
|
48
48
|
/** Derive a Bandersnatch public key from a seed. */
|
|
49
49
|
export declare function publicKey(seed: Uint8Array): BandersnatchKey;
|
|
50
|
+
export declare function checkNativeBindings(): Result<OK, string>;
|
|
50
51
|
//# sourceMappingURL=bandersnatch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bandersnatch.d.ts","sourceRoot":"","sources":["../../../../../packages/core/crypto/bandersnatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,OAAO,EAAS,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"bandersnatch.d.ts","sourceRoot":"","sources":["../../../../../packages/core/crypto/bandersnatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,OAAO,EAAS,EAAE,EAAE,KAAK,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAElE,oCAAoC;AACpC,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,MAAM,MAAM,sBAAsB,GAAG,OAAO,sBAAsB,CAAC;AAEnE,sCAAsC;AACtC,eAAO,MAAM,gCAAgC,KAAK,CAAC;AACnD,MAAM,MAAM,gCAAgC,GAAG,OAAO,gCAAgC,CAAC;AAEvF,wCAAwC;AACxC,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAChD,MAAM,MAAM,4BAA4B,GAAG,OAAO,4BAA4B,CAAC;AAE/E,8BAA8B;AAC9B,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAC5C,MAAM,MAAM,wBAAwB,GAAG,OAAO,wBAAwB,CAAC;AAEvE,2BAA2B;AAC3B,eAAO,MAAM,aAAa,MAAM,CAAC;AACjC,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,CAAC;AAEjD;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,EAAE,iBAAiB,CAAC,CAAC;AAEvF;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,KAAK,CAAC,4BAA4B,CAAC,EAAE,sBAAsB,CAAC,CAAC;AAEvG;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,EAAE,0BAA0B,CAAC,CAAC;AAEnH;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,EAAE,2BAA2B,CAAC,CAAC;AAErG;;;;GAIG;AACH,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,CAAC;AAE5D,oDAAoD;AACpD,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,eAAe,CAM3D;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAMxD"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Bytes } from "#@typeberry/bytes";
|
|
2
2
|
import { bandersnatch } from "@typeberry/native";
|
|
3
|
-
import { check } from "#@typeberry/utils";
|
|
3
|
+
import { check, OK, Result } from "#@typeberry/utils";
|
|
4
4
|
/** Bandersnatch public key size. */
|
|
5
5
|
export const BANDERSNATCH_KEY_BYTES = 32;
|
|
6
6
|
/** Bandersnatch VRF signature size */
|
|
@@ -13,7 +13,14 @@ export const BANDERSNATCH_PROOF_BYTES = 784;
|
|
|
13
13
|
export const BLS_KEY_BYTES = 144;
|
|
14
14
|
/** Derive a Bandersnatch public key from a seed. */
|
|
15
15
|
export function publicKey(seed) {
|
|
16
|
-
const key = bandersnatch.
|
|
16
|
+
const key = bandersnatch.derivePublicKey(seed);
|
|
17
17
|
check `${key[0] === 0} Invalid Bandersnatch public key derived from seed`;
|
|
18
18
|
return Bytes.fromBlob(key.subarray(1), BANDERSNATCH_KEY_BYTES).asOpaque();
|
|
19
19
|
}
|
|
20
|
+
export function checkNativeBindings() {
|
|
21
|
+
if (bandersnatch.isNativeBinding()) {
|
|
22
|
+
return Result.ok(OK);
|
|
23
|
+
}
|
|
24
|
+
const error = "native binding error";
|
|
25
|
+
return Result.error(bandersnatch.getNativeBindingError() ?? error, () => error);
|
|
26
|
+
}
|
|
@@ -3,6 +3,7 @@ import { before, describe, it } from "node:test";
|
|
|
3
3
|
import { Bytes } from "#@typeberry/bytes";
|
|
4
4
|
import { Blake2b } from "#@typeberry/hash";
|
|
5
5
|
import { tryAsU32 } from "#@typeberry/numbers";
|
|
6
|
+
import { deepEqual } from "#@typeberry/utils";
|
|
6
7
|
import { initWasm } from "./index.js";
|
|
7
8
|
import { deriveBandersnatchPublicKey, deriveBandersnatchSecretKey, deriveEd25519PublicKey, deriveEd25519SecretKey, SEED_SIZE, trivialSeed, } from "./key-derivation.js";
|
|
8
9
|
before(initWasm);
|
|
@@ -183,42 +184,42 @@ describe("Key Derivation: Bandersnatch public key", () => {
|
|
|
183
184
|
const seed = trivialSeed(tryAsU32(0));
|
|
184
185
|
const bandersnatch_seed = deriveBandersnatchSecretKey(seed, blake2b);
|
|
185
186
|
const bandersnatch_public_key = deriveBandersnatchPublicKey(bandersnatch_seed);
|
|
186
|
-
|
|
187
|
+
deepEqual(bandersnatch_public_key, Bytes.fromBlob(Bytes.parseBlobNoPrefix("ff71c6c03ff88adb5ed52c9681de1629a54e702fc14729f6b50d2f0a76f185b3").raw, SEED_SIZE).asOpaque());
|
|
187
188
|
});
|
|
188
189
|
it("should derive from seed: 1", () => {
|
|
189
190
|
const seed = trivialSeed(tryAsU32(1));
|
|
190
191
|
const bandersnatch_seed = deriveBandersnatchSecretKey(seed, blake2b);
|
|
191
192
|
const bandersnatch_public_key = deriveBandersnatchPublicKey(bandersnatch_seed);
|
|
192
|
-
|
|
193
|
+
deepEqual(bandersnatch_public_key, Bytes.fromBlob(Bytes.parseBlobNoPrefix("dee6d555b82024f1ccf8a1e37e60fa60fd40b1958c4bb3006af78647950e1b91").raw, SEED_SIZE).asOpaque());
|
|
193
194
|
});
|
|
194
195
|
it("should derive from seed: 2", () => {
|
|
195
196
|
const seed = trivialSeed(tryAsU32(2));
|
|
196
197
|
const bandersnatch_seed = deriveBandersnatchSecretKey(seed, blake2b);
|
|
197
198
|
const bandersnatch_public_key = deriveBandersnatchPublicKey(bandersnatch_seed);
|
|
198
|
-
|
|
199
|
+
deepEqual(bandersnatch_public_key, Bytes.fromBlob(Bytes.parseBlobNoPrefix("9326edb21e5541717fde24ec085000b28709847b8aab1ac51f84e94b37ca1b66").raw, SEED_SIZE).asOpaque());
|
|
199
200
|
});
|
|
200
201
|
it("should derive from seed: 3", () => {
|
|
201
202
|
const seed = trivialSeed(tryAsU32(3));
|
|
202
203
|
const bandersnatch_seed = deriveBandersnatchSecretKey(seed, blake2b);
|
|
203
204
|
const bandersnatch_public_key = deriveBandersnatchPublicKey(bandersnatch_seed);
|
|
204
|
-
|
|
205
|
+
deepEqual(bandersnatch_public_key, Bytes.fromBlob(Bytes.parseBlobNoPrefix("0746846d17469fb2f95ef365efcab9f4e22fa1feb53111c995376be8019981cc").raw, SEED_SIZE).asOpaque());
|
|
205
206
|
});
|
|
206
207
|
it("should derive from seed: 4", () => {
|
|
207
208
|
const seed = trivialSeed(tryAsU32(4));
|
|
208
209
|
const bandersnatch_seed = deriveBandersnatchSecretKey(seed, blake2b);
|
|
209
210
|
const bandersnatch_public_key = deriveBandersnatchPublicKey(bandersnatch_seed);
|
|
210
|
-
|
|
211
|
+
deepEqual(bandersnatch_public_key, Bytes.fromBlob(Bytes.parseBlobNoPrefix("151e5c8fe2b9d8a606966a79edd2f9e5db47e83947ce368ccba53bf6ba20a40b").raw, SEED_SIZE).asOpaque());
|
|
211
212
|
});
|
|
212
213
|
it("should derive from seed: 5", () => {
|
|
213
214
|
const seed = trivialSeed(tryAsU32(5));
|
|
214
215
|
const bandersnatch_seed = deriveBandersnatchSecretKey(seed, blake2b);
|
|
215
216
|
const bandersnatch_public_key = deriveBandersnatchPublicKey(bandersnatch_seed);
|
|
216
|
-
|
|
217
|
+
deepEqual(bandersnatch_public_key, Bytes.fromBlob(Bytes.parseBlobNoPrefix("2105650944fcd101621fd5bb3124c9fd191d114b7ad936c1d79d734f9f21392e").raw, SEED_SIZE).asOpaque());
|
|
217
218
|
});
|
|
218
219
|
it("should derive from seed: f92d...d9d1", () => {
|
|
219
220
|
const seed = Bytes.fromBlob(Bytes.parseBlobNoPrefix("f92d680ea3f0ac06307795490d8a03c5c0d4572b5e0a8cffec87e1294855d9d1").raw, SEED_SIZE).asOpaque();
|
|
220
221
|
const bandersnatch_seed = deriveBandersnatchSecretKey(seed, blake2b);
|
|
221
222
|
const bandersnatch_public_key = deriveBandersnatchPublicKey(bandersnatch_seed);
|
|
222
|
-
|
|
223
|
+
deepEqual(bandersnatch_public_key, Bytes.fromBlob(Bytes.parseBlobNoPrefix("299bdfd8d615aadd9e6c58718f9893a5144d60e897bc9da1f3d73c935715c650").raw, SEED_SIZE).asOpaque());
|
|
223
224
|
});
|
|
224
225
|
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { PvmBackend } from "#@typeberry/config";
|
|
2
2
|
import { tryAsGas } from "#@typeberry/pvm-interface";
|
|
3
|
-
import { HostCalls } from "./host-calls.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
const hostCalls = new
|
|
7
|
-
const pvmInstanceManager = await
|
|
8
|
-
const pvmHostCallExtension = new
|
|
3
|
+
import { HostCalls, NoopMissing } from "./host-calls.js";
|
|
4
|
+
import { HostCallsExecutor } from "./host-calls-executor.js";
|
|
5
|
+
import { PvmInstanceManager } from "./pvm-instance-manager.js";
|
|
6
|
+
const hostCalls = new HostCalls({ missing: new NoopMissing(), handlers: [] });
|
|
7
|
+
const pvmInstanceManager = await PvmInstanceManager.new(PvmBackend.BuiltIn);
|
|
8
|
+
const pvmHostCallExtension = new HostCallsExecutor(pvmInstanceManager, hostCalls);
|
|
9
9
|
const program = new Uint8Array([
|
|
10
10
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x1, 0x0, 0x0, 0xf9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0xd9, 0x5, 0x12,
|
|
11
11
|
0x0, 0x0, 0x0, 0x5, 0x11, 0x0, 0x0, 0x0, 0x5, 0xa3, 0x0, 0x0, 0x0, 0x5, 0xc6, 0x0, 0x4, 0x7, 0x13, 0x0, 0x2, 0x11,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { U32, U64 } from "#@typeberry/numbers";
|
|
2
|
+
import type { RegisterIndex } from "#@typeberry/pvm-interpreter";
|
|
3
|
+
/**
|
|
4
|
+
* Interface for tracking PVM I/O operations during host call execution.
|
|
5
|
+
*
|
|
6
|
+
* Implementations record memory reads/writes and register modifications
|
|
7
|
+
* for debugging, tracing, or replay purposes.
|
|
8
|
+
*/
|
|
9
|
+
export interface IoTracker {
|
|
10
|
+
/** Record a register write operation. */
|
|
11
|
+
setReg(idx: number, val: U64): void;
|
|
12
|
+
/** Record a memory read operation. */
|
|
13
|
+
memRead(address: U32, data: Uint8Array): void;
|
|
14
|
+
/** Record a memory write operation. */
|
|
15
|
+
memWrite(address: U32, data: Uint8Array): void;
|
|
16
|
+
/** Clear all recorded operations. */
|
|
17
|
+
clear(): void;
|
|
18
|
+
}
|
|
19
|
+
/** Create a no-op tracker that discards all operations. */
|
|
20
|
+
export declare function noopTracker(): NoopIoTracker;
|
|
21
|
+
/**
|
|
22
|
+
* No-op implementation that discards all tracked operations.
|
|
23
|
+
* Used when I/O tracing is disabled.
|
|
24
|
+
*/
|
|
25
|
+
declare class NoopIoTracker implements IoTracker {
|
|
26
|
+
clear(): void;
|
|
27
|
+
setReg(_idx: RegisterIndex, _val: U64): void;
|
|
28
|
+
memRead(_address: U32, _data: Uint8Array): void;
|
|
29
|
+
memWrite(_address: U32, _data: Uint8Array): void;
|
|
30
|
+
}
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=ecalli-io-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecalli-io-tracker.d.ts","sourceRoot":"","sources":["../../../../../packages/core/pvm-host-calls/ecalli-io-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEhE;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,yCAAyC;IACzC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC;IACpC,sCAAsC;IACtC,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9C,uCAAuC;IACvC,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/C,qCAAqC;IACrC,KAAK,IAAI,IAAI,CAAC;CACf;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,kBAE1B;AAED;;;GAGG;AACH,cAAM,aAAc,YAAW,SAAS;IACtC,KAAK,IAAI,IAAI;IACb,MAAM,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IAC5C,OAAO,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAC/C,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;CACjD"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Create a no-op tracker that discards all operations. */
|
|
2
|
+
export function noopTracker() {
|
|
3
|
+
return new NoopIoTracker();
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* No-op implementation that discards all tracked operations.
|
|
7
|
+
* Used when I/O tracing is disabled.
|
|
8
|
+
*/
|
|
9
|
+
class NoopIoTracker {
|
|
10
|
+
clear() { }
|
|
11
|
+
setReg(_idx, _val) { }
|
|
12
|
+
memRead(_address, _data) { }
|
|
13
|
+
memWrite(_address, _data) { }
|
|
14
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import type { U32, U64 } from "#@typeberry/numbers";
|
|
2
|
+
import type { Gas } from "#@typeberry/pvm-interface";
|
|
3
|
+
import type { IoTracker } from "./ecalli-io-tracker.js";
|
|
4
|
+
import type { HostCallIndex } from "./host-call-handler.js";
|
|
5
|
+
import type { HostCallRegisters } from "./host-call-registers.js";
|
|
6
|
+
/**
|
|
7
|
+
* Output function type for IO trace logging.
|
|
8
|
+
* Each call should output a single line.
|
|
9
|
+
*/
|
|
10
|
+
export type IoTraceOutput = (line: string) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Ecalli PVM IO Trace Logger.
|
|
13
|
+
*
|
|
14
|
+
* Implements the logging format specified for PVM execution tracing.
|
|
15
|
+
* This format is designed to be:
|
|
16
|
+
* - Human-readable, newline-delimited text
|
|
17
|
+
* - Self-contained for stateless re-execution
|
|
18
|
+
* - Comparable using simple textual diff tools
|
|
19
|
+
*
|
|
20
|
+
* @see https://github.com/tomusdrw/JIPs/pull/2
|
|
21
|
+
*/
|
|
22
|
+
export declare class EcalliTraceLogger {
|
|
23
|
+
private readonly output;
|
|
24
|
+
/** Returns a tracker for IO operations. */
|
|
25
|
+
tracker(): IoTraceTracker | null;
|
|
26
|
+
/**
|
|
27
|
+
* Create an IoTraceLogger that outputs to the `ecalli` module logger.
|
|
28
|
+
*
|
|
29
|
+
* Returns `null` if the `ecalli` logger is not configured for at least TRACE level.
|
|
30
|
+
* Enable with: `JAM_LOG=ecalli=trace` or `JAM_LOG=trace`
|
|
31
|
+
*/
|
|
32
|
+
static create(): EcalliTraceLogger | null;
|
|
33
|
+
/**
|
|
34
|
+
* Create a no-op IoTraceLogger that discards all output.
|
|
35
|
+
* Used when tracing is disabled.
|
|
36
|
+
*/
|
|
37
|
+
static noop(): EcalliTraceLogger;
|
|
38
|
+
static new(output: IoTraceOutput): EcalliTraceLogger;
|
|
39
|
+
private constructor();
|
|
40
|
+
/**
|
|
41
|
+
* Log optional context lines (implementation metadata, execution environment).
|
|
42
|
+
*/
|
|
43
|
+
logContext(context: string): void;
|
|
44
|
+
/**
|
|
45
|
+
* Log the program blob being executed and the write data (if any)
|
|
46
|
+
*
|
|
47
|
+
* Format: `program {hex-encoded-program-with-metadata}`
|
|
48
|
+
* Format: `memwrite {hex-encoded-address} len={blob-byte-length} <- {hex-encoded-bytes}`
|
|
49
|
+
*/
|
|
50
|
+
logProgram(program: Uint8Array, args: Uint8Array): void;
|
|
51
|
+
/**
|
|
52
|
+
* Log initial execution state (prelude).
|
|
53
|
+
*
|
|
54
|
+
* Format: `start pc={pc} gas={gas} {register-dump}`
|
|
55
|
+
*/
|
|
56
|
+
logStart(pc: number, gas: Gas, registers: HostCallRegisters): void;
|
|
57
|
+
/**
|
|
58
|
+
* Log ecalli invocation with register dump.
|
|
59
|
+
*
|
|
60
|
+
* Format: `ecalli={index} pc={pc} gas={gas} {register-dump}`
|
|
61
|
+
*/
|
|
62
|
+
logEcalli(index: HostCallIndex, pc: number, gas: Gas, registers: HostCallRegisters): void;
|
|
63
|
+
/**
|
|
64
|
+
* Log memory read operation.
|
|
65
|
+
*
|
|
66
|
+
* Format: `memread {hex-encoded-address} len={blob-byte-length} -> {hex-encoded-data-read}`
|
|
67
|
+
*/
|
|
68
|
+
logMemRead(address: number, len: number, data: string): void;
|
|
69
|
+
/**
|
|
70
|
+
* Log memory write operation.
|
|
71
|
+
*
|
|
72
|
+
* Format: `memwrite {hex-encoded-address} len={blob-byte-length} <- {hex-encoded-bytes}`
|
|
73
|
+
*/
|
|
74
|
+
logMemWrite(address: number, len: number, data: string): void;
|
|
75
|
+
/**
|
|
76
|
+
* Log register write operation.
|
|
77
|
+
*
|
|
78
|
+
* Format: `setreg r{idx} <- {hex-encoded-value}`
|
|
79
|
+
*/
|
|
80
|
+
logSetReg(index: number, value: bigint): void;
|
|
81
|
+
/**
|
|
82
|
+
* Log gas overwrite operation.
|
|
83
|
+
*
|
|
84
|
+
* Format: `setgas <- {gas}`
|
|
85
|
+
*/
|
|
86
|
+
logSetGas(gas: Gas): void;
|
|
87
|
+
/**
|
|
88
|
+
* Log all host actions from a single ecalli invocation.
|
|
89
|
+
* Actions are logged in the order specified by JIP-6:
|
|
90
|
+
* 1. Memory reads (sorted by address)
|
|
91
|
+
* 2. Memory writes (sorted by address)
|
|
92
|
+
* 3. Register writes (sorted by index)
|
|
93
|
+
* 4. Gas overwrite
|
|
94
|
+
*/
|
|
95
|
+
logHostActions(ioTracker: IoTraceTracker | null, gasBefore: Gas, gasAfter: Gas): void;
|
|
96
|
+
/**
|
|
97
|
+
* Log PANIC termination.
|
|
98
|
+
*
|
|
99
|
+
* Format: `PANIC={argument} pc={pc} gas={gas} {register-dump}`
|
|
100
|
+
*/
|
|
101
|
+
logPanic(argument: number, pc: number, gas: Gas, registers: HostCallRegisters): void;
|
|
102
|
+
/**
|
|
103
|
+
* Log OOG (out of gas) termination.
|
|
104
|
+
*
|
|
105
|
+
* Format: `OOG pc={pc} gas={gas} {register-dump}`
|
|
106
|
+
*/
|
|
107
|
+
logOog(pc: number, gas: Gas, registers: HostCallRegisters): void;
|
|
108
|
+
/**
|
|
109
|
+
* Log HALT termination.
|
|
110
|
+
*
|
|
111
|
+
* Format: `HALT pc={pc} gas={gas} {register-dump}`
|
|
112
|
+
*/
|
|
113
|
+
logHalt(pc: number, gas: Gas, registers: HostCallRegisters): void;
|
|
114
|
+
}
|
|
115
|
+
type MemoryOperation = {
|
|
116
|
+
address: number;
|
|
117
|
+
hex: string;
|
|
118
|
+
len: number;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* IoTracker implementation that records all I/O operations for trace logging.
|
|
122
|
+
*
|
|
123
|
+
* Stores memory reads, writes, and register modifications as hex-encoded strings
|
|
124
|
+
* for output via IoTraceLogger.
|
|
125
|
+
*/
|
|
126
|
+
export declare class IoTraceTracker implements IoTracker {
|
|
127
|
+
/** Recorded memory read operations (address + hex data + len). */
|
|
128
|
+
reads: MemoryOperation[];
|
|
129
|
+
/** Recorded memory write operations (address + hex data + len). */
|
|
130
|
+
writes: MemoryOperation[];
|
|
131
|
+
/** Recorded register write operations (index -> value). */
|
|
132
|
+
registers: Map<number, U64>;
|
|
133
|
+
setReg(idx: number, val: U64): void;
|
|
134
|
+
memRead(address: U32, data: Uint8Array): void;
|
|
135
|
+
memWrite(address: U32, data: Uint8Array): void;
|
|
136
|
+
clear(): void;
|
|
137
|
+
}
|
|
138
|
+
export {};
|
|
139
|
+
//# sourceMappingURL=ecalli-trace-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecalli-trace-logger.d.ts","sourceRoot":"","sources":["../../../../../packages/core/pvm-host-calls/ecalli-trace-logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { BytesBlob } from "#@typeberry/bytes";
|
|
2
|
+
import { Level, Logger } from "#@typeberry/logger";
|
|
3
|
+
const ecalliLogger = Logger.new(import.meta.filename, "ecalli");
|
|
4
|
+
const defaultOutput = (line) => {
|
|
5
|
+
ecalliLogger.trace `${line}`;
|
|
6
|
+
};
|
|
7
|
+
const emptyOutput = () => { };
|
|
8
|
+
/**
|
|
9
|
+
* Ecalli PVM IO Trace Logger.
|
|
10
|
+
*
|
|
11
|
+
* Implements the logging format specified for PVM execution tracing.
|
|
12
|
+
* This format is designed to be:
|
|
13
|
+
* - Human-readable, newline-delimited text
|
|
14
|
+
* - Self-contained for stateless re-execution
|
|
15
|
+
* - Comparable using simple textual diff tools
|
|
16
|
+
*
|
|
17
|
+
* @see https://github.com/tomusdrw/JIPs/pull/2
|
|
18
|
+
*/
|
|
19
|
+
export class EcalliTraceLogger {
|
|
20
|
+
output;
|
|
21
|
+
/** Returns a tracker for IO operations. */
|
|
22
|
+
tracker() {
|
|
23
|
+
return this.output === emptyOutput ? null : new IoTraceTracker();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Create an IoTraceLogger that outputs to the `ecalli` module logger.
|
|
27
|
+
*
|
|
28
|
+
* Returns `null` if the `ecalli` logger is not configured for at least TRACE level.
|
|
29
|
+
* Enable with: `JAM_LOG=ecalli=trace` or `JAM_LOG=trace`
|
|
30
|
+
*/
|
|
31
|
+
static create() {
|
|
32
|
+
if (ecalliLogger.getLevel() > Level.TRACE) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
return EcalliTraceLogger.new(defaultOutput);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create a no-op IoTraceLogger that discards all output.
|
|
39
|
+
* Used when tracing is disabled.
|
|
40
|
+
*/
|
|
41
|
+
static noop() {
|
|
42
|
+
return new EcalliTraceLogger(emptyOutput);
|
|
43
|
+
}
|
|
44
|
+
static new(output) {
|
|
45
|
+
return new EcalliTraceLogger(output);
|
|
46
|
+
}
|
|
47
|
+
constructor(output) {
|
|
48
|
+
this.output = output;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Log optional context lines (implementation metadata, execution environment).
|
|
52
|
+
*/
|
|
53
|
+
logContext(context) {
|
|
54
|
+
this.output(context);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Log the program blob being executed and the write data (if any)
|
|
58
|
+
*
|
|
59
|
+
* Format: `program {hex-encoded-program-with-metadata}`
|
|
60
|
+
* Format: `memwrite {hex-encoded-address} len={blob-byte-length} <- {hex-encoded-bytes}`
|
|
61
|
+
*/
|
|
62
|
+
logProgram(program, args) {
|
|
63
|
+
const SPI_ARGS_SEGMENT = 0xfe_ff_00_00;
|
|
64
|
+
this.output(`program ${BytesBlob.blobFrom(program)}`);
|
|
65
|
+
if (args.length > 0) {
|
|
66
|
+
this.output(`memwrite ${toHexAddress(SPI_ARGS_SEGMENT)} len=${args.length} <- ${BytesBlob.blobFrom(args)}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Log initial execution state (prelude).
|
|
71
|
+
*
|
|
72
|
+
* Format: `start pc={pc} gas={gas} {register-dump}`
|
|
73
|
+
*/
|
|
74
|
+
logStart(pc, gas, registers) {
|
|
75
|
+
const line = `start pc=${pc} gas=${gas} ${registers}`;
|
|
76
|
+
this.output(line);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Log ecalli invocation with register dump.
|
|
80
|
+
*
|
|
81
|
+
* Format: `ecalli={index} pc={pc} gas={gas} {register-dump}`
|
|
82
|
+
*/
|
|
83
|
+
logEcalli(index, pc, gas, registers) {
|
|
84
|
+
const line = `ecalli=${index} pc=${pc} gas=${gas} ${registers}`;
|
|
85
|
+
this.output(line);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Log memory read operation.
|
|
89
|
+
*
|
|
90
|
+
* Format: `memread {hex-encoded-address} len={blob-byte-length} -> {hex-encoded-data-read}`
|
|
91
|
+
*/
|
|
92
|
+
logMemRead(address, len, data) {
|
|
93
|
+
this.output(`memread ${toHexAddress(address)} len=${len} -> ${data}`);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Log memory write operation.
|
|
97
|
+
*
|
|
98
|
+
* Format: `memwrite {hex-encoded-address} len={blob-byte-length} <- {hex-encoded-bytes}`
|
|
99
|
+
*/
|
|
100
|
+
logMemWrite(address, len, data) {
|
|
101
|
+
this.output(`memwrite ${toHexAddress(address)} len=${len} <- ${data}`);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Log register write operation.
|
|
105
|
+
*
|
|
106
|
+
* Format: `setreg r{idx} <- {hex-encoded-value}`
|
|
107
|
+
*/
|
|
108
|
+
logSetReg(index, value) {
|
|
109
|
+
const paddedIdx = index.toString().padStart(2, "0");
|
|
110
|
+
this.output(`setreg r${paddedIdx} <- ${value.toString(16)}`);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Log gas overwrite operation.
|
|
114
|
+
*
|
|
115
|
+
* Format: `setgas <- {gas}`
|
|
116
|
+
*/
|
|
117
|
+
logSetGas(gas) {
|
|
118
|
+
this.output(`setgas <- ${gas}`);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Log all host actions from a single ecalli invocation.
|
|
122
|
+
* Actions are logged in the order specified by JIP-6:
|
|
123
|
+
* 1. Memory reads (sorted by address)
|
|
124
|
+
* 2. Memory writes (sorted by address)
|
|
125
|
+
* 3. Register writes (sorted by index)
|
|
126
|
+
* 4. Gas overwrite
|
|
127
|
+
*/
|
|
128
|
+
logHostActions(ioTracker, gasBefore, gasAfter) {
|
|
129
|
+
if (ioTracker === null) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const reads = ioTracker.reads.sort((a, b) => a.address - b.address);
|
|
133
|
+
for (const op of reads) {
|
|
134
|
+
this.logMemRead(op.address, op.len, op.hex);
|
|
135
|
+
}
|
|
136
|
+
const writes = ioTracker.writes.sort((a, b) => a.address - b.address);
|
|
137
|
+
for (const op of writes) {
|
|
138
|
+
this.logMemWrite(op.address, op.len, op.hex);
|
|
139
|
+
}
|
|
140
|
+
const sortedRegWrites = [...ioTracker.registers.entries()].sort((a, b) => a[0] - b[0]);
|
|
141
|
+
for (const op of sortedRegWrites) {
|
|
142
|
+
this.logSetReg(op[0], op[1]);
|
|
143
|
+
}
|
|
144
|
+
if (gasBefore !== gasAfter) {
|
|
145
|
+
this.logSetGas(gasAfter);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Log PANIC termination.
|
|
150
|
+
*
|
|
151
|
+
* Format: `PANIC={argument} pc={pc} gas={gas} {register-dump}`
|
|
152
|
+
*/
|
|
153
|
+
logPanic(argument, pc, gas, registers) {
|
|
154
|
+
const line = `PANIC=${argument} pc=${pc} gas=${gas} ${registers}`;
|
|
155
|
+
this.output(line);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Log OOG (out of gas) termination.
|
|
159
|
+
*
|
|
160
|
+
* Format: `OOG pc={pc} gas={gas} {register-dump}`
|
|
161
|
+
*/
|
|
162
|
+
logOog(pc, gas, registers) {
|
|
163
|
+
const line = `OOG pc=${pc} gas=${gas} ${registers}`;
|
|
164
|
+
this.output(line);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Log HALT termination.
|
|
168
|
+
*
|
|
169
|
+
* Format: `HALT pc={pc} gas={gas} {register-dump}`
|
|
170
|
+
*/
|
|
171
|
+
logHalt(pc, gas, registers) {
|
|
172
|
+
const line = `HALT pc=${pc} gas=${gas} ${registers}`;
|
|
173
|
+
this.output(line);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Convert 32-bit address to 0x-prefixed hex string.
|
|
178
|
+
*/
|
|
179
|
+
function toHexAddress(address) {
|
|
180
|
+
return `0x${address.toString(16).padStart(8, "0")}`;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* IoTracker implementation that records all I/O operations for trace logging.
|
|
184
|
+
*
|
|
185
|
+
* Stores memory reads, writes, and register modifications as hex-encoded strings
|
|
186
|
+
* for output via IoTraceLogger.
|
|
187
|
+
*/
|
|
188
|
+
export class IoTraceTracker {
|
|
189
|
+
/** Recorded memory read operations (address + hex data + len). */
|
|
190
|
+
reads = [];
|
|
191
|
+
/** Recorded memory write operations (address + hex data + len). */
|
|
192
|
+
writes = [];
|
|
193
|
+
/** Recorded register write operations (index -> value). */
|
|
194
|
+
registers = new Map();
|
|
195
|
+
setReg(idx, val) {
|
|
196
|
+
this.registers.set(idx, val);
|
|
197
|
+
}
|
|
198
|
+
memRead(address, data) {
|
|
199
|
+
this.reads.push({ address, hex: BytesBlob.blobFrom(data).toString(), len: data.length });
|
|
200
|
+
}
|
|
201
|
+
memWrite(address, data) {
|
|
202
|
+
this.writes.push({ address, hex: BytesBlob.blobFrom(data).toString(), len: data.length });
|
|
203
|
+
}
|
|
204
|
+
clear() {
|
|
205
|
+
this.reads.length = 0;
|
|
206
|
+
this.writes.length = 0;
|
|
207
|
+
this.registers.clear();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecalli-trace-logger.test.d.ts","sourceRoot":"","sources":["../../../../../packages/core/pvm-host-calls/ecalli-trace-logger.test.ts"],"names":[],"mappings":""}
|