@typeberry/lib 0.2.0-e767e74 → 0.2.0-ef1ea0e
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 +362 -386
- package/index.d.ts +1218 -1013
- package/index.js +362 -386
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -322,7 +322,7 @@ type ErrorResult<Error> = {
|
|
|
322
322
|
isOk: false;
|
|
323
323
|
isError: true;
|
|
324
324
|
error: Error;
|
|
325
|
-
details: string;
|
|
325
|
+
details: () => string;
|
|
326
326
|
};
|
|
327
327
|
|
|
328
328
|
/**
|
|
@@ -383,7 +383,7 @@ declare function resultToString<Ok, Error>(res: Result$2<Ok, Error>) {
|
|
|
383
383
|
if (res.isOk) {
|
|
384
384
|
return `OK: ${typeof res.ok === "symbol" ? res.ok.toString() : res.ok}`;
|
|
385
385
|
}
|
|
386
|
-
return `${res.details}\nError: ${maybeTaggedErrorToString(res.error)}`;
|
|
386
|
+
return `${res.details()}\nError: ${maybeTaggedErrorToString(res.error)}`;
|
|
387
387
|
}
|
|
388
388
|
|
|
389
389
|
/** An indication of two possible outcomes returned from a function. */
|
|
@@ -402,7 +402,7 @@ declare const Result$2 = {
|
|
|
402
402
|
},
|
|
403
403
|
|
|
404
404
|
/** Create new [`Result`] with `Error` status. */
|
|
405
|
-
error: <Error>(error: Error, details
|
|
405
|
+
error: <Error>(error: Error, details: () => string): ErrorResult<Error> => {
|
|
406
406
|
check`${error !== undefined} 'Error' type cannot be undefined.`;
|
|
407
407
|
return {
|
|
408
408
|
isOk: false,
|
|
@@ -556,7 +556,7 @@ declare function deepEqual<T>(
|
|
|
556
556
|
|
|
557
557
|
if (actual.isError && expected.isError) {
|
|
558
558
|
deepEqual(actual.error, expected.error, { context: ctx.concat(["error"]), errorsCollector: errors, ignore });
|
|
559
|
-
deepEqual(actual.details, expected.details, {
|
|
559
|
+
deepEqual(actual.details(), expected.details(), {
|
|
560
560
|
context: ctx.concat(["details"]),
|
|
561
561
|
errorsCollector: errors,
|
|
562
562
|
// display details when error does not match
|
|
@@ -1467,8 +1467,8 @@ declare class Decoder {
|
|
|
1467
1467
|
/**
|
|
1468
1468
|
* Create a new [`Decoder`] instance given a raw array of bytes as a source.
|
|
1469
1469
|
*/
|
|
1470
|
-
static fromBlob(source: Uint8Array) {
|
|
1471
|
-
return new Decoder(source);
|
|
1470
|
+
static fromBlob(source: Uint8Array, context?: unknown) {
|
|
1471
|
+
return new Decoder(source, undefined, context);
|
|
1472
1472
|
}
|
|
1473
1473
|
|
|
1474
1474
|
/**
|
|
@@ -1818,7 +1818,7 @@ declare class Decoder {
|
|
|
1818
1818
|
private ensureHasBytes(bytes: number) {
|
|
1819
1819
|
check`${bytes >= 0} Negative number of bytes given.`;
|
|
1820
1820
|
if (this.offset + bytes > this.source.length) {
|
|
1821
|
-
throw new
|
|
1821
|
+
throw new EndOfDataError(
|
|
1822
1822
|
`Attempting to decode more data than there is left. Need ${bytes}, left: ${this.source.length - this.offset}.`,
|
|
1823
1823
|
);
|
|
1824
1824
|
}
|
|
@@ -1837,6 +1837,8 @@ declare function decodeVariableLengthExtraBytes(firstByte: number) {
|
|
|
1837
1837
|
return 0;
|
|
1838
1838
|
}
|
|
1839
1839
|
|
|
1840
|
+
declare class EndOfDataError extends Error {}
|
|
1841
|
+
|
|
1840
1842
|
/** Hint for how big the encoded object will be. */
|
|
1841
1843
|
type SizeHint = {
|
|
1842
1844
|
/** Number of bytes in the encoding. */
|
|
@@ -2879,6 +2881,15 @@ declare namespace codec$1 {
|
|
|
2879
2881
|
};
|
|
2880
2882
|
})();
|
|
2881
2883
|
|
|
2884
|
+
/** Zero-size `void` value. */
|
|
2885
|
+
export const nothing = Descriptor.new<void>(
|
|
2886
|
+
"void",
|
|
2887
|
+
{ bytes: 0, isExact: true },
|
|
2888
|
+
(_e, _v) => {},
|
|
2889
|
+
(_d) => {},
|
|
2890
|
+
(_s) => {},
|
|
2891
|
+
);
|
|
2892
|
+
|
|
2882
2893
|
/** Variable-length U32. */
|
|
2883
2894
|
export const varU32 = Descriptor.new<U32>(
|
|
2884
2895
|
"var_u32",
|
|
@@ -3346,6 +3357,9 @@ declare function forEachDescriptor<T>(
|
|
|
3346
3357
|
try {
|
|
3347
3358
|
f(k, descriptors[k]);
|
|
3348
3359
|
} catch (e) {
|
|
3360
|
+
if (e instanceof EndOfDataError) {
|
|
3361
|
+
throw new EndOfDataError(`${key}: ${e}`);
|
|
3362
|
+
}
|
|
3349
3363
|
throw new Error(`${key}: ${e}`);
|
|
3350
3364
|
}
|
|
3351
3365
|
}
|
|
@@ -3469,6 +3483,8 @@ type index$q_DescriptorRecord<T> = DescriptorRecord<T>;
|
|
|
3469
3483
|
type index$q_Encode<T> = Encode<T>;
|
|
3470
3484
|
type index$q_Encoder = Encoder;
|
|
3471
3485
|
declare const index$q_Encoder: typeof Encoder;
|
|
3486
|
+
type index$q_EndOfDataError = EndOfDataError;
|
|
3487
|
+
declare const index$q_EndOfDataError: typeof EndOfDataError;
|
|
3472
3488
|
type index$q_LengthRange = LengthRange;
|
|
3473
3489
|
declare const index$q_MASKS: typeof MASKS;
|
|
3474
3490
|
declare const index$q_MAX_LENGTH: typeof MAX_LENGTH;
|
|
@@ -3497,7 +3513,7 @@ declare const index$q_sequenceViewVarLen: typeof sequenceViewVarLen;
|
|
|
3497
3513
|
declare const index$q_tryAsExactBytes: typeof tryAsExactBytes;
|
|
3498
3514
|
declare const index$q_validateLength: typeof validateLength;
|
|
3499
3515
|
declare namespace index$q {
|
|
3500
|
-
export { index$q_DEFAULT_START_LENGTH as DEFAULT_START_LENGTH, index$q_Decoder as Decoder, index$q_Descriptor as Descriptor, index$q_Encoder as Encoder, index$q_MASKS as MASKS, index$q_MAX_LENGTH as MAX_LENGTH, index$q_ObjectView as ObjectView, index$q_SequenceView as SequenceView, index$q_TYPICAL_DICTIONARY_LENGTH as TYPICAL_DICTIONARY_LENGTH, index$q_TYPICAL_SEQUENCE_LENGTH as TYPICAL_SEQUENCE_LENGTH, index$q_ViewField as ViewField, index$q_addSizeHints as addSizeHints, codec$1 as codec, index$q_decodeVariableLengthExtraBytes as decodeVariableLengthExtraBytes, index$q_exactHint as exactHint, index$q_forEachDescriptor as forEachDescriptor, index$q_hasUniqueView as hasUniqueView, index$q_objectView as objectView, index$q_readonlyArray as readonlyArray, index$q_sequenceViewFixLen as sequenceViewFixLen, index$q_sequenceViewVarLen as sequenceViewVarLen, index$q_tryAsExactBytes as tryAsExactBytes, index$q_validateLength as validateLength };
|
|
3516
|
+
export { index$q_DEFAULT_START_LENGTH as DEFAULT_START_LENGTH, index$q_Decoder as Decoder, index$q_Descriptor as Descriptor, index$q_Encoder as Encoder, index$q_EndOfDataError as EndOfDataError, index$q_MASKS as MASKS, index$q_MAX_LENGTH as MAX_LENGTH, index$q_ObjectView as ObjectView, index$q_SequenceView as SequenceView, index$q_TYPICAL_DICTIONARY_LENGTH as TYPICAL_DICTIONARY_LENGTH, index$q_TYPICAL_SEQUENCE_LENGTH as TYPICAL_SEQUENCE_LENGTH, index$q_ViewField as ViewField, index$q_addSizeHints as addSizeHints, codec$1 as codec, index$q_decodeVariableLengthExtraBytes as decodeVariableLengthExtraBytes, index$q_exactHint as exactHint, index$q_forEachDescriptor as forEachDescriptor, index$q_hasUniqueView as hasUniqueView, index$q_objectView as objectView, index$q_readonlyArray as readonlyArray, index$q_sequenceViewFixLen as sequenceViewFixLen, index$q_sequenceViewVarLen as sequenceViewVarLen, index$q_tryAsExactBytes as tryAsExactBytes, index$q_validateLength as validateLength };
|
|
3501
3517
|
export type { index$q_ClassConstructor as ClassConstructor, index$q_Codec as Codec, index$q_CodecRecord as CodecRecord, index$q_CodecWithView as CodecWithView, index$q_Decode as Decode, index$q_DescribedBy as DescribedBy, index$q_DescriptorRecord as DescriptorRecord, index$q_Encode as Encode, index$q_LengthRange as LengthRange, index$q_OptionalRecord as OptionalRecord, Options$1 as Options, index$q_PropertyKeys as PropertyKeys, index$q_SimpleDescriptorRecord as SimpleDescriptorRecord, index$q_SizeHint as SizeHint, index$q_ViewOf as ViewOf };
|
|
3502
3518
|
}
|
|
3503
3519
|
|
|
@@ -4263,7 +4279,7 @@ declare class SortedArray<V> implements ImmutableSortedArray<V> {
|
|
|
4263
4279
|
};
|
|
4264
4280
|
}
|
|
4265
4281
|
|
|
4266
|
-
/** Create a new
|
|
4282
|
+
/** Create a new SortedArray from two sorted collections. */
|
|
4267
4283
|
static fromTwoSortedCollections<V>(first: ImmutableSortedArray<V>, second: ImmutableSortedArray<V>) {
|
|
4268
4284
|
check`${first.comparator === second.comparator} Cannot merge arrays if they do not use the same comparator`;
|
|
4269
4285
|
const comparator = first.comparator;
|
|
@@ -5070,29 +5086,6 @@ declare const fullChainSpec = new ChainSpec({
|
|
|
5070
5086
|
maxLookupAnchorAge: tryAsU32(14_400),
|
|
5071
5087
|
});
|
|
5072
5088
|
|
|
5073
|
-
/**
|
|
5074
|
-
* Configuration object for typeberry workers.
|
|
5075
|
-
*/
|
|
5076
|
-
declare class WorkerConfig {
|
|
5077
|
-
/**
|
|
5078
|
-
* Since we loose prototypes when transferring the context,
|
|
5079
|
-
* this function is re-initializing proper types.
|
|
5080
|
-
*
|
|
5081
|
-
* TODO [ToDr] instead of doing this hack, we might prefer to pass data
|
|
5082
|
-
* between workers using JAM codec maybe?
|
|
5083
|
-
*/
|
|
5084
|
-
static reInit(config: unknown) {
|
|
5085
|
-
const { chainSpec, dbPath, omitSealVerification } = config as WorkerConfig;
|
|
5086
|
-
return new WorkerConfig(new ChainSpec(chainSpec), dbPath, omitSealVerification);
|
|
5087
|
-
}
|
|
5088
|
-
|
|
5089
|
-
constructor(
|
|
5090
|
-
public readonly chainSpec: ChainSpec,
|
|
5091
|
-
public readonly dbPath: string,
|
|
5092
|
-
public readonly omitSealVerification: boolean = false,
|
|
5093
|
-
) {}
|
|
5094
|
-
}
|
|
5095
|
-
|
|
5096
5089
|
/** Peer id. */
|
|
5097
5090
|
type PeerId = Opaque<string, "peerId">;
|
|
5098
5091
|
|
|
@@ -5135,12 +5128,10 @@ declare const index$m_EST_VALIDATORS: typeof EST_VALIDATORS;
|
|
|
5135
5128
|
declare const index$m_EST_VALIDATORS_SUPER_MAJORITY: typeof EST_VALIDATORS_SUPER_MAJORITY;
|
|
5136
5129
|
type index$m_PeerAddress = PeerAddress;
|
|
5137
5130
|
type index$m_PeerId = PeerId;
|
|
5138
|
-
type index$m_WorkerConfig = WorkerConfig;
|
|
5139
|
-
declare const index$m_WorkerConfig: typeof WorkerConfig;
|
|
5140
5131
|
declare const index$m_fullChainSpec: typeof fullChainSpec;
|
|
5141
5132
|
declare const index$m_tinyChainSpec: typeof tinyChainSpec;
|
|
5142
5133
|
declare namespace index$m {
|
|
5143
|
-
export { index$m_Bootnode as Bootnode, index$m_ChainSpec as ChainSpec, index$m_EC_SEGMENT_SIZE as EC_SEGMENT_SIZE, index$m_EST_CORES as EST_CORES, index$m_EST_EPOCH_LENGTH as EST_EPOCH_LENGTH, index$m_EST_VALIDATORS as EST_VALIDATORS, index$m_EST_VALIDATORS_SUPER_MAJORITY as EST_VALIDATORS_SUPER_MAJORITY, index$
|
|
5134
|
+
export { index$m_Bootnode as Bootnode, index$m_ChainSpec as ChainSpec, index$m_EC_SEGMENT_SIZE as EC_SEGMENT_SIZE, index$m_EST_CORES as EST_CORES, index$m_EST_EPOCH_LENGTH as EST_EPOCH_LENGTH, index$m_EST_VALIDATORS as EST_VALIDATORS, index$m_EST_VALIDATORS_SUPER_MAJORITY as EST_VALIDATORS_SUPER_MAJORITY, index$m_fullChainSpec as fullChainSpec, index$m_tinyChainSpec as tinyChainSpec };
|
|
5144
5135
|
export type { index$m_PeerAddress as PeerAddress, index$m_PeerId as PeerId };
|
|
5145
5136
|
}
|
|
5146
5137
|
|
|
@@ -8192,7 +8183,7 @@ declare class NodeConfiguration {
|
|
|
8192
8183
|
version: "number",
|
|
8193
8184
|
flavor: knownChainSpecFromJson,
|
|
8194
8185
|
chain_spec: JipChainSpec.fromJson,
|
|
8195
|
-
database_base_path: "string",
|
|
8186
|
+
database_base_path: json.optional("string"),
|
|
8196
8187
|
authorship: AuthorshipOptions.fromJson,
|
|
8197
8188
|
},
|
|
8198
8189
|
NodeConfiguration.new,
|
|
@@ -8202,7 +8193,7 @@ declare class NodeConfiguration {
|
|
|
8202
8193
|
if (version !== 1) {
|
|
8203
8194
|
throw new Error("Only version=1 config is supported.");
|
|
8204
8195
|
}
|
|
8205
|
-
return new NodeConfiguration($schema, version, flavor, chain_spec, database_base_path, authorship);
|
|
8196
|
+
return new NodeConfiguration($schema, version, flavor, chain_spec, database_base_path ?? undefined, authorship);
|
|
8206
8197
|
}
|
|
8207
8198
|
|
|
8208
8199
|
private constructor(
|
|
@@ -8210,7 +8201,8 @@ declare class NodeConfiguration {
|
|
|
8210
8201
|
public readonly version: number,
|
|
8211
8202
|
public readonly flavor: KnownChainSpec,
|
|
8212
8203
|
public readonly chainSpec: JipChainSpec,
|
|
8213
|
-
|
|
8204
|
+
/** If database path is not provided, we load an in-memory db. */
|
|
8205
|
+
public readonly databaseBasePath: string | undefined,
|
|
8214
8206
|
public readonly authorship: AuthorshipOptions,
|
|
8215
8207
|
) {}
|
|
8216
8208
|
}
|
|
@@ -8285,6 +8277,8 @@ interface BlocksDb {
|
|
|
8285
8277
|
* NOTE: this is not extrinsic hash!
|
|
8286
8278
|
*/
|
|
8287
8279
|
getExtrinsic(hash: HeaderHash): ExtrinsicView | null;
|
|
8280
|
+
/** Close the database and free resources. */
|
|
8281
|
+
close(): Promise<void>;
|
|
8288
8282
|
}
|
|
8289
8283
|
|
|
8290
8284
|
/** In-memory (non-persistent) blocks database. */
|
|
@@ -8343,6 +8337,8 @@ declare class InMemoryBlocks implements BlocksDb {
|
|
|
8343
8337
|
getExtrinsic(hash: HeaderHash): ExtrinsicView | null {
|
|
8344
8338
|
return this.extrinsicsByHeaderHash.get(hash) ?? null;
|
|
8345
8339
|
}
|
|
8340
|
+
|
|
8341
|
+
async close() {}
|
|
8346
8342
|
}
|
|
8347
8343
|
|
|
8348
8344
|
type StateKey$1 = Opaque<OpaqueHash, "trieStateKey">;
|
|
@@ -10659,7 +10655,6 @@ declare enum UpdatePreimageKind {
|
|
|
10659
10655
|
*/
|
|
10660
10656
|
declare class UpdatePreimage {
|
|
10661
10657
|
private constructor(
|
|
10662
|
-
public readonly serviceId: ServiceId,
|
|
10663
10658
|
public readonly action:
|
|
10664
10659
|
| {
|
|
10665
10660
|
kind: UpdatePreimageKind.Provide;
|
|
@@ -10679,16 +10674,8 @@ declare class UpdatePreimage {
|
|
|
10679
10674
|
) {}
|
|
10680
10675
|
|
|
10681
10676
|
/** A preimage is provided. We should update the lookuphistory and add the preimage to db. */
|
|
10682
|
-
static provide({
|
|
10683
|
-
|
|
10684
|
-
preimage,
|
|
10685
|
-
slot,
|
|
10686
|
-
}: {
|
|
10687
|
-
serviceId: ServiceId;
|
|
10688
|
-
preimage: PreimageItem;
|
|
10689
|
-
slot: TimeSlot | null;
|
|
10690
|
-
}) {
|
|
10691
|
-
return new UpdatePreimage(serviceId, {
|
|
10677
|
+
static provide({ preimage, slot }: { preimage: PreimageItem; slot: TimeSlot | null }) {
|
|
10678
|
+
return new UpdatePreimage({
|
|
10692
10679
|
kind: UpdatePreimageKind.Provide,
|
|
10693
10680
|
preimage,
|
|
10694
10681
|
slot,
|
|
@@ -10696,8 +10683,8 @@ declare class UpdatePreimage {
|
|
|
10696
10683
|
}
|
|
10697
10684
|
|
|
10698
10685
|
/** The preimage should be removed completely from the database. */
|
|
10699
|
-
static remove({
|
|
10700
|
-
return new UpdatePreimage(
|
|
10686
|
+
static remove({ hash, length }: { hash: PreimageHash; length: U32 }) {
|
|
10687
|
+
return new UpdatePreimage({
|
|
10701
10688
|
kind: UpdatePreimageKind.Remove,
|
|
10702
10689
|
hash,
|
|
10703
10690
|
length,
|
|
@@ -10705,8 +10692,8 @@ declare class UpdatePreimage {
|
|
|
10705
10692
|
}
|
|
10706
10693
|
|
|
10707
10694
|
/** Update the lookup history of some preimage or add a new one (request). */
|
|
10708
|
-
static updateOrAdd({
|
|
10709
|
-
return new UpdatePreimage(
|
|
10695
|
+
static updateOrAdd({ lookupHistory }: { lookupHistory: LookupHistoryItem }) {
|
|
10696
|
+
return new UpdatePreimage({
|
|
10710
10697
|
kind: UpdatePreimageKind.UpdateOrAdd,
|
|
10711
10698
|
item: lookupHistory,
|
|
10712
10699
|
});
|
|
@@ -10744,12 +10731,12 @@ declare enum UpdateServiceKind {
|
|
|
10744
10731
|
/** Create a new `Service` instance. */
|
|
10745
10732
|
Create = 1,
|
|
10746
10733
|
}
|
|
10734
|
+
|
|
10747
10735
|
/**
|
|
10748
|
-
* Update service info
|
|
10736
|
+
* Update service info or create a new one.
|
|
10749
10737
|
*/
|
|
10750
10738
|
declare class UpdateService {
|
|
10751
10739
|
private constructor(
|
|
10752
|
-
public readonly serviceId: ServiceId,
|
|
10753
10740
|
public readonly action:
|
|
10754
10741
|
| {
|
|
10755
10742
|
kind: UpdateServiceKind.Update;
|
|
@@ -10762,23 +10749,21 @@ declare class UpdateService {
|
|
|
10762
10749
|
},
|
|
10763
10750
|
) {}
|
|
10764
10751
|
|
|
10765
|
-
static update({
|
|
10766
|
-
return new UpdateService(
|
|
10752
|
+
static update({ serviceInfo }: { serviceInfo: ServiceAccountInfo }) {
|
|
10753
|
+
return new UpdateService({
|
|
10767
10754
|
kind: UpdateServiceKind.Update,
|
|
10768
10755
|
account: serviceInfo,
|
|
10769
10756
|
});
|
|
10770
10757
|
}
|
|
10771
10758
|
|
|
10772
10759
|
static create({
|
|
10773
|
-
serviceId,
|
|
10774
10760
|
serviceInfo,
|
|
10775
10761
|
lookupHistory,
|
|
10776
10762
|
}: {
|
|
10777
|
-
serviceId: ServiceId;
|
|
10778
10763
|
serviceInfo: ServiceAccountInfo;
|
|
10779
10764
|
lookupHistory: LookupHistoryItem | null;
|
|
10780
10765
|
}) {
|
|
10781
|
-
return new UpdateService(
|
|
10766
|
+
return new UpdateService({
|
|
10782
10767
|
kind: UpdateServiceKind.Create,
|
|
10783
10768
|
account: serviceInfo,
|
|
10784
10769
|
lookupHistory,
|
|
@@ -10800,7 +10785,6 @@ declare enum UpdateStorageKind {
|
|
|
10800
10785
|
*/
|
|
10801
10786
|
declare class UpdateStorage {
|
|
10802
10787
|
private constructor(
|
|
10803
|
-
public readonly serviceId: ServiceId,
|
|
10804
10788
|
public readonly action:
|
|
10805
10789
|
| {
|
|
10806
10790
|
kind: UpdateStorageKind.Set;
|
|
@@ -10812,12 +10796,12 @@ declare class UpdateStorage {
|
|
|
10812
10796
|
},
|
|
10813
10797
|
) {}
|
|
10814
10798
|
|
|
10815
|
-
static set({
|
|
10816
|
-
return new UpdateStorage(
|
|
10799
|
+
static set({ storage }: { storage: StorageItem }) {
|
|
10800
|
+
return new UpdateStorage({ kind: UpdateStorageKind.Set, storage });
|
|
10817
10801
|
}
|
|
10818
10802
|
|
|
10819
|
-
static remove({
|
|
10820
|
-
return new UpdateStorage(
|
|
10803
|
+
static remove({ key }: { key: StorageKey }) {
|
|
10804
|
+
return new UpdateStorage({ kind: UpdateStorageKind.Remove, key });
|
|
10821
10805
|
}
|
|
10822
10806
|
|
|
10823
10807
|
get key() {
|
|
@@ -10835,16 +10819,17 @@ declare class UpdateStorage {
|
|
|
10835
10819
|
}
|
|
10836
10820
|
}
|
|
10837
10821
|
|
|
10838
|
-
// TODO [ToDr] This would be more convenient to use if the data was grouped by `ServiceId`.
|
|
10839
10822
|
type ServicesUpdate = {
|
|
10840
10823
|
/** Service ids to remove from state alongside all their data. */
|
|
10841
|
-
|
|
10842
|
-
/** Services
|
|
10843
|
-
|
|
10824
|
+
removed: ServiceId[];
|
|
10825
|
+
/** Services newly created. */
|
|
10826
|
+
created: ServiceId[];
|
|
10827
|
+
/** Services to update. */
|
|
10828
|
+
updated: Map<ServiceId, UpdateService>;
|
|
10844
10829
|
/** Service preimages to update and potentially lookup history */
|
|
10845
|
-
preimages: UpdatePreimage[]
|
|
10830
|
+
preimages: Map<ServiceId, UpdatePreimage[]>;
|
|
10846
10831
|
/** Service storage to update. */
|
|
10847
|
-
storage: UpdateStorage[]
|
|
10832
|
+
storage: Map<ServiceId, UpdateStorage[]>;
|
|
10848
10833
|
};
|
|
10849
10834
|
|
|
10850
10835
|
declare enum UpdateError {
|
|
@@ -11040,13 +11025,13 @@ declare class InMemoryState extends WithDebug implements State, WithStateView, E
|
|
|
11040
11025
|
* Modify the state and apply a single state update.
|
|
11041
11026
|
*/
|
|
11042
11027
|
applyUpdate(update: Partial<State & ServicesUpdate>): Result$2<OK, UpdateError> {
|
|
11043
|
-
const {
|
|
11028
|
+
const { removed, created: _, updated, preimages, storage, ...rest } = update;
|
|
11044
11029
|
// just assign all other variables
|
|
11045
11030
|
Object.assign(this, rest);
|
|
11046
11031
|
|
|
11047
11032
|
// and update the services state
|
|
11048
11033
|
let result: Result<OK, UpdateError>;
|
|
11049
|
-
result = this.updateServices(
|
|
11034
|
+
result = this.updateServices(updated);
|
|
11050
11035
|
if (result.isError) {
|
|
11051
11036
|
return result;
|
|
11052
11037
|
}
|
|
@@ -11058,7 +11043,7 @@ declare class InMemoryState extends WithDebug implements State, WithStateView, E
|
|
|
11058
11043
|
if (result.isError) {
|
|
11059
11044
|
return result;
|
|
11060
11045
|
}
|
|
11061
|
-
this.removeServices(
|
|
11046
|
+
this.removeServices(removed);
|
|
11062
11047
|
|
|
11063
11048
|
return Result.ok(OK);
|
|
11064
11049
|
}
|
|
@@ -11070,93 +11055,108 @@ declare class InMemoryState extends WithDebug implements State, WithStateView, E
|
|
|
11070
11055
|
}
|
|
11071
11056
|
}
|
|
11072
11057
|
|
|
11073
|
-
private updateStorage(
|
|
11074
|
-
|
|
11075
|
-
|
|
11076
|
-
|
|
11077
|
-
|
|
11078
|
-
|
|
11079
|
-
|
|
11080
|
-
|
|
11081
|
-
)
|
|
11082
|
-
|
|
11058
|
+
private updateStorage(storageUpdates: Map<ServiceId, UpdateStorage[]> | undefined): Result$2<OK, UpdateError> {
|
|
11059
|
+
if (storageUpdates === undefined) {
|
|
11060
|
+
return Result.ok(OK);
|
|
11061
|
+
}
|
|
11062
|
+
for (const [serviceId, updates] of storageUpdates.entries()) {
|
|
11063
|
+
for (const update of updates) {
|
|
11064
|
+
const { kind } = update.action;
|
|
11065
|
+
const service = this.services.get(serviceId);
|
|
11066
|
+
if (service === undefined) {
|
|
11067
|
+
return Result.error(
|
|
11068
|
+
UpdateError.NoService,
|
|
11069
|
+
() => `Attempting to update storage of non-existing service: ${serviceId}`,
|
|
11070
|
+
);
|
|
11071
|
+
}
|
|
11083
11072
|
|
|
11084
|
-
|
|
11085
|
-
|
|
11086
|
-
|
|
11087
|
-
|
|
11088
|
-
|
|
11089
|
-
|
|
11073
|
+
if (kind === UpdateStorageKind.Set) {
|
|
11074
|
+
const { key, value } = update.action.storage;
|
|
11075
|
+
service.data.storage.set(key.toString(), StorageItem.create({ key, value }));
|
|
11076
|
+
} else if (kind === UpdateStorageKind.Remove) {
|
|
11077
|
+
const { key } = update.action;
|
|
11078
|
+
check`
|
|
11090
11079
|
${service.data.storage.has(key.toString())}
|
|
11091
|
-
Attempting to remove non-existing storage item at ${serviceId}: ${action.key}
|
|
11080
|
+
Attempting to remove non-existing storage item at ${serviceId}: ${update.action.key}
|
|
11092
11081
|
`;
|
|
11093
|
-
|
|
11094
|
-
|
|
11095
|
-
|
|
11082
|
+
service.data.storage.delete(key.toString());
|
|
11083
|
+
} else {
|
|
11084
|
+
assertNever(kind);
|
|
11085
|
+
}
|
|
11096
11086
|
}
|
|
11097
11087
|
}
|
|
11098
|
-
|
|
11099
11088
|
return Result.ok(OK);
|
|
11100
11089
|
}
|
|
11101
11090
|
|
|
11102
|
-
private updatePreimages(
|
|
11103
|
-
|
|
11091
|
+
private updatePreimages(preimagesUpdates: Map<ServiceId, UpdatePreimage[]> | undefined): Result$2<OK, UpdateError> {
|
|
11092
|
+
if (preimagesUpdates === undefined) {
|
|
11093
|
+
return Result.ok(OK);
|
|
11094
|
+
}
|
|
11095
|
+
for (const [serviceId, updates] of preimagesUpdates.entries()) {
|
|
11104
11096
|
const service = this.services.get(serviceId);
|
|
11105
11097
|
if (service === undefined) {
|
|
11106
11098
|
return Result.error(
|
|
11107
11099
|
UpdateError.NoService,
|
|
11108
|
-
`Attempting to update preimage of non-existing service: ${serviceId}`,
|
|
11100
|
+
() => `Attempting to update preimage of non-existing service: ${serviceId}`,
|
|
11109
11101
|
);
|
|
11110
11102
|
}
|
|
11111
|
-
const
|
|
11112
|
-
|
|
11113
|
-
|
|
11114
|
-
|
|
11115
|
-
|
|
11116
|
-
|
|
11117
|
-
|
|
11118
|
-
|
|
11119
|
-
|
|
11120
|
-
const length = tryAsU32(preimage.blob.length);
|
|
11121
|
-
const lookup = new LookupHistoryItem(preimage.hash, length, tryAsLookupHistorySlots([slot]));
|
|
11122
|
-
if (lookupHistory === undefined) {
|
|
11123
|
-
// no lookup history for that preimage at all (edge case, should be requested)
|
|
11124
|
-
service.data.lookupHistory.set(preimage.hash, [lookup]);
|
|
11125
|
-
} else {
|
|
11126
|
-
// insert or replace exiting entry
|
|
11127
|
-
const index = lookupHistory.map((x) => x.length).indexOf(length);
|
|
11128
|
-
lookupHistory.splice(index, index === -1 ? 0 : 1, lookup);
|
|
11103
|
+
for (const update of updates) {
|
|
11104
|
+
const { kind } = update.action;
|
|
11105
|
+
if (kind === UpdatePreimageKind.Provide) {
|
|
11106
|
+
const { preimage, slot } = update.action;
|
|
11107
|
+
if (service.data.preimages.has(preimage.hash)) {
|
|
11108
|
+
return Result.error(
|
|
11109
|
+
UpdateError.PreimageExists,
|
|
11110
|
+
() => `Overwriting existing preimage at ${serviceId}: ${preimage}`,
|
|
11111
|
+
);
|
|
11129
11112
|
}
|
|
11113
|
+
service.data.preimages.set(preimage.hash, preimage);
|
|
11114
|
+
if (slot !== null) {
|
|
11115
|
+
const lookupHistory = service.data.lookupHistory.get(preimage.hash);
|
|
11116
|
+
const length = tryAsU32(preimage.blob.length);
|
|
11117
|
+
const lookup = new LookupHistoryItem(preimage.hash, length, tryAsLookupHistorySlots([slot]));
|
|
11118
|
+
if (lookupHistory === undefined) {
|
|
11119
|
+
// no lookup history for that preimage at all (edge case, should be requested)
|
|
11120
|
+
service.data.lookupHistory.set(preimage.hash, [lookup]);
|
|
11121
|
+
} else {
|
|
11122
|
+
// insert or replace exiting entry
|
|
11123
|
+
const index = lookupHistory.map((x) => x.length).indexOf(length);
|
|
11124
|
+
lookupHistory.splice(index, index === -1 ? 0 : 1, lookup);
|
|
11125
|
+
}
|
|
11126
|
+
}
|
|
11127
|
+
} else if (kind === UpdatePreimageKind.Remove) {
|
|
11128
|
+
const { hash, length } = update.action;
|
|
11129
|
+
service.data.preimages.delete(hash);
|
|
11130
|
+
const history = service.data.lookupHistory.get(hash) ?? [];
|
|
11131
|
+
const idx = history.map((x) => x.length).indexOf(length);
|
|
11132
|
+
if (idx !== -1) {
|
|
11133
|
+
history.splice(idx, 1);
|
|
11134
|
+
}
|
|
11135
|
+
} else if (kind === UpdatePreimageKind.UpdateOrAdd) {
|
|
11136
|
+
const { item } = update.action;
|
|
11137
|
+
const history = service.data.lookupHistory.get(item.hash) ?? [];
|
|
11138
|
+
const existingIdx = history.map((x) => x.length).indexOf(item.length);
|
|
11139
|
+
const removeCount = existingIdx === -1 ? 0 : 1;
|
|
11140
|
+
history.splice(existingIdx, removeCount, item);
|
|
11141
|
+
service.data.lookupHistory.set(item.hash, history);
|
|
11142
|
+
} else {
|
|
11143
|
+
assertNever(kind);
|
|
11130
11144
|
}
|
|
11131
|
-
} else if (kind === UpdatePreimageKind.Remove) {
|
|
11132
|
-
const { hash, length } = action;
|
|
11133
|
-
service.data.preimages.delete(hash);
|
|
11134
|
-
const history = service.data.lookupHistory.get(hash) ?? [];
|
|
11135
|
-
const idx = history.map((x) => x.length).indexOf(length);
|
|
11136
|
-
if (idx !== -1) {
|
|
11137
|
-
history.splice(idx, 1);
|
|
11138
|
-
}
|
|
11139
|
-
} else if (kind === UpdatePreimageKind.UpdateOrAdd) {
|
|
11140
|
-
const { item } = action;
|
|
11141
|
-
const history = service.data.lookupHistory.get(item.hash) ?? [];
|
|
11142
|
-
const existingIdx = history.map((x) => x.length).indexOf(item.length);
|
|
11143
|
-
const removeCount = existingIdx === -1 ? 0 : 1;
|
|
11144
|
-
history.splice(existingIdx, removeCount, item);
|
|
11145
|
-
service.data.lookupHistory.set(item.hash, history);
|
|
11146
|
-
} else {
|
|
11147
|
-
assertNever(kind);
|
|
11148
11145
|
}
|
|
11149
11146
|
}
|
|
11150
11147
|
return Result.ok(OK);
|
|
11151
11148
|
}
|
|
11152
11149
|
|
|
11153
|
-
private updateServices(servicesUpdates
|
|
11154
|
-
|
|
11155
|
-
|
|
11150
|
+
private updateServices(servicesUpdates: Map<ServiceId, UpdateService> | undefined): Result$2<OK, UpdateError> {
|
|
11151
|
+
if (servicesUpdates === undefined) {
|
|
11152
|
+
return Result.ok(OK);
|
|
11153
|
+
}
|
|
11154
|
+
for (const [serviceId, update] of servicesUpdates.entries()) {
|
|
11155
|
+
const { kind, account } = update.action;
|
|
11156
11156
|
if (kind === UpdateServiceKind.Create) {
|
|
11157
|
-
const { lookupHistory } = action;
|
|
11157
|
+
const { lookupHistory } = update.action;
|
|
11158
11158
|
if (this.services.has(serviceId)) {
|
|
11159
|
-
return Result.error(UpdateError.DuplicateService, `${serviceId} already exists!`);
|
|
11159
|
+
return Result.error(UpdateError.DuplicateService, () => `${serviceId} already exists!`);
|
|
11160
11160
|
}
|
|
11161
11161
|
this.services.set(
|
|
11162
11162
|
serviceId,
|
|
@@ -11172,7 +11172,7 @@ declare class InMemoryState extends WithDebug implements State, WithStateView, E
|
|
|
11172
11172
|
} else if (kind === UpdateServiceKind.Update) {
|
|
11173
11173
|
const existingService = this.services.get(serviceId);
|
|
11174
11174
|
if (existingService === undefined) {
|
|
11175
|
-
return Result.error(UpdateError.NoService, `Cannot update ${serviceId} because it does not exist.`);
|
|
11175
|
+
return Result.error(UpdateError.NoService, () => `Cannot update ${serviceId} because it does not exist.`);
|
|
11176
11176
|
}
|
|
11177
11177
|
existingService.data.info = account;
|
|
11178
11178
|
} else {
|
|
@@ -11975,89 +11975,104 @@ declare function* serializeStateUpdate(
|
|
|
11975
11975
|
const encode = <T>(codec: Encode<T>, val: T) => Encoder.encodeObject(codec, val, spec);
|
|
11976
11976
|
|
|
11977
11977
|
// then let's proceed with service updates
|
|
11978
|
-
yield* serializeServiceUpdates(update.
|
|
11978
|
+
yield* serializeServiceUpdates(update.updated, encode, blake2b);
|
|
11979
11979
|
yield* serializePreimages(update.preimages, encode, blake2b);
|
|
11980
11980
|
yield* serializeStorage(update.storage, blake2b);
|
|
11981
|
-
yield* serializeRemovedServices(update.
|
|
11981
|
+
yield* serializeRemovedServices(update.removed);
|
|
11982
11982
|
}
|
|
11983
11983
|
|
|
11984
11984
|
declare function* serializeRemovedServices(servicesRemoved: ServiceId[] | undefined): Generator<StateEntryUpdate> {
|
|
11985
|
-
|
|
11985
|
+
if (servicesRemoved === undefined) {
|
|
11986
|
+
return;
|
|
11987
|
+
}
|
|
11988
|
+
for (const serviceId of servicesRemoved) {
|
|
11986
11989
|
// TODO [ToDr] what about all data associated with a service?
|
|
11987
11990
|
const codec = serialize.serviceData(serviceId);
|
|
11988
11991
|
yield [StateEntryUpdateAction.Remove, codec.key, EMPTY_BLOB];
|
|
11989
11992
|
}
|
|
11990
11993
|
}
|
|
11991
11994
|
|
|
11992
|
-
declare function* serializeStorage(
|
|
11993
|
-
|
|
11994
|
-
|
|
11995
|
-
|
|
11996
|
-
|
|
11997
|
-
|
|
11998
|
-
|
|
11999
|
-
|
|
12000
|
-
|
|
12001
|
-
|
|
12002
|
-
|
|
12003
|
-
|
|
12004
|
-
|
|
12005
|
-
|
|
11995
|
+
declare function* serializeStorage(
|
|
11996
|
+
storageUpdates: Map<ServiceId, UpdateStorage[]> | undefined,
|
|
11997
|
+
blake2b: Blake2b,
|
|
11998
|
+
): Generator<StateEntryUpdate> {
|
|
11999
|
+
if (storageUpdates === undefined) {
|
|
12000
|
+
return;
|
|
12001
|
+
}
|
|
12002
|
+
for (const [serviceId, updates] of storageUpdates.entries()) {
|
|
12003
|
+
for (const { action } of updates) {
|
|
12004
|
+
switch (action.kind) {
|
|
12005
|
+
case UpdateStorageKind.Set: {
|
|
12006
|
+
const key = action.storage.key;
|
|
12007
|
+
const codec = serialize.serviceStorage(blake2b, serviceId, key);
|
|
12008
|
+
yield [StateEntryUpdateAction.Insert, codec.key, action.storage.value];
|
|
12009
|
+
break;
|
|
12010
|
+
}
|
|
12011
|
+
case UpdateStorageKind.Remove: {
|
|
12012
|
+
const key = action.key;
|
|
12013
|
+
const codec = serialize.serviceStorage(blake2b, serviceId, key);
|
|
12014
|
+
yield [StateEntryUpdateAction.Remove, codec.key, EMPTY_BLOB];
|
|
12015
|
+
break;
|
|
12016
|
+
}
|
|
12006
12017
|
}
|
|
12007
|
-
default:
|
|
12008
|
-
assertNever(action);
|
|
12009
12018
|
}
|
|
12010
12019
|
}
|
|
12011
12020
|
}
|
|
12012
12021
|
|
|
12013
12022
|
declare function* serializePreimages(
|
|
12014
|
-
|
|
12023
|
+
preimagesUpdates: Map<ServiceId, UpdatePreimage[]> | undefined,
|
|
12015
12024
|
encode: EncodeFun,
|
|
12016
12025
|
blake2b: Blake2b,
|
|
12017
12026
|
): Generator<StateEntryUpdate> {
|
|
12018
|
-
|
|
12019
|
-
|
|
12020
|
-
|
|
12021
|
-
|
|
12022
|
-
|
|
12023
|
-
|
|
12024
|
-
|
|
12025
|
-
|
|
12026
|
-
const
|
|
12027
|
-
yield [
|
|
12028
|
-
|
|
12029
|
-
|
|
12030
|
-
|
|
12031
|
-
|
|
12027
|
+
if (preimagesUpdates === undefined) {
|
|
12028
|
+
return;
|
|
12029
|
+
}
|
|
12030
|
+
for (const [serviceId, updates] of preimagesUpdates.entries()) {
|
|
12031
|
+
for (const { action } of updates) {
|
|
12032
|
+
switch (action.kind) {
|
|
12033
|
+
case UpdatePreimageKind.Provide: {
|
|
12034
|
+
const { hash, blob } = action.preimage;
|
|
12035
|
+
const codec = serialize.servicePreimages(blake2b, serviceId, hash);
|
|
12036
|
+
yield [StateEntryUpdateAction.Insert, codec.key, blob];
|
|
12037
|
+
|
|
12038
|
+
if (action.slot !== null) {
|
|
12039
|
+
const codec2 = serialize.serviceLookupHistory(blake2b, serviceId, hash, tryAsU32(blob.length));
|
|
12040
|
+
yield [
|
|
12041
|
+
StateEntryUpdateAction.Insert,
|
|
12042
|
+
codec2.key,
|
|
12043
|
+
encode(codec2.Codec, tryAsLookupHistorySlots([action.slot])),
|
|
12044
|
+
];
|
|
12045
|
+
}
|
|
12046
|
+
break;
|
|
12032
12047
|
}
|
|
12033
|
-
|
|
12034
|
-
|
|
12035
|
-
|
|
12036
|
-
|
|
12037
|
-
|
|
12038
|
-
|
|
12039
|
-
|
|
12040
|
-
|
|
12041
|
-
|
|
12042
|
-
|
|
12043
|
-
const codec = serialize.servicePreimages(blake2b, serviceId, hash);
|
|
12044
|
-
yield [StateEntryUpdateAction.Remove, codec.key, EMPTY_BLOB];
|
|
12048
|
+
case UpdatePreimageKind.UpdateOrAdd: {
|
|
12049
|
+
const { hash, length, slots } = action.item;
|
|
12050
|
+
const codec = serialize.serviceLookupHistory(blake2b, serviceId, hash, length);
|
|
12051
|
+
yield [StateEntryUpdateAction.Insert, codec.key, encode(codec.Codec, slots)];
|
|
12052
|
+
break;
|
|
12053
|
+
}
|
|
12054
|
+
case UpdatePreimageKind.Remove: {
|
|
12055
|
+
const { hash, length } = action;
|
|
12056
|
+
const codec = serialize.servicePreimages(blake2b, serviceId, hash);
|
|
12057
|
+
yield [StateEntryUpdateAction.Remove, codec.key, EMPTY_BLOB];
|
|
12045
12058
|
|
|
12046
|
-
|
|
12047
|
-
|
|
12048
|
-
|
|
12059
|
+
const codec2 = serialize.serviceLookupHistory(blake2b, serviceId, hash, length);
|
|
12060
|
+
yield [StateEntryUpdateAction.Remove, codec2.key, EMPTY_BLOB];
|
|
12061
|
+
break;
|
|
12062
|
+
}
|
|
12049
12063
|
}
|
|
12050
|
-
default:
|
|
12051
|
-
assertNever(action);
|
|
12052
12064
|
}
|
|
12053
12065
|
}
|
|
12054
12066
|
}
|
|
12055
12067
|
declare function* serializeServiceUpdates(
|
|
12056
|
-
servicesUpdates: UpdateService
|
|
12068
|
+
servicesUpdates: Map<ServiceId, UpdateService> | undefined,
|
|
12057
12069
|
encode: EncodeFun,
|
|
12058
12070
|
blake2b: Blake2b,
|
|
12059
12071
|
): Generator<StateEntryUpdate> {
|
|
12060
|
-
|
|
12072
|
+
if (servicesUpdates === undefined) {
|
|
12073
|
+
return;
|
|
12074
|
+
}
|
|
12075
|
+
for (const [serviceId, { action }] of servicesUpdates.entries()) {
|
|
12061
12076
|
// new service being created or updated
|
|
12062
12077
|
const codec = serialize.serviceData(serviceId);
|
|
12063
12078
|
yield [StateEntryUpdateAction.Insert, codec.key, encode(codec.Codec, action.account)];
|
|
@@ -12646,7 +12661,7 @@ interface ValuesDb {
|
|
|
12646
12661
|
* Missing value is considered an irrecoverable error, so the implementations
|
|
12647
12662
|
* are free to throw if that happens.
|
|
12648
12663
|
*/
|
|
12649
|
-
get(key:
|
|
12664
|
+
get(key: ValueHash): Uint8Array;
|
|
12650
12665
|
}
|
|
12651
12666
|
|
|
12652
12667
|
/**
|
|
@@ -12663,7 +12678,7 @@ declare class LeafDb implements SerializedStateBackend {
|
|
|
12663
12678
|
if (blob.length % TRIE_NODE_BYTES !== 0) {
|
|
12664
12679
|
return Result.error(
|
|
12665
12680
|
LeafDbError.InvalidLeafData,
|
|
12666
|
-
`${blob.length} is not a multiply of ${TRIE_NODE_BYTES}: ${blob}`,
|
|
12681
|
+
() => `${blob.length} is not a multiply of ${TRIE_NODE_BYTES}: ${blob}`,
|
|
12667
12682
|
);
|
|
12668
12683
|
}
|
|
12669
12684
|
|
|
@@ -12671,7 +12686,7 @@ declare class LeafDb implements SerializedStateBackend {
|
|
|
12671
12686
|
for (const nodeData of blob.chunks(TRIE_NODE_BYTES)) {
|
|
12672
12687
|
const node = new TrieNode(nodeData.raw);
|
|
12673
12688
|
if (node.getNodeType() === NodeType.Branch) {
|
|
12674
|
-
return Result.error(LeafDbError.InvalidLeafData, `Branch node detected: ${nodeData}`);
|
|
12689
|
+
return Result.error(LeafDbError.InvalidLeafData, () => `Branch node detected: ${nodeData}`);
|
|
12675
12690
|
}
|
|
12676
12691
|
leaves.insert(node.asLeafNode());
|
|
12677
12692
|
}
|
|
@@ -12679,15 +12694,20 @@ declare class LeafDb implements SerializedStateBackend {
|
|
|
12679
12694
|
return Result.ok(new LeafDb(leaves, db));
|
|
12680
12695
|
}
|
|
12681
12696
|
|
|
12697
|
+
/** Create leaf db from sorted set of leaves. */
|
|
12698
|
+
static fromLeaves(leaves: SortedSet<LeafNode>, db: ValuesDb): LeafDb {
|
|
12699
|
+
return new LeafDb(leaves, db);
|
|
12700
|
+
}
|
|
12701
|
+
|
|
12682
12702
|
/** A mapping between an embedded value or db lookup key. */
|
|
12683
12703
|
private readonly lookup: TruncatedHashDictionary<StateKey, Lookup>;
|
|
12684
12704
|
|
|
12685
12705
|
private constructor(
|
|
12686
|
-
public readonly
|
|
12706
|
+
public readonly leafs: SortedSet<LeafNode>,
|
|
12687
12707
|
public readonly db: ValuesDb,
|
|
12688
12708
|
) {
|
|
12689
12709
|
this.lookup = TruncatedHashDictionary.fromEntries(
|
|
12690
|
-
|
|
12710
|
+
leafs.array.map((leaf) => {
|
|
12691
12711
|
const key: StateKey = leaf.getKey().asOpaque();
|
|
12692
12712
|
const value: Lookup = leaf.hasEmbeddedValue()
|
|
12693
12713
|
? {
|
|
@@ -12696,7 +12716,7 @@ declare class LeafDb implements SerializedStateBackend {
|
|
|
12696
12716
|
}
|
|
12697
12717
|
: {
|
|
12698
12718
|
kind: LookupKind.DbKey,
|
|
12699
|
-
key: leaf.getValueHash()
|
|
12719
|
+
key: leaf.getValueHash(),
|
|
12700
12720
|
};
|
|
12701
12721
|
return [key, value];
|
|
12702
12722
|
}),
|
|
@@ -12722,7 +12742,7 @@ declare class LeafDb implements SerializedStateBackend {
|
|
|
12722
12742
|
|
|
12723
12743
|
getStateRoot(blake2b: Blake2b): StateRootHash {
|
|
12724
12744
|
const blake2bTrieHasher = getBlake2bTrieHasher(blake2b);
|
|
12725
|
-
return InMemoryTrie.computeStateRoot(blake2bTrieHasher, this.
|
|
12745
|
+
return InMemoryTrie.computeStateRoot(blake2bTrieHasher, this.leafs).asOpaque();
|
|
12726
12746
|
}
|
|
12727
12747
|
|
|
12728
12748
|
intoStateEntries(): StateEntries {
|
|
@@ -12756,9 +12776,42 @@ type Lookup =
|
|
|
12756
12776
|
}
|
|
12757
12777
|
| {
|
|
12758
12778
|
kind: LookupKind.DbKey;
|
|
12759
|
-
key:
|
|
12779
|
+
key: ValueHash;
|
|
12760
12780
|
};
|
|
12761
12781
|
|
|
12782
|
+
declare function updateLeafs(
|
|
12783
|
+
leafs: SortedSet<LeafNode>,
|
|
12784
|
+
blake2b: Blake2b,
|
|
12785
|
+
data: Iterable<[StateEntryUpdateAction, StateKey | TruncatedHash, BytesBlob]>,
|
|
12786
|
+
): {
|
|
12787
|
+
values: [ValueHash, BytesBlob][];
|
|
12788
|
+
leafs: SortedSet<LeafNode>;
|
|
12789
|
+
} {
|
|
12790
|
+
const blake2bTrieHasher = getBlake2bTrieHasher(blake2b);
|
|
12791
|
+
// We will collect all values that don't fit directly into leaf nodes.
|
|
12792
|
+
const values: [ValueHash, BytesBlob][] = [];
|
|
12793
|
+
for (const [action, key, value] of data) {
|
|
12794
|
+
if (action === StateEntryUpdateAction.Insert) {
|
|
12795
|
+
const leafNode = InMemoryTrie.constructLeaf(blake2bTrieHasher, key.asOpaque(), value);
|
|
12796
|
+
leafs.replace(leafNode);
|
|
12797
|
+
if (!leafNode.hasEmbeddedValue()) {
|
|
12798
|
+
values.push([leafNode.getValueHash(), value]);
|
|
12799
|
+
}
|
|
12800
|
+
} else if (action === StateEntryUpdateAction.Remove) {
|
|
12801
|
+
const leafNode = InMemoryTrie.constructLeaf(blake2bTrieHasher, key.asOpaque(), BytesBlob.empty());
|
|
12802
|
+
leafs.removeOne(leafNode);
|
|
12803
|
+
// TODO [ToDr] Handle ref-counting values or updating some header-hash-based references.
|
|
12804
|
+
} else {
|
|
12805
|
+
assertNever(action);
|
|
12806
|
+
}
|
|
12807
|
+
}
|
|
12808
|
+
|
|
12809
|
+
return {
|
|
12810
|
+
values,
|
|
12811
|
+
leafs,
|
|
12812
|
+
};
|
|
12813
|
+
}
|
|
12814
|
+
|
|
12762
12815
|
/** A potential error that occured during state update. */
|
|
12763
12816
|
declare enum StateUpdateError {
|
|
12764
12817
|
/** A conflicting state update has been provided. */
|
|
@@ -12766,6 +12819,13 @@ declare enum StateUpdateError {
|
|
|
12766
12819
|
/** There was an error committing the changes. */
|
|
12767
12820
|
Commit = 1,
|
|
12768
12821
|
}
|
|
12822
|
+
|
|
12823
|
+
/** Interface to initialize states db. Typically used in conjunction with `StatesDb`. */
|
|
12824
|
+
interface InitStatesDb<T = State> {
|
|
12825
|
+
/** Insert a pre-defined initial state directly into the database. */
|
|
12826
|
+
insertInitialState(headerHash: HeaderHash, initialState: T): Promise<Result$2<OK, StateUpdateError>>;
|
|
12827
|
+
}
|
|
12828
|
+
|
|
12769
12829
|
/**
|
|
12770
12830
|
* Interface for accessing states stored in the database.
|
|
12771
12831
|
*
|
|
@@ -12791,12 +12851,18 @@ interface StatesDb<T extends State = State> {
|
|
|
12791
12851
|
|
|
12792
12852
|
/** Retrieve posterior state of given header. */
|
|
12793
12853
|
getState(header: HeaderHash): T | null;
|
|
12854
|
+
|
|
12855
|
+
/** Close the database and free resources. */
|
|
12856
|
+
close(): Promise<void>;
|
|
12794
12857
|
}
|
|
12795
12858
|
|
|
12796
12859
|
declare class InMemoryStates implements StatesDb<InMemoryState> {
|
|
12797
|
-
private readonly db: HashDictionary<HeaderHash,
|
|
12860
|
+
private readonly db: HashDictionary<HeaderHash, InMemoryState> = HashDictionary.new();
|
|
12861
|
+
private readonly blake2b: Promise<Blake2b>;
|
|
12798
12862
|
|
|
12799
|
-
constructor(private readonly spec: ChainSpec) {
|
|
12863
|
+
constructor(private readonly spec: ChainSpec) {
|
|
12864
|
+
this.blake2b = Blake2b.createHasher();
|
|
12865
|
+
}
|
|
12800
12866
|
|
|
12801
12867
|
async updateAndSetState(
|
|
12802
12868
|
headerHash: HeaderHash,
|
|
@@ -12805,7 +12871,7 @@ declare class InMemoryStates implements StatesDb<InMemoryState> {
|
|
|
12805
12871
|
): Promise<Result$2<OK, StateUpdateError>> {
|
|
12806
12872
|
const res = state.applyUpdate(update);
|
|
12807
12873
|
if (res.isOk) {
|
|
12808
|
-
return await this.
|
|
12874
|
+
return await this.insertInitialState(headerHash, state);
|
|
12809
12875
|
}
|
|
12810
12876
|
|
|
12811
12877
|
switch (res.error) {
|
|
@@ -12819,32 +12885,126 @@ declare class InMemoryStates implements StatesDb<InMemoryState> {
|
|
|
12819
12885
|
}
|
|
12820
12886
|
|
|
12821
12887
|
async getStateRoot(state: InMemoryState): Promise<StateRootHash> {
|
|
12822
|
-
const blake2b = await
|
|
12888
|
+
const blake2b = await this.blake2b;
|
|
12823
12889
|
return StateEntries.serializeInMemory(this.spec, blake2b, state).getRootHash(blake2b);
|
|
12824
12890
|
}
|
|
12825
12891
|
|
|
12826
12892
|
/** Insert a full state into the database. */
|
|
12827
|
-
async
|
|
12828
|
-
const
|
|
12829
|
-
this.db.set(headerHash,
|
|
12893
|
+
async insertInitialState(headerHash: HeaderHash, state: InMemoryState): Promise<Result$2<OK, StateUpdateError>> {
|
|
12894
|
+
const copy = InMemoryState.copyFrom(this.spec, state, state.intoServicesData());
|
|
12895
|
+
this.db.set(headerHash, copy);
|
|
12830
12896
|
return Result.ok(OK);
|
|
12831
12897
|
}
|
|
12832
12898
|
|
|
12833
12899
|
getState(headerHash: HeaderHash): InMemoryState | null {
|
|
12834
|
-
const
|
|
12835
|
-
if (
|
|
12900
|
+
const state = this.db.get(headerHash);
|
|
12901
|
+
if (state === undefined) {
|
|
12836
12902
|
return null;
|
|
12837
12903
|
}
|
|
12838
12904
|
|
|
12839
|
-
return
|
|
12905
|
+
return InMemoryState.copyFrom(this.spec, state, state.intoServicesData());
|
|
12906
|
+
}
|
|
12907
|
+
|
|
12908
|
+
async close() {}
|
|
12909
|
+
}
|
|
12910
|
+
|
|
12911
|
+
/** Root database. */
|
|
12912
|
+
interface RootDb<TBlocks = BlocksDb, TStates = StatesDb> {
|
|
12913
|
+
/** Blocks DB. */
|
|
12914
|
+
getBlocksDb(): TBlocks;
|
|
12915
|
+
|
|
12916
|
+
/** States DB. */
|
|
12917
|
+
getStatesDb(): TStates;
|
|
12918
|
+
|
|
12919
|
+
/** Close access to the DB. */
|
|
12920
|
+
close(): Promise<void>;
|
|
12921
|
+
}
|
|
12922
|
+
|
|
12923
|
+
/** Abstract serialized-states db. */
|
|
12924
|
+
type SerializedStatesDb = StatesDb<SerializedState<LeafDb>> & InitStatesDb<StateEntries>;
|
|
12925
|
+
|
|
12926
|
+
/** In-memory serialized-states db. */
|
|
12927
|
+
declare class InMemorySerializedStates implements StatesDb<SerializedState<LeafDb>>, InitStatesDb<StateEntries> {
|
|
12928
|
+
private readonly db: HashDictionary<HeaderHash, SortedSet<LeafNode>> = HashDictionary.new();
|
|
12929
|
+
private readonly valuesDb: HashDictionary<ValueHash, BytesBlob> = HashDictionary.new();
|
|
12930
|
+
|
|
12931
|
+
constructor(
|
|
12932
|
+
private readonly spec: ChainSpec,
|
|
12933
|
+
private readonly blake2b: Blake2b,
|
|
12934
|
+
) {}
|
|
12935
|
+
|
|
12936
|
+
async insertInitialState(headerHash: HeaderHash, entries: StateEntries): Promise<Result$2<OK, StateUpdateError>> {
|
|
12937
|
+
// convert state entries into leafdb
|
|
12938
|
+
const { values, leafs } = updateLeafs(
|
|
12939
|
+
SortedSet.fromArray(leafComparator, []),
|
|
12940
|
+
this.blake2b,
|
|
12941
|
+
Array.from(entries, (x) => [StateEntryUpdateAction.Insert, x[0], x[1]]),
|
|
12942
|
+
);
|
|
12943
|
+
|
|
12944
|
+
// insert values to the db.
|
|
12945
|
+
for (const val of values) {
|
|
12946
|
+
this.valuesDb.set(val[0], val[1]);
|
|
12947
|
+
}
|
|
12948
|
+
|
|
12949
|
+
this.db.set(headerHash, leafs);
|
|
12950
|
+
return Result.ok(OK);
|
|
12951
|
+
}
|
|
12952
|
+
|
|
12953
|
+
async getStateRoot(state: SerializedState<LeafDb>): Promise<StateRootHash> {
|
|
12954
|
+
return state.backend.getStateRoot(this.blake2b);
|
|
12955
|
+
}
|
|
12956
|
+
|
|
12957
|
+
async updateAndSetState(
|
|
12958
|
+
header: HeaderHash,
|
|
12959
|
+
state: SerializedState<LeafDb>,
|
|
12960
|
+
update: Partial<State & ServicesUpdate>,
|
|
12961
|
+
): Promise<Result$2<OK, StateUpdateError>> {
|
|
12962
|
+
const blake2b = this.blake2b;
|
|
12963
|
+
const updatedValues = serializeStateUpdate(this.spec, blake2b, update);
|
|
12964
|
+
const { values, leafs } = updateLeafs(state.backend.leafs, blake2b, updatedValues);
|
|
12965
|
+
|
|
12966
|
+
// insert values to the db
|
|
12967
|
+
// valuesdb can be shared between all states because it's just
|
|
12968
|
+
// <valuehash> -> <value> mapping and existence is managed by trie leafs.
|
|
12969
|
+
for (const val of values) {
|
|
12970
|
+
this.valuesDb.set(val[0], val[1]);
|
|
12971
|
+
}
|
|
12972
|
+
|
|
12973
|
+
// make sure to clone the leafs before writing, since the collection is re-used.
|
|
12974
|
+
this.db.set(header, SortedSet.fromSortedArray(leafComparator, leafs.slice()));
|
|
12975
|
+
|
|
12976
|
+
return Result.ok(OK);
|
|
12977
|
+
}
|
|
12978
|
+
|
|
12979
|
+
getState(header: HeaderHash): SerializedState<LeafDb> | null {
|
|
12980
|
+
const leafs = this.db.get(header);
|
|
12981
|
+
if (leafs === undefined) {
|
|
12982
|
+
return null;
|
|
12983
|
+
}
|
|
12984
|
+
// now create a leafdb with shared values db.
|
|
12985
|
+
const leafDb = LeafDb.fromLeaves(leafs, {
|
|
12986
|
+
get: (key: ValueHash) => {
|
|
12987
|
+
const val = this.valuesDb.get(key);
|
|
12988
|
+
if (val === undefined) {
|
|
12989
|
+
throw new Error(`Missing value at key: ${key}`);
|
|
12990
|
+
}
|
|
12991
|
+
return val.raw;
|
|
12992
|
+
},
|
|
12993
|
+
});
|
|
12994
|
+
return SerializedState.new(this.spec, this.blake2b, leafDb);
|
|
12840
12995
|
}
|
|
12996
|
+
|
|
12997
|
+
async close() {}
|
|
12841
12998
|
}
|
|
12842
12999
|
|
|
12843
13000
|
type index$c_BlocksDb = BlocksDb;
|
|
12844
13001
|
type index$c_InMemoryBlocks = InMemoryBlocks;
|
|
12845
13002
|
declare const index$c_InMemoryBlocks: typeof InMemoryBlocks;
|
|
13003
|
+
type index$c_InMemorySerializedStates = InMemorySerializedStates;
|
|
13004
|
+
declare const index$c_InMemorySerializedStates: typeof InMemorySerializedStates;
|
|
12846
13005
|
type index$c_InMemoryStates = InMemoryStates;
|
|
12847
13006
|
declare const index$c_InMemoryStates: typeof InMemoryStates;
|
|
13007
|
+
type index$c_InitStatesDb<T = State> = InitStatesDb<T>;
|
|
12848
13008
|
type index$c_LeafDb = LeafDb;
|
|
12849
13009
|
declare const index$c_LeafDb: typeof LeafDb;
|
|
12850
13010
|
type index$c_LeafDbError = LeafDbError;
|
|
@@ -12852,13 +13012,16 @@ declare const index$c_LeafDbError: typeof LeafDbError;
|
|
|
12852
13012
|
type index$c_Lookup = Lookup;
|
|
12853
13013
|
type index$c_LookupKind = LookupKind;
|
|
12854
13014
|
declare const index$c_LookupKind: typeof LookupKind;
|
|
13015
|
+
type index$c_RootDb<TBlocks = BlocksDb, TStates = StatesDb> = RootDb<TBlocks, TStates>;
|
|
13016
|
+
type index$c_SerializedStatesDb = SerializedStatesDb;
|
|
12855
13017
|
type index$c_StateUpdateError = StateUpdateError;
|
|
12856
13018
|
declare const index$c_StateUpdateError: typeof StateUpdateError;
|
|
12857
13019
|
type index$c_StatesDb<T extends State = State> = StatesDb<T>;
|
|
12858
13020
|
type index$c_ValuesDb = ValuesDb;
|
|
13021
|
+
declare const index$c_updateLeafs: typeof updateLeafs;
|
|
12859
13022
|
declare namespace index$c {
|
|
12860
|
-
export { index$c_InMemoryBlocks as InMemoryBlocks, index$c_InMemoryStates as InMemoryStates, index$c_LeafDb as LeafDb, index$c_LeafDbError as LeafDbError, index$c_LookupKind as LookupKind, index$c_StateUpdateError as StateUpdateError };
|
|
12861
|
-
export type { index$c_BlocksDb as BlocksDb, index$c_Lookup as Lookup, index$c_StatesDb as StatesDb, index$c_ValuesDb as ValuesDb };
|
|
13023
|
+
export { index$c_InMemoryBlocks as InMemoryBlocks, index$c_InMemorySerializedStates as InMemorySerializedStates, index$c_InMemoryStates as InMemoryStates, index$c_LeafDb as LeafDb, index$c_LeafDbError as LeafDbError, index$c_LookupKind as LookupKind, index$c_StateUpdateError as StateUpdateError, index$c_updateLeafs as updateLeafs };
|
|
13024
|
+
export type { index$c_BlocksDb as BlocksDb, index$c_InitStatesDb as InitStatesDb, index$c_Lookup as Lookup, index$c_RootDb as RootDb, index$c_SerializedStatesDb as SerializedStatesDb, index$c_StatesDb as StatesDb, index$c_ValuesDb as ValuesDb };
|
|
12862
13025
|
}
|
|
12863
13026
|
|
|
12864
13027
|
/**
|
|
@@ -14196,6 +14359,82 @@ interface GasCounter {
|
|
|
14196
14359
|
sub(g: Gas): boolean;
|
|
14197
14360
|
}
|
|
14198
14361
|
|
|
14362
|
+
declare const NO_OF_REGISTERS$1 = 13;
|
|
14363
|
+
|
|
14364
|
+
type RegisterIndex = Opaque<number, "register index">;
|
|
14365
|
+
|
|
14366
|
+
declare class Registers {
|
|
14367
|
+
private asSigned: BigInt64Array;
|
|
14368
|
+
private asUnsigned: BigUint64Array;
|
|
14369
|
+
|
|
14370
|
+
constructor(private readonly bytes = safeAllocUint8Array(NO_OF_REGISTERS << REGISTER_SIZE_SHIFT)) {
|
|
14371
|
+
check`${bytes.length === NO_OF_REGISTERS << REGISTER_SIZE_SHIFT} Invalid size of registers array.`;
|
|
14372
|
+
this.asSigned = new BigInt64Array(bytes.buffer, bytes.byteOffset);
|
|
14373
|
+
this.asUnsigned = new BigUint64Array(bytes.buffer, bytes.byteOffset);
|
|
14374
|
+
}
|
|
14375
|
+
|
|
14376
|
+
static fromBytes(bytes: Uint8Array) {
|
|
14377
|
+
check`${bytes.length === NO_OF_REGISTERS << REGISTER_SIZE_SHIFT} Invalid size of registers array.`;
|
|
14378
|
+
return new Registers(bytes);
|
|
14379
|
+
}
|
|
14380
|
+
|
|
14381
|
+
getBytesAsLittleEndian(index: number, len: number) {
|
|
14382
|
+
const offset = index << REGISTER_SIZE_SHIFT;
|
|
14383
|
+
return this.bytes.subarray(offset, offset + len);
|
|
14384
|
+
}
|
|
14385
|
+
|
|
14386
|
+
getAllBytesAsLittleEndian() {
|
|
14387
|
+
return this.bytes;
|
|
14388
|
+
}
|
|
14389
|
+
|
|
14390
|
+
copyFrom(regs: Registers | BigUint64Array) {
|
|
14391
|
+
const array = regs instanceof BigUint64Array ? regs : regs.asUnsigned;
|
|
14392
|
+
this.asUnsigned.set(array);
|
|
14393
|
+
}
|
|
14394
|
+
|
|
14395
|
+
reset() {
|
|
14396
|
+
for (let i = 0; i < NO_OF_REGISTERS; i++) {
|
|
14397
|
+
this.asUnsigned[i] = 0n;
|
|
14398
|
+
}
|
|
14399
|
+
}
|
|
14400
|
+
|
|
14401
|
+
getLowerU32(registerIndex: number) {
|
|
14402
|
+
return Number(this.asUnsigned[registerIndex] & 0xff_ff_ff_ffn);
|
|
14403
|
+
}
|
|
14404
|
+
|
|
14405
|
+
getLowerI32(registerIndex: number) {
|
|
14406
|
+
return Number(this.getLowerU32(registerIndex)) >> 0;
|
|
14407
|
+
}
|
|
14408
|
+
|
|
14409
|
+
setU32(registerIndex: number, value: number) {
|
|
14410
|
+
this.asUnsigned[registerIndex] = signExtend32To64(value);
|
|
14411
|
+
}
|
|
14412
|
+
|
|
14413
|
+
setI32(registerIndex: number, value: number) {
|
|
14414
|
+
this.asSigned[registerIndex] = signExtend32To64(value);
|
|
14415
|
+
}
|
|
14416
|
+
|
|
14417
|
+
getU64(registerIndex: number) {
|
|
14418
|
+
return this.asUnsigned[registerIndex];
|
|
14419
|
+
}
|
|
14420
|
+
|
|
14421
|
+
getI64(registerIndex: number) {
|
|
14422
|
+
return this.asSigned[registerIndex];
|
|
14423
|
+
}
|
|
14424
|
+
|
|
14425
|
+
setU64(registerIndex: number, value: bigint) {
|
|
14426
|
+
this.asUnsigned[registerIndex] = value;
|
|
14427
|
+
}
|
|
14428
|
+
|
|
14429
|
+
setI64(registerIndex: number, value: bigint) {
|
|
14430
|
+
this.asSigned[registerIndex] = value;
|
|
14431
|
+
}
|
|
14432
|
+
|
|
14433
|
+
getAllU64() {
|
|
14434
|
+
return this.asUnsigned;
|
|
14435
|
+
}
|
|
14436
|
+
}
|
|
14437
|
+
|
|
14199
14438
|
/**
|
|
14200
14439
|
* Mask class is an implementation of skip function defined in GP.
|
|
14201
14440
|
*
|
|
@@ -14365,99 +14604,23 @@ declare class ImmediateDecoder {
|
|
|
14365
14604
|
}
|
|
14366
14605
|
}
|
|
14367
14606
|
|
|
14368
|
-
declare
|
|
14369
|
-
|
|
14370
|
-
type RegisterIndex = Opaque<number, "register index">;
|
|
14371
|
-
|
|
14372
|
-
declare class Registers {
|
|
14373
|
-
private asSigned: BigInt64Array;
|
|
14374
|
-
private asUnsigned: BigUint64Array;
|
|
14607
|
+
declare class NibblesDecoder {
|
|
14608
|
+
private byte = new Int8Array(1);
|
|
14375
14609
|
|
|
14376
|
-
|
|
14377
|
-
|
|
14378
|
-
this.asSigned = new BigInt64Array(bytes.buffer, bytes.byteOffset);
|
|
14379
|
-
this.asUnsigned = new BigUint64Array(bytes.buffer, bytes.byteOffset);
|
|
14610
|
+
setByte(byte: number) {
|
|
14611
|
+
this.byte[0] = byte;
|
|
14380
14612
|
}
|
|
14381
14613
|
|
|
14382
|
-
|
|
14383
|
-
|
|
14384
|
-
return new Registers(bytes);
|
|
14614
|
+
getHighNibble() {
|
|
14615
|
+
return (this.byte[0] & 0xf0) >>> 4;
|
|
14385
14616
|
}
|
|
14386
14617
|
|
|
14387
|
-
|
|
14388
|
-
|
|
14389
|
-
return this.bytes.subarray(offset, offset + len);
|
|
14618
|
+
getLowNibble() {
|
|
14619
|
+
return this.byte[0] & 0x0f;
|
|
14390
14620
|
}
|
|
14391
14621
|
|
|
14392
|
-
|
|
14393
|
-
return this.
|
|
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
|
-
declare class NibblesDecoder {
|
|
14445
|
-
private byte = new Int8Array(1);
|
|
14446
|
-
|
|
14447
|
-
setByte(byte: number) {
|
|
14448
|
-
this.byte[0] = byte;
|
|
14449
|
-
}
|
|
14450
|
-
|
|
14451
|
-
getHighNibble() {
|
|
14452
|
-
return (this.byte[0] & 0xf0) >>> 4;
|
|
14453
|
-
}
|
|
14454
|
-
|
|
14455
|
-
getLowNibble() {
|
|
14456
|
-
return this.byte[0] & 0x0f;
|
|
14457
|
-
}
|
|
14458
|
-
|
|
14459
|
-
getHighNibbleAsRegisterIndex() {
|
|
14460
|
-
return Math.min(this.getHighNibble(), MAX_REGISTER_INDEX);
|
|
14622
|
+
getHighNibbleAsRegisterIndex() {
|
|
14623
|
+
return Math.min(this.getHighNibble(), MAX_REGISTER_INDEX);
|
|
14461
14624
|
}
|
|
14462
14625
|
|
|
14463
14626
|
getLowNibbleAsRegisterIndex() {
|
|
@@ -15483,7 +15646,7 @@ declare class Memory {
|
|
|
15483
15646
|
const pagesResult = this.getPages(address, bytes.length, AccessType.WRITE);
|
|
15484
15647
|
|
|
15485
15648
|
if (pagesResult.isError) {
|
|
15486
|
-
return Result.error(pagesResult.error);
|
|
15649
|
+
return Result.error(pagesResult.error, pagesResult.details);
|
|
15487
15650
|
}
|
|
15488
15651
|
|
|
15489
15652
|
const pages = pagesResult.ok;
|
|
@@ -15516,17 +15679,23 @@ declare class Memory {
|
|
|
15516
15679
|
|
|
15517
15680
|
for (const pageNumber of pageRange) {
|
|
15518
15681
|
if (pageNumber < RESERVED_NUMBER_OF_PAGES) {
|
|
15519
|
-
return Result.error(
|
|
15682
|
+
return Result.error(
|
|
15683
|
+
PageFault.fromPageNumber(pageNumber, true),
|
|
15684
|
+
() => `Page fault: attempted to access reserved page ${pageNumber}`,
|
|
15685
|
+
);
|
|
15520
15686
|
}
|
|
15521
15687
|
|
|
15522
15688
|
const page = this.memory.get(pageNumber);
|
|
15523
15689
|
|
|
15524
15690
|
if (page === undefined) {
|
|
15525
|
-
return Result.error(PageFault.fromPageNumber(pageNumber));
|
|
15691
|
+
return Result.error(PageFault.fromPageNumber(pageNumber), () => `Page fault: page ${pageNumber} not allocated`);
|
|
15526
15692
|
}
|
|
15527
15693
|
|
|
15528
15694
|
if (accessType === AccessType.WRITE && !page.isWriteable()) {
|
|
15529
|
-
return Result.error(
|
|
15695
|
+
return Result.error(
|
|
15696
|
+
PageFault.fromPageNumber(pageNumber, true),
|
|
15697
|
+
() => `Page fault: attempted to write to read-only page ${pageNumber}`,
|
|
15698
|
+
);
|
|
15530
15699
|
}
|
|
15531
15700
|
|
|
15532
15701
|
pages.push(page);
|
|
@@ -15548,7 +15717,7 @@ declare class Memory {
|
|
|
15548
15717
|
const pagesResult = this.getPages(startAddress, result.length, AccessType.READ);
|
|
15549
15718
|
|
|
15550
15719
|
if (pagesResult.isError) {
|
|
15551
|
-
return Result.error(pagesResult.error);
|
|
15720
|
+
return Result.error(pagesResult.error, pagesResult.details);
|
|
15552
15721
|
}
|
|
15553
15722
|
|
|
15554
15723
|
const pages = pagesResult.ok;
|
|
@@ -17533,7 +17702,7 @@ declare class ProgramDecoder {
|
|
|
17533
17702
|
return Result.ok(new ProgramDecoder(program));
|
|
17534
17703
|
} catch (e) {
|
|
17535
17704
|
logger.error`Invalid program: ${e}`;
|
|
17536
|
-
return Result.error(ProgramDecoderError.InvalidProgramError);
|
|
17705
|
+
return Result.error(ProgramDecoderError.InvalidProgramError, () => `Program decoder error: ${e}`);
|
|
17537
17706
|
}
|
|
17538
17707
|
}
|
|
17539
17708
|
}
|
|
@@ -17877,870 +18046,896 @@ declare namespace index$8 {
|
|
|
17877
18046
|
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
18047
|
}
|
|
17879
18048
|
|
|
17880
|
-
|
|
17881
|
-
|
|
17882
|
-
|
|
17883
|
-
* https://graypaper.fluffylabs.dev/#/1c979cb/2e3f012e3f01?v=0.7.1
|
|
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));
|
|
17888
|
-
|
|
17889
|
-
/** Running PVM instance identifier. */
|
|
17890
|
-
type MachineId = Opaque<U64, "MachineId[u64]">;
|
|
17891
|
-
/** Convert a number into PVM instance identifier. */
|
|
17892
|
-
declare const tryAsMachineId = (v: number | bigint): MachineId => asOpaqueType(tryAsU64(v));
|
|
17893
|
-
|
|
17894
|
-
declare class MachineInstance {
|
|
17895
|
-
async run(gas: BigGas, registers: Registers): Promise<MachineResult> {
|
|
17896
|
-
return {
|
|
17897
|
-
result: {
|
|
17898
|
-
status: Status.OK,
|
|
17899
|
-
},
|
|
17900
|
-
gas,
|
|
17901
|
-
registers,
|
|
17902
|
-
};
|
|
17903
|
-
}
|
|
18049
|
+
interface IHostCallMemory {
|
|
18050
|
+
storeFrom(address: U64, bytes: Uint8Array): Result$2<OK, PageFault | OutOfBounds>;
|
|
18051
|
+
loadInto(result: Uint8Array, startAddress: U64): Result$2<OK, PageFault | OutOfBounds>;
|
|
17904
18052
|
}
|
|
17905
18053
|
|
|
17906
|
-
|
|
17907
|
-
|
|
17908
|
-
|
|
17909
|
-
|
|
18054
|
+
declare class HostCallMemory implements IHostCallMemory {
|
|
18055
|
+
constructor(private readonly memory: Memory) {}
|
|
18056
|
+
|
|
18057
|
+
storeFrom(address: U64, bytes: Uint8Array): Result$2<OK, PageFault | OutOfBounds> {
|
|
18058
|
+
if (bytes.length === 0) {
|
|
18059
|
+
return Result.ok(OK);
|
|
17910
18060
|
}
|
|
17911
|
-
|
|
17912
|
-
|
|
17913
|
-
|
|
18061
|
+
|
|
18062
|
+
if (address + tryAsU64(bytes.length) > MEMORY_SIZE) {
|
|
18063
|
+
return Result.error(
|
|
18064
|
+
new OutOfBounds(),
|
|
18065
|
+
() => `Memory access out of bounds: address ${address} + length ${bytes.length} exceeds memory size`,
|
|
18066
|
+
);
|
|
17914
18067
|
}
|
|
17915
|
-
| {
|
|
17916
|
-
status: typeof Status.OK | typeof Status.HALT | typeof Status.PANIC | typeof Status.OOG;
|
|
17917
|
-
};
|
|
17918
18068
|
|
|
17919
|
-
|
|
17920
|
-
|
|
17921
|
-
result: MachineStatus;
|
|
17922
|
-
gas: BigGas;
|
|
17923
|
-
registers: Registers;
|
|
17924
|
-
};
|
|
18069
|
+
return this.memory.storeFrom(tryAsMemoryIndex(Number(address)), bytes);
|
|
18070
|
+
}
|
|
17925
18071
|
|
|
17926
|
-
|
|
17927
|
-
|
|
17928
|
-
|
|
17929
|
-
|
|
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,
|
|
17938
|
-
}
|
|
18072
|
+
loadInto(result: Uint8Array, startAddress: U64): Result$2<OK, PageFault | OutOfBounds> {
|
|
18073
|
+
if (result.length === 0) {
|
|
18074
|
+
return Result.ok(OK);
|
|
18075
|
+
}
|
|
17939
18076
|
|
|
17940
|
-
|
|
17941
|
-
|
|
17942
|
-
|
|
18077
|
+
if (startAddress + tryAsU64(result.length) > MEMORY_SIZE) {
|
|
18078
|
+
return Result.error(
|
|
18079
|
+
new OutOfBounds(),
|
|
18080
|
+
() => `Memory access out of bounds: address ${startAddress} + length ${result.length} exceeds memory size`,
|
|
18081
|
+
);
|
|
18082
|
+
}
|
|
17943
18083
|
|
|
17944
|
-
|
|
17945
|
-
|
|
17946
|
-
/** Source page fault. */
|
|
17947
|
-
SourcePageFault = 0,
|
|
17948
|
-
/** Destination page fault. */
|
|
17949
|
-
DestinationPageFault = 1,
|
|
17950
|
-
/** No machine under given machine index. */
|
|
17951
|
-
NoMachine = 2,
|
|
18084
|
+
return this.memory.loadInto(result, tryAsMemoryIndex(Number(startAddress)));
|
|
18085
|
+
}
|
|
17952
18086
|
}
|
|
17953
18087
|
|
|
17954
|
-
|
|
17955
|
-
|
|
17956
|
-
|
|
17957
|
-
/** Attempting to void or zero non-accessible page. */
|
|
17958
|
-
InvalidPage = 1,
|
|
18088
|
+
interface IHostCallRegisters {
|
|
18089
|
+
get(registerIndex: number): U64;
|
|
18090
|
+
set(registerIndex: number, value: U64): void;
|
|
17959
18091
|
}
|
|
17960
18092
|
|
|
17961
|
-
declare
|
|
17962
|
-
|
|
17963
|
-
NoMachine = 0,
|
|
17964
|
-
/** Invalid memory operation. */
|
|
17965
|
-
InvalidOperation = 1,
|
|
17966
|
-
/** Attempting to change non-accessible page or trying to preserve value of voided page. */
|
|
17967
|
-
InvalidPage = 2,
|
|
17968
|
-
}
|
|
18093
|
+
declare class HostCallRegisters implements IHostCallRegisters {
|
|
18094
|
+
constructor(private readonly registers: Registers) {}
|
|
17969
18095
|
|
|
17970
|
-
|
|
17971
|
-
|
|
17972
|
-
|
|
18096
|
+
get(registerIndex: number): U64 {
|
|
18097
|
+
return tryAsU64(this.registers.getU64(registerIndex));
|
|
18098
|
+
}
|
|
17973
18099
|
|
|
17974
|
-
|
|
17975
|
-
|
|
17976
|
-
|
|
18100
|
+
set(registerIndex: number, value: U64) {
|
|
18101
|
+
this.registers.setU64(registerIndex, value);
|
|
18102
|
+
}
|
|
18103
|
+
}
|
|
17977
18104
|
|
|
17978
|
-
/**
|
|
17979
|
-
|
|
17980
|
-
|
|
17981
|
-
|
|
18105
|
+
/** Strictly-typed host call index. */
|
|
18106
|
+
type HostCallIndex = Opaque<U32, "HostCallIndex[U32]">;
|
|
18107
|
+
/** Attempt to convert a number into `HostCallIndex`. */
|
|
18108
|
+
declare const tryAsHostCallIndex = (v: number): HostCallIndex => asOpaqueType(tryAsU32(v));
|
|
17982
18109
|
|
|
17983
|
-
|
|
17984
|
-
|
|
18110
|
+
/**
|
|
18111
|
+
* Host-call exit reason.
|
|
18112
|
+
*
|
|
18113
|
+
* https://graypaper.fluffylabs.dev/#/ab2cdbd/24a30124a501?v=0.7.2
|
|
18114
|
+
*/
|
|
18115
|
+
declare enum PvmExecution {
|
|
18116
|
+
Halt = 0,
|
|
18117
|
+
Panic = 1,
|
|
18118
|
+
OOG = 2, // out-of-gas
|
|
18119
|
+
}
|
|
17985
18120
|
|
|
17986
|
-
|
|
17987
|
-
|
|
18121
|
+
/** A utility function to easily trace a bunch of registers. */
|
|
18122
|
+
declare function traceRegisters(...regs: number[]) {
|
|
18123
|
+
return regs.map(tryAsRegisterIndex);
|
|
18124
|
+
}
|
|
17988
18125
|
|
|
17989
|
-
|
|
17990
|
-
|
|
17991
|
-
|
|
17992
|
-
|
|
17993
|
-
sourceStart: U64,
|
|
17994
|
-
length: U64,
|
|
17995
|
-
destination: Memory,
|
|
17996
|
-
): Promise<Result$2<OK, PeekPokeError>>;
|
|
18126
|
+
/** An interface for a host call implementation */
|
|
18127
|
+
interface HostCallHandler {
|
|
18128
|
+
/** Index of that host call (i.e. what PVM invokes via `ecalli`) */
|
|
18129
|
+
readonly index: HostCallIndex;
|
|
17997
18130
|
|
|
17998
|
-
/**
|
|
17999
|
-
|
|
18000
|
-
|
|
18001
|
-
|
|
18002
|
-
|
|
18003
|
-
|
|
18004
|
-
source: Memory,
|
|
18005
|
-
): Promise<Result$2<OK, PeekPokeError>>;
|
|
18131
|
+
/**
|
|
18132
|
+
* The gas cost of invocation of that host call.
|
|
18133
|
+
*
|
|
18134
|
+
* NOTE: `((reg: IHostCallRegisters) => Gas)` function is for compatibility reasons: pre GP 0.7.2
|
|
18135
|
+
*/
|
|
18136
|
+
readonly basicGasCost: SmallGas | ((reg: IHostCallRegisters) => Gas);
|
|
18006
18137
|
|
|
18007
|
-
/**
|
|
18008
|
-
|
|
18138
|
+
/** Currently executing service id. */
|
|
18139
|
+
readonly currentServiceId: U32;
|
|
18009
18140
|
|
|
18010
|
-
/**
|
|
18011
|
-
|
|
18012
|
-
machineIndex: MachineId,
|
|
18013
|
-
gas: BigGas,
|
|
18014
|
-
registers: Registers,
|
|
18015
|
-
): Promise<Result$2<MachineResult, NoMachineError>>;
|
|
18141
|
+
/** Input&Output registers that we should add to tracing log. */
|
|
18142
|
+
readonly tracedRegisters: RegisterIndex[];
|
|
18016
18143
|
|
|
18017
18144
|
/**
|
|
18018
|
-
*
|
|
18145
|
+
* Actually execute the host call.
|
|
18019
18146
|
*
|
|
18020
|
-
*
|
|
18147
|
+
* NOTE the call is ALLOWED and expected to modify registers and memory.
|
|
18021
18148
|
*/
|
|
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>>;
|
|
18149
|
+
execute(gas: GasCounter, regs: IHostCallRegisters, memory: IHostCallMemory): Promise<undefined | PvmExecution>;
|
|
18034
18150
|
}
|
|
18035
18151
|
|
|
18036
|
-
|
|
18037
|
-
|
|
18038
|
-
|
|
18039
|
-
|
|
18040
|
-
type ServiceStateUpdate = Partial<Pick<State, "privilegedServices" | "authQueues" | "designatedValidatorData">> &
|
|
18041
|
-
ServicesUpdate;
|
|
18152
|
+
/** Container for all available host calls. */
|
|
18153
|
+
declare class HostCallsManager {
|
|
18154
|
+
private readonly hostCalls = new Map<HostCallIndex, HostCallHandler>();
|
|
18155
|
+
private readonly missing;
|
|
18042
18156
|
|
|
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;
|
|
18157
|
+
constructor({
|
|
18158
|
+
missing,
|
|
18159
|
+
handlers = [],
|
|
18160
|
+
}: {
|
|
18161
|
+
missing: HostCallHandler;
|
|
18162
|
+
handlers?: HostCallHandler[];
|
|
18163
|
+
}) {
|
|
18164
|
+
this.missing = missing;
|
|
18056
18165
|
|
|
18057
|
-
|
|
18058
|
-
|
|
18059
|
-
|
|
18060
|
-
|
|
18061
|
-
|
|
18062
|
-
/** Yielded accumulation root. */
|
|
18063
|
-
public readonly yieldedRoots: Map<ServiceId, OpaqueHash> = new Map(),
|
|
18064
|
-
) {}
|
|
18166
|
+
for (const handler of handlers) {
|
|
18167
|
+
check`${this.hostCalls.get(handler.index) === undefined} Overwriting host call handler at index ${handler.index}`;
|
|
18168
|
+
this.hostCalls.set(handler.index, handler);
|
|
18169
|
+
}
|
|
18170
|
+
}
|
|
18065
18171
|
|
|
18066
|
-
/**
|
|
18067
|
-
|
|
18068
|
-
return
|
|
18069
|
-
{
|
|
18070
|
-
servicesUpdates: [],
|
|
18071
|
-
servicesRemoved: [],
|
|
18072
|
-
preimages: [],
|
|
18073
|
-
storage: [],
|
|
18074
|
-
},
|
|
18075
|
-
[],
|
|
18076
|
-
);
|
|
18172
|
+
/** Get a host call by index. */
|
|
18173
|
+
get(hostCallIndex: HostCallIndex): HostCallHandler {
|
|
18174
|
+
return this.hostCalls.get(hostCallIndex) ?? this.missing;
|
|
18077
18175
|
}
|
|
18078
18176
|
|
|
18079
|
-
|
|
18080
|
-
|
|
18081
|
-
|
|
18082
|
-
|
|
18083
|
-
|
|
18084
|
-
|
|
18085
|
-
|
|
18086
|
-
|
|
18177
|
+
traceHostCall(
|
|
18178
|
+
context: string,
|
|
18179
|
+
hostCallIndex: HostCallIndex,
|
|
18180
|
+
hostCallHandler: HostCallHandler,
|
|
18181
|
+
registers: IHostCallRegisters,
|
|
18182
|
+
gas: Gas,
|
|
18183
|
+
) {
|
|
18184
|
+
const { currentServiceId } = hostCallHandler;
|
|
18185
|
+
const requested = hostCallIndex !== hostCallHandler.index ? ` (${hostCallIndex})` : "";
|
|
18186
|
+
const name = `${hostCallHandler.constructor.name}:${hostCallHandler.index}`;
|
|
18187
|
+
const registerValues = hostCallHandler.tracedRegisters
|
|
18188
|
+
.map((idx) => [idx.toString().padStart(2, "0"), registers.get(idx)] as const)
|
|
18189
|
+
.filter((v) => v[1] !== 0n)
|
|
18190
|
+
.map(([idx, value]) => {
|
|
18191
|
+
return `r${idx}=${value} (0x${value.toString(16)})`;
|
|
18192
|
+
})
|
|
18193
|
+
.join(", ");
|
|
18194
|
+
logger.insane`[${currentServiceId}] ${context} ${name}${requested}. Gas: ${gas}. Regs: ${registerValues}.`;
|
|
18087
18195
|
}
|
|
18196
|
+
}
|
|
18088
18197
|
|
|
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));
|
|
18198
|
+
type ResolveFn = (pvm: Interpreter) => void;
|
|
18099
18199
|
|
|
18100
|
-
|
|
18101
|
-
|
|
18102
|
-
|
|
18103
|
-
}
|
|
18200
|
+
declare class InterpreterInstanceManager {
|
|
18201
|
+
private instances: Interpreter[] = [];
|
|
18202
|
+
private waitingQueue: ResolveFn[] = [];
|
|
18104
18203
|
|
|
18105
|
-
|
|
18106
|
-
|
|
18204
|
+
constructor(noOfPvmInstances: number) {
|
|
18205
|
+
for (let i = 0; i < noOfPvmInstances; i++) {
|
|
18206
|
+
this.instances.push(
|
|
18207
|
+
new Interpreter({
|
|
18208
|
+
useSbrkGas: false,
|
|
18209
|
+
}),
|
|
18210
|
+
);
|
|
18107
18211
|
}
|
|
18212
|
+
}
|
|
18108
18213
|
|
|
18109
|
-
|
|
18110
|
-
|
|
18111
|
-
|
|
18112
|
-
|
|
18113
|
-
});
|
|
18214
|
+
async getInstance(): Promise<Interpreter> {
|
|
18215
|
+
const instance = this.instances.pop();
|
|
18216
|
+
if (instance !== undefined) {
|
|
18217
|
+
return Promise.resolve(instance);
|
|
18114
18218
|
}
|
|
18115
|
-
return
|
|
18219
|
+
return new Promise((resolve) => {
|
|
18220
|
+
this.waitingQueue.push(resolve);
|
|
18221
|
+
});
|
|
18116
18222
|
}
|
|
18117
18223
|
|
|
18118
|
-
|
|
18119
|
-
|
|
18120
|
-
|
|
18121
|
-
|
|
18122
|
-
|
|
18224
|
+
releaseInstance(pvm: Interpreter) {
|
|
18225
|
+
const waiting = this.waitingQueue.shift();
|
|
18226
|
+
if (waiting !== undefined) {
|
|
18227
|
+
return waiting(pvm);
|
|
18228
|
+
}
|
|
18229
|
+
this.instances.push(pvm);
|
|
18123
18230
|
}
|
|
18124
18231
|
}
|
|
18125
18232
|
|
|
18126
|
-
|
|
18127
|
-
|
|
18128
|
-
|
|
18129
|
-
|
|
18130
|
-
|
|
18131
|
-
|
|
18132
|
-
constructor(
|
|
18133
|
-
/** Original (unmodified state). */
|
|
18134
|
-
public readonly state: T,
|
|
18135
|
-
stateUpdate?: AccumulationStateUpdate,
|
|
18233
|
+
declare class ReturnValue {
|
|
18234
|
+
private constructor(
|
|
18235
|
+
public consumedGas: Gas,
|
|
18236
|
+
public status: Status | null,
|
|
18237
|
+
public memorySlice: Uint8Array | null,
|
|
18136
18238
|
) {
|
|
18137
|
-
|
|
18138
|
-
|
|
18239
|
+
check`
|
|
18240
|
+
${(status === null && memorySlice !== null) || (status !== null && memorySlice === null)}
|
|
18241
|
+
'status' and 'memorySlice' must not both be null or both be non-null — exactly one must be provided
|
|
18242
|
+
`;
|
|
18139
18243
|
}
|
|
18140
18244
|
|
|
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
|
-
}
|
|
18245
|
+
static fromStatus(consumedGas: Gas, status: Status) {
|
|
18246
|
+
return new ReturnValue(consumedGas, status, null);
|
|
18247
|
+
}
|
|
18165
18248
|
|
|
18166
|
-
|
|
18249
|
+
static fromMemorySlice(consumedGas: Gas, memorySlice: Uint8Array) {
|
|
18250
|
+
return new ReturnValue(consumedGas, null, memorySlice);
|
|
18167
18251
|
}
|
|
18168
18252
|
|
|
18169
|
-
|
|
18170
|
-
|
|
18171
|
-
|
|
18172
|
-
return item.value;
|
|
18173
|
-
}
|
|
18253
|
+
hasMemorySlice(): this is this & { status: null; memorySlice: Uint8Array } {
|
|
18254
|
+
return this.memorySlice instanceof Uint8Array && this.status === null;
|
|
18255
|
+
}
|
|
18174
18256
|
|
|
18175
|
-
|
|
18176
|
-
return
|
|
18257
|
+
hasStatus(): this is this & { status: Status; memorySlice: null } {
|
|
18258
|
+
return !this.hasMemorySlice();
|
|
18177
18259
|
}
|
|
18260
|
+
}
|
|
18261
|
+
declare class HostCalls {
|
|
18262
|
+
constructor(
|
|
18263
|
+
private pvmInstanceManager: InterpreterInstanceManager,
|
|
18264
|
+
private hostCalls: HostCallsManager,
|
|
18265
|
+
) {}
|
|
18178
18266
|
|
|
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;
|
|
18267
|
+
private getReturnValue(status: Status, pvmInstance: Interpreter): ReturnValue {
|
|
18268
|
+
const gasConsumed = pvmInstance.getGasConsumed();
|
|
18269
|
+
if (status === Status.OOG) {
|
|
18270
|
+
return ReturnValue.fromStatus(gasConsumed, status);
|
|
18194
18271
|
}
|
|
18195
18272
|
|
|
18196
|
-
|
|
18197
|
-
|
|
18198
|
-
|
|
18199
|
-
|
|
18200
|
-
|
|
18273
|
+
if (status === Status.HALT) {
|
|
18274
|
+
const memory = pvmInstance.getMemory();
|
|
18275
|
+
const regs = pvmInstance.getRegisters();
|
|
18276
|
+
const maybeAddress = regs.getLowerU32(7);
|
|
18277
|
+
const maybeLength = regs.getLowerU32(8);
|
|
18201
18278
|
|
|
18202
|
-
|
|
18203
|
-
|
|
18279
|
+
const result = safeAllocUint8Array(maybeLength);
|
|
18280
|
+
const startAddress = tryAsMemoryIndex(maybeAddress);
|
|
18281
|
+
const loadResult = memory.loadInto(result, startAddress);
|
|
18204
18282
|
|
|
18205
|
-
|
|
18206
|
-
|
|
18207
|
-
|
|
18208
|
-
|
|
18209
|
-
|
|
18210
|
-
if (freshlyProvided !== undefined && freshlyProvided.action.kind === UpdatePreimageKind.Provide) {
|
|
18211
|
-
return freshlyProvided.action.preimage.blob;
|
|
18283
|
+
if (loadResult.isError) {
|
|
18284
|
+
return ReturnValue.fromMemorySlice(gasConsumed, new Uint8Array());
|
|
18285
|
+
}
|
|
18286
|
+
|
|
18287
|
+
return ReturnValue.fromMemorySlice(gasConsumed, result);
|
|
18212
18288
|
}
|
|
18213
18289
|
|
|
18214
|
-
|
|
18215
|
-
return service?.getPreimage(hash) ?? null;
|
|
18290
|
+
return ReturnValue.fromStatus(gasConsumed, Status.PANIC);
|
|
18216
18291
|
}
|
|
18217
18292
|
|
|
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;
|
|
18293
|
+
private async execute(pvmInstance: Interpreter) {
|
|
18294
|
+
pvmInstance.runProgram();
|
|
18295
|
+
for (;;) {
|
|
18296
|
+
let status = pvmInstance.getStatus();
|
|
18297
|
+
if (status !== Status.HOST) {
|
|
18298
|
+
return this.getReturnValue(status, pvmInstance);
|
|
18238
18299
|
}
|
|
18300
|
+
check`
|
|
18301
|
+
${pvmInstance.getExitParam() !== null}
|
|
18302
|
+
"We know that the exit param is not null, because the status is 'Status.HOST'
|
|
18303
|
+
`;
|
|
18304
|
+
const hostCallIndex = pvmInstance.getExitParam() ?? -1;
|
|
18305
|
+
const gas = pvmInstance.getGasCounter();
|
|
18306
|
+
const regs = new HostCallRegisters(pvmInstance.getRegisters());
|
|
18307
|
+
const memory = new HostCallMemory(pvmInstance.getMemory());
|
|
18308
|
+
const index = tryAsHostCallIndex(hostCallIndex);
|
|
18239
18309
|
|
|
18240
|
-
const
|
|
18241
|
-
|
|
18242
|
-
|
|
18310
|
+
const hostCall = this.hostCalls.get(index);
|
|
18311
|
+
const gasBefore = gas.get();
|
|
18312
|
+
// NOTE: `basicGasCost(regs)` function is for compatibility reasons: pre GP 0.7.2
|
|
18313
|
+
const basicGasCost =
|
|
18314
|
+
typeof hostCall.basicGasCost === "number" ? hostCall.basicGasCost : hostCall.basicGasCost(regs);
|
|
18315
|
+
const underflow = gas.sub(basicGasCost);
|
|
18243
18316
|
|
|
18244
|
-
|
|
18245
|
-
|
|
18246
|
-
|
|
18317
|
+
const pcLog = `[PC: ${pvmInstance.getPC()}]`;
|
|
18318
|
+
if (underflow) {
|
|
18319
|
+
this.hostCalls.traceHostCall(`${pcLog} OOG`, index, hostCall, regs, gas.get());
|
|
18320
|
+
return ReturnValue.fromStatus(pvmInstance.getGasConsumed(), Status.OOG);
|
|
18321
|
+
}
|
|
18322
|
+
this.hostCalls.traceHostCall(`${pcLog} Invoking`, index, hostCall, regs, gasBefore);
|
|
18323
|
+
const result = await hostCall.execute(gas, regs, memory);
|
|
18324
|
+
this.hostCalls.traceHostCall(
|
|
18325
|
+
result === undefined ? `${pcLog} Result` : `${pcLog} Status(${PvmExecution[result]})`,
|
|
18326
|
+
index,
|
|
18327
|
+
hostCall,
|
|
18328
|
+
regs,
|
|
18329
|
+
gas.get(),
|
|
18330
|
+
);
|
|
18247
18331
|
|
|
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]));
|
|
18332
|
+
if (result === PvmExecution.Halt) {
|
|
18333
|
+
status = Status.HALT;
|
|
18334
|
+
return this.getReturnValue(status, pvmInstance);
|
|
18253
18335
|
}
|
|
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
18336
|
|
|
18261
|
-
|
|
18337
|
+
if (result === PvmExecution.Panic) {
|
|
18338
|
+
status = Status.PANIC;
|
|
18339
|
+
return this.getReturnValue(status, pvmInstance);
|
|
18262
18340
|
}
|
|
18263
|
-
|
|
18264
|
-
|
|
18341
|
+
|
|
18342
|
+
if (result === PvmExecution.OOG) {
|
|
18343
|
+
status = Status.OOG;
|
|
18344
|
+
return this.getReturnValue(status, pvmInstance);
|
|
18265
18345
|
}
|
|
18346
|
+
|
|
18347
|
+
if (result === undefined) {
|
|
18348
|
+
pvmInstance.runProgram();
|
|
18349
|
+
status = pvmInstance.getStatus();
|
|
18350
|
+
continue;
|
|
18351
|
+
}
|
|
18352
|
+
|
|
18353
|
+
assertNever(result);
|
|
18266
18354
|
}
|
|
18355
|
+
}
|
|
18267
18356
|
|
|
18268
|
-
|
|
18357
|
+
async runProgram(
|
|
18358
|
+
rawProgram: Uint8Array,
|
|
18359
|
+
initialPc: number,
|
|
18360
|
+
initialGas: Gas,
|
|
18361
|
+
maybeRegisters?: Registers,
|
|
18362
|
+
maybeMemory?: Memory,
|
|
18363
|
+
): Promise<ReturnValue> {
|
|
18364
|
+
const pvmInstance = await this.pvmInstanceManager.getInstance();
|
|
18365
|
+
pvmInstance.reset(rawProgram, initialPc, initialGas, maybeRegisters, maybeMemory);
|
|
18366
|
+
try {
|
|
18367
|
+
return await this.execute(pvmInstance);
|
|
18368
|
+
} finally {
|
|
18369
|
+
this.pvmInstanceManager.releaseInstance(pvmInstance);
|
|
18370
|
+
}
|
|
18269
18371
|
}
|
|
18372
|
+
}
|
|
18270
18373
|
|
|
18271
|
-
|
|
18374
|
+
type index$7_HostCallHandler = HostCallHandler;
|
|
18375
|
+
type index$7_HostCallMemory = HostCallMemory;
|
|
18376
|
+
declare const index$7_HostCallMemory: typeof HostCallMemory;
|
|
18377
|
+
type index$7_HostCallRegisters = HostCallRegisters;
|
|
18378
|
+
declare const index$7_HostCallRegisters: typeof HostCallRegisters;
|
|
18379
|
+
type index$7_IHostCallMemory = IHostCallMemory;
|
|
18380
|
+
type index$7_IHostCallRegisters = IHostCallRegisters;
|
|
18381
|
+
type index$7_PvmExecution = PvmExecution;
|
|
18382
|
+
declare const index$7_PvmExecution: typeof PvmExecution;
|
|
18383
|
+
declare const index$7_traceRegisters: typeof traceRegisters;
|
|
18384
|
+
declare const index$7_tryAsHostCallIndex: typeof tryAsHostCallIndex;
|
|
18385
|
+
declare namespace index$7 {
|
|
18386
|
+
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 };
|
|
18387
|
+
export type { index$7_HostCallHandler as HostCallHandler, index$7_IHostCallMemory as IHostCallMemory, index$7_IHostCallRegisters as IHostCallRegisters };
|
|
18388
|
+
}
|
|
18272
18389
|
|
|
18273
|
-
|
|
18274
|
-
|
|
18275
|
-
|
|
18276
|
-
|
|
18277
|
-
|
|
18278
|
-
|
|
18279
|
-
|
|
18280
|
-
|
|
18390
|
+
/**
|
|
18391
|
+
* Program counter is a 64-bit unsigned integer that points to the next instruction
|
|
18392
|
+
*
|
|
18393
|
+
* https://graypaper.fluffylabs.dev/#/1c979cb/2e3f012e3f01?v=0.7.1
|
|
18394
|
+
*/
|
|
18395
|
+
type ProgramCounter = Opaque<U64, "ProgramCounter[u64]">;
|
|
18396
|
+
/** Convert a number into ProgramCounter. */
|
|
18397
|
+
declare const tryAsProgramCounter = (v: number | bigint): ProgramCounter => asOpaqueType(tryAsU64(v));
|
|
18281
18398
|
|
|
18282
|
-
|
|
18283
|
-
|
|
18284
|
-
|
|
18285
|
-
|
|
18286
|
-
this.stateUpdate.services.storage.splice(index, count, update);
|
|
18287
|
-
}
|
|
18399
|
+
/** Running PVM instance identifier. */
|
|
18400
|
+
type MachineId = Opaque<U64, "MachineId[u64]">;
|
|
18401
|
+
/** Convert a number into PVM instance identifier. */
|
|
18402
|
+
declare const tryAsMachineId = (v: number | bigint): MachineId => asOpaqueType(tryAsU64(v));
|
|
18288
18403
|
|
|
18289
|
-
|
|
18290
|
-
|
|
18291
|
-
|
|
18292
|
-
|
|
18293
|
-
|
|
18294
|
-
|
|
18295
|
-
|
|
18296
|
-
|
|
18404
|
+
declare class MachineInstance {
|
|
18405
|
+
async run(gas: BigGas, registers: Registers): Promise<MachineResult> {
|
|
18406
|
+
return {
|
|
18407
|
+
result: {
|
|
18408
|
+
status: Status.OK,
|
|
18409
|
+
},
|
|
18410
|
+
gas,
|
|
18411
|
+
registers,
|
|
18412
|
+
};
|
|
18297
18413
|
}
|
|
18414
|
+
}
|
|
18298
18415
|
|
|
18299
|
-
|
|
18300
|
-
|
|
18301
|
-
|
|
18302
|
-
|
|
18303
|
-
|
|
18304
|
-
|
|
18305
|
-
|
|
18306
|
-
|
|
18416
|
+
type MachineStatus =
|
|
18417
|
+
| {
|
|
18418
|
+
status: typeof Status.HOST;
|
|
18419
|
+
hostCallIndex: U64;
|
|
18420
|
+
}
|
|
18421
|
+
| {
|
|
18422
|
+
status: typeof Status.FAULT;
|
|
18423
|
+
address: U64;
|
|
18424
|
+
}
|
|
18425
|
+
| {
|
|
18426
|
+
status: typeof Status.OK | typeof Status.HALT | typeof Status.PANIC | typeof Status.OOG;
|
|
18427
|
+
};
|
|
18307
18428
|
|
|
18308
|
-
|
|
18309
|
-
|
|
18429
|
+
/** Data returned by a machine invocation. */
|
|
18430
|
+
type MachineResult = {
|
|
18431
|
+
result: MachineStatus;
|
|
18432
|
+
gas: BigGas;
|
|
18433
|
+
registers: Registers;
|
|
18434
|
+
};
|
|
18310
18435
|
|
|
18311
|
-
|
|
18312
|
-
|
|
18313
|
-
|
|
18314
|
-
|
|
18436
|
+
/** Types of possbile operations to request by Pages host call. */
|
|
18437
|
+
declare enum MemoryOperation {
|
|
18438
|
+
/** Zeroes memory and set access to unreadable. */
|
|
18439
|
+
Void = 0,
|
|
18440
|
+
/** Zeroes memory and set access to read-only. */
|
|
18441
|
+
ZeroRead = 1,
|
|
18442
|
+
/** Zeroes memory and set access to read-write. */
|
|
18443
|
+
ZeroWrite = 2,
|
|
18444
|
+
/** Preserve memory and set access to read-only. */
|
|
18445
|
+
Read = 3,
|
|
18446
|
+
/** Preserve memory and set access to read-write. */
|
|
18447
|
+
Write = 4,
|
|
18448
|
+
}
|
|
18315
18449
|
|
|
18316
|
-
|
|
18317
|
-
|
|
18318
|
-
|
|
18319
|
-
}
|
|
18450
|
+
/** Convert a number into MemoryOperation or null (if invalid). */
|
|
18451
|
+
declare const toMemoryOperation = (v: number | bigint): MemoryOperation | null =>
|
|
18452
|
+
v <= MemoryOperation.Write && v >= MemoryOperation.Void ? Number(v) : null;
|
|
18320
18453
|
|
|
18321
|
-
|
|
18322
|
-
|
|
18323
|
-
|
|
18324
|
-
|
|
18325
|
-
|
|
18326
|
-
|
|
18327
|
-
|
|
18328
|
-
|
|
18329
|
-
|
|
18330
|
-
return Result.ok(OK);
|
|
18331
|
-
}
|
|
18454
|
+
/** An error that may occur during `peek` or `poke` host call. */
|
|
18455
|
+
declare enum PeekPokeError {
|
|
18456
|
+
/** Source page fault. */
|
|
18457
|
+
SourcePageFault = 0,
|
|
18458
|
+
/** Destination page fault. */
|
|
18459
|
+
DestinationPageFault = 1,
|
|
18460
|
+
/** No machine under given machine index. */
|
|
18461
|
+
NoMachine = 2,
|
|
18462
|
+
}
|
|
18332
18463
|
|
|
18333
|
-
|
|
18334
|
-
|
|
18335
|
-
|
|
18336
|
-
|
|
18337
|
-
|
|
18338
|
-
|
|
18339
|
-
this.stateUpdate.services.servicesUpdates.splice(
|
|
18340
|
-
idx,
|
|
18341
|
-
toRemove,
|
|
18342
|
-
UpdateService.create({
|
|
18343
|
-
serviceId,
|
|
18344
|
-
serviceInfo: newInfo,
|
|
18345
|
-
lookupHistory: existingItem.action.lookupHistory,
|
|
18346
|
-
}),
|
|
18347
|
-
);
|
|
18464
|
+
declare enum ZeroVoidError {
|
|
18465
|
+
/** No machine under given machine index. */
|
|
18466
|
+
NoMachine = 0,
|
|
18467
|
+
/** Attempting to void or zero non-accessible page. */
|
|
18468
|
+
InvalidPage = 1,
|
|
18469
|
+
}
|
|
18348
18470
|
|
|
18349
|
-
|
|
18350
|
-
|
|
18471
|
+
declare enum PagesError {
|
|
18472
|
+
/** No machine under given machine index. */
|
|
18473
|
+
NoMachine = 0,
|
|
18474
|
+
/** Invalid memory operation. */
|
|
18475
|
+
InvalidOperation = 1,
|
|
18476
|
+
/** Attempting to change non-accessible page or trying to preserve value of voided page. */
|
|
18477
|
+
InvalidPage = 2,
|
|
18478
|
+
}
|
|
18351
18479
|
|
|
18352
|
-
|
|
18353
|
-
|
|
18354
|
-
|
|
18355
|
-
UpdateService.update({
|
|
18356
|
-
serviceId,
|
|
18357
|
-
serviceInfo: newInfo,
|
|
18358
|
-
}),
|
|
18359
|
-
);
|
|
18360
|
-
}
|
|
18480
|
+
/** Error machine is not found. */
|
|
18481
|
+
declare const NoMachineError = Symbol("Machine index not found.");
|
|
18482
|
+
type NoMachineError = typeof NoMachineError;
|
|
18361
18483
|
|
|
18362
|
-
|
|
18363
|
-
|
|
18364
|
-
|
|
18365
|
-
}
|
|
18484
|
+
/** Too many segments already exported. */
|
|
18485
|
+
declare const SegmentExportError = Symbol("Too many segments already exported.");
|
|
18486
|
+
type SegmentExportError = typeof SegmentExportError;
|
|
18366
18487
|
|
|
18367
|
-
|
|
18368
|
-
|
|
18488
|
+
/** Host functions external invocations available during refine phase. */
|
|
18489
|
+
interface RefineExternalities {
|
|
18490
|
+
/** Forget a previously started nested VM. */
|
|
18491
|
+
machineExpunge(machineIndex: MachineId): Promise<Result$2<ProgramCounter, NoMachineError>>;
|
|
18492
|
+
|
|
18493
|
+
/** Set given range of pages as non-accessible and re-initialize them with zeros. */
|
|
18494
|
+
machineVoidPages(machineIndex: MachineId, pageStart: U64, pageCount: U64): Promise<Result$2<OK, ZeroVoidError>>;
|
|
18495
|
+
|
|
18496
|
+
/** Set given range of pages as writeable and initialize them with zeros. */
|
|
18497
|
+
machineZeroPages(machineIndex: MachineId, pageStart: U64, pageCount: U64): Promise<Result$2<OK, ZeroVoidError>>;
|
|
18498
|
+
|
|
18499
|
+
/** Copy a fragment of memory from `machineIndex` into given destination memory. */
|
|
18500
|
+
machinePeekFrom(
|
|
18501
|
+
machineIndex: MachineId,
|
|
18502
|
+
destinationStart: U64,
|
|
18503
|
+
sourceStart: U64,
|
|
18504
|
+
length: U64,
|
|
18505
|
+
destination: IHostCallMemory,
|
|
18506
|
+
): Promise<Result$2<OK, PeekPokeError>>;
|
|
18507
|
+
|
|
18508
|
+
/** Write a fragment of memory into `machineIndex` from given source memory. */
|
|
18509
|
+
machinePokeInto(
|
|
18510
|
+
machineIndex: MachineId,
|
|
18511
|
+
sourceStart: U64,
|
|
18512
|
+
destinationStart: U64,
|
|
18513
|
+
length: U64,
|
|
18514
|
+
source: IHostCallMemory,
|
|
18515
|
+
): Promise<Result$2<OK, PeekPokeError>>;
|
|
18516
|
+
|
|
18517
|
+
/** Start an inner PVM instance with given entry point and starting code. */
|
|
18518
|
+
machineInit(code: BytesBlob, programCounter: ProgramCounter): Promise<Result$2<MachineId, ProgramDecoderError>>;
|
|
18519
|
+
|
|
18520
|
+
/** Run a previously initialized PVM instance with given gas and registers. */
|
|
18521
|
+
machineInvoke(
|
|
18522
|
+
machineIndex: MachineId,
|
|
18523
|
+
gas: BigGas,
|
|
18524
|
+
registers: Registers,
|
|
18525
|
+
): Promise<Result$2<MachineResult, NoMachineError>>;
|
|
18526
|
+
|
|
18527
|
+
/**
|
|
18528
|
+
* Export segment for future retrieval.
|
|
18529
|
+
*
|
|
18530
|
+
* Returns the index assigned to that segment or an error if there is too many already exported.
|
|
18531
|
+
*/
|
|
18532
|
+
exportSegment(segment: Segment): Result$2<SegmentIndex, SegmentExportError>;
|
|
18533
|
+
|
|
18534
|
+
/** Lookup a historical preimage. */
|
|
18535
|
+
historicalLookup(serviceId: ServiceId | null, hash: Blake2bHash): Promise<BytesBlob | null>;
|
|
18536
|
+
|
|
18537
|
+
/** Change access to and/or zero the value of memory. */
|
|
18538
|
+
machinePages(
|
|
18539
|
+
machineIndex: MachineId,
|
|
18540
|
+
pageStart: U64,
|
|
18541
|
+
pageCount: U64,
|
|
18542
|
+
requestType: MemoryOperation | null,
|
|
18543
|
+
): Promise<Result$2<OK, PagesError>>;
|
|
18369
18544
|
}
|
|
18370
18545
|
|
|
18371
|
-
declare
|
|
18372
|
-
|
|
18373
|
-
|
|
18546
|
+
declare const InsufficientFundsError = "insufficient funds";
|
|
18547
|
+
type InsufficientFundsError = typeof InsufficientFundsError;
|
|
18548
|
+
|
|
18549
|
+
/** Update of the state entries coming from accumulation of a single service. */
|
|
18550
|
+
type ServiceStateUpdate = Partial<Pick<State, "privilegedServices" | "authQueues" | "designatedValidatorData">> &
|
|
18551
|
+
ServicesUpdate;
|
|
18552
|
+
|
|
18553
|
+
/** Deep clone of a map with array. */
|
|
18554
|
+
declare function deepCloneMapWithArray<K, V>(map: Map<K, V[]>): Map<K, V[]> {
|
|
18555
|
+
const cloned: [K, V[]][] = [];
|
|
18556
|
+
|
|
18557
|
+
for (const [k, v] of map.entries()) {
|
|
18558
|
+
cloned.push([k, v.slice()]);
|
|
18559
|
+
}
|
|
18560
|
+
|
|
18561
|
+
return new Map(cloned);
|
|
18374
18562
|
}
|
|
18375
18563
|
|
|
18376
18564
|
/**
|
|
18377
|
-
*
|
|
18565
|
+
* State updates that currently accumulating service produced.
|
|
18378
18566
|
*
|
|
18379
|
-
* https://graypaper.fluffylabs.dev/#/
|
|
18567
|
+
* `x_u`: https://graypaper.fluffylabs.dev/#/9a08063/2f31012f3101?v=0.6.6
|
|
18380
18568
|
*/
|
|
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) {}
|
|
18569
|
+
declare class AccumulationStateUpdate {
|
|
18570
|
+
/** Updated authorization queues for cores. */
|
|
18571
|
+
public readonly authorizationQueues: Map<CoreIndex, FixedSizeArray<AuthorizerHash, AUTHORIZATION_QUEUE_SIZE>> =
|
|
18572
|
+
new Map();
|
|
18573
|
+
/** New validators data. */
|
|
18574
|
+
public validatorsData: PerValidator<ValidatorData> | null = null;
|
|
18575
|
+
/** Updated priviliged services. */
|
|
18576
|
+
public privilegedServices: PrivilegedServices | null = null;
|
|
18412
18577
|
|
|
18413
|
-
|
|
18414
|
-
|
|
18415
|
-
|
|
18416
|
-
|
|
18578
|
+
private constructor(
|
|
18579
|
+
/** Services state updates. */
|
|
18580
|
+
public readonly services: ServicesUpdate,
|
|
18581
|
+
/** Pending transfers. */
|
|
18582
|
+
public transfers: PendingTransfer[],
|
|
18583
|
+
/** Yielded accumulation root. */
|
|
18584
|
+
public readonly yieldedRoots: Map<ServiceId, OpaqueHash> = new Map(),
|
|
18585
|
+
) {}
|
|
18417
18586
|
|
|
18418
|
-
|
|
18419
|
-
|
|
18420
|
-
|
|
18587
|
+
/** Create new empty state update. */
|
|
18588
|
+
static empty(): AccumulationStateUpdate {
|
|
18589
|
+
return new AccumulationStateUpdate(
|
|
18590
|
+
{
|
|
18591
|
+
created: [],
|
|
18592
|
+
updated: new Map(),
|
|
18593
|
+
removed: [],
|
|
18594
|
+
preimages: new Map(),
|
|
18595
|
+
storage: new Map(),
|
|
18596
|
+
},
|
|
18597
|
+
[],
|
|
18598
|
+
);
|
|
18599
|
+
}
|
|
18421
18600
|
|
|
18422
|
-
|
|
18601
|
+
/** Create a state update with some existing, yet uncommited services updates. */
|
|
18602
|
+
static new(update: ServicesUpdate): AccumulationStateUpdate {
|
|
18603
|
+
return new AccumulationStateUpdate(
|
|
18604
|
+
{
|
|
18605
|
+
...update,
|
|
18606
|
+
},
|
|
18607
|
+
[],
|
|
18608
|
+
);
|
|
18423
18609
|
}
|
|
18424
18610
|
|
|
18425
|
-
|
|
18426
|
-
|
|
18427
|
-
|
|
18611
|
+
/** Create a copy of another `StateUpdate`. Used by checkpoints. */
|
|
18612
|
+
static copyFrom(from: AccumulationStateUpdate): AccumulationStateUpdate {
|
|
18613
|
+
const serviceUpdates: ServicesUpdate = {
|
|
18614
|
+
// shallow copy
|
|
18615
|
+
created: [...from.services.created],
|
|
18616
|
+
updated: new Map(from.services.updated),
|
|
18617
|
+
removed: [...from.services.removed],
|
|
18618
|
+
// deep copy
|
|
18619
|
+
preimages: deepCloneMapWithArray(from.services.preimages),
|
|
18620
|
+
storage: deepCloneMapWithArray(from.services.storage),
|
|
18621
|
+
};
|
|
18622
|
+
const transfers = [...from.transfers];
|
|
18623
|
+
const update = new AccumulationStateUpdate(serviceUpdates, transfers, new Map(from.yieldedRoots));
|
|
18624
|
+
|
|
18625
|
+
// update entries
|
|
18626
|
+
for (const [k, v] of from.authorizationQueues) {
|
|
18627
|
+
update.authorizationQueues.set(k, v);
|
|
18428
18628
|
}
|
|
18429
18629
|
|
|
18430
|
-
if (
|
|
18431
|
-
|
|
18630
|
+
if (from.validatorsData !== null) {
|
|
18631
|
+
update.validatorsData = asKnownSize([...from.validatorsData]);
|
|
18432
18632
|
}
|
|
18433
18633
|
|
|
18434
|
-
|
|
18634
|
+
if (from.privilegedServices !== null) {
|
|
18635
|
+
update.privilegedServices = PrivilegedServices.create({
|
|
18636
|
+
...from.privilegedServices,
|
|
18637
|
+
assigners: asKnownSize([...from.privilegedServices.assigners]),
|
|
18638
|
+
});
|
|
18639
|
+
}
|
|
18640
|
+
return update;
|
|
18435
18641
|
}
|
|
18436
18642
|
|
|
18437
|
-
|
|
18438
|
-
|
|
18643
|
+
/** Retrieve and clear pending transfers. */
|
|
18644
|
+
takeTransfers() {
|
|
18645
|
+
const transfers = this.transfers;
|
|
18646
|
+
this.transfers = [];
|
|
18647
|
+
return transfers;
|
|
18439
18648
|
}
|
|
18440
18649
|
}
|
|
18441
18650
|
|
|
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) {}
|
|
18651
|
+
type StateSlice = Pick<State, "getService" | "privilegedServices">;
|
|
18449
18652
|
|
|
18450
|
-
|
|
18451
|
-
|
|
18452
|
-
|
|
18653
|
+
declare class PartiallyUpdatedState<T extends StateSlice = StateSlice> {
|
|
18654
|
+
/** A collection of state updates. */
|
|
18655
|
+
public readonly stateUpdate;
|
|
18453
18656
|
|
|
18454
|
-
|
|
18455
|
-
|
|
18657
|
+
constructor(
|
|
18658
|
+
/** Original (unmodified state). */
|
|
18659
|
+
public readonly state: T,
|
|
18660
|
+
stateUpdate?: AccumulationStateUpdate,
|
|
18661
|
+
) {
|
|
18662
|
+
this.stateUpdate =
|
|
18663
|
+
stateUpdate === undefined ? AccumulationStateUpdate.empty() : AccumulationStateUpdate.copyFrom(stateUpdate);
|
|
18456
18664
|
}
|
|
18457
|
-
}
|
|
18458
18665
|
|
|
18459
|
-
/**
|
|
18460
|
-
|
|
18461
|
-
|
|
18462
|
-
|
|
18666
|
+
/**
|
|
18667
|
+
* Retrieve info of service with given id.
|
|
18668
|
+
*
|
|
18669
|
+
* NOTE the info may be updated compared to what is in the state.
|
|
18670
|
+
*
|
|
18671
|
+
* Takes into account ejected and newly created services as well.
|
|
18672
|
+
*/
|
|
18673
|
+
getServiceInfo(destination: ServiceId | null): ServiceAccountInfo | null {
|
|
18674
|
+
if (destination === null) {
|
|
18675
|
+
return null;
|
|
18676
|
+
}
|
|
18463
18677
|
|
|
18464
|
-
|
|
18465
|
-
* Host-call exit reason.
|
|
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
|
-
}
|
|
18678
|
+
const maybeUpdatedServiceInfo = this.stateUpdate.services.updated.get(destination);
|
|
18474
18679
|
|
|
18475
|
-
|
|
18476
|
-
|
|
18477
|
-
|
|
18478
|
-
}
|
|
18680
|
+
if (maybeUpdatedServiceInfo !== undefined) {
|
|
18681
|
+
return maybeUpdatedServiceInfo.action.account;
|
|
18682
|
+
}
|
|
18479
18683
|
|
|
18480
|
-
|
|
18481
|
-
|
|
18482
|
-
|
|
18483
|
-
|
|
18684
|
+
const maybeService = this.state.getService(destination);
|
|
18685
|
+
if (maybeService === null) {
|
|
18686
|
+
return null;
|
|
18687
|
+
}
|
|
18484
18688
|
|
|
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);
|
|
18689
|
+
return maybeService.getInfo();
|
|
18690
|
+
}
|
|
18491
18691
|
|
|
18492
|
-
|
|
18493
|
-
|
|
18692
|
+
getStorage(serviceId: ServiceId, rawKey: StorageKey): BytesBlob | null {
|
|
18693
|
+
const storages = this.stateUpdate.services.storage.get(serviceId) ?? [];
|
|
18694
|
+
const item = storages.find((x) => x.key.isEqualTo(rawKey));
|
|
18695
|
+
if (item !== undefined) {
|
|
18696
|
+
return item.value;
|
|
18697
|
+
}
|
|
18494
18698
|
|
|
18495
|
-
|
|
18496
|
-
|
|
18699
|
+
const service = this.state.getService(serviceId);
|
|
18700
|
+
return service?.getStorage(rawKey) ?? null;
|
|
18701
|
+
}
|
|
18497
18702
|
|
|
18498
18703
|
/**
|
|
18499
|
-
*
|
|
18704
|
+
* Returns `true` if the preimage is already provided either in current
|
|
18705
|
+
* accumulation scope or earlier.
|
|
18500
18706
|
*
|
|
18501
|
-
* NOTE
|
|
18707
|
+
* NOTE: Does not check if the preimage is available, we just check
|
|
18708
|
+
* the existence in `preimages` map.
|
|
18502
18709
|
*/
|
|
18503
|
-
|
|
18504
|
-
|
|
18710
|
+
hasPreimage(serviceId: ServiceId, hash: PreimageHash): boolean {
|
|
18711
|
+
const preimages = this.stateUpdate.services.preimages.get(serviceId) ?? [];
|
|
18712
|
+
const providedPreimage = preimages.find(
|
|
18713
|
+
// we ignore the action here, since if there is <any> update on that
|
|
18714
|
+
// hash it means it has to exist, right?
|
|
18715
|
+
(p) => p.hash.isEqualTo(hash),
|
|
18716
|
+
);
|
|
18717
|
+
if (providedPreimage !== undefined) {
|
|
18718
|
+
return true;
|
|
18719
|
+
}
|
|
18505
18720
|
|
|
18506
|
-
|
|
18507
|
-
|
|
18508
|
-
|
|
18509
|
-
|
|
18721
|
+
// fallback to state preimages
|
|
18722
|
+
const service = this.state.getService(serviceId);
|
|
18723
|
+
if (service === undefined) {
|
|
18724
|
+
return false;
|
|
18725
|
+
}
|
|
18510
18726
|
|
|
18511
|
-
|
|
18512
|
-
|
|
18513
|
-
handlers = [],
|
|
18514
|
-
}: {
|
|
18515
|
-
missing: HostCallHandler;
|
|
18516
|
-
handlers?: HostCallHandler[];
|
|
18517
|
-
}) {
|
|
18518
|
-
this.missing = missing;
|
|
18727
|
+
return service?.hasPreimage(hash) ?? false;
|
|
18728
|
+
}
|
|
18519
18729
|
|
|
18520
|
-
|
|
18521
|
-
|
|
18522
|
-
|
|
18730
|
+
getPreimage(serviceId: ServiceId, hash: PreimageHash): BytesBlob | null {
|
|
18731
|
+
// TODO [ToDr] Should we verify availability here?
|
|
18732
|
+
const preimages = this.stateUpdate.services.preimages.get(serviceId) ?? [];
|
|
18733
|
+
const freshlyProvided = preimages.find((x) => x.hash.isEqualTo(hash));
|
|
18734
|
+
if (freshlyProvided !== undefined && freshlyProvided.action.kind === UpdatePreimageKind.Provide) {
|
|
18735
|
+
return freshlyProvided.action.preimage.blob;
|
|
18523
18736
|
}
|
|
18524
|
-
}
|
|
18525
18737
|
|
|
18526
|
-
|
|
18527
|
-
|
|
18528
|
-
return this.hostCalls.get(hostCallIndex) ?? this.missing;
|
|
18738
|
+
const service = this.state.getService(serviceId);
|
|
18739
|
+
return service?.getPreimage(hash) ?? null;
|
|
18529
18740
|
}
|
|
18530
18741
|
|
|
18531
|
-
|
|
18532
|
-
|
|
18533
|
-
|
|
18534
|
-
|
|
18535
|
-
|
|
18536
|
-
|
|
18537
|
-
) {
|
|
18538
|
-
const
|
|
18539
|
-
|
|
18540
|
-
|
|
18541
|
-
|
|
18542
|
-
|
|
18543
|
-
|
|
18544
|
-
|
|
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
|
-
}
|
|
18742
|
+
/** Get status of a preimage of current service taking into account any updates. */
|
|
18743
|
+
getLookupHistory(
|
|
18744
|
+
currentTimeslot: TimeSlot,
|
|
18745
|
+
serviceId: ServiceId,
|
|
18746
|
+
hash: PreimageHash,
|
|
18747
|
+
length: U64,
|
|
18748
|
+
): LookupHistoryItem | null {
|
|
18749
|
+
const preimages = this.stateUpdate.services.preimages.get(serviceId) ?? [];
|
|
18750
|
+
// TODO [ToDr] This is most likely wrong. We may have `provide` and `remove` within
|
|
18751
|
+
// the same state update. We should however switch to proper "updated state"
|
|
18752
|
+
// representation soon.
|
|
18753
|
+
const updatedPreimage = preimages.findLast(
|
|
18754
|
+
(update) => update.hash.isEqualTo(hash) && BigInt(update.length) === length,
|
|
18755
|
+
);
|
|
18551
18756
|
|
|
18552
|
-
|
|
18757
|
+
const stateFallback = () => {
|
|
18758
|
+
// fallback to state lookup
|
|
18759
|
+
const service = this.state.getService(serviceId);
|
|
18760
|
+
const lenU32 = preimageLenAsU32(length);
|
|
18761
|
+
if (lenU32 === null || service === null) {
|
|
18762
|
+
return null;
|
|
18763
|
+
}
|
|
18553
18764
|
|
|
18554
|
-
|
|
18555
|
-
|
|
18556
|
-
|
|
18765
|
+
const slots = service.getLookupHistory(hash, lenU32);
|
|
18766
|
+
return slots === null ? null : new LookupHistoryItem(hash, lenU32, slots);
|
|
18767
|
+
};
|
|
18557
18768
|
|
|
18558
|
-
|
|
18559
|
-
|
|
18560
|
-
this.instances.push(
|
|
18561
|
-
new Interpreter({
|
|
18562
|
-
useSbrkGas: false,
|
|
18563
|
-
}),
|
|
18564
|
-
);
|
|
18769
|
+
if (updatedPreimage === undefined) {
|
|
18770
|
+
return stateFallback();
|
|
18565
18771
|
}
|
|
18566
|
-
}
|
|
18567
18772
|
|
|
18568
|
-
|
|
18569
|
-
|
|
18570
|
-
|
|
18571
|
-
|
|
18773
|
+
const { action } = updatedPreimage;
|
|
18774
|
+
switch (action.kind) {
|
|
18775
|
+
case UpdatePreimageKind.Provide: {
|
|
18776
|
+
// casting to U32 is safe, since we compare with object we have in memory.
|
|
18777
|
+
return new LookupHistoryItem(hash, updatedPreimage.length, tryAsLookupHistorySlots([currentTimeslot]));
|
|
18778
|
+
}
|
|
18779
|
+
case UpdatePreimageKind.Remove: {
|
|
18780
|
+
const state = stateFallback();
|
|
18781
|
+
// kinda impossible, since we know it's there because it's removed.
|
|
18782
|
+
if (state === null) {
|
|
18783
|
+
return null;
|
|
18784
|
+
}
|
|
18785
|
+
|
|
18786
|
+
return new LookupHistoryItem(hash, state.length, tryAsLookupHistorySlots([...state.slots, currentTimeslot]));
|
|
18787
|
+
}
|
|
18788
|
+
case UpdatePreimageKind.UpdateOrAdd: {
|
|
18789
|
+
return action.item;
|
|
18790
|
+
}
|
|
18572
18791
|
}
|
|
18573
|
-
return new Promise((resolve) => {
|
|
18574
|
-
this.waitingQueue.push(resolve);
|
|
18575
|
-
});
|
|
18576
|
-
}
|
|
18577
18792
|
|
|
18578
|
-
|
|
18579
|
-
const waiting = this.waitingQueue.shift();
|
|
18580
|
-
if (waiting !== undefined) {
|
|
18581
|
-
return waiting(pvm);
|
|
18582
|
-
}
|
|
18583
|
-
this.instances.push(pvm);
|
|
18793
|
+
assertNever(action);
|
|
18584
18794
|
}
|
|
18585
|
-
}
|
|
18586
18795
|
|
|
18587
|
-
|
|
18588
|
-
|
|
18589
|
-
|
|
18590
|
-
|
|
18591
|
-
|
|
18592
|
-
|
|
18593
|
-
|
|
18594
|
-
|
|
18595
|
-
'status' and 'memorySlice' must not both be null or both be non-null — exactly one must be provided
|
|
18596
|
-
`;
|
|
18597
|
-
}
|
|
18796
|
+
/* State update functions. */
|
|
18797
|
+
updateStorage(serviceId: ServiceId, key: StorageKey, value: BytesBlob | null) {
|
|
18798
|
+
const update =
|
|
18799
|
+
value === null
|
|
18800
|
+
? UpdateStorage.remove({ key })
|
|
18801
|
+
: UpdateStorage.set({
|
|
18802
|
+
storage: StorageItem.create({ key, value }),
|
|
18803
|
+
});
|
|
18598
18804
|
|
|
18599
|
-
|
|
18600
|
-
|
|
18805
|
+
const storages = this.stateUpdate.services.storage.get(serviceId) ?? [];
|
|
18806
|
+
const index = storages.findIndex((x) => x.key.isEqualTo(key));
|
|
18807
|
+
const count = index === -1 ? 0 : 1;
|
|
18808
|
+
storages.splice(index, count, update);
|
|
18809
|
+
this.stateUpdate.services.storage.set(serviceId, storages);
|
|
18601
18810
|
}
|
|
18602
18811
|
|
|
18603
|
-
|
|
18604
|
-
|
|
18812
|
+
/**
|
|
18813
|
+
* Update a preimage.
|
|
18814
|
+
*
|
|
18815
|
+
* Note we store all previous entries as well, since there might be a sequence of:
|
|
18816
|
+
* `provide` -> `remove` and both should update the end state somehow.
|
|
18817
|
+
*/
|
|
18818
|
+
updatePreimage(serviceId: ServiceId, newUpdate: UpdatePreimage) {
|
|
18819
|
+
const updatePreimages = this.stateUpdate.services.preimages.get(serviceId) ?? [];
|
|
18820
|
+
updatePreimages.push(newUpdate);
|
|
18821
|
+
this.stateUpdate.services.preimages.set(serviceId, updatePreimages);
|
|
18605
18822
|
}
|
|
18606
18823
|
|
|
18607
|
-
|
|
18608
|
-
|
|
18609
|
-
|
|
18824
|
+
updateServiceStorageUtilisation(
|
|
18825
|
+
serviceId: ServiceId,
|
|
18826
|
+
items: number,
|
|
18827
|
+
bytes: bigint,
|
|
18828
|
+
serviceInfo: ServiceAccountInfo,
|
|
18829
|
+
): Result$2<OK, InsufficientFundsError> {
|
|
18830
|
+
check`${items >= 0} storageUtilisationCount has to be a positive number, got: ${items}`;
|
|
18831
|
+
check`${bytes >= 0} storageUtilisationBytes has to be a positive number, got: ${bytes}`;
|
|
18610
18832
|
|
|
18611
|
-
|
|
18612
|
-
|
|
18613
|
-
}
|
|
18614
|
-
}
|
|
18615
|
-
declare class HostCalls {
|
|
18616
|
-
constructor(
|
|
18617
|
-
private pvmInstanceManager: InterpreterInstanceManager,
|
|
18618
|
-
private hostCalls: HostCallsManager,
|
|
18619
|
-
) {}
|
|
18833
|
+
const overflowItems = !isU32(items);
|
|
18834
|
+
const overflowBytes = !isU64(bytes);
|
|
18620
18835
|
|
|
18621
|
-
|
|
18622
|
-
|
|
18623
|
-
|
|
18624
|
-
|
|
18836
|
+
// TODO [ToDr] this is not specified in GP, but it seems sensible.
|
|
18837
|
+
if (overflowItems || overflowBytes) {
|
|
18838
|
+
return Result.error(
|
|
18839
|
+
InsufficientFundsError,
|
|
18840
|
+
() => `Storage utilisation overflow: items=${overflowItems}, bytes=${overflowBytes}`,
|
|
18841
|
+
);
|
|
18625
18842
|
}
|
|
18626
18843
|
|
|
18627
|
-
|
|
18628
|
-
|
|
18629
|
-
|
|
18630
|
-
|
|
18631
|
-
|
|
18632
|
-
|
|
18633
|
-
const result = safeAllocUint8Array(maybeLength);
|
|
18634
|
-
const startAddress = tryAsMemoryIndex(maybeAddress);
|
|
18635
|
-
const loadResult = memory.loadInto(result, startAddress);
|
|
18636
|
-
|
|
18637
|
-
if (loadResult.isError) {
|
|
18638
|
-
return ReturnValue.fromMemorySlice(gasConsumed, new Uint8Array());
|
|
18639
|
-
}
|
|
18640
|
-
|
|
18641
|
-
return ReturnValue.fromMemorySlice(gasConsumed, result);
|
|
18844
|
+
const thresholdBalance = ServiceAccountInfo.calculateThresholdBalance(items, bytes, serviceInfo.gratisStorage);
|
|
18845
|
+
if (serviceInfo.balance < thresholdBalance) {
|
|
18846
|
+
return Result.error(
|
|
18847
|
+
InsufficientFundsError,
|
|
18848
|
+
() => `Service balance (${serviceInfo.balance}) below threshold (${thresholdBalance})`,
|
|
18849
|
+
);
|
|
18642
18850
|
}
|
|
18643
18851
|
|
|
18644
|
-
|
|
18852
|
+
// Update service info with new details.
|
|
18853
|
+
this.updateServiceInfo(
|
|
18854
|
+
serviceId,
|
|
18855
|
+
ServiceAccountInfo.create({
|
|
18856
|
+
...serviceInfo,
|
|
18857
|
+
storageUtilisationBytes: bytes,
|
|
18858
|
+
storageUtilisationCount: items,
|
|
18859
|
+
}),
|
|
18860
|
+
);
|
|
18861
|
+
return Result.ok(OK);
|
|
18645
18862
|
}
|
|
18646
18863
|
|
|
18647
|
-
|
|
18648
|
-
|
|
18649
|
-
for (;;) {
|
|
18650
|
-
let status = pvmInstance.getStatus();
|
|
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);
|
|
18864
|
+
updateServiceInfo(serviceId: ServiceId, newInfo: ServiceAccountInfo) {
|
|
18865
|
+
const existingUpdate = this.stateUpdate.services.updated.get(serviceId);
|
|
18670
18866
|
|
|
18671
|
-
|
|
18672
|
-
|
|
18673
|
-
|
|
18674
|
-
|
|
18675
|
-
|
|
18676
|
-
|
|
18677
|
-
|
|
18678
|
-
this.hostCalls.traceHostCall(
|
|
18679
|
-
result === undefined ? `${pcLog} Result` : `${pcLog} Status(${PvmExecution[result]})`,
|
|
18680
|
-
index,
|
|
18681
|
-
hostCall,
|
|
18682
|
-
regs,
|
|
18683
|
-
gas.get(),
|
|
18867
|
+
if (existingUpdate?.action.kind === UpdateServiceKind.Create) {
|
|
18868
|
+
this.stateUpdate.services.updated.set(
|
|
18869
|
+
serviceId,
|
|
18870
|
+
UpdateService.create({
|
|
18871
|
+
serviceInfo: newInfo,
|
|
18872
|
+
lookupHistory: existingUpdate.action.lookupHistory,
|
|
18873
|
+
}),
|
|
18684
18874
|
);
|
|
18875
|
+
return;
|
|
18876
|
+
}
|
|
18685
18877
|
|
|
18686
|
-
|
|
18687
|
-
|
|
18688
|
-
|
|
18689
|
-
|
|
18690
|
-
|
|
18691
|
-
|
|
18692
|
-
|
|
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
|
-
}
|
|
18878
|
+
this.stateUpdate.services.updated.set(
|
|
18879
|
+
serviceId,
|
|
18880
|
+
UpdateService.update({
|
|
18881
|
+
serviceInfo: newInfo,
|
|
18882
|
+
}),
|
|
18883
|
+
);
|
|
18884
|
+
}
|
|
18706
18885
|
|
|
18707
|
-
|
|
18708
|
-
|
|
18886
|
+
createService(serviceId: ServiceId, newInfo: ServiceAccountInfo, newLookupHistory: LookupHistoryItem) {
|
|
18887
|
+
this.stateUpdate.services.created.push(serviceId);
|
|
18888
|
+
this.stateUpdate.services.updated.set(
|
|
18889
|
+
serviceId,
|
|
18890
|
+
UpdateService.create({
|
|
18891
|
+
serviceInfo: newInfo,
|
|
18892
|
+
lookupHistory: newLookupHistory,
|
|
18893
|
+
}),
|
|
18894
|
+
);
|
|
18709
18895
|
}
|
|
18710
18896
|
|
|
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);
|
|
18897
|
+
getPrivilegedServices() {
|
|
18898
|
+
if (this.stateUpdate.privilegedServices !== null) {
|
|
18899
|
+
return this.stateUpdate.privilegedServices;
|
|
18724
18900
|
}
|
|
18901
|
+
|
|
18902
|
+
return this.state.privilegedServices;
|
|
18725
18903
|
}
|
|
18726
18904
|
}
|
|
18727
18905
|
|
|
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 };
|
|
18906
|
+
declare function preimageLenAsU32(length: U64) {
|
|
18907
|
+
// Safe to convert to Number and U32: we check that len < 2^32 before conversion
|
|
18908
|
+
return length >= 2n ** 32n ? null : tryAsU32(Number(length));
|
|
18742
18909
|
}
|
|
18743
18910
|
|
|
18911
|
+
/**
|
|
18912
|
+
* Host call result constants.
|
|
18913
|
+
*
|
|
18914
|
+
* https://graypaper.fluffylabs.dev/#/85129da/2c7c022c7c02?v=0.6.3
|
|
18915
|
+
*/
|
|
18916
|
+
declare const HostCallResult = {
|
|
18917
|
+
/** The return value indicating an item does not exist. */
|
|
18918
|
+
NONE: tryAsU64(0xffff_ffff_ffff_ffffn), // 2**64 - 1
|
|
18919
|
+
/** Name unknown. */
|
|
18920
|
+
WHAT: tryAsU64(0xffff_ffff_ffff_fffen), // 2**64 - 2
|
|
18921
|
+
/** The inner PVM memory index provided for reading/writing is not accessible. */
|
|
18922
|
+
OOB: tryAsU64(0xffff_ffff_ffff_fffdn), // 2**64 - 3
|
|
18923
|
+
/** Index unknown. */
|
|
18924
|
+
WHO: tryAsU64(0xffff_ffff_ffff_fffcn), // 2**64 - 4
|
|
18925
|
+
/** Storage full or resource already allocated. */
|
|
18926
|
+
FULL: tryAsU64(0xffff_ffff_ffff_fffbn), // 2**64 - 5
|
|
18927
|
+
/** Core index unknown. */
|
|
18928
|
+
CORE: tryAsU64(0xffff_ffff_ffff_fffan), // 2**64 - 6
|
|
18929
|
+
/** Insufficient funds. */
|
|
18930
|
+
CASH: tryAsU64(0xffff_ffff_ffff_fff9n), // 2**64 - 7
|
|
18931
|
+
/** Gas limit too low. */
|
|
18932
|
+
LOW: tryAsU64(0xffff_ffff_ffff_fff8n), // 2**64 - 8
|
|
18933
|
+
/** The item is already solicited, cannot be forgotten or the operation is invalid due to privilege level. */
|
|
18934
|
+
HUH: tryAsU64(0xffff_ffff_ffff_fff7n), // 2**64 - 9
|
|
18935
|
+
/** The return value indicating general success. */
|
|
18936
|
+
OK: tryAsU64(0n),
|
|
18937
|
+
} as const;
|
|
18938
|
+
|
|
18744
18939
|
declare const MAX_U32 = tryAsU32(2 ** 32 - 1);
|
|
18745
18940
|
declare const MAX_U32_BIG_INT = tryAsU64(MAX_U32);
|
|
18746
18941
|
declare const SERVICE_ID_BYTES = 4;
|
|
@@ -18831,6 +19026,7 @@ declare const index$6_UpdatePrivilegesError: typeof UpdatePrivilegesError;
|
|
|
18831
19026
|
type index$6_ZeroVoidError = ZeroVoidError;
|
|
18832
19027
|
declare const index$6_ZeroVoidError: typeof ZeroVoidError;
|
|
18833
19028
|
declare const index$6_clampU64ToU32: typeof clampU64ToU32;
|
|
19029
|
+
declare const index$6_deepCloneMapWithArray: typeof deepCloneMapWithArray;
|
|
18834
19030
|
declare const index$6_getServiceId: typeof getServiceId;
|
|
18835
19031
|
declare const index$6_getServiceIdOrCurrent: typeof getServiceIdOrCurrent;
|
|
18836
19032
|
declare const index$6_preimageLenAsU32: typeof preimageLenAsU32;
|
|
@@ -18840,7 +19036,7 @@ declare const index$6_tryAsMachineId: typeof tryAsMachineId;
|
|
|
18840
19036
|
declare const index$6_tryAsProgramCounter: typeof tryAsProgramCounter;
|
|
18841
19037
|
declare const index$6_writeServiceIdAsLeBytes: typeof writeServiceIdAsLeBytes;
|
|
18842
19038
|
declare namespace index$6 {
|
|
18843
|
-
export { index$6_AccumulationStateUpdate as AccumulationStateUpdate, index$6_CURRENT_SERVICE_ID as CURRENT_SERVICE_ID, index$6_EjectError as EjectError, index$6_ForgetPreimageError as ForgetPreimageError, index$6_HostCallResult as HostCallResult, index$6_MAX_U32 as MAX_U32, index$6_MAX_U32_BIG_INT as MAX_U32_BIG_INT, index$6_MachineInstance as MachineInstance, index$6_MemoryOperation as MemoryOperation, index$6_NewServiceError as NewServiceError, index$6_PagesError as PagesError, index$6_PartiallyUpdatedState as PartiallyUpdatedState, index$6_PeekPokeError as PeekPokeError, index$6_PendingTransfer as PendingTransfer, index$6_PreimageStatusKind as PreimageStatusKind, index$6_ProvidePreimageError as ProvidePreimageError, index$6_RequestPreimageError as RequestPreimageError, index$6_SERVICE_ID_BYTES as SERVICE_ID_BYTES, index$6_TransferError as TransferError, index$6_UpdatePrivilegesError as UpdatePrivilegesError, index$6_ZeroVoidError as ZeroVoidError, index$6_clampU64ToU32 as clampU64ToU32, index$6_getServiceId as getServiceId, index$6_getServiceIdOrCurrent as getServiceIdOrCurrent, index$6_preimageLenAsU32 as preimageLenAsU32, index$6_slotsToPreimageStatus as slotsToPreimageStatus, index$6_toMemoryOperation as toMemoryOperation, index$6_tryAsMachineId as tryAsMachineId, index$6_tryAsProgramCounter as tryAsProgramCounter, index$6_writeServiceIdAsLeBytes as writeServiceIdAsLeBytes };
|
|
19039
|
+
export { index$6_AccumulationStateUpdate as AccumulationStateUpdate, index$6_CURRENT_SERVICE_ID as CURRENT_SERVICE_ID, index$6_EjectError as EjectError, index$6_ForgetPreimageError as ForgetPreimageError, index$6_HostCallResult as HostCallResult, index$6_MAX_U32 as MAX_U32, index$6_MAX_U32_BIG_INT as MAX_U32_BIG_INT, index$6_MachineInstance as MachineInstance, index$6_MemoryOperation as MemoryOperation, index$6_NewServiceError as NewServiceError, index$6_PagesError as PagesError, index$6_PartiallyUpdatedState as PartiallyUpdatedState, index$6_PeekPokeError as PeekPokeError, index$6_PendingTransfer as PendingTransfer, index$6_PreimageStatusKind as PreimageStatusKind, index$6_ProvidePreimageError as ProvidePreimageError, index$6_RequestPreimageError as RequestPreimageError, index$6_SERVICE_ID_BYTES as SERVICE_ID_BYTES, index$6_TransferError as TransferError, index$6_UpdatePrivilegesError as UpdatePrivilegesError, index$6_ZeroVoidError as ZeroVoidError, index$6_clampU64ToU32 as clampU64ToU32, index$6_deepCloneMapWithArray as deepCloneMapWithArray, index$6_getServiceId as getServiceId, index$6_getServiceIdOrCurrent as getServiceIdOrCurrent, index$6_preimageLenAsU32 as preimageLenAsU32, index$6_slotsToPreimageStatus as slotsToPreimageStatus, index$6_toMemoryOperation as toMemoryOperation, index$6_tryAsMachineId as tryAsMachineId, index$6_tryAsProgramCounter as tryAsProgramCounter, index$6_writeServiceIdAsLeBytes as writeServiceIdAsLeBytes };
|
|
18844
19040
|
export type { index$6_InsufficientFundsError as InsufficientFundsError, index$6_MachineId as MachineId, index$6_MachineResult as MachineResult, index$6_MachineStatus as MachineStatus, index$6_NoMachineError as NoMachineError, index$6_PartialState as PartialState, index$6_PreimageStatus as PreimageStatus, index$6_ProgramCounter as ProgramCounter, index$6_RefineExternalities as RefineExternalities, index$6_SegmentExportError as SegmentExportError, index$6_ServiceStateUpdate as ServiceStateUpdate, index$6_StateSlice as StateSlice, index$6_TRANSFER_MEMO_BYTES as TRANSFER_MEMO_BYTES, index$6_UnprivilegedError as UnprivilegedError };
|
|
18845
19041
|
}
|
|
18846
19042
|
|
|
@@ -19241,6 +19437,7 @@ declare const index$3_check: typeof check;
|
|
|
19241
19437
|
declare const index$3_clampU64ToU32: typeof clampU64ToU32;
|
|
19242
19438
|
declare const index$3_createResults: typeof createResults;
|
|
19243
19439
|
declare const index$3_decodeStandardProgram: typeof decodeStandardProgram;
|
|
19440
|
+
declare const index$3_deepCloneMapWithArray: typeof deepCloneMapWithArray;
|
|
19244
19441
|
declare const index$3_extractCodeAndMetadata: typeof extractCodeAndMetadata;
|
|
19245
19442
|
declare const index$3_getServiceId: typeof getServiceId;
|
|
19246
19443
|
declare const index$3_getServiceIdOrCurrent: typeof getServiceIdOrCurrent;
|
|
@@ -19259,7 +19456,7 @@ declare const index$3_tryAsMachineId: typeof tryAsMachineId;
|
|
|
19259
19456
|
declare const index$3_tryAsProgramCounter: typeof tryAsProgramCounter;
|
|
19260
19457
|
declare const index$3_writeServiceIdAsLeBytes: typeof writeServiceIdAsLeBytes;
|
|
19261
19458
|
declare namespace index$3 {
|
|
19262
|
-
export { index$3_AccumulationStateUpdate as AccumulationStateUpdate, index$3_ArgsDecoder as ArgsDecoder, index$3_ArgumentType as ArgumentType, index$3_BasicBlocks as BasicBlocks, index$3_CURRENT_SERVICE_ID as CURRENT_SERVICE_ID, index$3_EjectError as EjectError, index$3_ExtendedWitdthImmediateDecoder as ExtendedWitdthImmediateDecoder, index$3_ForgetPreimageError as ForgetPreimageError, index$3_HostCallMemory as HostCallMemory, index$3_HostCallRegisters as HostCallRegisters, index$3_HostCallResult as HostCallResult, index$3_ImmediateDecoder as ImmediateDecoder, index$3_MAX_U32 as MAX_U32, index$3_MAX_U32_BIG_INT as MAX_U32_BIG_INT, index$3_MachineInstance as MachineInstance, index$3_Mask as Mask, index$3_MemoryOperation as MemoryOperation, index$3_MemorySegment as MemorySegment, NO_OF_REGISTERS$1 as NO_OF_REGISTERS, index$3_NewServiceError as NewServiceError, index$3_NibblesDecoder as NibblesDecoder, index$3_PagesError as PagesError, index$3_PartiallyUpdatedState as PartiallyUpdatedState, index$3_PeekPokeError as PeekPokeError, index$3_PendingTransfer as PendingTransfer, index$3_PreimageStatusKind as PreimageStatusKind, index$3_Program as Program, index$3_ProgramDecoder as ProgramDecoder, index$3_ProvidePreimageError as ProvidePreimageError, DebuggerAdapter as Pvm, index$3_Registers as Registers, index$3_RequestPreimageError as RequestPreimageError, Result$2 as Result, index$3_RichTaggedError as RichTaggedError, index$3_SERVICE_ID_BYTES as SERVICE_ID_BYTES, index$3_SpiMemory as SpiMemory, index$3_SpiProgram as SpiProgram, index$3_TransferError as TransferError, index$3_UpdatePrivilegesError as UpdatePrivilegesError, index$3_WithDebug as WithDebug, index$3_ZeroVoidError as ZeroVoidError, index$3___OPAQUE_TYPE__ as __OPAQUE_TYPE__, index$3_asOpaqueType as asOpaqueType, index$3_assertEmpty as assertEmpty, index$3_assertNever as assertNever, index$l as block, index$s as bytes, index$3_check as check, index$3_clampU64ToU32 as clampU64ToU32, index$3_createResults as createResults, index$3_decodeStandardProgram as decodeStandardProgram, index$3_extractCodeAndMetadata as extractCodeAndMetadata, index$3_getServiceId as getServiceId, index$3_getServiceIdOrCurrent as getServiceIdOrCurrent, index$p as hash, index$3_inspect as inspect, index$3_instructionArgumentTypeMap as instructionArgumentTypeMap, index$8 as interpreter, index$3_isBrowser as isBrowser, index$3_isTaggedError as isTaggedError, index$3_maybeTaggedErrorToString as maybeTaggedErrorToString, index$3_measure as measure, index$r as numbers, index$3_preimageLenAsU32 as preimageLenAsU32, index$3_resultToString as resultToString, index$3_seeThrough as seeThrough, index$3_slotsToPreimageStatus as slotsToPreimageStatus, index$3_toMemoryOperation as toMemoryOperation, index$3_tryAsMachineId as tryAsMachineId, index$3_tryAsProgramCounter as tryAsProgramCounter, index$3_writeServiceIdAsLeBytes as writeServiceIdAsLeBytes };
|
|
19459
|
+
export { index$3_AccumulationStateUpdate as AccumulationStateUpdate, index$3_ArgsDecoder as ArgsDecoder, index$3_ArgumentType as ArgumentType, index$3_BasicBlocks as BasicBlocks, index$3_CURRENT_SERVICE_ID as CURRENT_SERVICE_ID, index$3_EjectError as EjectError, index$3_ExtendedWitdthImmediateDecoder as ExtendedWitdthImmediateDecoder, index$3_ForgetPreimageError as ForgetPreimageError, index$3_HostCallMemory as HostCallMemory, index$3_HostCallRegisters as HostCallRegisters, index$3_HostCallResult as HostCallResult, index$3_ImmediateDecoder as ImmediateDecoder, index$3_MAX_U32 as MAX_U32, index$3_MAX_U32_BIG_INT as MAX_U32_BIG_INT, index$3_MachineInstance as MachineInstance, index$3_Mask as Mask, index$3_MemoryOperation as MemoryOperation, index$3_MemorySegment as MemorySegment, NO_OF_REGISTERS$1 as NO_OF_REGISTERS, index$3_NewServiceError as NewServiceError, index$3_NibblesDecoder as NibblesDecoder, index$3_PagesError as PagesError, index$3_PartiallyUpdatedState as PartiallyUpdatedState, index$3_PeekPokeError as PeekPokeError, index$3_PendingTransfer as PendingTransfer, index$3_PreimageStatusKind as PreimageStatusKind, index$3_Program as Program, index$3_ProgramDecoder as ProgramDecoder, index$3_ProvidePreimageError as ProvidePreimageError, DebuggerAdapter as Pvm, index$3_Registers as Registers, index$3_RequestPreimageError as RequestPreimageError, Result$2 as Result, index$3_RichTaggedError as RichTaggedError, index$3_SERVICE_ID_BYTES as SERVICE_ID_BYTES, index$3_SpiMemory as SpiMemory, index$3_SpiProgram as SpiProgram, index$3_TransferError as TransferError, index$3_UpdatePrivilegesError as UpdatePrivilegesError, index$3_WithDebug as WithDebug, index$3_ZeroVoidError as ZeroVoidError, index$3___OPAQUE_TYPE__ as __OPAQUE_TYPE__, index$3_asOpaqueType as asOpaqueType, index$3_assertEmpty as assertEmpty, index$3_assertNever as assertNever, index$l as block, index$s as bytes, index$3_check as check, index$3_clampU64ToU32 as clampU64ToU32, index$3_createResults as createResults, index$3_decodeStandardProgram as decodeStandardProgram, index$3_deepCloneMapWithArray as deepCloneMapWithArray, index$3_extractCodeAndMetadata as extractCodeAndMetadata, index$3_getServiceId as getServiceId, index$3_getServiceIdOrCurrent as getServiceIdOrCurrent, index$p as hash, index$3_inspect as inspect, index$3_instructionArgumentTypeMap as instructionArgumentTypeMap, index$8 as interpreter, index$3_isBrowser as isBrowser, index$3_isTaggedError as isTaggedError, index$3_maybeTaggedErrorToString as maybeTaggedErrorToString, index$3_measure as measure, index$r as numbers, index$3_preimageLenAsU32 as preimageLenAsU32, index$3_resultToString as resultToString, index$3_seeThrough as seeThrough, index$3_slotsToPreimageStatus as slotsToPreimageStatus, index$3_toMemoryOperation as toMemoryOperation, index$3_tryAsMachineId as tryAsMachineId, index$3_tryAsProgramCounter as tryAsProgramCounter, index$3_writeServiceIdAsLeBytes as writeServiceIdAsLeBytes };
|
|
19263
19460
|
export type { index$3_Args as Args, index$3_EnumMapping as EnumMapping, index$3_ErrorResult as ErrorResult, index$3_IHostCallMemory as IHostCallMemory, index$3_IHostCallRegisters as IHostCallRegisters, index$3_InsufficientFundsError as InsufficientFundsError, index$3_MachineId as MachineId, index$3_MachineResult as MachineResult, index$3_MachineStatus as MachineStatus, index$3_NoMachineError as NoMachineError, index$3_OK as OK, index$3_OkResult as OkResult, index$3_Opaque as Opaque, index$3_PartialState as PartialState, index$3_PreimageStatus as PreimageStatus, index$3_ProgramCounter as ProgramCounter, index$3_RefineExternalities as RefineExternalities, index$3_SegmentExportError as SegmentExportError, index$3_ServiceStateUpdate as ServiceStateUpdate, index$3_StateSlice as StateSlice, index$3_StringLiteral as StringLiteral, index$3_TRANSFER_MEMO_BYTES as TRANSFER_MEMO_BYTES, index$3_TaggedError as TaggedError, index$3_TokenOf as TokenOf, index$3_Uninstantiable as Uninstantiable, index$3_UnprivilegedError as UnprivilegedError, index$3_WithOpaque as WithOpaque };
|
|
19264
19461
|
}
|
|
19265
19462
|
|
|
@@ -20089,12 +20286,15 @@ declare class Preimages {
|
|
|
20089
20286
|
prevPreimage.requester > currPreimage.requester ||
|
|
20090
20287
|
currPreimage.blob.compare(prevPreimage.blob).isLessOrEqual()
|
|
20091
20288
|
) {
|
|
20092
|
-
return Result.error(
|
|
20289
|
+
return Result.error(
|
|
20290
|
+
PreimagesErrorCode.PreimagesNotSortedUnique,
|
|
20291
|
+
() => `Preimages not sorted/unique at index ${i}`,
|
|
20292
|
+
);
|
|
20093
20293
|
}
|
|
20094
20294
|
}
|
|
20095
20295
|
|
|
20096
20296
|
const { preimages, slot } = input;
|
|
20097
|
-
const pendingChanges
|
|
20297
|
+
const pendingChanges = new Map<ServiceId, UpdatePreimage[]>();
|
|
20098
20298
|
|
|
20099
20299
|
// select preimages for integration
|
|
20100
20300
|
for (const preimage of preimages) {
|
|
@@ -20103,7 +20303,7 @@ declare class Preimages {
|
|
|
20103
20303
|
|
|
20104
20304
|
const service = this.state.getService(requester);
|
|
20105
20305
|
if (service === null) {
|
|
20106
|
-
return Result.error(PreimagesErrorCode.AccountNotFound);
|
|
20306
|
+
return Result.error(PreimagesErrorCode.AccountNotFound, () => `Service not found: ${requester}`);
|
|
20107
20307
|
}
|
|
20108
20308
|
|
|
20109
20309
|
const hasPreimage = service.hasPreimage(hash);
|
|
@@ -20111,17 +20311,22 @@ declare class Preimages {
|
|
|
20111
20311
|
// https://graypaper.fluffylabs.dev/#/5f542d7/181800181900
|
|
20112
20312
|
// https://graypaper.fluffylabs.dev/#/5f542d7/116f0011a500
|
|
20113
20313
|
if (hasPreimage || slots === null || !LookupHistoryItem.isRequested(slots)) {
|
|
20114
|
-
return Result.error(
|
|
20314
|
+
return Result.error(
|
|
20315
|
+
PreimagesErrorCode.PreimageUnneeded,
|
|
20316
|
+
() =>
|
|
20317
|
+
`Preimage unneeded: requester=${requester}, hash=${hash}, hasPreimage=${hasPreimage}, isRequested=${slots !== null && LookupHistoryItem.isRequested(slots)}`,
|
|
20318
|
+
);
|
|
20115
20319
|
}
|
|
20116
20320
|
|
|
20117
20321
|
// https://graypaper.fluffylabs.dev/#/5f542d7/18c00018f300
|
|
20118
|
-
pendingChanges.
|
|
20322
|
+
const updates = pendingChanges.get(requester) ?? [];
|
|
20323
|
+
updates.push(
|
|
20119
20324
|
UpdatePreimage.provide({
|
|
20120
|
-
serviceId: requester,
|
|
20121
20325
|
preimage: PreimageItem.create({ hash, blob }),
|
|
20122
20326
|
slot,
|
|
20123
20327
|
}),
|
|
20124
20328
|
);
|
|
20329
|
+
pendingChanges.set(requester, updates);
|
|
20125
20330
|
}
|
|
20126
20331
|
|
|
20127
20332
|
return Result.ok({
|