@typeberry/lib 0.2.0-b6667ce → 0.2.0-c3df163
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/index.cjs +0 -3
- package/index.d.ts +772 -777
- package/index.js +0 -3
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -14196,6 +14196,82 @@ interface GasCounter {
|
|
|
14196
14196
|
sub(g: Gas): boolean;
|
|
14197
14197
|
}
|
|
14198
14198
|
|
|
14199
|
+
declare const NO_OF_REGISTERS$1 = 13;
|
|
14200
|
+
|
|
14201
|
+
type RegisterIndex = Opaque<number, "register index">;
|
|
14202
|
+
|
|
14203
|
+
declare class Registers {
|
|
14204
|
+
private asSigned: BigInt64Array;
|
|
14205
|
+
private asUnsigned: BigUint64Array;
|
|
14206
|
+
|
|
14207
|
+
constructor(private readonly bytes = safeAllocUint8Array(NO_OF_REGISTERS << REGISTER_SIZE_SHIFT)) {
|
|
14208
|
+
check`${bytes.length === NO_OF_REGISTERS << REGISTER_SIZE_SHIFT} Invalid size of registers array.`;
|
|
14209
|
+
this.asSigned = new BigInt64Array(bytes.buffer, bytes.byteOffset);
|
|
14210
|
+
this.asUnsigned = new BigUint64Array(bytes.buffer, bytes.byteOffset);
|
|
14211
|
+
}
|
|
14212
|
+
|
|
14213
|
+
static fromBytes(bytes: Uint8Array) {
|
|
14214
|
+
check`${bytes.length === NO_OF_REGISTERS << REGISTER_SIZE_SHIFT} Invalid size of registers array.`;
|
|
14215
|
+
return new Registers(bytes);
|
|
14216
|
+
}
|
|
14217
|
+
|
|
14218
|
+
getBytesAsLittleEndian(index: number, len: number) {
|
|
14219
|
+
const offset = index << REGISTER_SIZE_SHIFT;
|
|
14220
|
+
return this.bytes.subarray(offset, offset + len);
|
|
14221
|
+
}
|
|
14222
|
+
|
|
14223
|
+
getAllBytesAsLittleEndian() {
|
|
14224
|
+
return this.bytes;
|
|
14225
|
+
}
|
|
14226
|
+
|
|
14227
|
+
copyFrom(regs: Registers | BigUint64Array) {
|
|
14228
|
+
const array = regs instanceof BigUint64Array ? regs : regs.asUnsigned;
|
|
14229
|
+
this.asUnsigned.set(array);
|
|
14230
|
+
}
|
|
14231
|
+
|
|
14232
|
+
reset() {
|
|
14233
|
+
for (let i = 0; i < NO_OF_REGISTERS; i++) {
|
|
14234
|
+
this.asUnsigned[i] = 0n;
|
|
14235
|
+
}
|
|
14236
|
+
}
|
|
14237
|
+
|
|
14238
|
+
getLowerU32(registerIndex: number) {
|
|
14239
|
+
return Number(this.asUnsigned[registerIndex] & 0xff_ff_ff_ffn);
|
|
14240
|
+
}
|
|
14241
|
+
|
|
14242
|
+
getLowerI32(registerIndex: number) {
|
|
14243
|
+
return Number(this.getLowerU32(registerIndex)) >> 0;
|
|
14244
|
+
}
|
|
14245
|
+
|
|
14246
|
+
setU32(registerIndex: number, value: number) {
|
|
14247
|
+
this.asUnsigned[registerIndex] = signExtend32To64(value);
|
|
14248
|
+
}
|
|
14249
|
+
|
|
14250
|
+
setI32(registerIndex: number, value: number) {
|
|
14251
|
+
this.asSigned[registerIndex] = signExtend32To64(value);
|
|
14252
|
+
}
|
|
14253
|
+
|
|
14254
|
+
getU64(registerIndex: number) {
|
|
14255
|
+
return this.asUnsigned[registerIndex];
|
|
14256
|
+
}
|
|
14257
|
+
|
|
14258
|
+
getI64(registerIndex: number) {
|
|
14259
|
+
return this.asSigned[registerIndex];
|
|
14260
|
+
}
|
|
14261
|
+
|
|
14262
|
+
setU64(registerIndex: number, value: bigint) {
|
|
14263
|
+
this.asUnsigned[registerIndex] = value;
|
|
14264
|
+
}
|
|
14265
|
+
|
|
14266
|
+
setI64(registerIndex: number, value: bigint) {
|
|
14267
|
+
this.asSigned[registerIndex] = value;
|
|
14268
|
+
}
|
|
14269
|
+
|
|
14270
|
+
getAllU64() {
|
|
14271
|
+
return this.asUnsigned;
|
|
14272
|
+
}
|
|
14273
|
+
}
|
|
14274
|
+
|
|
14199
14275
|
/**
|
|
14200
14276
|
* Mask class is an implementation of skip function defined in GP.
|
|
14201
14277
|
*
|
|
@@ -14365,82 +14441,6 @@ declare class ImmediateDecoder {
|
|
|
14365
14441
|
}
|
|
14366
14442
|
}
|
|
14367
14443
|
|
|
14368
|
-
declare const NO_OF_REGISTERS$1 = 13;
|
|
14369
|
-
|
|
14370
|
-
type RegisterIndex = Opaque<number, "register index">;
|
|
14371
|
-
|
|
14372
|
-
declare class Registers {
|
|
14373
|
-
private asSigned: BigInt64Array;
|
|
14374
|
-
private asUnsigned: BigUint64Array;
|
|
14375
|
-
|
|
14376
|
-
constructor(private readonly bytes = safeAllocUint8Array(NO_OF_REGISTERS << REGISTER_SIZE_SHIFT)) {
|
|
14377
|
-
check`${bytes.length === NO_OF_REGISTERS << REGISTER_SIZE_SHIFT} Invalid size of registers array.`;
|
|
14378
|
-
this.asSigned = new BigInt64Array(bytes.buffer, bytes.byteOffset);
|
|
14379
|
-
this.asUnsigned = new BigUint64Array(bytes.buffer, bytes.byteOffset);
|
|
14380
|
-
}
|
|
14381
|
-
|
|
14382
|
-
static fromBytes(bytes: Uint8Array) {
|
|
14383
|
-
check`${bytes.length === NO_OF_REGISTERS << REGISTER_SIZE_SHIFT} Invalid size of registers array.`;
|
|
14384
|
-
return new Registers(bytes);
|
|
14385
|
-
}
|
|
14386
|
-
|
|
14387
|
-
getBytesAsLittleEndian(index: number, len: number) {
|
|
14388
|
-
const offset = index << REGISTER_SIZE_SHIFT;
|
|
14389
|
-
return this.bytes.subarray(offset, offset + len);
|
|
14390
|
-
}
|
|
14391
|
-
|
|
14392
|
-
getAllBytesAsLittleEndian() {
|
|
14393
|
-
return this.bytes;
|
|
14394
|
-
}
|
|
14395
|
-
|
|
14396
|
-
copyFrom(regs: Registers | BigUint64Array) {
|
|
14397
|
-
const array = regs instanceof BigUint64Array ? regs : regs.asUnsigned;
|
|
14398
|
-
this.asUnsigned.set(array);
|
|
14399
|
-
}
|
|
14400
|
-
|
|
14401
|
-
reset() {
|
|
14402
|
-
for (let i = 0; i < NO_OF_REGISTERS; i++) {
|
|
14403
|
-
this.asUnsigned[i] = 0n;
|
|
14404
|
-
}
|
|
14405
|
-
}
|
|
14406
|
-
|
|
14407
|
-
getLowerU32(registerIndex: number) {
|
|
14408
|
-
return Number(this.asUnsigned[registerIndex] & 0xff_ff_ff_ffn);
|
|
14409
|
-
}
|
|
14410
|
-
|
|
14411
|
-
getLowerI32(registerIndex: number) {
|
|
14412
|
-
return Number(this.getLowerU32(registerIndex)) >> 0;
|
|
14413
|
-
}
|
|
14414
|
-
|
|
14415
|
-
setU32(registerIndex: number, value: number) {
|
|
14416
|
-
this.asUnsigned[registerIndex] = signExtend32To64(value);
|
|
14417
|
-
}
|
|
14418
|
-
|
|
14419
|
-
setI32(registerIndex: number, value: number) {
|
|
14420
|
-
this.asSigned[registerIndex] = signExtend32To64(value);
|
|
14421
|
-
}
|
|
14422
|
-
|
|
14423
|
-
getU64(registerIndex: number) {
|
|
14424
|
-
return this.asUnsigned[registerIndex];
|
|
14425
|
-
}
|
|
14426
|
-
|
|
14427
|
-
getI64(registerIndex: number) {
|
|
14428
|
-
return this.asSigned[registerIndex];
|
|
14429
|
-
}
|
|
14430
|
-
|
|
14431
|
-
setU64(registerIndex: number, value: bigint) {
|
|
14432
|
-
this.asUnsigned[registerIndex] = value;
|
|
14433
|
-
}
|
|
14434
|
-
|
|
14435
|
-
setI64(registerIndex: number, value: bigint) {
|
|
14436
|
-
this.asSigned[registerIndex] = value;
|
|
14437
|
-
}
|
|
14438
|
-
|
|
14439
|
-
getAllU64() {
|
|
14440
|
-
return this.asUnsigned;
|
|
14441
|
-
}
|
|
14442
|
-
}
|
|
14443
|
-
|
|
14444
14444
|
declare class NibblesDecoder {
|
|
14445
14445
|
private byte = new Int8Array(1);
|
|
14446
14446
|
|
|
@@ -17877,870 +17877,865 @@ declare namespace index$8 {
|
|
|
17877
17877
|
export type { index$8_BigGas as BigGas, index$8_Gas as Gas, index$8_GasCounter as GasCounter, index$8_InterpreterOptions as InterpreterOptions, index$8_MemoryIndex as MemoryIndex, index$8_SbrkIndex as SbrkIndex, index$8_SmallGas as SmallGas };
|
|
17878
17878
|
}
|
|
17879
17879
|
|
|
17880
|
-
|
|
17881
|
-
|
|
17882
|
-
|
|
17883
|
-
|
|
17884
|
-
*/
|
|
17885
|
-
type ProgramCounter = Opaque<U64, "ProgramCounter[u64]">;
|
|
17886
|
-
/** Convert a number into ProgramCounter. */
|
|
17887
|
-
declare const tryAsProgramCounter = (v: number | bigint): ProgramCounter => asOpaqueType(tryAsU64(v));
|
|
17880
|
+
interface IHostCallMemory {
|
|
17881
|
+
storeFrom(address: U64, bytes: Uint8Array): Result$2<OK, PageFault | OutOfBounds>;
|
|
17882
|
+
loadInto(result: Uint8Array, startAddress: U64): Result$2<OK, PageFault | OutOfBounds>;
|
|
17883
|
+
}
|
|
17888
17884
|
|
|
17889
|
-
|
|
17890
|
-
|
|
17891
|
-
/** Convert a number into PVM instance identifier. */
|
|
17892
|
-
declare const tryAsMachineId = (v: number | bigint): MachineId => asOpaqueType(tryAsU64(v));
|
|
17885
|
+
declare class HostCallMemory implements IHostCallMemory {
|
|
17886
|
+
constructor(private readonly memory: Memory) {}
|
|
17893
17887
|
|
|
17894
|
-
|
|
17895
|
-
|
|
17896
|
-
|
|
17897
|
-
|
|
17898
|
-
|
|
17899
|
-
|
|
17900
|
-
|
|
17901
|
-
|
|
17902
|
-
|
|
17888
|
+
storeFrom(address: U64, bytes: Uint8Array): Result$2<OK, PageFault | OutOfBounds> {
|
|
17889
|
+
if (bytes.length === 0) {
|
|
17890
|
+
return Result.ok(OK);
|
|
17891
|
+
}
|
|
17892
|
+
|
|
17893
|
+
if (address + tryAsU64(bytes.length) > MEMORY_SIZE) {
|
|
17894
|
+
return Result.error(new OutOfBounds());
|
|
17895
|
+
}
|
|
17896
|
+
|
|
17897
|
+
return this.memory.storeFrom(tryAsMemoryIndex(Number(address)), bytes);
|
|
17903
17898
|
}
|
|
17904
|
-
}
|
|
17905
17899
|
|
|
17906
|
-
|
|
17907
|
-
|
|
17908
|
-
|
|
17909
|
-
hostCallIndex: U64;
|
|
17900
|
+
loadInto(result: Uint8Array, startAddress: U64): Result$2<OK, PageFault | OutOfBounds> {
|
|
17901
|
+
if (result.length === 0) {
|
|
17902
|
+
return Result.ok(OK);
|
|
17910
17903
|
}
|
|
17911
|
-
|
|
17912
|
-
|
|
17913
|
-
|
|
17904
|
+
|
|
17905
|
+
if (startAddress + tryAsU64(result.length) > MEMORY_SIZE) {
|
|
17906
|
+
return Result.error(new OutOfBounds());
|
|
17914
17907
|
}
|
|
17915
|
-
| {
|
|
17916
|
-
status: typeof Status.OK | typeof Status.HALT | typeof Status.PANIC | typeof Status.OOG;
|
|
17917
|
-
};
|
|
17918
17908
|
|
|
17919
|
-
|
|
17920
|
-
|
|
17921
|
-
|
|
17922
|
-
gas: BigGas;
|
|
17923
|
-
registers: Registers;
|
|
17924
|
-
};
|
|
17909
|
+
return this.memory.loadInto(result, tryAsMemoryIndex(Number(startAddress)));
|
|
17910
|
+
}
|
|
17911
|
+
}
|
|
17925
17912
|
|
|
17926
|
-
|
|
17927
|
-
|
|
17928
|
-
|
|
17929
|
-
Void = 0,
|
|
17930
|
-
/** Zeroes memory and set access to read-only. */
|
|
17931
|
-
ZeroRead = 1,
|
|
17932
|
-
/** Zeroes memory and set access to read-write. */
|
|
17933
|
-
ZeroWrite = 2,
|
|
17934
|
-
/** Preserve memory and set access to read-only. */
|
|
17935
|
-
Read = 3,
|
|
17936
|
-
/** Preserve memory and set access to read-write. */
|
|
17937
|
-
Write = 4,
|
|
17913
|
+
interface IHostCallRegisters {
|
|
17914
|
+
get(registerIndex: number): U64;
|
|
17915
|
+
set(registerIndex: number, value: U64): void;
|
|
17938
17916
|
}
|
|
17939
17917
|
|
|
17940
|
-
|
|
17941
|
-
|
|
17942
|
-
v <= MemoryOperation.Write && v >= MemoryOperation.Void ? Number(v) : null;
|
|
17918
|
+
declare class HostCallRegisters implements IHostCallRegisters {
|
|
17919
|
+
constructor(private readonly registers: Registers) {}
|
|
17943
17920
|
|
|
17944
|
-
|
|
17945
|
-
|
|
17946
|
-
|
|
17947
|
-
SourcePageFault = 0,
|
|
17948
|
-
/** Destination page fault. */
|
|
17949
|
-
DestinationPageFault = 1,
|
|
17950
|
-
/** No machine under given machine index. */
|
|
17951
|
-
NoMachine = 2,
|
|
17952
|
-
}
|
|
17921
|
+
get(registerIndex: number): U64 {
|
|
17922
|
+
return tryAsU64(this.registers.getU64(registerIndex));
|
|
17923
|
+
}
|
|
17953
17924
|
|
|
17954
|
-
|
|
17955
|
-
|
|
17956
|
-
|
|
17957
|
-
/** Attempting to void or zero non-accessible page. */
|
|
17958
|
-
InvalidPage = 1,
|
|
17925
|
+
set(registerIndex: number, value: U64) {
|
|
17926
|
+
this.registers.setU64(registerIndex, value);
|
|
17927
|
+
}
|
|
17959
17928
|
}
|
|
17960
17929
|
|
|
17961
|
-
|
|
17962
|
-
|
|
17963
|
-
|
|
17964
|
-
|
|
17965
|
-
InvalidOperation = 1,
|
|
17966
|
-
/** Attempting to change non-accessible page or trying to preserve value of voided page. */
|
|
17967
|
-
InvalidPage = 2,
|
|
17968
|
-
}
|
|
17969
|
-
|
|
17970
|
-
/** Error machine is not found. */
|
|
17971
|
-
declare const NoMachineError = Symbol("Machine index not found.");
|
|
17972
|
-
type NoMachineError = typeof NoMachineError;
|
|
17973
|
-
|
|
17974
|
-
/** Too many segments already exported. */
|
|
17975
|
-
declare const SegmentExportError = Symbol("Too many segments already exported.");
|
|
17976
|
-
type SegmentExportError = typeof SegmentExportError;
|
|
17977
|
-
|
|
17978
|
-
/** Host functions external invocations available during refine phase. */
|
|
17979
|
-
interface RefineExternalities {
|
|
17980
|
-
/** Forget a previously started nested VM. */
|
|
17981
|
-
machineExpunge(machineIndex: MachineId): Promise<Result$2<ProgramCounter, NoMachineError>>;
|
|
17930
|
+
/** Strictly-typed host call index. */
|
|
17931
|
+
type HostCallIndex = Opaque<U32, "HostCallIndex[U32]">;
|
|
17932
|
+
/** Attempt to convert a number into `HostCallIndex`. */
|
|
17933
|
+
declare const tryAsHostCallIndex = (v: number): HostCallIndex => asOpaqueType(tryAsU32(v));
|
|
17982
17934
|
|
|
17983
|
-
|
|
17984
|
-
|
|
17935
|
+
/**
|
|
17936
|
+
* Host-call exit reason.
|
|
17937
|
+
*
|
|
17938
|
+
* https://graypaper.fluffylabs.dev/#/ab2cdbd/24a30124a501?v=0.7.2
|
|
17939
|
+
*/
|
|
17940
|
+
declare enum PvmExecution {
|
|
17941
|
+
Halt = 0,
|
|
17942
|
+
Panic = 1,
|
|
17943
|
+
OOG = 2, // out-of-gas
|
|
17944
|
+
}
|
|
17985
17945
|
|
|
17986
|
-
|
|
17987
|
-
|
|
17946
|
+
/** A utility function to easily trace a bunch of registers. */
|
|
17947
|
+
declare function traceRegisters(...regs: number[]) {
|
|
17948
|
+
return regs.map(tryAsRegisterIndex);
|
|
17949
|
+
}
|
|
17988
17950
|
|
|
17989
|
-
|
|
17990
|
-
|
|
17991
|
-
|
|
17992
|
-
|
|
17993
|
-
sourceStart: U64,
|
|
17994
|
-
length: U64,
|
|
17995
|
-
destination: Memory,
|
|
17996
|
-
): Promise<Result$2<OK, PeekPokeError>>;
|
|
17951
|
+
/** An interface for a host call implementation */
|
|
17952
|
+
interface HostCallHandler {
|
|
17953
|
+
/** Index of that host call (i.e. what PVM invokes via `ecalli`) */
|
|
17954
|
+
readonly index: HostCallIndex;
|
|
17997
17955
|
|
|
17998
|
-
/**
|
|
17999
|
-
|
|
18000
|
-
|
|
18001
|
-
|
|
18002
|
-
|
|
18003
|
-
|
|
18004
|
-
source: Memory,
|
|
18005
|
-
): Promise<Result$2<OK, PeekPokeError>>;
|
|
17956
|
+
/**
|
|
17957
|
+
* The gas cost of invocation of that host call.
|
|
17958
|
+
*
|
|
17959
|
+
* NOTE: `((reg: IHostCallRegisters) => Gas)` function is for compatibility reasons: pre GP 0.7.2
|
|
17960
|
+
*/
|
|
17961
|
+
readonly basicGasCost: SmallGas | ((reg: IHostCallRegisters) => Gas);
|
|
18006
17962
|
|
|
18007
|
-
/**
|
|
18008
|
-
|
|
17963
|
+
/** Currently executing service id. */
|
|
17964
|
+
readonly currentServiceId: U32;
|
|
18009
17965
|
|
|
18010
|
-
/**
|
|
18011
|
-
|
|
18012
|
-
machineIndex: MachineId,
|
|
18013
|
-
gas: BigGas,
|
|
18014
|
-
registers: Registers,
|
|
18015
|
-
): Promise<Result$2<MachineResult, NoMachineError>>;
|
|
17966
|
+
/** Input&Output registers that we should add to tracing log. */
|
|
17967
|
+
readonly tracedRegisters: RegisterIndex[];
|
|
18016
17968
|
|
|
18017
17969
|
/**
|
|
18018
|
-
*
|
|
17970
|
+
* Actually execute the host call.
|
|
18019
17971
|
*
|
|
18020
|
-
*
|
|
17972
|
+
* NOTE the call is ALLOWED and expected to modify registers and memory.
|
|
18021
17973
|
*/
|
|
18022
|
-
|
|
18023
|
-
|
|
18024
|
-
/** Lookup a historical preimage. */
|
|
18025
|
-
historicalLookup(serviceId: ServiceId | null, hash: Blake2bHash): Promise<BytesBlob | null>;
|
|
18026
|
-
|
|
18027
|
-
/** Change access to and/or zero the value of memory. */
|
|
18028
|
-
machinePages(
|
|
18029
|
-
machineIndex: MachineId,
|
|
18030
|
-
pageStart: U64,
|
|
18031
|
-
pageCount: U64,
|
|
18032
|
-
requestType: MemoryOperation | null,
|
|
18033
|
-
): Promise<Result$2<OK, PagesError>>;
|
|
17974
|
+
execute(gas: GasCounter, regs: IHostCallRegisters, memory: IHostCallMemory): Promise<undefined | PvmExecution>;
|
|
18034
17975
|
}
|
|
18035
17976
|
|
|
18036
|
-
|
|
18037
|
-
|
|
18038
|
-
|
|
18039
|
-
|
|
18040
|
-
type ServiceStateUpdate = Partial<Pick<State, "privilegedServices" | "authQueues" | "designatedValidatorData">> &
|
|
18041
|
-
ServicesUpdate;
|
|
17977
|
+
/** Container for all available host calls. */
|
|
17978
|
+
declare class HostCallsManager {
|
|
17979
|
+
private readonly hostCalls = new Map<HostCallIndex, HostCallHandler>();
|
|
17980
|
+
private readonly missing;
|
|
18042
17981
|
|
|
18043
|
-
|
|
18044
|
-
|
|
18045
|
-
|
|
18046
|
-
|
|
18047
|
-
|
|
18048
|
-
|
|
18049
|
-
|
|
18050
|
-
|
|
18051
|
-
new Map();
|
|
18052
|
-
/** New validators data. */
|
|
18053
|
-
public validatorsData: PerValidator<ValidatorData> | null = null;
|
|
18054
|
-
/** Updated priviliged services. */
|
|
18055
|
-
public privilegedServices: PrivilegedServices | null = null;
|
|
17982
|
+
constructor({
|
|
17983
|
+
missing,
|
|
17984
|
+
handlers = [],
|
|
17985
|
+
}: {
|
|
17986
|
+
missing: HostCallHandler;
|
|
17987
|
+
handlers?: HostCallHandler[];
|
|
17988
|
+
}) {
|
|
17989
|
+
this.missing = missing;
|
|
18056
17990
|
|
|
18057
|
-
|
|
18058
|
-
|
|
18059
|
-
|
|
18060
|
-
|
|
18061
|
-
|
|
18062
|
-
/** Yielded accumulation root. */
|
|
18063
|
-
public readonly yieldedRoots: Map<ServiceId, OpaqueHash> = new Map(),
|
|
18064
|
-
) {}
|
|
17991
|
+
for (const handler of handlers) {
|
|
17992
|
+
check`${this.hostCalls.get(handler.index) === undefined} Overwriting host call handler at index ${handler.index}`;
|
|
17993
|
+
this.hostCalls.set(handler.index, handler);
|
|
17994
|
+
}
|
|
17995
|
+
}
|
|
18065
17996
|
|
|
18066
|
-
/**
|
|
18067
|
-
|
|
18068
|
-
return
|
|
18069
|
-
{
|
|
18070
|
-
servicesUpdates: [],
|
|
18071
|
-
servicesRemoved: [],
|
|
18072
|
-
preimages: [],
|
|
18073
|
-
storage: [],
|
|
18074
|
-
},
|
|
18075
|
-
[],
|
|
18076
|
-
);
|
|
17997
|
+
/** Get a host call by index. */
|
|
17998
|
+
get(hostCallIndex: HostCallIndex): HostCallHandler {
|
|
17999
|
+
return this.hostCalls.get(hostCallIndex) ?? this.missing;
|
|
18077
18000
|
}
|
|
18078
18001
|
|
|
18079
|
-
|
|
18080
|
-
|
|
18081
|
-
|
|
18082
|
-
|
|
18083
|
-
|
|
18084
|
-
|
|
18085
|
-
|
|
18086
|
-
|
|
18002
|
+
traceHostCall(
|
|
18003
|
+
context: string,
|
|
18004
|
+
hostCallIndex: HostCallIndex,
|
|
18005
|
+
hostCallHandler: HostCallHandler,
|
|
18006
|
+
registers: IHostCallRegisters,
|
|
18007
|
+
gas: Gas,
|
|
18008
|
+
) {
|
|
18009
|
+
const { currentServiceId } = hostCallHandler;
|
|
18010
|
+
const requested = hostCallIndex !== hostCallHandler.index ? ` (${hostCallIndex})` : "";
|
|
18011
|
+
const name = `${hostCallHandler.constructor.name}:${hostCallHandler.index}`;
|
|
18012
|
+
const registerValues = hostCallHandler.tracedRegisters
|
|
18013
|
+
.map((idx) => [idx.toString().padStart(2, "0"), registers.get(idx)] as const)
|
|
18014
|
+
.filter((v) => v[1] !== 0n)
|
|
18015
|
+
.map(([idx, value]) => {
|
|
18016
|
+
return `r${idx}=${value} (0x${value.toString(16)})`;
|
|
18017
|
+
})
|
|
18018
|
+
.join(", ");
|
|
18019
|
+
logger.insane`[${currentServiceId}] ${context} ${name}${requested}. Gas: ${gas}. Regs: ${registerValues}.`;
|
|
18087
18020
|
}
|
|
18021
|
+
}
|
|
18088
18022
|
|
|
18089
|
-
|
|
18090
|
-
static copyFrom(from: AccumulationStateUpdate): AccumulationStateUpdate {
|
|
18091
|
-
const serviceUpdates: ServicesUpdate = {
|
|
18092
|
-
servicesUpdates: [...from.services.servicesUpdates],
|
|
18093
|
-
servicesRemoved: [...from.services.servicesRemoved],
|
|
18094
|
-
preimages: [...from.services.preimages],
|
|
18095
|
-
storage: [...from.services.storage],
|
|
18096
|
-
};
|
|
18097
|
-
const transfers = [...from.transfers];
|
|
18098
|
-
const update = new AccumulationStateUpdate(serviceUpdates, transfers, new Map(from.yieldedRoots));
|
|
18023
|
+
type ResolveFn = (pvm: Interpreter) => void;
|
|
18099
18024
|
|
|
18100
|
-
|
|
18101
|
-
|
|
18102
|
-
|
|
18103
|
-
}
|
|
18025
|
+
declare class InterpreterInstanceManager {
|
|
18026
|
+
private instances: Interpreter[] = [];
|
|
18027
|
+
private waitingQueue: ResolveFn[] = [];
|
|
18104
18028
|
|
|
18105
|
-
|
|
18106
|
-
|
|
18029
|
+
constructor(noOfPvmInstances: number) {
|
|
18030
|
+
for (let i = 0; i < noOfPvmInstances; i++) {
|
|
18031
|
+
this.instances.push(
|
|
18032
|
+
new Interpreter({
|
|
18033
|
+
useSbrkGas: false,
|
|
18034
|
+
}),
|
|
18035
|
+
);
|
|
18107
18036
|
}
|
|
18037
|
+
}
|
|
18108
18038
|
|
|
18109
|
-
|
|
18110
|
-
|
|
18111
|
-
|
|
18112
|
-
|
|
18113
|
-
});
|
|
18039
|
+
async getInstance(): Promise<Interpreter> {
|
|
18040
|
+
const instance = this.instances.pop();
|
|
18041
|
+
if (instance !== undefined) {
|
|
18042
|
+
return Promise.resolve(instance);
|
|
18114
18043
|
}
|
|
18115
|
-
return
|
|
18044
|
+
return new Promise((resolve) => {
|
|
18045
|
+
this.waitingQueue.push(resolve);
|
|
18046
|
+
});
|
|
18116
18047
|
}
|
|
18117
18048
|
|
|
18118
|
-
|
|
18119
|
-
|
|
18120
|
-
|
|
18121
|
-
|
|
18122
|
-
|
|
18049
|
+
releaseInstance(pvm: Interpreter) {
|
|
18050
|
+
const waiting = this.waitingQueue.shift();
|
|
18051
|
+
if (waiting !== undefined) {
|
|
18052
|
+
return waiting(pvm);
|
|
18053
|
+
}
|
|
18054
|
+
this.instances.push(pvm);
|
|
18123
18055
|
}
|
|
18124
18056
|
}
|
|
18125
18057
|
|
|
18126
|
-
|
|
18127
|
-
|
|
18128
|
-
|
|
18129
|
-
|
|
18130
|
-
|
|
18131
|
-
|
|
18132
|
-
constructor(
|
|
18133
|
-
/** Original (unmodified state). */
|
|
18134
|
-
public readonly state: T,
|
|
18135
|
-
stateUpdate?: AccumulationStateUpdate,
|
|
18058
|
+
declare class ReturnValue {
|
|
18059
|
+
private constructor(
|
|
18060
|
+
public consumedGas: Gas,
|
|
18061
|
+
public status: Status | null,
|
|
18062
|
+
public memorySlice: Uint8Array | null,
|
|
18136
18063
|
) {
|
|
18137
|
-
|
|
18138
|
-
|
|
18064
|
+
check`
|
|
18065
|
+
${(status === null && memorySlice !== null) || (status !== null && memorySlice === null)}
|
|
18066
|
+
'status' and 'memorySlice' must not both be null or both be non-null — exactly one must be provided
|
|
18067
|
+
`;
|
|
18139
18068
|
}
|
|
18140
18069
|
|
|
18141
|
-
|
|
18142
|
-
|
|
18143
|
-
|
|
18144
|
-
* NOTE the info may be updated compared to what is in the state.
|
|
18145
|
-
*
|
|
18146
|
-
* Takes into account ejected and newly created services as well.
|
|
18147
|
-
*/
|
|
18148
|
-
getServiceInfo(destination: ServiceId | null): ServiceAccountInfo | null {
|
|
18149
|
-
if (destination === null) {
|
|
18150
|
-
return null;
|
|
18151
|
-
}
|
|
18152
|
-
|
|
18153
|
-
const maybeNewService = this.stateUpdate.services.servicesUpdates.find(
|
|
18154
|
-
(update) => update.serviceId === destination,
|
|
18155
|
-
);
|
|
18156
|
-
|
|
18157
|
-
if (maybeNewService !== undefined) {
|
|
18158
|
-
return maybeNewService.action.account;
|
|
18159
|
-
}
|
|
18160
|
-
|
|
18161
|
-
const maybeService = this.state.getService(destination);
|
|
18162
|
-
if (maybeService === null) {
|
|
18163
|
-
return null;
|
|
18164
|
-
}
|
|
18070
|
+
static fromStatus(consumedGas: Gas, status: Status) {
|
|
18071
|
+
return new ReturnValue(consumedGas, status, null);
|
|
18072
|
+
}
|
|
18165
18073
|
|
|
18166
|
-
|
|
18074
|
+
static fromMemorySlice(consumedGas: Gas, memorySlice: Uint8Array) {
|
|
18075
|
+
return new ReturnValue(consumedGas, null, memorySlice);
|
|
18167
18076
|
}
|
|
18168
18077
|
|
|
18169
|
-
|
|
18170
|
-
|
|
18171
|
-
|
|
18172
|
-
return item.value;
|
|
18173
|
-
}
|
|
18078
|
+
hasMemorySlice(): this is this & { status: null; memorySlice: Uint8Array } {
|
|
18079
|
+
return this.memorySlice instanceof Uint8Array && this.status === null;
|
|
18080
|
+
}
|
|
18174
18081
|
|
|
18175
|
-
|
|
18176
|
-
return
|
|
18082
|
+
hasStatus(): this is this & { status: Status; memorySlice: null } {
|
|
18083
|
+
return !this.hasMemorySlice();
|
|
18177
18084
|
}
|
|
18085
|
+
}
|
|
18086
|
+
declare class HostCalls {
|
|
18087
|
+
constructor(
|
|
18088
|
+
private pvmInstanceManager: InterpreterInstanceManager,
|
|
18089
|
+
private hostCalls: HostCallsManager,
|
|
18090
|
+
) {}
|
|
18178
18091
|
|
|
18179
|
-
|
|
18180
|
-
|
|
18181
|
-
|
|
18182
|
-
|
|
18183
|
-
* NOTE: Does not check if the preimage is available, we just check
|
|
18184
|
-
* the existence in `preimages` map.
|
|
18185
|
-
*/
|
|
18186
|
-
hasPreimage(serviceId: ServiceId, hash: PreimageHash): boolean {
|
|
18187
|
-
const providedPreimage = this.stateUpdate.services.preimages.find(
|
|
18188
|
-
// we ignore the action here, since if there is <any> update on that
|
|
18189
|
-
// hash it means it has to exist, right?
|
|
18190
|
-
(p) => p.serviceId === serviceId && p.hash.isEqualTo(hash),
|
|
18191
|
-
);
|
|
18192
|
-
if (providedPreimage !== undefined) {
|
|
18193
|
-
return true;
|
|
18092
|
+
private getReturnValue(status: Status, pvmInstance: Interpreter): ReturnValue {
|
|
18093
|
+
const gasConsumed = pvmInstance.getGasConsumed();
|
|
18094
|
+
if (status === Status.OOG) {
|
|
18095
|
+
return ReturnValue.fromStatus(gasConsumed, status);
|
|
18194
18096
|
}
|
|
18195
18097
|
|
|
18196
|
-
|
|
18197
|
-
|
|
18198
|
-
|
|
18199
|
-
|
|
18200
|
-
|
|
18098
|
+
if (status === Status.HALT) {
|
|
18099
|
+
const memory = pvmInstance.getMemory();
|
|
18100
|
+
const regs = pvmInstance.getRegisters();
|
|
18101
|
+
const maybeAddress = regs.getLowerU32(7);
|
|
18102
|
+
const maybeLength = regs.getLowerU32(8);
|
|
18201
18103
|
|
|
18202
|
-
|
|
18203
|
-
|
|
18104
|
+
const result = safeAllocUint8Array(maybeLength);
|
|
18105
|
+
const startAddress = tryAsMemoryIndex(maybeAddress);
|
|
18106
|
+
const loadResult = memory.loadInto(result, startAddress);
|
|
18204
18107
|
|
|
18205
|
-
|
|
18206
|
-
|
|
18207
|
-
|
|
18208
|
-
|
|
18209
|
-
|
|
18210
|
-
if (freshlyProvided !== undefined && freshlyProvided.action.kind === UpdatePreimageKind.Provide) {
|
|
18211
|
-
return freshlyProvided.action.preimage.blob;
|
|
18108
|
+
if (loadResult.isError) {
|
|
18109
|
+
return ReturnValue.fromMemorySlice(gasConsumed, new Uint8Array());
|
|
18110
|
+
}
|
|
18111
|
+
|
|
18112
|
+
return ReturnValue.fromMemorySlice(gasConsumed, result);
|
|
18212
18113
|
}
|
|
18213
18114
|
|
|
18214
|
-
|
|
18215
|
-
return service?.getPreimage(hash) ?? null;
|
|
18115
|
+
return ReturnValue.fromStatus(gasConsumed, Status.PANIC);
|
|
18216
18116
|
}
|
|
18217
18117
|
|
|
18218
|
-
|
|
18219
|
-
|
|
18220
|
-
|
|
18221
|
-
|
|
18222
|
-
|
|
18223
|
-
|
|
18224
|
-
): LookupHistoryItem | null {
|
|
18225
|
-
// TODO [ToDr] This is most likely wrong. We may have `provide` and `remove` within
|
|
18226
|
-
// the same state update. We should however switch to proper "updated state"
|
|
18227
|
-
// representation soon.
|
|
18228
|
-
const updatedPreimage = this.stateUpdate.services.preimages.findLast(
|
|
18229
|
-
(update) => update.serviceId === serviceId && update.hash.isEqualTo(hash) && BigInt(update.length) === length,
|
|
18230
|
-
);
|
|
18231
|
-
|
|
18232
|
-
const stateFallback = () => {
|
|
18233
|
-
// fallback to state lookup
|
|
18234
|
-
const service = this.state.getService(serviceId);
|
|
18235
|
-
const lenU32 = preimageLenAsU32(length);
|
|
18236
|
-
if (lenU32 === null || service === null) {
|
|
18237
|
-
return null;
|
|
18118
|
+
private async execute(pvmInstance: Interpreter) {
|
|
18119
|
+
pvmInstance.runProgram();
|
|
18120
|
+
for (;;) {
|
|
18121
|
+
let status = pvmInstance.getStatus();
|
|
18122
|
+
if (status !== Status.HOST) {
|
|
18123
|
+
return this.getReturnValue(status, pvmInstance);
|
|
18238
18124
|
}
|
|
18125
|
+
check`
|
|
18126
|
+
${pvmInstance.getExitParam() !== null}
|
|
18127
|
+
"We know that the exit param is not null, because the status is 'Status.HOST'
|
|
18128
|
+
`;
|
|
18129
|
+
const hostCallIndex = pvmInstance.getExitParam() ?? -1;
|
|
18130
|
+
const gas = pvmInstance.getGasCounter();
|
|
18131
|
+
const regs = new HostCallRegisters(pvmInstance.getRegisters());
|
|
18132
|
+
const memory = new HostCallMemory(pvmInstance.getMemory());
|
|
18133
|
+
const index = tryAsHostCallIndex(hostCallIndex);
|
|
18239
18134
|
|
|
18240
|
-
const
|
|
18241
|
-
|
|
18242
|
-
|
|
18135
|
+
const hostCall = this.hostCalls.get(index);
|
|
18136
|
+
const gasBefore = gas.get();
|
|
18137
|
+
// NOTE: `basicGasCost(regs)` function is for compatibility reasons: pre GP 0.7.2
|
|
18138
|
+
const basicGasCost =
|
|
18139
|
+
typeof hostCall.basicGasCost === "number" ? hostCall.basicGasCost : hostCall.basicGasCost(regs);
|
|
18140
|
+
const underflow = gas.sub(basicGasCost);
|
|
18243
18141
|
|
|
18244
|
-
|
|
18245
|
-
|
|
18246
|
-
|
|
18142
|
+
const pcLog = `[PC: ${pvmInstance.getPC()}]`;
|
|
18143
|
+
if (underflow) {
|
|
18144
|
+
this.hostCalls.traceHostCall(`${pcLog} OOG`, index, hostCall, regs, gas.get());
|
|
18145
|
+
return ReturnValue.fromStatus(pvmInstance.getGasConsumed(), Status.OOG);
|
|
18146
|
+
}
|
|
18147
|
+
this.hostCalls.traceHostCall(`${pcLog} Invoking`, index, hostCall, regs, gasBefore);
|
|
18148
|
+
const result = await hostCall.execute(gas, regs, memory);
|
|
18149
|
+
this.hostCalls.traceHostCall(
|
|
18150
|
+
result === undefined ? `${pcLog} Result` : `${pcLog} Status(${PvmExecution[result]})`,
|
|
18151
|
+
index,
|
|
18152
|
+
hostCall,
|
|
18153
|
+
regs,
|
|
18154
|
+
gas.get(),
|
|
18155
|
+
);
|
|
18247
18156
|
|
|
18248
|
-
|
|
18249
|
-
|
|
18250
|
-
|
|
18251
|
-
// casting to U32 is safe, since we compare with object we have in memory.
|
|
18252
|
-
return new LookupHistoryItem(hash, updatedPreimage.length, tryAsLookupHistorySlots([currentTimeslot]));
|
|
18157
|
+
if (result === PvmExecution.Halt) {
|
|
18158
|
+
status = Status.HALT;
|
|
18159
|
+
return this.getReturnValue(status, pvmInstance);
|
|
18253
18160
|
}
|
|
18254
|
-
case UpdatePreimageKind.Remove: {
|
|
18255
|
-
const state = stateFallback();
|
|
18256
|
-
// kinda impossible, since we know it's there because it's removed.
|
|
18257
|
-
if (state === null) {
|
|
18258
|
-
return null;
|
|
18259
|
-
}
|
|
18260
18161
|
|
|
18261
|
-
|
|
18162
|
+
if (result === PvmExecution.Panic) {
|
|
18163
|
+
status = Status.PANIC;
|
|
18164
|
+
return this.getReturnValue(status, pvmInstance);
|
|
18262
18165
|
}
|
|
18263
|
-
|
|
18264
|
-
|
|
18166
|
+
|
|
18167
|
+
if (result === PvmExecution.OOG) {
|
|
18168
|
+
status = Status.OOG;
|
|
18169
|
+
return this.getReturnValue(status, pvmInstance);
|
|
18170
|
+
}
|
|
18171
|
+
|
|
18172
|
+
if (result === undefined) {
|
|
18173
|
+
pvmInstance.runProgram();
|
|
18174
|
+
status = pvmInstance.getStatus();
|
|
18175
|
+
continue;
|
|
18265
18176
|
}
|
|
18177
|
+
|
|
18178
|
+
assertNever(result);
|
|
18266
18179
|
}
|
|
18180
|
+
}
|
|
18267
18181
|
|
|
18268
|
-
|
|
18182
|
+
async runProgram(
|
|
18183
|
+
rawProgram: Uint8Array,
|
|
18184
|
+
initialPc: number,
|
|
18185
|
+
initialGas: Gas,
|
|
18186
|
+
maybeRegisters?: Registers,
|
|
18187
|
+
maybeMemory?: Memory,
|
|
18188
|
+
): Promise<ReturnValue> {
|
|
18189
|
+
const pvmInstance = await this.pvmInstanceManager.getInstance();
|
|
18190
|
+
pvmInstance.reset(rawProgram, initialPc, initialGas, maybeRegisters, maybeMemory);
|
|
18191
|
+
try {
|
|
18192
|
+
return await this.execute(pvmInstance);
|
|
18193
|
+
} finally {
|
|
18194
|
+
this.pvmInstanceManager.releaseInstance(pvmInstance);
|
|
18195
|
+
}
|
|
18269
18196
|
}
|
|
18197
|
+
}
|
|
18270
18198
|
|
|
18271
|
-
|
|
18199
|
+
type index$7_HostCallHandler = HostCallHandler;
|
|
18200
|
+
type index$7_HostCallMemory = HostCallMemory;
|
|
18201
|
+
declare const index$7_HostCallMemory: typeof HostCallMemory;
|
|
18202
|
+
type index$7_HostCallRegisters = HostCallRegisters;
|
|
18203
|
+
declare const index$7_HostCallRegisters: typeof HostCallRegisters;
|
|
18204
|
+
type index$7_IHostCallMemory = IHostCallMemory;
|
|
18205
|
+
type index$7_IHostCallRegisters = IHostCallRegisters;
|
|
18206
|
+
type index$7_PvmExecution = PvmExecution;
|
|
18207
|
+
declare const index$7_PvmExecution: typeof PvmExecution;
|
|
18208
|
+
declare const index$7_traceRegisters: typeof traceRegisters;
|
|
18209
|
+
declare const index$7_tryAsHostCallIndex: typeof tryAsHostCallIndex;
|
|
18210
|
+
declare namespace index$7 {
|
|
18211
|
+
export { index$7_HostCallMemory as HostCallMemory, index$7_HostCallRegisters as HostCallRegisters, HostCallsManager as HostCalls, index$7_PvmExecution as PvmExecution, HostCalls as PvmHostCallExtension, InterpreterInstanceManager as PvmInstanceManager, index$7_traceRegisters as traceRegisters, index$7_tryAsHostCallIndex as tryAsHostCallIndex };
|
|
18212
|
+
export type { index$7_HostCallHandler as HostCallHandler, index$7_IHostCallMemory as IHostCallMemory, index$7_IHostCallRegisters as IHostCallRegisters };
|
|
18213
|
+
}
|
|
18272
18214
|
|
|
18273
|
-
|
|
18274
|
-
|
|
18275
|
-
|
|
18276
|
-
|
|
18277
|
-
|
|
18278
|
-
|
|
18279
|
-
|
|
18280
|
-
|
|
18215
|
+
/**
|
|
18216
|
+
* Program counter is a 64-bit unsigned integer that points to the next instruction
|
|
18217
|
+
*
|
|
18218
|
+
* https://graypaper.fluffylabs.dev/#/1c979cb/2e3f012e3f01?v=0.7.1
|
|
18219
|
+
*/
|
|
18220
|
+
type ProgramCounter = Opaque<U64, "ProgramCounter[u64]">;
|
|
18221
|
+
/** Convert a number into ProgramCounter. */
|
|
18222
|
+
declare const tryAsProgramCounter = (v: number | bigint): ProgramCounter => asOpaqueType(tryAsU64(v));
|
|
18281
18223
|
|
|
18282
|
-
|
|
18283
|
-
|
|
18284
|
-
|
|
18285
|
-
|
|
18286
|
-
|
|
18224
|
+
/** Running PVM instance identifier. */
|
|
18225
|
+
type MachineId = Opaque<U64, "MachineId[u64]">;
|
|
18226
|
+
/** Convert a number into PVM instance identifier. */
|
|
18227
|
+
declare const tryAsMachineId = (v: number | bigint): MachineId => asOpaqueType(tryAsU64(v));
|
|
18228
|
+
|
|
18229
|
+
declare class MachineInstance {
|
|
18230
|
+
async run(gas: BigGas, registers: Registers): Promise<MachineResult> {
|
|
18231
|
+
return {
|
|
18232
|
+
result: {
|
|
18233
|
+
status: Status.OK,
|
|
18234
|
+
},
|
|
18235
|
+
gas,
|
|
18236
|
+
registers,
|
|
18237
|
+
};
|
|
18287
18238
|
}
|
|
18239
|
+
}
|
|
18288
18240
|
|
|
18289
|
-
|
|
18290
|
-
|
|
18291
|
-
|
|
18292
|
-
|
|
18293
|
-
|
|
18294
|
-
|
|
18295
|
-
|
|
18296
|
-
|
|
18297
|
-
|
|
18241
|
+
type MachineStatus =
|
|
18242
|
+
| {
|
|
18243
|
+
status: typeof Status.HOST;
|
|
18244
|
+
hostCallIndex: U64;
|
|
18245
|
+
}
|
|
18246
|
+
| {
|
|
18247
|
+
status: typeof Status.FAULT;
|
|
18248
|
+
address: U64;
|
|
18249
|
+
}
|
|
18250
|
+
| {
|
|
18251
|
+
status: typeof Status.OK | typeof Status.HALT | typeof Status.PANIC | typeof Status.OOG;
|
|
18252
|
+
};
|
|
18298
18253
|
|
|
18299
|
-
|
|
18300
|
-
|
|
18301
|
-
|
|
18302
|
-
|
|
18303
|
-
|
|
18304
|
-
|
|
18305
|
-
check`${items >= 0} storageUtilisationCount has to be a positive number, got: ${items}`;
|
|
18306
|
-
check`${bytes >= 0} storageUtilisationBytes has to be a positive number, got: ${bytes}`;
|
|
18254
|
+
/** Data returned by a machine invocation. */
|
|
18255
|
+
type MachineResult = {
|
|
18256
|
+
result: MachineStatus;
|
|
18257
|
+
gas: BigGas;
|
|
18258
|
+
registers: Registers;
|
|
18259
|
+
};
|
|
18307
18260
|
|
|
18308
|
-
|
|
18309
|
-
|
|
18261
|
+
/** Types of possbile operations to request by Pages host call. */
|
|
18262
|
+
declare enum MemoryOperation {
|
|
18263
|
+
/** Zeroes memory and set access to unreadable. */
|
|
18264
|
+
Void = 0,
|
|
18265
|
+
/** Zeroes memory and set access to read-only. */
|
|
18266
|
+
ZeroRead = 1,
|
|
18267
|
+
/** Zeroes memory and set access to read-write. */
|
|
18268
|
+
ZeroWrite = 2,
|
|
18269
|
+
/** Preserve memory and set access to read-only. */
|
|
18270
|
+
Read = 3,
|
|
18271
|
+
/** Preserve memory and set access to read-write. */
|
|
18272
|
+
Write = 4,
|
|
18273
|
+
}
|
|
18310
18274
|
|
|
18311
|
-
|
|
18312
|
-
|
|
18313
|
-
|
|
18314
|
-
}
|
|
18275
|
+
/** Convert a number into MemoryOperation or null (if invalid). */
|
|
18276
|
+
declare const toMemoryOperation = (v: number | bigint): MemoryOperation | null =>
|
|
18277
|
+
v <= MemoryOperation.Write && v >= MemoryOperation.Void ? Number(v) : null;
|
|
18315
18278
|
|
|
18316
|
-
|
|
18317
|
-
|
|
18318
|
-
|
|
18319
|
-
|
|
18279
|
+
/** An error that may occur during `peek` or `poke` host call. */
|
|
18280
|
+
declare enum PeekPokeError {
|
|
18281
|
+
/** Source page fault. */
|
|
18282
|
+
SourcePageFault = 0,
|
|
18283
|
+
/** Destination page fault. */
|
|
18284
|
+
DestinationPageFault = 1,
|
|
18285
|
+
/** No machine under given machine index. */
|
|
18286
|
+
NoMachine = 2,
|
|
18287
|
+
}
|
|
18320
18288
|
|
|
18321
|
-
|
|
18322
|
-
|
|
18323
|
-
|
|
18324
|
-
|
|
18325
|
-
|
|
18326
|
-
|
|
18327
|
-
storageUtilisationCount: items,
|
|
18328
|
-
}),
|
|
18329
|
-
);
|
|
18330
|
-
return Result.ok(OK);
|
|
18331
|
-
}
|
|
18289
|
+
declare enum ZeroVoidError {
|
|
18290
|
+
/** No machine under given machine index. */
|
|
18291
|
+
NoMachine = 0,
|
|
18292
|
+
/** Attempting to void or zero non-accessible page. */
|
|
18293
|
+
InvalidPage = 1,
|
|
18294
|
+
}
|
|
18332
18295
|
|
|
18333
|
-
|
|
18334
|
-
|
|
18335
|
-
|
|
18336
|
-
|
|
18296
|
+
declare enum PagesError {
|
|
18297
|
+
/** No machine under given machine index. */
|
|
18298
|
+
NoMachine = 0,
|
|
18299
|
+
/** Invalid memory operation. */
|
|
18300
|
+
InvalidOperation = 1,
|
|
18301
|
+
/** Attempting to change non-accessible page or trying to preserve value of voided page. */
|
|
18302
|
+
InvalidPage = 2,
|
|
18303
|
+
}
|
|
18337
18304
|
|
|
18338
|
-
|
|
18339
|
-
|
|
18340
|
-
|
|
18341
|
-
toRemove,
|
|
18342
|
-
UpdateService.create({
|
|
18343
|
-
serviceId,
|
|
18344
|
-
serviceInfo: newInfo,
|
|
18345
|
-
lookupHistory: existingItem.action.lookupHistory,
|
|
18346
|
-
}),
|
|
18347
|
-
);
|
|
18305
|
+
/** Error machine is not found. */
|
|
18306
|
+
declare const NoMachineError = Symbol("Machine index not found.");
|
|
18307
|
+
type NoMachineError = typeof NoMachineError;
|
|
18348
18308
|
|
|
18349
|
-
|
|
18350
|
-
|
|
18309
|
+
/** Too many segments already exported. */
|
|
18310
|
+
declare const SegmentExportError = Symbol("Too many segments already exported.");
|
|
18311
|
+
type SegmentExportError = typeof SegmentExportError;
|
|
18351
18312
|
|
|
18352
|
-
|
|
18353
|
-
|
|
18354
|
-
|
|
18355
|
-
|
|
18356
|
-
serviceId,
|
|
18357
|
-
serviceInfo: newInfo,
|
|
18358
|
-
}),
|
|
18359
|
-
);
|
|
18360
|
-
}
|
|
18313
|
+
/** Host functions external invocations available during refine phase. */
|
|
18314
|
+
interface RefineExternalities {
|
|
18315
|
+
/** Forget a previously started nested VM. */
|
|
18316
|
+
machineExpunge(machineIndex: MachineId): Promise<Result$2<ProgramCounter, NoMachineError>>;
|
|
18361
18317
|
|
|
18362
|
-
|
|
18363
|
-
|
|
18364
|
-
return this.stateUpdate.privilegedServices;
|
|
18365
|
-
}
|
|
18318
|
+
/** Set given range of pages as non-accessible and re-initialize them with zeros. */
|
|
18319
|
+
machineVoidPages(machineIndex: MachineId, pageStart: U64, pageCount: U64): Promise<Result$2<OK, ZeroVoidError>>;
|
|
18366
18320
|
|
|
18367
|
-
|
|
18368
|
-
|
|
18369
|
-
}
|
|
18321
|
+
/** Set given range of pages as writeable and initialize them with zeros. */
|
|
18322
|
+
machineZeroPages(machineIndex: MachineId, pageStart: U64, pageCount: U64): Promise<Result$2<OK, ZeroVoidError>>;
|
|
18370
18323
|
|
|
18371
|
-
|
|
18372
|
-
|
|
18373
|
-
|
|
18324
|
+
/** Copy a fragment of memory from `machineIndex` into given destination memory. */
|
|
18325
|
+
machinePeekFrom(
|
|
18326
|
+
machineIndex: MachineId,
|
|
18327
|
+
destinationStart: U64,
|
|
18328
|
+
sourceStart: U64,
|
|
18329
|
+
length: U64,
|
|
18330
|
+
destination: IHostCallMemory,
|
|
18331
|
+
): Promise<Result$2<OK, PeekPokeError>>;
|
|
18332
|
+
|
|
18333
|
+
/** Write a fragment of memory into `machineIndex` from given source memory. */
|
|
18334
|
+
machinePokeInto(
|
|
18335
|
+
machineIndex: MachineId,
|
|
18336
|
+
sourceStart: U64,
|
|
18337
|
+
destinationStart: U64,
|
|
18338
|
+
length: U64,
|
|
18339
|
+
source: IHostCallMemory,
|
|
18340
|
+
): Promise<Result$2<OK, PeekPokeError>>;
|
|
18341
|
+
|
|
18342
|
+
/** Start an inner PVM instance with given entry point and starting code. */
|
|
18343
|
+
machineInit(code: BytesBlob, programCounter: ProgramCounter): Promise<Result$2<MachineId, ProgramDecoderError>>;
|
|
18344
|
+
|
|
18345
|
+
/** Run a previously initialized PVM instance with given gas and registers. */
|
|
18346
|
+
machineInvoke(
|
|
18347
|
+
machineIndex: MachineId,
|
|
18348
|
+
gas: BigGas,
|
|
18349
|
+
registers: Registers,
|
|
18350
|
+
): Promise<Result$2<MachineResult, NoMachineError>>;
|
|
18351
|
+
|
|
18352
|
+
/**
|
|
18353
|
+
* Export segment for future retrieval.
|
|
18354
|
+
*
|
|
18355
|
+
* Returns the index assigned to that segment or an error if there is too many already exported.
|
|
18356
|
+
*/
|
|
18357
|
+
exportSegment(segment: Segment): Result$2<SegmentIndex, SegmentExportError>;
|
|
18358
|
+
|
|
18359
|
+
/** Lookup a historical preimage. */
|
|
18360
|
+
historicalLookup(serviceId: ServiceId | null, hash: Blake2bHash): Promise<BytesBlob | null>;
|
|
18361
|
+
|
|
18362
|
+
/** Change access to and/or zero the value of memory. */
|
|
18363
|
+
machinePages(
|
|
18364
|
+
machineIndex: MachineId,
|
|
18365
|
+
pageStart: U64,
|
|
18366
|
+
pageCount: U64,
|
|
18367
|
+
requestType: MemoryOperation | null,
|
|
18368
|
+
): Promise<Result$2<OK, PagesError>>;
|
|
18374
18369
|
}
|
|
18375
18370
|
|
|
18371
|
+
declare const InsufficientFundsError = "insufficient funds";
|
|
18372
|
+
type InsufficientFundsError = typeof InsufficientFundsError;
|
|
18373
|
+
|
|
18374
|
+
/** Update of the state entries coming from accumulation of a single service. */
|
|
18375
|
+
type ServiceStateUpdate = Partial<Pick<State, "privilegedServices" | "authQueues" | "designatedValidatorData">> &
|
|
18376
|
+
ServicesUpdate;
|
|
18377
|
+
|
|
18376
18378
|
/**
|
|
18377
|
-
*
|
|
18379
|
+
* State updates that currently accumulating service produced.
|
|
18378
18380
|
*
|
|
18379
|
-
* https://graypaper.fluffylabs.dev/#/
|
|
18381
|
+
* `x_u`: https://graypaper.fluffylabs.dev/#/9a08063/2f31012f3101?v=0.6.6
|
|
18380
18382
|
*/
|
|
18381
|
-
declare
|
|
18382
|
-
/**
|
|
18383
|
-
|
|
18384
|
-
|
|
18385
|
-
|
|
18386
|
-
|
|
18387
|
-
|
|
18388
|
-
|
|
18389
|
-
WHO: tryAsU64(0xffff_ffff_ffff_fffcn), // 2**64 - 4
|
|
18390
|
-
/** Storage full or resource already allocated. */
|
|
18391
|
-
FULL: tryAsU64(0xffff_ffff_ffff_fffbn), // 2**64 - 5
|
|
18392
|
-
/** Core index unknown. */
|
|
18393
|
-
CORE: tryAsU64(0xffff_ffff_ffff_fffan), // 2**64 - 6
|
|
18394
|
-
/** Insufficient funds. */
|
|
18395
|
-
CASH: tryAsU64(0xffff_ffff_ffff_fff9n), // 2**64 - 7
|
|
18396
|
-
/** Gas limit too low. */
|
|
18397
|
-
LOW: tryAsU64(0xffff_ffff_ffff_fff8n), // 2**64 - 8
|
|
18398
|
-
/** The item is already solicited, cannot be forgotten or the operation is invalid due to privilege level. */
|
|
18399
|
-
HUH: tryAsU64(0xffff_ffff_ffff_fff7n), // 2**64 - 9
|
|
18400
|
-
/** The return value indicating general success. */
|
|
18401
|
-
OK: tryAsU64(0n),
|
|
18402
|
-
} as const;
|
|
18403
|
-
|
|
18404
|
-
interface IHostCallMemory {
|
|
18405
|
-
storeFrom(address: U64, bytes: Uint8Array): Result$2<OK, PageFault | OutOfBounds>;
|
|
18406
|
-
loadInto(result: Uint8Array, startAddress: U64): Result$2<OK, PageFault | OutOfBounds>;
|
|
18407
|
-
getMemory(): Memory;
|
|
18408
|
-
}
|
|
18409
|
-
|
|
18410
|
-
declare class HostCallMemory implements IHostCallMemory {
|
|
18411
|
-
constructor(private readonly memory: Memory) {}
|
|
18383
|
+
declare class AccumulationStateUpdate {
|
|
18384
|
+
/** Updated authorization queues for cores. */
|
|
18385
|
+
public readonly authorizationQueues: Map<CoreIndex, FixedSizeArray<AuthorizerHash, AUTHORIZATION_QUEUE_SIZE>> =
|
|
18386
|
+
new Map();
|
|
18387
|
+
/** New validators data. */
|
|
18388
|
+
public validatorsData: PerValidator<ValidatorData> | null = null;
|
|
18389
|
+
/** Updated priviliged services. */
|
|
18390
|
+
public privilegedServices: PrivilegedServices | null = null;
|
|
18412
18391
|
|
|
18413
|
-
|
|
18414
|
-
|
|
18415
|
-
|
|
18416
|
-
|
|
18392
|
+
private constructor(
|
|
18393
|
+
/** Services state updates. */
|
|
18394
|
+
public readonly services: ServicesUpdate,
|
|
18395
|
+
/** Pending transfers. */
|
|
18396
|
+
public transfers: PendingTransfer[],
|
|
18397
|
+
/** Yielded accumulation root. */
|
|
18398
|
+
public readonly yieldedRoots: Map<ServiceId, OpaqueHash> = new Map(),
|
|
18399
|
+
) {}
|
|
18417
18400
|
|
|
18418
|
-
|
|
18419
|
-
|
|
18420
|
-
|
|
18401
|
+
/** Create new empty state update. */
|
|
18402
|
+
static empty(): AccumulationStateUpdate {
|
|
18403
|
+
return new AccumulationStateUpdate(
|
|
18404
|
+
{
|
|
18405
|
+
servicesUpdates: [],
|
|
18406
|
+
servicesRemoved: [],
|
|
18407
|
+
preimages: [],
|
|
18408
|
+
storage: [],
|
|
18409
|
+
},
|
|
18410
|
+
[],
|
|
18411
|
+
);
|
|
18412
|
+
}
|
|
18421
18413
|
|
|
18422
|
-
|
|
18414
|
+
/** Create a state update with some existing, yet uncommited services updates. */
|
|
18415
|
+
static new(update: ServicesUpdate): AccumulationStateUpdate {
|
|
18416
|
+
return new AccumulationStateUpdate(
|
|
18417
|
+
{
|
|
18418
|
+
...update,
|
|
18419
|
+
},
|
|
18420
|
+
[],
|
|
18421
|
+
);
|
|
18423
18422
|
}
|
|
18424
18423
|
|
|
18425
|
-
|
|
18426
|
-
|
|
18427
|
-
|
|
18424
|
+
/** Create a copy of another `StateUpdate`. Used by checkpoints. */
|
|
18425
|
+
static copyFrom(from: AccumulationStateUpdate): AccumulationStateUpdate {
|
|
18426
|
+
const serviceUpdates: ServicesUpdate = {
|
|
18427
|
+
servicesUpdates: [...from.services.servicesUpdates],
|
|
18428
|
+
servicesRemoved: [...from.services.servicesRemoved],
|
|
18429
|
+
preimages: [...from.services.preimages],
|
|
18430
|
+
storage: [...from.services.storage],
|
|
18431
|
+
};
|
|
18432
|
+
const transfers = [...from.transfers];
|
|
18433
|
+
const update = new AccumulationStateUpdate(serviceUpdates, transfers, new Map(from.yieldedRoots));
|
|
18434
|
+
|
|
18435
|
+
// update entries
|
|
18436
|
+
for (const [k, v] of from.authorizationQueues) {
|
|
18437
|
+
update.authorizationQueues.set(k, v);
|
|
18428
18438
|
}
|
|
18429
18439
|
|
|
18430
|
-
if (
|
|
18431
|
-
|
|
18440
|
+
if (from.validatorsData !== null) {
|
|
18441
|
+
update.validatorsData = asKnownSize([...from.validatorsData]);
|
|
18432
18442
|
}
|
|
18433
18443
|
|
|
18434
|
-
|
|
18444
|
+
if (from.privilegedServices !== null) {
|
|
18445
|
+
update.privilegedServices = PrivilegedServices.create({
|
|
18446
|
+
...from.privilegedServices,
|
|
18447
|
+
assigners: asKnownSize([...from.privilegedServices.assigners]),
|
|
18448
|
+
});
|
|
18449
|
+
}
|
|
18450
|
+
return update;
|
|
18435
18451
|
}
|
|
18436
18452
|
|
|
18437
|
-
|
|
18438
|
-
|
|
18453
|
+
/** Retrieve and clear pending transfers. */
|
|
18454
|
+
takeTransfers() {
|
|
18455
|
+
const transfers = this.transfers;
|
|
18456
|
+
this.transfers = [];
|
|
18457
|
+
return transfers;
|
|
18439
18458
|
}
|
|
18440
18459
|
}
|
|
18441
18460
|
|
|
18442
|
-
|
|
18443
|
-
get(registerIndex: number): U64;
|
|
18444
|
-
set(registerIndex: number, value: U64): void;
|
|
18445
|
-
}
|
|
18446
|
-
|
|
18447
|
-
declare class HostCallRegisters implements IHostCallRegisters {
|
|
18448
|
-
constructor(private readonly registers: Registers) {}
|
|
18461
|
+
type StateSlice = Pick<State, "getService" | "privilegedServices">;
|
|
18449
18462
|
|
|
18450
|
-
|
|
18451
|
-
|
|
18452
|
-
|
|
18463
|
+
declare class PartiallyUpdatedState<T extends StateSlice = StateSlice> {
|
|
18464
|
+
/** A collection of state updates. */
|
|
18465
|
+
public readonly stateUpdate;
|
|
18453
18466
|
|
|
18454
|
-
|
|
18455
|
-
|
|
18467
|
+
constructor(
|
|
18468
|
+
/** Original (unmodified state). */
|
|
18469
|
+
public readonly state: T,
|
|
18470
|
+
stateUpdate?: AccumulationStateUpdate,
|
|
18471
|
+
) {
|
|
18472
|
+
this.stateUpdate =
|
|
18473
|
+
stateUpdate === undefined ? AccumulationStateUpdate.empty() : AccumulationStateUpdate.copyFrom(stateUpdate);
|
|
18456
18474
|
}
|
|
18457
|
-
}
|
|
18458
18475
|
|
|
18459
|
-
/**
|
|
18460
|
-
|
|
18461
|
-
|
|
18462
|
-
|
|
18476
|
+
/**
|
|
18477
|
+
* Retrieve info of service with given id.
|
|
18478
|
+
*
|
|
18479
|
+
* NOTE the info may be updated compared to what is in the state.
|
|
18480
|
+
*
|
|
18481
|
+
* Takes into account ejected and newly created services as well.
|
|
18482
|
+
*/
|
|
18483
|
+
getServiceInfo(destination: ServiceId | null): ServiceAccountInfo | null {
|
|
18484
|
+
if (destination === null) {
|
|
18485
|
+
return null;
|
|
18486
|
+
}
|
|
18463
18487
|
|
|
18464
|
-
|
|
18465
|
-
|
|
18466
|
-
|
|
18467
|
-
* https://graypaper.fluffylabs.dev/#/ab2cdbd/24a30124a501?v=0.7.2
|
|
18468
|
-
*/
|
|
18469
|
-
declare enum PvmExecution {
|
|
18470
|
-
Halt = 0,
|
|
18471
|
-
Panic = 1,
|
|
18472
|
-
OOG = 2, // out-of-gas
|
|
18473
|
-
}
|
|
18488
|
+
const maybeNewService = this.stateUpdate.services.servicesUpdates.find(
|
|
18489
|
+
(update) => update.serviceId === destination,
|
|
18490
|
+
);
|
|
18474
18491
|
|
|
18475
|
-
|
|
18476
|
-
|
|
18477
|
-
|
|
18478
|
-
}
|
|
18492
|
+
if (maybeNewService !== undefined) {
|
|
18493
|
+
return maybeNewService.action.account;
|
|
18494
|
+
}
|
|
18479
18495
|
|
|
18480
|
-
|
|
18481
|
-
|
|
18482
|
-
|
|
18483
|
-
|
|
18496
|
+
const maybeService = this.state.getService(destination);
|
|
18497
|
+
if (maybeService === null) {
|
|
18498
|
+
return null;
|
|
18499
|
+
}
|
|
18484
18500
|
|
|
18485
|
-
|
|
18486
|
-
|
|
18487
|
-
*
|
|
18488
|
-
* NOTE: `((reg: IHostCallRegisters) => Gas)` function is for compatibility reasons: pre GP 0.7.2
|
|
18489
|
-
*/
|
|
18490
|
-
readonly basicGasCost: SmallGas | ((reg: IHostCallRegisters) => Gas);
|
|
18501
|
+
return maybeService.getInfo();
|
|
18502
|
+
}
|
|
18491
18503
|
|
|
18492
|
-
|
|
18493
|
-
|
|
18504
|
+
getStorage(serviceId: ServiceId, rawKey: StorageKey): BytesBlob | null {
|
|
18505
|
+
const item = this.stateUpdate.services.storage.find((x) => x.serviceId === serviceId && x.key.isEqualTo(rawKey));
|
|
18506
|
+
if (item !== undefined) {
|
|
18507
|
+
return item.value;
|
|
18508
|
+
}
|
|
18494
18509
|
|
|
18495
|
-
|
|
18496
|
-
|
|
18510
|
+
const service = this.state.getService(serviceId);
|
|
18511
|
+
return service?.getStorage(rawKey) ?? null;
|
|
18512
|
+
}
|
|
18497
18513
|
|
|
18498
18514
|
/**
|
|
18499
|
-
*
|
|
18515
|
+
* Returns `true` if the preimage is already provided either in current
|
|
18516
|
+
* accumulation scope or earlier.
|
|
18500
18517
|
*
|
|
18501
|
-
* NOTE
|
|
18518
|
+
* NOTE: Does not check if the preimage is available, we just check
|
|
18519
|
+
* the existence in `preimages` map.
|
|
18502
18520
|
*/
|
|
18503
|
-
|
|
18504
|
-
|
|
18521
|
+
hasPreimage(serviceId: ServiceId, hash: PreimageHash): boolean {
|
|
18522
|
+
const providedPreimage = this.stateUpdate.services.preimages.find(
|
|
18523
|
+
// we ignore the action here, since if there is <any> update on that
|
|
18524
|
+
// hash it means it has to exist, right?
|
|
18525
|
+
(p) => p.serviceId === serviceId && p.hash.isEqualTo(hash),
|
|
18526
|
+
);
|
|
18527
|
+
if (providedPreimage !== undefined) {
|
|
18528
|
+
return true;
|
|
18529
|
+
}
|
|
18505
18530
|
|
|
18506
|
-
|
|
18507
|
-
|
|
18508
|
-
|
|
18509
|
-
|
|
18531
|
+
// fallback to state preimages
|
|
18532
|
+
const service = this.state.getService(serviceId);
|
|
18533
|
+
if (service === undefined) {
|
|
18534
|
+
return false;
|
|
18535
|
+
}
|
|
18510
18536
|
|
|
18511
|
-
|
|
18512
|
-
|
|
18513
|
-
handlers = [],
|
|
18514
|
-
}: {
|
|
18515
|
-
missing: HostCallHandler;
|
|
18516
|
-
handlers?: HostCallHandler[];
|
|
18517
|
-
}) {
|
|
18518
|
-
this.missing = missing;
|
|
18537
|
+
return service?.hasPreimage(hash) ?? false;
|
|
18538
|
+
}
|
|
18519
18539
|
|
|
18520
|
-
|
|
18521
|
-
|
|
18522
|
-
|
|
18540
|
+
getPreimage(serviceId: ServiceId, hash: PreimageHash): BytesBlob | null {
|
|
18541
|
+
// TODO [ToDr] Should we verify availability here?
|
|
18542
|
+
const freshlyProvided = this.stateUpdate.services.preimages.find(
|
|
18543
|
+
(x) => x.serviceId === serviceId && x.hash.isEqualTo(hash),
|
|
18544
|
+
);
|
|
18545
|
+
if (freshlyProvided !== undefined && freshlyProvided.action.kind === UpdatePreimageKind.Provide) {
|
|
18546
|
+
return freshlyProvided.action.preimage.blob;
|
|
18523
18547
|
}
|
|
18524
|
-
}
|
|
18525
18548
|
|
|
18526
|
-
|
|
18527
|
-
|
|
18528
|
-
return this.hostCalls.get(hostCallIndex) ?? this.missing;
|
|
18549
|
+
const service = this.state.getService(serviceId);
|
|
18550
|
+
return service?.getPreimage(hash) ?? null;
|
|
18529
18551
|
}
|
|
18530
18552
|
|
|
18531
|
-
|
|
18532
|
-
|
|
18533
|
-
|
|
18534
|
-
|
|
18535
|
-
|
|
18536
|
-
|
|
18537
|
-
) {
|
|
18538
|
-
|
|
18539
|
-
|
|
18540
|
-
|
|
18541
|
-
const
|
|
18542
|
-
|
|
18543
|
-
|
|
18544
|
-
.map(([idx, value]) => {
|
|
18545
|
-
return `r${idx}=${value} (0x${value.toString(16)})`;
|
|
18546
|
-
})
|
|
18547
|
-
.join(", ");
|
|
18548
|
-
logger.insane`[${currentServiceId}] ${context} ${name}${requested}. Gas: ${gas}. Regs: ${registerValues}.`;
|
|
18549
|
-
}
|
|
18550
|
-
}
|
|
18553
|
+
/** Get status of a preimage of current service taking into account any updates. */
|
|
18554
|
+
getLookupHistory(
|
|
18555
|
+
currentTimeslot: TimeSlot,
|
|
18556
|
+
serviceId: ServiceId,
|
|
18557
|
+
hash: PreimageHash,
|
|
18558
|
+
length: U64,
|
|
18559
|
+
): LookupHistoryItem | null {
|
|
18560
|
+
// TODO [ToDr] This is most likely wrong. We may have `provide` and `remove` within
|
|
18561
|
+
// the same state update. We should however switch to proper "updated state"
|
|
18562
|
+
// representation soon.
|
|
18563
|
+
const updatedPreimage = this.stateUpdate.services.preimages.findLast(
|
|
18564
|
+
(update) => update.serviceId === serviceId && update.hash.isEqualTo(hash) && BigInt(update.length) === length,
|
|
18565
|
+
);
|
|
18551
18566
|
|
|
18552
|
-
|
|
18567
|
+
const stateFallback = () => {
|
|
18568
|
+
// fallback to state lookup
|
|
18569
|
+
const service = this.state.getService(serviceId);
|
|
18570
|
+
const lenU32 = preimageLenAsU32(length);
|
|
18571
|
+
if (lenU32 === null || service === null) {
|
|
18572
|
+
return null;
|
|
18573
|
+
}
|
|
18553
18574
|
|
|
18554
|
-
|
|
18555
|
-
|
|
18556
|
-
|
|
18575
|
+
const slots = service.getLookupHistory(hash, lenU32);
|
|
18576
|
+
return slots === null ? null : new LookupHistoryItem(hash, lenU32, slots);
|
|
18577
|
+
};
|
|
18557
18578
|
|
|
18558
|
-
|
|
18559
|
-
|
|
18560
|
-
this.instances.push(
|
|
18561
|
-
new Interpreter({
|
|
18562
|
-
useSbrkGas: false,
|
|
18563
|
-
}),
|
|
18564
|
-
);
|
|
18579
|
+
if (updatedPreimage === undefined) {
|
|
18580
|
+
return stateFallback();
|
|
18565
18581
|
}
|
|
18566
|
-
}
|
|
18567
18582
|
|
|
18568
|
-
|
|
18569
|
-
|
|
18570
|
-
|
|
18571
|
-
|
|
18572
|
-
|
|
18573
|
-
|
|
18574
|
-
|
|
18575
|
-
|
|
18576
|
-
|
|
18583
|
+
const { action } = updatedPreimage;
|
|
18584
|
+
switch (action.kind) {
|
|
18585
|
+
case UpdatePreimageKind.Provide: {
|
|
18586
|
+
// casting to U32 is safe, since we compare with object we have in memory.
|
|
18587
|
+
return new LookupHistoryItem(hash, updatedPreimage.length, tryAsLookupHistorySlots([currentTimeslot]));
|
|
18588
|
+
}
|
|
18589
|
+
case UpdatePreimageKind.Remove: {
|
|
18590
|
+
const state = stateFallback();
|
|
18591
|
+
// kinda impossible, since we know it's there because it's removed.
|
|
18592
|
+
if (state === null) {
|
|
18593
|
+
return null;
|
|
18594
|
+
}
|
|
18577
18595
|
|
|
18578
|
-
|
|
18579
|
-
|
|
18580
|
-
|
|
18581
|
-
|
|
18596
|
+
return new LookupHistoryItem(hash, state.length, tryAsLookupHistorySlots([...state.slots, currentTimeslot]));
|
|
18597
|
+
}
|
|
18598
|
+
case UpdatePreimageKind.UpdateOrAdd: {
|
|
18599
|
+
return action.item;
|
|
18600
|
+
}
|
|
18582
18601
|
}
|
|
18583
|
-
this.instances.push(pvm);
|
|
18584
|
-
}
|
|
18585
|
-
}
|
|
18586
18602
|
|
|
18587
|
-
|
|
18588
|
-
private constructor(
|
|
18589
|
-
public consumedGas: Gas,
|
|
18590
|
-
public status: Status | null,
|
|
18591
|
-
public memorySlice: Uint8Array | null,
|
|
18592
|
-
) {
|
|
18593
|
-
check`
|
|
18594
|
-
${(status === null && memorySlice !== null) || (status !== null && memorySlice === null)}
|
|
18595
|
-
'status' and 'memorySlice' must not both be null or both be non-null — exactly one must be provided
|
|
18596
|
-
`;
|
|
18603
|
+
assertNever(action);
|
|
18597
18604
|
}
|
|
18598
18605
|
|
|
18599
|
-
|
|
18600
|
-
return new ReturnValue(consumedGas, status, null);
|
|
18601
|
-
}
|
|
18606
|
+
/* State update functions. */
|
|
18602
18607
|
|
|
18603
|
-
|
|
18604
|
-
|
|
18605
|
-
|
|
18608
|
+
updateStorage(serviceId: ServiceId, key: StorageKey, value: BytesBlob | null) {
|
|
18609
|
+
const update =
|
|
18610
|
+
value === null
|
|
18611
|
+
? UpdateStorage.remove({ serviceId, key })
|
|
18612
|
+
: UpdateStorage.set({
|
|
18613
|
+
serviceId,
|
|
18614
|
+
storage: StorageItem.create({ key, value }),
|
|
18615
|
+
});
|
|
18606
18616
|
|
|
18607
|
-
|
|
18608
|
-
|
|
18617
|
+
const index = this.stateUpdate.services.storage.findIndex(
|
|
18618
|
+
(x) => x.serviceId === update.serviceId && x.key.isEqualTo(key),
|
|
18619
|
+
);
|
|
18620
|
+
const count = index === -1 ? 0 : 1;
|
|
18621
|
+
this.stateUpdate.services.storage.splice(index, count, update);
|
|
18609
18622
|
}
|
|
18610
18623
|
|
|
18611
|
-
|
|
18612
|
-
|
|
18624
|
+
/**
|
|
18625
|
+
* Update a preimage.
|
|
18626
|
+
*
|
|
18627
|
+
* Note we store all previous entries as well, since there might be a sequence of:
|
|
18628
|
+
* `provide` -> `remove` and both should update the end state somehow.
|
|
18629
|
+
*/
|
|
18630
|
+
updatePreimage(newUpdate: UpdatePreimage) {
|
|
18631
|
+
this.stateUpdate.services.preimages.push(newUpdate);
|
|
18613
18632
|
}
|
|
18614
|
-
}
|
|
18615
|
-
declare class HostCalls {
|
|
18616
|
-
constructor(
|
|
18617
|
-
private pvmInstanceManager: InterpreterInstanceManager,
|
|
18618
|
-
private hostCalls: HostCallsManager,
|
|
18619
|
-
) {}
|
|
18620
|
-
|
|
18621
|
-
private getReturnValue(status: Status, pvmInstance: Interpreter): ReturnValue {
|
|
18622
|
-
const gasConsumed = pvmInstance.getGasConsumed();
|
|
18623
|
-
if (status === Status.OOG) {
|
|
18624
|
-
return ReturnValue.fromStatus(gasConsumed, status);
|
|
18625
|
-
}
|
|
18626
18633
|
|
|
18627
|
-
|
|
18628
|
-
|
|
18629
|
-
|
|
18630
|
-
|
|
18631
|
-
|
|
18634
|
+
updateServiceStorageUtilisation(
|
|
18635
|
+
serviceId: ServiceId,
|
|
18636
|
+
items: number,
|
|
18637
|
+
bytes: bigint,
|
|
18638
|
+
serviceInfo: ServiceAccountInfo,
|
|
18639
|
+
): Result$2<OK, InsufficientFundsError> {
|
|
18640
|
+
check`${items >= 0} storageUtilisationCount has to be a positive number, got: ${items}`;
|
|
18641
|
+
check`${bytes >= 0} storageUtilisationBytes has to be a positive number, got: ${bytes}`;
|
|
18632
18642
|
|
|
18633
|
-
|
|
18634
|
-
|
|
18635
|
-
const loadResult = memory.loadInto(result, startAddress);
|
|
18643
|
+
const overflowItems = !isU32(items);
|
|
18644
|
+
const overflowBytes = !isU64(bytes);
|
|
18636
18645
|
|
|
18637
|
-
|
|
18638
|
-
|
|
18639
|
-
|
|
18646
|
+
// TODO [ToDr] this is not specified in GP, but it seems sensible.
|
|
18647
|
+
if (overflowItems || overflowBytes) {
|
|
18648
|
+
return Result.error(InsufficientFundsError);
|
|
18649
|
+
}
|
|
18640
18650
|
|
|
18641
|
-
|
|
18651
|
+
const thresholdBalance = ServiceAccountInfo.calculateThresholdBalance(items, bytes, serviceInfo.gratisStorage);
|
|
18652
|
+
if (serviceInfo.balance < thresholdBalance) {
|
|
18653
|
+
return Result.error(InsufficientFundsError);
|
|
18642
18654
|
}
|
|
18643
18655
|
|
|
18644
|
-
|
|
18656
|
+
// Update service info with new details.
|
|
18657
|
+
this.updateServiceInfo(
|
|
18658
|
+
serviceId,
|
|
18659
|
+
ServiceAccountInfo.create({
|
|
18660
|
+
...serviceInfo,
|
|
18661
|
+
storageUtilisationBytes: bytes,
|
|
18662
|
+
storageUtilisationCount: items,
|
|
18663
|
+
}),
|
|
18664
|
+
);
|
|
18665
|
+
return Result.ok(OK);
|
|
18645
18666
|
}
|
|
18646
18667
|
|
|
18647
|
-
|
|
18648
|
-
|
|
18649
|
-
|
|
18650
|
-
|
|
18651
|
-
if (status !== Status.HOST) {
|
|
18652
|
-
return this.getReturnValue(status, pvmInstance);
|
|
18653
|
-
}
|
|
18654
|
-
check`
|
|
18655
|
-
${pvmInstance.getExitParam() !== null}
|
|
18656
|
-
"We know that the exit param is not null, because the status is 'Status.HOST'
|
|
18657
|
-
`;
|
|
18658
|
-
const hostCallIndex = pvmInstance.getExitParam() ?? -1;
|
|
18659
|
-
const gas = pvmInstance.getGasCounter();
|
|
18660
|
-
const regs = new HostCallRegisters(pvmInstance.getRegisters());
|
|
18661
|
-
const memory = new HostCallMemory(pvmInstance.getMemory());
|
|
18662
|
-
const index = tryAsHostCallIndex(hostCallIndex);
|
|
18663
|
-
|
|
18664
|
-
const hostCall = this.hostCalls.get(index);
|
|
18665
|
-
const gasBefore = gas.get();
|
|
18666
|
-
// NOTE: `basicGasCost(regs)` function is for compatibility reasons: pre GP 0.7.2
|
|
18667
|
-
const basicGasCost =
|
|
18668
|
-
typeof hostCall.basicGasCost === "number" ? hostCall.basicGasCost : hostCall.basicGasCost(regs);
|
|
18669
|
-
const underflow = gas.sub(basicGasCost);
|
|
18668
|
+
updateServiceInfo(serviceId: ServiceId, newInfo: ServiceAccountInfo) {
|
|
18669
|
+
const idx = this.stateUpdate.services.servicesUpdates.findIndex((x) => x.serviceId === serviceId);
|
|
18670
|
+
const toRemove = idx === -1 ? 0 : 1;
|
|
18671
|
+
const existingItem = this.stateUpdate.services.servicesUpdates[idx];
|
|
18670
18672
|
|
|
18671
|
-
|
|
18672
|
-
|
|
18673
|
-
|
|
18674
|
-
|
|
18675
|
-
|
|
18676
|
-
|
|
18677
|
-
|
|
18678
|
-
|
|
18679
|
-
|
|
18680
|
-
index,
|
|
18681
|
-
hostCall,
|
|
18682
|
-
regs,
|
|
18683
|
-
gas.get(),
|
|
18673
|
+
if (existingItem?.action.kind === UpdateServiceKind.Create) {
|
|
18674
|
+
this.stateUpdate.services.servicesUpdates.splice(
|
|
18675
|
+
idx,
|
|
18676
|
+
toRemove,
|
|
18677
|
+
UpdateService.create({
|
|
18678
|
+
serviceId,
|
|
18679
|
+
serviceInfo: newInfo,
|
|
18680
|
+
lookupHistory: existingItem.action.lookupHistory,
|
|
18681
|
+
}),
|
|
18684
18682
|
);
|
|
18685
18683
|
|
|
18686
|
-
|
|
18687
|
-
status = Status.HALT;
|
|
18688
|
-
return this.getReturnValue(status, pvmInstance);
|
|
18689
|
-
}
|
|
18690
|
-
|
|
18691
|
-
if (result === PvmExecution.Panic) {
|
|
18692
|
-
status = Status.PANIC;
|
|
18693
|
-
return this.getReturnValue(status, pvmInstance);
|
|
18694
|
-
}
|
|
18695
|
-
|
|
18696
|
-
if (result === PvmExecution.OOG) {
|
|
18697
|
-
status = Status.OOG;
|
|
18698
|
-
return this.getReturnValue(status, pvmInstance);
|
|
18699
|
-
}
|
|
18700
|
-
|
|
18701
|
-
if (result === undefined) {
|
|
18702
|
-
pvmInstance.runProgram();
|
|
18703
|
-
status = pvmInstance.getStatus();
|
|
18704
|
-
continue;
|
|
18705
|
-
}
|
|
18706
|
-
|
|
18707
|
-
assertNever(result);
|
|
18684
|
+
return;
|
|
18708
18685
|
}
|
|
18686
|
+
|
|
18687
|
+
this.stateUpdate.services.servicesUpdates.splice(
|
|
18688
|
+
idx,
|
|
18689
|
+
toRemove,
|
|
18690
|
+
UpdateService.update({
|
|
18691
|
+
serviceId,
|
|
18692
|
+
serviceInfo: newInfo,
|
|
18693
|
+
}),
|
|
18694
|
+
);
|
|
18709
18695
|
}
|
|
18710
18696
|
|
|
18711
|
-
|
|
18712
|
-
|
|
18713
|
-
|
|
18714
|
-
initialGas: Gas,
|
|
18715
|
-
maybeRegisters?: Registers,
|
|
18716
|
-
maybeMemory?: Memory,
|
|
18717
|
-
): Promise<ReturnValue> {
|
|
18718
|
-
const pvmInstance = await this.pvmInstanceManager.getInstance();
|
|
18719
|
-
pvmInstance.reset(rawProgram, initialPc, initialGas, maybeRegisters, maybeMemory);
|
|
18720
|
-
try {
|
|
18721
|
-
return await this.execute(pvmInstance);
|
|
18722
|
-
} finally {
|
|
18723
|
-
this.pvmInstanceManager.releaseInstance(pvmInstance);
|
|
18697
|
+
getPrivilegedServices() {
|
|
18698
|
+
if (this.stateUpdate.privilegedServices !== null) {
|
|
18699
|
+
return this.stateUpdate.privilegedServices;
|
|
18724
18700
|
}
|
|
18701
|
+
|
|
18702
|
+
return this.state.privilegedServices;
|
|
18725
18703
|
}
|
|
18726
18704
|
}
|
|
18727
18705
|
|
|
18728
|
-
|
|
18729
|
-
|
|
18730
|
-
|
|
18731
|
-
type index$7_HostCallRegisters = HostCallRegisters;
|
|
18732
|
-
declare const index$7_HostCallRegisters: typeof HostCallRegisters;
|
|
18733
|
-
type index$7_IHostCallMemory = IHostCallMemory;
|
|
18734
|
-
type index$7_IHostCallRegisters = IHostCallRegisters;
|
|
18735
|
-
type index$7_PvmExecution = PvmExecution;
|
|
18736
|
-
declare const index$7_PvmExecution: typeof PvmExecution;
|
|
18737
|
-
declare const index$7_traceRegisters: typeof traceRegisters;
|
|
18738
|
-
declare const index$7_tryAsHostCallIndex: typeof tryAsHostCallIndex;
|
|
18739
|
-
declare namespace index$7 {
|
|
18740
|
-
export { index$7_HostCallMemory as HostCallMemory, index$7_HostCallRegisters as HostCallRegisters, HostCallsManager as HostCalls, index$7_PvmExecution as PvmExecution, HostCalls as PvmHostCallExtension, InterpreterInstanceManager as PvmInstanceManager, index$7_traceRegisters as traceRegisters, index$7_tryAsHostCallIndex as tryAsHostCallIndex };
|
|
18741
|
-
export type { index$7_HostCallHandler as HostCallHandler, index$7_IHostCallMemory as IHostCallMemory, index$7_IHostCallRegisters as IHostCallRegisters };
|
|
18706
|
+
declare function preimageLenAsU32(length: U64) {
|
|
18707
|
+
// Safe to convert to Number and U32: we check that len < 2^32 before conversion
|
|
18708
|
+
return length >= 2n ** 32n ? null : tryAsU32(Number(length));
|
|
18742
18709
|
}
|
|
18743
18710
|
|
|
18711
|
+
/**
|
|
18712
|
+
* Host call result constants.
|
|
18713
|
+
*
|
|
18714
|
+
* https://graypaper.fluffylabs.dev/#/85129da/2c7c022c7c02?v=0.6.3
|
|
18715
|
+
*/
|
|
18716
|
+
declare const HostCallResult = {
|
|
18717
|
+
/** The return value indicating an item does not exist. */
|
|
18718
|
+
NONE: tryAsU64(0xffff_ffff_ffff_ffffn), // 2**64 - 1
|
|
18719
|
+
/** Name unknown. */
|
|
18720
|
+
WHAT: tryAsU64(0xffff_ffff_ffff_fffen), // 2**64 - 2
|
|
18721
|
+
/** The inner PVM memory index provided for reading/writing is not accessible. */
|
|
18722
|
+
OOB: tryAsU64(0xffff_ffff_ffff_fffdn), // 2**64 - 3
|
|
18723
|
+
/** Index unknown. */
|
|
18724
|
+
WHO: tryAsU64(0xffff_ffff_ffff_fffcn), // 2**64 - 4
|
|
18725
|
+
/** Storage full or resource already allocated. */
|
|
18726
|
+
FULL: tryAsU64(0xffff_ffff_ffff_fffbn), // 2**64 - 5
|
|
18727
|
+
/** Core index unknown. */
|
|
18728
|
+
CORE: tryAsU64(0xffff_ffff_ffff_fffan), // 2**64 - 6
|
|
18729
|
+
/** Insufficient funds. */
|
|
18730
|
+
CASH: tryAsU64(0xffff_ffff_ffff_fff9n), // 2**64 - 7
|
|
18731
|
+
/** Gas limit too low. */
|
|
18732
|
+
LOW: tryAsU64(0xffff_ffff_ffff_fff8n), // 2**64 - 8
|
|
18733
|
+
/** The item is already solicited, cannot be forgotten or the operation is invalid due to privilege level. */
|
|
18734
|
+
HUH: tryAsU64(0xffff_ffff_ffff_fff7n), // 2**64 - 9
|
|
18735
|
+
/** The return value indicating general success. */
|
|
18736
|
+
OK: tryAsU64(0n),
|
|
18737
|
+
} as const;
|
|
18738
|
+
|
|
18744
18739
|
declare const MAX_U32 = tryAsU32(2 ** 32 - 1);
|
|
18745
18740
|
declare const MAX_U32_BIG_INT = tryAsU64(MAX_U32);
|
|
18746
18741
|
declare const SERVICE_ID_BYTES = 4;
|