@typeberry/lib 0.5.2 → 0.5.3-aa4626d
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 +9 -5
- 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/hash/hash.d.ts.map +1 -1
- package/packages/core/hash/hash.js +1 -0
- package/packages/core/networking/package.json +1 -1
- package/packages/core/numbers/index.d.ts +4 -0
- package/packages/core/numbers/index.d.ts.map +1 -1
- package/packages/core/numbers/index.js +4 -4
- 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 +37 -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 +129 -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/pvm-interpreter/ops/math-consts.d.ts +2 -3
- package/packages/core/pvm-interpreter/ops/math-consts.d.ts.map +1 -1
- package/packages/core/pvm-interpreter/ops/math-consts.js +2 -3
- package/packages/core/pvm-interpreter/ops/math-ops.js +3 -3
- package/packages/core/pvm-interpreter/ops/math-utils.js +13 -13
- package/packages/core/pvm-interpreter/ops/math-utils.test.js +17 -16
- package/packages/core/telemetry/package.json +1 -1
- package/packages/jam/block/work-item.d.ts +13 -4
- package/packages/jam/block/work-item.d.ts.map +1 -1
- package/packages/jam/block/work-result.d.ts +3 -5
- package/packages/jam/block/work-result.d.ts.map +1 -1
- package/packages/jam/block/work-result.js +6 -0
- package/packages/jam/block-json/work-result.d.ts.map +1 -1
- package/packages/jam/block-json/work-result.js +6 -6
- package/packages/jam/database-lmdb/states.test.js +4 -3
- package/packages/jam/executor/index.d.ts +4 -0
- package/packages/jam/executor/index.d.ts.map +1 -0
- package/packages/jam/executor/index.js +2 -0
- package/packages/jam/{transition/accumulate → executor}/pvm-executor.d.ts +19 -16
- package/packages/jam/executor/pvm-executor.d.ts.map +1 -0
- package/packages/jam/{transition/accumulate → executor}/pvm-executor.js +48 -5
- package/packages/jam/in-core/externalities/refine.d.ts +24 -0
- package/packages/jam/in-core/externalities/refine.d.ts.map +1 -0
- package/packages/jam/in-core/externalities/refine.js +36 -0
- package/packages/jam/in-core/in-core.d.ts +60 -0
- package/packages/jam/in-core/in-core.d.ts.map +1 -0
- package/packages/jam/in-core/in-core.js +294 -0
- package/packages/jam/in-core/in-core.test.d.ts +2 -0
- package/packages/jam/in-core/in-core.test.d.ts.map +1 -0
- package/packages/jam/in-core/in-core.test.js +81 -0
- package/packages/jam/in-core/index.d.ts +2 -0
- package/packages/jam/in-core/index.d.ts.map +1 -0
- package/packages/jam/in-core/index.js +1 -0
- package/packages/jam/jam-host-calls/accumulate/bless.test.js +4 -5
- package/packages/jam/jamnp-s/protocol/ce-133-work-package-submission.d.ts +3 -3
- package/packages/jam/jamnp-s/protocol/ce-133-work-package-submission.d.ts.map +1 -1
- package/packages/jam/jamnp-s/protocol/ce-135-work-report-distribution.test.js +2 -2
- 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/rpc-validation/types.d.ts +7 -3
- package/packages/jam/rpc-validation/types.d.ts.map +1 -1
- package/packages/jam/rpc-validation/validation.d.ts +254 -36
- package/packages/jam/rpc-validation/validation.d.ts.map +1 -1
- package/packages/jam/rpc-validation/validation.js +20 -2
- 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/state/in-memory-state.d.ts.map +1 -1
- package/packages/jam/state/in-memory-state.js +2 -3
- package/packages/jam/state/test.utils.d.ts.map +1 -1
- package/packages/jam/state/test.utils.js +2 -3
- package/packages/jam/transition/accumulate/accumulate-data.d.ts.map +1 -1
- package/packages/jam/transition/accumulate/accumulate-data.js +1 -2
- package/packages/jam/transition/accumulate/accumulate-queue.test.js +2 -2
- package/packages/jam/transition/accumulate/accumulate-utils.test.js +2 -2
- package/packages/jam/transition/accumulate/accumulate.d.ts.map +1 -1
- package/packages/jam/transition/accumulate/accumulate.js +8 -13
- package/packages/jam/transition/accumulate/accumulate.test.js +2 -2
- package/packages/jam/transition/accumulate/accumulation-result-merge-utils.d.ts.map +1 -1
- package/packages/jam/transition/accumulate/accumulation-result-merge-utils.js +1 -2
- package/packages/jam/transition/accumulate/accumulation-result-merge-utils.test.js +1 -2
- package/packages/jam/transition/accumulate/deferred-transfers.d.ts +1 -1
- package/packages/jam/transition/accumulate/deferred-transfers.d.ts.map +1 -1
- package/packages/jam/transition/accumulate/deferred-transfers.js +6 -7
- package/packages/jam/transition/disputes/disputes.d.ts.map +1 -1
- package/packages/jam/transition/disputes/disputes.js +5 -4
- package/packages/jam/transition/disputes/disputes.test.data2.js +2 -2
- package/packages/jam/transition/externalities/fetch-externalities.d.ts +7 -1
- package/packages/jam/transition/externalities/fetch-externalities.d.ts.map +1 -1
- package/packages/jam/transition/externalities/fetch-externalities.js +4 -0
- package/packages/jam/transition/externalities/fetch-externalities.test.js +2 -2
- package/packages/jam/transition/hasher.test.js +2 -2
- package/packages/jam/transition/reports/test.utils.d.ts.map +1 -1
- package/packages/jam/transition/reports/test.utils.js +2 -2
- 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/packages/jam/transition/accumulate/pvm-executor.d.ts.map +0 -1
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { Status } from "#@typeberry/pvm-interface";
|
|
2
|
+
import { assertNever, check, safeAllocUint8Array } from "#@typeberry/utils";
|
|
3
|
+
import { EcalliTraceLogger } from "./ecalli-trace-logger.js";
|
|
4
|
+
import { PvmExecution, tryAsHostCallIndex } from "./host-call-handler.js";
|
|
5
|
+
import { HostCallMemory } from "./host-call-memory.js";
|
|
6
|
+
import { HostCallRegisters } from "./host-call-registers.js";
|
|
7
|
+
/**
|
|
8
|
+
* Outer VM return status.
|
|
9
|
+
*
|
|
10
|
+
* This is a limited status returned by outer VM.
|
|
11
|
+
*
|
|
12
|
+
* https://graypaper.fluffylabs.dev/#/ab2cdbd/24a10124a101?v=0.7.2
|
|
13
|
+
*/
|
|
14
|
+
export var ReturnStatus;
|
|
15
|
+
(function (ReturnStatus) {
|
|
16
|
+
/** Execution succesful. */
|
|
17
|
+
ReturnStatus[ReturnStatus["OK"] = 0] = "OK";
|
|
18
|
+
/** Execution went out of gas. */
|
|
19
|
+
ReturnStatus[ReturnStatus["OOG"] = 1] = "OOG";
|
|
20
|
+
/** Execution trapped or panicked. */
|
|
21
|
+
ReturnStatus[ReturnStatus["PANIC"] = 2] = "PANIC";
|
|
22
|
+
})(ReturnStatus || (ReturnStatus = {}));
|
|
23
|
+
export class HostCallsExecutor {
|
|
24
|
+
pvmInstanceManager;
|
|
25
|
+
hostCalls;
|
|
26
|
+
ioTracer;
|
|
27
|
+
constructor(pvmInstanceManager, hostCalls, ioTracer = EcalliTraceLogger.create()) {
|
|
28
|
+
this.pvmInstanceManager = pvmInstanceManager;
|
|
29
|
+
this.hostCalls = hostCalls;
|
|
30
|
+
this.ioTracer = ioTracer;
|
|
31
|
+
}
|
|
32
|
+
getReturnValue(status, pvmInstance, registers, memory) {
|
|
33
|
+
const consumedGas = pvmInstance.gas.used();
|
|
34
|
+
const pc = pvmInstance.getPC();
|
|
35
|
+
const gas = pvmInstance.gas.get();
|
|
36
|
+
if (status === Status.OOG) {
|
|
37
|
+
this.ioTracer?.logOog(pc, gas, registers);
|
|
38
|
+
return { consumedGas, status: ReturnStatus.OOG };
|
|
39
|
+
}
|
|
40
|
+
if (status === Status.HALT) {
|
|
41
|
+
this.ioTracer?.logHalt(pc, gas, registers);
|
|
42
|
+
const address = registers.get(7);
|
|
43
|
+
// NOTE we are taking the the lower U32 part of the register, hence it's safe.
|
|
44
|
+
const length = Number(registers.get(8) & 0xffffffffn);
|
|
45
|
+
const result = safeAllocUint8Array(length);
|
|
46
|
+
const loadResult = memory.loadInto(result, address);
|
|
47
|
+
if (loadResult.isError) {
|
|
48
|
+
return { consumedGas, status: ReturnStatus.OK, memorySlice: new Uint8Array() };
|
|
49
|
+
}
|
|
50
|
+
return { consumedGas, status: ReturnStatus.OK, memorySlice: result };
|
|
51
|
+
}
|
|
52
|
+
this.ioTracer?.logPanic(pvmInstance.getExitParam() ?? 0, pc, gas, registers);
|
|
53
|
+
return { consumedGas, status: ReturnStatus.PANIC };
|
|
54
|
+
}
|
|
55
|
+
async execute(pvmInstance) {
|
|
56
|
+
const ioTracker = this.ioTracer?.tracker() ?? null;
|
|
57
|
+
const registers = new HostCallRegisters(pvmInstance.registers.getAllEncoded());
|
|
58
|
+
registers.ioTracker = ioTracker;
|
|
59
|
+
const memory = new HostCallMemory(pvmInstance.memory);
|
|
60
|
+
memory.ioTracker = ioTracker;
|
|
61
|
+
const gas = pvmInstance.gas;
|
|
62
|
+
// log start of execution (note the PVM initialisation should be logged already)
|
|
63
|
+
this.ioTracer?.logStart(pvmInstance.getPC(), pvmInstance.gas.get(), registers);
|
|
64
|
+
for (;;) {
|
|
65
|
+
// execute program as much as we can
|
|
66
|
+
pvmInstance.runProgram();
|
|
67
|
+
// and update the PVM state
|
|
68
|
+
registers.setEncoded(pvmInstance.registers.getAllEncoded());
|
|
69
|
+
const status = pvmInstance.getStatus();
|
|
70
|
+
const pc = pvmInstance.getPC();
|
|
71
|
+
const exitParam = pvmInstance.getExitParam() ?? -1;
|
|
72
|
+
if (status !== Status.HOST) {
|
|
73
|
+
return this.getReturnValue(status, pvmInstance, registers, memory);
|
|
74
|
+
}
|
|
75
|
+
// get the PVM state now
|
|
76
|
+
check `
|
|
77
|
+
${exitParam !== -1}
|
|
78
|
+
"We know that the exit param is not null, because the status is 'Status.HOST'
|
|
79
|
+
`;
|
|
80
|
+
const hostCallIndex = tryAsHostCallIndex(exitParam);
|
|
81
|
+
// retrieve the host call
|
|
82
|
+
const hostCall = this.hostCalls.get(hostCallIndex);
|
|
83
|
+
// NOTE: `basicGasCost(regs)` function is for compatibility reasons: pre GP 0.7.2
|
|
84
|
+
const basicGasCost = typeof hostCall.basicGasCost === "number" ? hostCall.basicGasCost : hostCall.basicGasCost(registers);
|
|
85
|
+
// calculate gas
|
|
86
|
+
const gasBefore = gas.get();
|
|
87
|
+
const underflow = gas.sub(basicGasCost);
|
|
88
|
+
const pcLog = `[PC: ${pc}]`;
|
|
89
|
+
if (underflow) {
|
|
90
|
+
const gasAfterBasicGas = gas.get();
|
|
91
|
+
this.hostCalls.traceHostCall(`${pcLog} OOG`, hostCallIndex, hostCall, registers, gasAfterBasicGas);
|
|
92
|
+
this.ioTracer?.logSetGas(gasAfterBasicGas);
|
|
93
|
+
return this.getReturnValue(Status.OOG, pvmInstance, registers, memory);
|
|
94
|
+
}
|
|
95
|
+
this.ioTracer?.logEcalli(hostCallIndex, pc, gasBefore, registers);
|
|
96
|
+
this.hostCalls.traceHostCall(`${pcLog} Invoking`, hostCallIndex, hostCall, registers, gasBefore);
|
|
97
|
+
ioTracker?.clear();
|
|
98
|
+
const result = await hostCall.execute(gas, registers, memory);
|
|
99
|
+
const gasAfter = gas.get();
|
|
100
|
+
this.ioTracer?.logHostActions(ioTracker, gasBefore, gasAfter);
|
|
101
|
+
this.hostCalls.traceHostCall(result === undefined ? `${pcLog} Result` : `${pcLog} Status(${PvmExecution[result]})`, hostCallIndex, hostCall, registers, gasAfter);
|
|
102
|
+
pvmInstance.registers.setAllEncoded(registers.getEncoded());
|
|
103
|
+
if (result === PvmExecution.Halt) {
|
|
104
|
+
return this.getReturnValue(Status.HALT, pvmInstance, registers, memory);
|
|
105
|
+
}
|
|
106
|
+
if (result === PvmExecution.Panic) {
|
|
107
|
+
return this.getReturnValue(Status.PANIC, pvmInstance, registers, memory);
|
|
108
|
+
}
|
|
109
|
+
if (result === PvmExecution.OOG) {
|
|
110
|
+
return this.getReturnValue(Status.OOG, pvmInstance, registers, memory);
|
|
111
|
+
}
|
|
112
|
+
if (result === undefined) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
assertNever(result);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async runProgram(program, args, initialPc, initialGas) {
|
|
119
|
+
const pvmInstance = await this.pvmInstanceManager.getInstance();
|
|
120
|
+
pvmInstance.resetJam(program, args, initialPc, initialGas);
|
|
121
|
+
try {
|
|
122
|
+
this.ioTracer?.logProgram(program, args);
|
|
123
|
+
return await this.execute(pvmInstance);
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
this.pvmInstanceManager.releaseInstance(pvmInstance);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -1,29 +1,23 @@
|
|
|
1
|
-
import { type Gas
|
|
2
|
-
import type
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
consumedGas: Gas;
|
|
6
|
-
status: Status | null;
|
|
7
|
-
memorySlice: Uint8Array | null;
|
|
8
|
-
private constructor();
|
|
9
|
-
static fromStatus(consumedGas: Gas, status: Status): ReturnValue;
|
|
10
|
-
static fromMemorySlice(consumedGas: Gas, memorySlice: Uint8Array): ReturnValue;
|
|
11
|
-
hasMemorySlice(): this is this & {
|
|
12
|
-
status: null;
|
|
13
|
-
memorySlice: Uint8Array;
|
|
14
|
-
};
|
|
15
|
-
hasStatus(): this is this & {
|
|
16
|
-
status: Status;
|
|
17
|
-
memorySlice: null;
|
|
18
|
-
};
|
|
19
|
-
}
|
|
1
|
+
import { type Gas } from "#@typeberry/pvm-interface";
|
|
2
|
+
import { type HostCallHandler, type HostCallIndex, type PvmExecution } from "./host-call-handler.js";
|
|
3
|
+
import type { HostCallRegisters } from "./host-call-registers.js";
|
|
4
|
+
/** Container for all available host calls. */
|
|
20
5
|
export declare class HostCalls {
|
|
21
|
-
private
|
|
22
|
-
private
|
|
23
|
-
constructor(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
6
|
+
private readonly hostCalls;
|
|
7
|
+
private readonly missing;
|
|
8
|
+
constructor({ missing, handlers, }: {
|
|
9
|
+
missing: HostCallHandler;
|
|
10
|
+
handlers?: HostCallHandler[];
|
|
11
|
+
});
|
|
12
|
+
/** Get a host call by index. */
|
|
13
|
+
get(hostCallIndex: HostCallIndex): HostCallHandler;
|
|
14
|
+
traceHostCall(context: string, hostCallIndex: HostCallIndex, hostCallHandler: HostCallHandler, registers: HostCallRegisters, gas: Gas): void;
|
|
15
|
+
}
|
|
16
|
+
export declare class NoopMissing implements HostCallHandler {
|
|
17
|
+
index: number & import("@typeberry/numbers").WithBytesRepresentation<4> & import("@typeberry/utils").WithOpaque<"HostCallIndex[U32]">;
|
|
18
|
+
basicGasCost: number & import("@typeberry/numbers").WithBytesRepresentation<4> & import("@typeberry/utils").WithOpaque<"SmallGas[U32]">;
|
|
19
|
+
currentServiceId: import("@typeberry/numbers").U32;
|
|
20
|
+
tracedRegisters: never[];
|
|
21
|
+
execute(): Promise<undefined | PvmExecution>;
|
|
27
22
|
}
|
|
28
|
-
export {};
|
|
29
23
|
//# sourceMappingURL=host-calls.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-calls.d.ts","sourceRoot":"","sources":["../../../../../packages/core/pvm-host-calls/host-calls.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"host-calls.d.ts","sourceRoot":"","sources":["../../../../../packages/core/pvm-host-calls/host-calls.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,GAAG,EAAiB,MAAM,0BAA0B,CAAC;AAEnE,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,YAAY,EAElB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAIlE,8CAA8C;AAC9C,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6C;IACvE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAEb,EACV,OAAO,EACP,QAAa,GACd,EAAE;QACD,OAAO,EAAE,eAAe,CAAC;QACzB,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;KAC9B;IASD,gCAAgC;IAChC,GAAG,CAAC,aAAa,EAAE,aAAa,GAAG,eAAe;IAIlD,aAAa,CACX,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,iBAAiB,EAC5B,GAAG,EAAE,GAAG;CAkBX;AAED,qBAAa,WAAY,YAAW,eAAe;IACjD,KAAK,iIAAmC;IACxC,YAAY,4HAAoB;IAChC,gBAAgB,mCAAe;IAC/B,eAAe,UAAM;IAEf,OAAO,IAAI,OAAO,CAAC,SAAS,GAAG,YAAY,CAAC;CAGnD"}
|
|
@@ -1,119 +1,47 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
constructor(
|
|
36
|
-
this.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
-
export
|
|
6
|
-
export
|
|
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,
|
|
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
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
-
export
|
|
6
|
-
export
|
|
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";
|
package/packages/core/pvm-host-calls/{interpreter-instance-manager.d.ts → pvm-instance-manager.d.ts}
RENAMED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { PvmBackend } from "#@typeberry/config";
|
|
2
2
|
import type { IPvmInterpreter } from "#@typeberry/pvm-interface";
|
|
3
|
-
export declare class
|
|
3
|
+
export declare class PvmInstanceManager {
|
|
4
4
|
private readonly instances;
|
|
5
5
|
private waitingQueue;
|
|
6
6
|
private constructor();
|
|
7
|
-
static new(interpreter: PvmBackend): Promise<
|
|
7
|
+
static new(interpreter: PvmBackend): Promise<PvmInstanceManager>;
|
|
8
8
|
getInstance(): Promise<IPvmInterpreter>;
|
|
9
9
|
releaseInstance(pvm: IPvmInterpreter): void;
|
|
10
10
|
}
|
|
11
|
-
//# sourceMappingURL=
|
|
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"}
|
package/packages/core/pvm-host-calls/{interpreter-instance-manager.js → pvm-instance-manager.js}
RENAMED
|
@@ -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
|
|
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
|
|
26
|
+
return new PvmInstanceManager(instances);
|
|
27
27
|
}
|
|
28
28
|
async getInstance() {
|
|
29
29
|
const instance = this.instances.pop();
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
export declare const
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const MIN_VALUE: number;
|
|
1
|
+
export declare const MAX_VALUE_I64: bigint;
|
|
2
|
+
export declare const MIN_VALUE_I32: number;
|
|
4
3
|
export declare const MAX_SHIFT_U32 = 32;
|
|
5
4
|
export declare const MAX_SHIFT_U64 = 64n;
|
|
6
5
|
//# sourceMappingURL=math-consts.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"math-consts.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/pvm-interpreter/ops/math-consts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,
|
|
1
|
+
{"version":3,"file":"math-consts.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/pvm-interpreter/ops/math-consts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,QAAY,CAAC;AACvC,eAAO,MAAM,aAAa,QAAa,CAAC;AACxC,eAAO,MAAM,aAAa,KAAK,CAAC;AAChC,eAAO,MAAM,aAAa,MAAM,CAAC"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
export const
|
|
2
|
-
export const
|
|
3
|
-
export const MIN_VALUE = -(2 ** 31);
|
|
1
|
+
export const MAX_VALUE_I64 = 2n ** 63n;
|
|
2
|
+
export const MIN_VALUE_I32 = -(2 ** 31);
|
|
4
3
|
export const MAX_SHIFT_U32 = 32;
|
|
5
4
|
export const MAX_SHIFT_U64 = 64n;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { signExtend32To64 } from "../registers.js";
|
|
2
|
-
import {
|
|
2
|
+
import { MIN_VALUE_I32 } from "./math-consts.js";
|
|
3
3
|
import { addWithOverflowU32, addWithOverflowU64, maxBigInt, minBigInt, mulLowerUnsignedU32, mulU64, mulUpperSS, mulUpperSU, mulUpperUU, subU32, subU64, } from "./math-utils.js";
|
|
4
4
|
export class MathOps {
|
|
5
5
|
regs;
|
|
@@ -61,7 +61,7 @@ export class MathOps {
|
|
|
61
61
|
if (this.regs.getLowerU32(secondIndex) === 0) {
|
|
62
62
|
this.regs.setU64(resultIndex, 2n ** 64n - 1n);
|
|
63
63
|
}
|
|
64
|
-
else if (this.regs.getLowerI32(secondIndex) === -1 && this.regs.getLowerI32(firstIndex) ===
|
|
64
|
+
else if (this.regs.getLowerI32(secondIndex) === -1 && this.regs.getLowerI32(firstIndex) === MIN_VALUE_I32) {
|
|
65
65
|
this.regs.setU64(resultIndex, signExtend32To64(this.regs.getLowerU32(firstIndex)));
|
|
66
66
|
}
|
|
67
67
|
else {
|
|
@@ -99,7 +99,7 @@ export class MathOps {
|
|
|
99
99
|
if (this.regs.getLowerU32(secondIndex) === 0) {
|
|
100
100
|
this.regs.setU64(resultIndex, BigInt(this.regs.getLowerI32(firstIndex)));
|
|
101
101
|
}
|
|
102
|
-
else if (this.regs.getLowerI32(secondIndex) === -1 && this.regs.getLowerI32(firstIndex) ===
|
|
102
|
+
else if (this.regs.getLowerI32(secondIndex) === -1 && this.regs.getLowerI32(firstIndex) === MIN_VALUE_I32) {
|
|
103
103
|
this.regs.setU64(resultIndex, 0n);
|
|
104
104
|
}
|
|
105
105
|
else {
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
+
import { MAX_VALUE_U32 } from "#@typeberry/numbers";
|
|
1
2
|
import { check } from "#@typeberry/utils";
|
|
2
|
-
import { MAX_VALUE } from "./math-consts.js";
|
|
3
3
|
/**
|
|
4
4
|
* Overflowing addition for two-complement representation of 32-bit signed numbers.
|
|
5
5
|
*/
|
|
6
6
|
export function addWithOverflowU32(a, b) {
|
|
7
|
-
if (a >
|
|
7
|
+
if (a > MAX_VALUE_U32 - b) {
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* =
|
|
12
|
-
* =
|
|
13
|
-
* = a + b -
|
|
9
|
+
* MAX_VALUE_U32 is equal to 2 ** 32 - 1
|
|
10
|
+
* MAX_VALUE_U32 - ( (MAX_VALUE_U32 - a) + (MAX_VALUE_U32 - b) ) - 1
|
|
11
|
+
* = MAX_VALUE_U32 - (2MAX_VALUE_U32 - a - b) -1
|
|
12
|
+
* = MAX_VALUE_U32 - 2MAX_VALUE_U32 + a + b - 1
|
|
13
|
+
* = a + b - MAX_VALUE_U32 - 1
|
|
14
14
|
* = a + b - 2 ** 32
|
|
15
|
-
* but we know that
|
|
15
|
+
* but we know that 2MAX_VALUE_U32 > a + b > MAX_VALUE_U32 so in this case:
|
|
16
16
|
* a + b - 2 ** 32 <=> (a + b) % 2 ** 32
|
|
17
|
-
* = (a + b) % (
|
|
17
|
+
* = (a + b) % (MAX_VALUE_U32 + 1)
|
|
18
18
|
*/
|
|
19
|
-
const spaceToMaxA =
|
|
20
|
-
const spaceToMaxB =
|
|
19
|
+
const spaceToMaxA = MAX_VALUE_U32 - a;
|
|
20
|
+
const spaceToMaxB = MAX_VALUE_U32 - b;
|
|
21
21
|
const overflowSum = spaceToMaxA + spaceToMaxB;
|
|
22
|
-
return
|
|
22
|
+
return MAX_VALUE_U32 - overflowSum - 1;
|
|
23
23
|
}
|
|
24
24
|
return a + b;
|
|
25
25
|
}
|
|
@@ -34,7 +34,7 @@ export function addWithOverflowU64(a, b) {
|
|
|
34
34
|
*/
|
|
35
35
|
export function subU32(a, b) {
|
|
36
36
|
if (b > a) {
|
|
37
|
-
return
|
|
37
|
+
return MAX_VALUE_U32 - b + a + 1;
|
|
38
38
|
}
|
|
39
39
|
return a - b;
|
|
40
40
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { describe, it } from "node:test";
|
|
3
|
-
import {
|
|
3
|
+
import { MAX_VALUE_U32 } from "#@typeberry/numbers";
|
|
4
|
+
import { MAX_VALUE_I64 } from "./math-consts.js";
|
|
4
5
|
import { addWithOverflowU32, addWithOverflowU64, maxBigInt, minBigInt, mulLowerUnsignedU32, mulU64, mulUpperSS, mulUpperSU, mulUpperUU, subU32, subU64, unsignedRightShiftBigInt, } from "./math-utils.js";
|
|
5
6
|
describe("math-utils", () => {
|
|
6
7
|
describe("addWithOverflow", () => {
|
|
@@ -12,7 +13,7 @@ describe("math-utils", () => {
|
|
|
12
13
|
assert.strictEqual(result, expectedResult);
|
|
13
14
|
});
|
|
14
15
|
it("should add two numbers (big and small) without overflow", () => {
|
|
15
|
-
const a =
|
|
16
|
+
const a = MAX_VALUE_U32;
|
|
16
17
|
const b = 6;
|
|
17
18
|
const expectedResult = 5;
|
|
18
19
|
const result = addWithOverflowU32(a, b);
|
|
@@ -26,9 +27,9 @@ describe("math-utils", () => {
|
|
|
26
27
|
assert.strictEqual(result, expectedResult);
|
|
27
28
|
});
|
|
28
29
|
it("should add max values with overflow", () => {
|
|
29
|
-
const a =
|
|
30
|
-
const b =
|
|
31
|
-
const expectedResult =
|
|
30
|
+
const a = MAX_VALUE_U32;
|
|
31
|
+
const b = MAX_VALUE_U32;
|
|
32
|
+
const expectedResult = MAX_VALUE_U32 - 1;
|
|
32
33
|
const result = addWithOverflowU32(a, b);
|
|
33
34
|
assert.strictEqual(result, expectedResult);
|
|
34
35
|
});
|
|
@@ -44,7 +45,7 @@ describe("math-utils", () => {
|
|
|
44
45
|
it("should subtract two numbers with overflow", () => {
|
|
45
46
|
const a = 5;
|
|
46
47
|
const b = 6;
|
|
47
|
-
const expectedResult =
|
|
48
|
+
const expectedResult = MAX_VALUE_U32;
|
|
48
49
|
const result = subU32(a, b);
|
|
49
50
|
assert.strictEqual(result, expectedResult);
|
|
50
51
|
});
|
|
@@ -95,29 +96,29 @@ describe("math-utils", () => {
|
|
|
95
96
|
assert.strictEqual(result, expectedResult);
|
|
96
97
|
});
|
|
97
98
|
it("should multiply two big positive numbers", () => {
|
|
98
|
-
const a =
|
|
99
|
-
const b =
|
|
99
|
+
const a = MAX_VALUE_I64;
|
|
100
|
+
const b = MAX_VALUE_I64;
|
|
100
101
|
const expectedResult = 0x4000000000000000n;
|
|
101
102
|
const result = mulUpperUU(a, b);
|
|
102
103
|
assert.strictEqual(result, expectedResult);
|
|
103
104
|
});
|
|
104
105
|
it("should multiply two big positive and negative numbers", () => {
|
|
105
|
-
const a =
|
|
106
|
-
const b = -
|
|
106
|
+
const a = MAX_VALUE_I64;
|
|
107
|
+
const b = -MAX_VALUE_I64;
|
|
107
108
|
const expectedResult = 4611686018427387904n;
|
|
108
109
|
const result = mulUpperUU(a, b);
|
|
109
110
|
assert.strictEqual(result, expectedResult);
|
|
110
111
|
});
|
|
111
112
|
it("should multiply two big negative and positive numbers", () => {
|
|
112
|
-
const a = -
|
|
113
|
-
const b =
|
|
113
|
+
const a = -MAX_VALUE_I64;
|
|
114
|
+
const b = MAX_VALUE_I64;
|
|
114
115
|
const expectedResult = 4611686018427387904n;
|
|
115
116
|
const result = mulUpperUU(a, b);
|
|
116
117
|
assert.strictEqual(result, expectedResult);
|
|
117
118
|
});
|
|
118
119
|
it("should multiply two big negative numbers", () => {
|
|
119
|
-
const a = -
|
|
120
|
-
const b = -
|
|
120
|
+
const a = -MAX_VALUE_I64;
|
|
121
|
+
const b = -MAX_VALUE_I64;
|
|
121
122
|
const expectedResult = 0x4000000000000000n;
|
|
122
123
|
const result = mulUpperUU(a, b);
|
|
123
124
|
assert.strictEqual(result, expectedResult);
|
|
@@ -153,8 +154,8 @@ describe("math-utils", () => {
|
|
|
153
154
|
assert.strictEqual(result, expectedResult);
|
|
154
155
|
});
|
|
155
156
|
it("should multiply two big positive numbers", () => {
|
|
156
|
-
const a =
|
|
157
|
-
const b =
|
|
157
|
+
const a = MAX_VALUE_I64;
|
|
158
|
+
const b = MAX_VALUE_I64;
|
|
158
159
|
const expectedResult = 0x4000000000000000n;
|
|
159
160
|
const result = mulUpperSU(a, b);
|
|
160
161
|
assert.strictEqual(result, expectedResult);
|