@typeberry/jam 0.1.3-ca63b35 → 0.2.0-b6e3410

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.
@@ -3540,7 +3540,7 @@ var GpVersion;
3540
3540
  (function (GpVersion) {
3541
3541
  GpVersion["V0_6_7"] = "0.6.7";
3542
3542
  GpVersion["V0_7_0"] = "0.7.0";
3543
- GpVersion["V0_7_1"] = "0.7.1-preview";
3543
+ GpVersion["V0_7_1"] = "0.7.1";
3544
3544
  GpVersion["V0_7_2"] = "0.7.2-preview";
3545
3545
  })(GpVersion || (GpVersion = {}));
3546
3546
  var TestSuite;
@@ -3549,11 +3549,11 @@ var TestSuite;
3549
3549
  TestSuite["JAMDUNA"] = "jamduna";
3550
3550
  })(TestSuite || (TestSuite = {}));
3551
3551
  const DEFAULT_SUITE = TestSuite.W3F_DAVXY;
3552
- const ALL_VERSIONS_IN_ORDER = [GpVersion.V0_6_7, GpVersion.V0_7_0, GpVersion.V0_7_1, GpVersion.V0_7_2];
3552
+ const DEFAULT_VERSION = GpVersion.V0_7_1;
3553
3553
  const env = typeof process === "undefined" ? {} : process.env;
3554
- const DEFAULT_VERSION = GpVersion.V0_7_0;
3555
3554
  let CURRENT_VERSION = parseCurrentVersion(env.GP_VERSION) ?? DEFAULT_VERSION;
3556
3555
  let CURRENT_SUITE = parseCurrentSuite(env.TEST_SUITE) ?? DEFAULT_SUITE;
3556
+ const ALL_VERSIONS_IN_ORDER = [GpVersion.V0_6_7, GpVersion.V0_7_0, GpVersion.V0_7_1, GpVersion.V0_7_2];
3557
3557
  function parseCurrentVersion(env) {
3558
3558
  if (env === undefined) {
3559
3559
  return undefined;
@@ -10335,6 +10335,7 @@ class UpdateStorage {
10335
10335
 
10336
10336
 
10337
10337
 
10338
+
10338
10339
  const codecServiceId = Compatibility.isSuite(TestSuite.W3F_DAVXY) || Compatibility.isSuite(TestSuite.JAMDUNA, GpVersion.V0_6_7)
10339
10340
  ? descriptors_codec.u32.asOpaque()
10340
10341
  : descriptors_codec.varU32.convert((s) => numbers_tryAsU32(s), (i) => tryAsServiceId(i));
@@ -10466,8 +10467,7 @@ class CoreStatistics {
10466
10467
  * Service statistics.
10467
10468
  * Updated per block, based on available work reports (`W`).
10468
10469
  *
10469
- * https://graypaper.fluffylabs.dev/#/68eaa1f/185104185104?v=0.6.4
10470
- * https://github.com/gavofyork/graypaper/blob/9bffb08f3ea7b67832019176754df4fb36b9557d/text/statistics.tex#L77
10470
+ * https://graypaper.fluffylabs.dev/#/1c979cb/199802199802?v=0.7.1
10471
10471
  */
10472
10472
  class ServiceStatistics {
10473
10473
  providedCount;
@@ -10482,22 +10482,8 @@ class ServiceStatistics {
10482
10482
  accumulateGasUsed;
10483
10483
  onTransfersCount;
10484
10484
  onTransfersGasUsed;
10485
- static Codec = Compatibility.isGreaterOrEqual(GpVersion.V0_7_0)
10486
- ? descriptors_codec.Class(ServiceStatistics, {
10487
- providedCount: codecVarU16,
10488
- providedSize: descriptors_codec.varU32,
10489
- refinementCount: descriptors_codec.varU32,
10490
- refinementGasUsed: codecVarGas,
10491
- imports: codecVarU16,
10492
- extrinsicCount: codecVarU16,
10493
- extrinsicSize: descriptors_codec.varU32,
10494
- exports: codecVarU16,
10495
- accumulateCount: descriptors_codec.varU32,
10496
- accumulateGasUsed: codecVarGas,
10497
- onTransfersCount: descriptors_codec.varU32,
10498
- onTransfersGasUsed: codecVarGas,
10499
- })
10500
- : descriptors_codec.Class(ServiceStatistics, {
10485
+ static Codec = Compatibility.selectIfGreaterOrEqual({
10486
+ fallback: descriptors_codec.Class(ServiceStatistics, {
10501
10487
  providedCount: codecVarU16,
10502
10488
  providedSize: descriptors_codec.varU32,
10503
10489
  refinementCount: descriptors_codec.varU32,
@@ -10510,7 +10496,38 @@ class ServiceStatistics {
10510
10496
  accumulateGasUsed: codecVarGas,
10511
10497
  onTransfersCount: descriptors_codec.varU32,
10512
10498
  onTransfersGasUsed: codecVarGas,
10513
- });
10499
+ }),
10500
+ versions: {
10501
+ [GpVersion.V0_7_0]: descriptors_codec.Class(ServiceStatistics, {
10502
+ providedCount: codecVarU16,
10503
+ providedSize: descriptors_codec.varU32,
10504
+ refinementCount: descriptors_codec.varU32,
10505
+ refinementGasUsed: codecVarGas,
10506
+ imports: codecVarU16,
10507
+ extrinsicCount: codecVarU16,
10508
+ extrinsicSize: descriptors_codec.varU32,
10509
+ exports: codecVarU16,
10510
+ accumulateCount: descriptors_codec.varU32,
10511
+ accumulateGasUsed: codecVarGas,
10512
+ onTransfersCount: descriptors_codec.varU32,
10513
+ onTransfersGasUsed: codecVarGas,
10514
+ }),
10515
+ [GpVersion.V0_7_1]: descriptors_codec.Class(ServiceStatistics, {
10516
+ providedCount: codecVarU16,
10517
+ providedSize: descriptors_codec.varU32,
10518
+ refinementCount: descriptors_codec.varU32,
10519
+ refinementGasUsed: codecVarGas,
10520
+ imports: codecVarU16,
10521
+ extrinsicCount: codecVarU16,
10522
+ extrinsicSize: descriptors_codec.varU32,
10523
+ exports: codecVarU16,
10524
+ accumulateCount: descriptors_codec.varU32,
10525
+ accumulateGasUsed: codecVarGas,
10526
+ onTransfersCount: ignoreValueWithDefault(numbers_tryAsU32(0)),
10527
+ onTransfersGasUsed: ignoreValueWithDefault(tryAsServiceGas(0)),
10528
+ }),
10529
+ },
10530
+ });
10514
10531
  static create(v) {
10515
10532
  return new ServiceStatistics(v.providedCount, v.providedSize, v.refinementCount, v.refinementGasUsed, v.imports, v.exports, v.extrinsicSize, v.extrinsicCount, v.accumulateCount, v.accumulateGasUsed, v.onTransfersCount, v.onTransfersGasUsed);
10516
10533
  }
@@ -10535,9 +10552,9 @@ class ServiceStatistics {
10535
10552
  accumulateCount,
10536
10553
  /** `a.1` */
10537
10554
  accumulateGasUsed,
10538
- /** `t.0` */
10555
+ /** `t.0` @deprecated since 0.7.1 */
10539
10556
  onTransfersCount,
10540
- /** `t.1` */
10557
+ /** `t.1` @deprecated since 0.7.1 */
10541
10558
  onTransfersGasUsed) {
10542
10559
  this.providedCount = providedCount;
10543
10560
  this.providedSize = providedSize;
@@ -15151,6 +15168,12 @@ class AccumulationStateUpdate {
15151
15168
  }
15152
15169
  return update;
15153
15170
  }
15171
+ /** Retrieve and clear pending transfers. */
15172
+ takeTransfers() {
15173
+ const transfers = this.transfers;
15174
+ this.transfers = [];
15175
+ return transfers;
15176
+ }
15154
15177
  }
15155
15178
  class PartiallyUpdatedState {
15156
15179
  state;
@@ -19190,6 +19213,24 @@ class Interpreter {
19190
19213
  getMemoryPage(pageNumber) {
19191
19214
  return this.memory.getPageDump(tryAsPageNumber(pageNumber));
19192
19215
  }
19216
+ calculateBlockGasCost() {
19217
+ const codeLength = this.code.length;
19218
+ const blocks = new Map();
19219
+ let currentBlock = "0";
19220
+ let gasCost = 0;
19221
+ const getNextIstructionIndex = (index) => index + 1 + this.mask.getNoOfBytesToNextInstruction(index + 1);
19222
+ for (let index = 0; index < codeLength; index = getNextIstructionIndex(index)) {
19223
+ const instruction = this.code[index];
19224
+ if (this.basicBlocks.isBeginningOfBasicBlock(index)) {
19225
+ blocks.set(currentBlock, gasCost);
19226
+ currentBlock = index.toString();
19227
+ gasCost = 0;
19228
+ }
19229
+ gasCost += instructionGasMap[instruction];
19230
+ }
19231
+ blocks.set(currentBlock, gasCost);
19232
+ return blocks;
19233
+ }
19193
19234
  }
19194
19235
 
19195
19236
  ;// CONCATENATED MODULE: ./packages/core/pvm-interpreter/index.ts
@@ -19895,24 +19936,78 @@ class AccumulateExternalities {
19895
19936
  this.updatedState.stateUpdate.authorizationQueues.set(coreIndex, authQueue);
19896
19937
  return result_Result.ok(result_OK);
19897
19938
  }
19939
+ updatePrivilegedServiceId(
19940
+ // The id that privileged service wants to be updated to
19941
+ newId,
19942
+ // Current id of privileged service (updated state)
19943
+ currentId, {
19944
+ // is current service id a manager (can update anything)
19945
+ isManager,
19946
+ // is current service attempting to update itself (privileged are owned)
19947
+ isSelf,
19948
+ // is the service id already changed in this block
19949
+ isAlreadyChanged, }) {
19950
+ if (isManager) {
19951
+ return newId;
19952
+ }
19953
+ // current service can update itself, only if it was a privileged
19954
+ // service at the start of the block. I.e. owned privileges cannot
19955
+ // be transfered multiple times in a block.
19956
+ if (isSelf && !isAlreadyChanged) {
19957
+ return newId;
19958
+ }
19959
+ return currentId;
19960
+ }
19898
19961
  updatePrivilegedServices(manager, authorizers, delegator, registrar, autoAccumulate) {
19899
19962
  /** https://graypaper.fluffylabs.dev/#/7e6ff6a/36d90036de00?v=0.6.7 */
19900
- const currentManager = this.updatedState.getPrivilegedServices().manager;
19901
- if (currentManager !== this.currentServiceId) {
19902
- return result_Result.error(UpdatePrivilegesError.UnprivilegedService);
19903
- }
19904
- if (manager === null || delegator === null) {
19905
- return result_Result.error(UpdatePrivilegesError.InvalidServiceId, "Either manager or delegator is not valid service id.");
19963
+ const current = this.updatedState.getPrivilegedServices();
19964
+ const isManager = current.manager === this.currentServiceId;
19965
+ if (Compatibility.isLessThan(GpVersion.V0_7_1)) {
19966
+ if (!isManager) {
19967
+ return result_Result.error(UpdatePrivilegesError.UnprivilegedService);
19968
+ }
19969
+ if (manager === null || delegator === null) {
19970
+ return result_Result.error(UpdatePrivilegesError.InvalidServiceId, "Either manager or delegator is not a valid service id.");
19971
+ }
19972
+ this.updatedState.stateUpdate.privilegedServices = PrivilegedServices.create({
19973
+ manager,
19974
+ assigners: authorizers,
19975
+ delegator: delegator,
19976
+ registrar: registrar ?? tryAsServiceId(0),
19977
+ autoAccumulateServices: autoAccumulate.map(([service, gasLimit]) => AutoAccumulate.create({ service, gasLimit })),
19978
+ });
19979
+ return result_Result.ok(result_OK);
19906
19980
  }
19907
- if (Compatibility.isGreaterOrEqual(GpVersion.V0_7_1) && registrar === null) {
19908
- return result_Result.error(UpdatePrivilegesError.InvalidServiceId, "Register manager is not valid service id.");
19981
+ const original = this.updatedState.state.privilegedServices;
19982
+ if (manager === null || delegator === null || registrar === null) {
19983
+ return result_Result.error(UpdatePrivilegesError.InvalidServiceId, "Either manager or delegator or registrar is not a valid service id.");
19909
19984
  }
19985
+ const newDelegator = this.updatePrivilegedServiceId(delegator, current.delegator, {
19986
+ isManager,
19987
+ isSelf: this.currentServiceId === current.delegator,
19988
+ isAlreadyChanged: current.delegator !== original.delegator,
19989
+ });
19990
+ const newRegistrar = this.updatePrivilegedServiceId(registrar, current.registrar, {
19991
+ isManager,
19992
+ isSelf: this.currentServiceId === current.registrar,
19993
+ isAlreadyChanged: current.registrar !== original.registrar,
19994
+ });
19995
+ const newAssigners = current.assigners.map((currentAssigner, index) => this.updatePrivilegedServiceId(authorizers[index], currentAssigner, {
19996
+ isManager,
19997
+ isSelf: this.currentServiceId === currentAssigner,
19998
+ isAlreadyChanged: currentAssigner !== original.assigners[index],
19999
+ }));
20000
+ const newManager = isManager ? manager : current.manager;
20001
+ const newAutoAccumulateServices = isManager
20002
+ ? autoAccumulate.map(([service, gasLimit]) => AutoAccumulate.create({ service, gasLimit }))
20003
+ : current.autoAccumulateServices;
20004
+ // finally update the privileges
19910
20005
  this.updatedState.stateUpdate.privilegedServices = PrivilegedServices.create({
19911
- manager,
19912
- assigners: authorizers,
19913
- delegator,
19914
- registrar: registrar ?? tryAsServiceId(0), // introduced in 0.7.1
19915
- autoAccumulateServices: autoAccumulate.map(([service, gasLimit]) => AutoAccumulate.create({ service, gasLimit })),
20006
+ manager: newManager,
20007
+ assigners: tryAsPerCore(newAssigners, this.chainSpec),
20008
+ delegator: newDelegator,
20009
+ registrar: newRegistrar,
20010
+ autoAccumulateServices: newAutoAccumulateServices,
19916
20011
  });
19917
20012
  return result_Result.ok(result_OK);
19918
20013
  }
@@ -21271,6 +21366,7 @@ class Bless {
21271
21366
  return;
21272
21367
  }
21273
21368
  const e = updateResult.error;
21369
+ // NOTE: `UpdatePrivilegesError.UnprivilegedService` won't happen in 0.7.1+
21274
21370
  if (e === UpdatePrivilegesError.UnprivilegedService) {
21275
21371
  logger_logger.trace `BLESS(${manager}, ${authorizers}, ${delegator}, ${registrar}, ${autoAccumulateEntries}) <- HUH`;
21276
21372
  regs.set(bless_IN_OUT_REG, HostCallResult.HUH);
@@ -22265,7 +22361,7 @@ class Lookup {
22265
22361
  }
22266
22362
  // v
22267
22363
  const preImage = this.account.lookup(serviceId, preImageHash);
22268
- logger_logger.trace `LOOKUP(${serviceId}, ${preImageHash}) <- ${preImage?.toStringTruncated()}...`;
22364
+ logger_logger.trace `LOOKUP(${serviceId}, ${preImageHash}) <- ${preImage?.toStringTruncated() ?? "<missing>"}...`;
22269
22365
  const preImageLength = preImage === null ? numbers_tryAsU64(0) : numbers_tryAsU64(preImage.raw.length);
22270
22366
  const preimageBlobOffset = regs.get(10);
22271
22367
  const lengthToWrite = regs.get(11);
@@ -22815,15 +22911,15 @@ class Accumulate {
22815
22911
  *
22816
22912
  * https://graypaper.fluffylabs.dev/#/7e6ff6a/2fdb012fdb01?v=0.6.7
22817
22913
  */
22818
- async pvmAccumulateInvocation(slot, serviceId, transfers, operands, gas, entropy, inputStateUpdate) {
22819
- const service = this.state.getService(serviceId);
22820
- if (service === null) {
22914
+ async pvmAccumulateInvocation(slot, serviceId, transfers, operands, gas, entropy, updatedState) {
22915
+ const serviceInfo = updatedState.getServiceInfo(serviceId);
22916
+ if (serviceInfo === null) {
22821
22917
  accumulate_logger.log `Service with id ${serviceId} not found.`;
22822
22918
  return result_Result.error(PvmInvocationError.NoService);
22823
22919
  }
22824
- const codeHash = service.getInfo().codeHash;
22920
+ const codeHash = serviceInfo.codeHash;
22825
22921
  // TODO [ToDr] Should we check that the preimage is still available?
22826
- const code = service.getPreimage(codeHash.asOpaque());
22922
+ const code = updatedState.getPreimage(serviceId, codeHash.asOpaque());
22827
22923
  if (code === null) {
22828
22924
  accumulate_logger.log `Code with hash ${codeHash} not found for service ${serviceId}.`;
22829
22925
  return result_Result.error(PvmInvocationError.NoPreimage);
@@ -22833,7 +22929,7 @@ class Accumulate {
22833
22929
  return result_Result.error(PvmInvocationError.PreimageTooLong);
22834
22930
  }
22835
22931
  const nextServiceId = generateNextServiceId({ serviceId, entropy, timeslot: slot }, this.chainSpec, this.blake2b);
22836
- const partialState = new AccumulateExternalities(this.chainSpec, this.blake2b, new PartiallyUpdatedState(this.state, inputStateUpdate), serviceId, nextServiceId, slot);
22932
+ const partialState = new AccumulateExternalities(this.chainSpec, this.blake2b, updatedState, serviceId, nextServiceId, slot);
22837
22933
  const fetchExternalities = Compatibility.isGreaterOrEqual(GpVersion.V0_7_1)
22838
22934
  ? FetchExternalities.createForAccumulate({ entropy, transfers, operands }, this.chainSpec)
22839
22935
  : FetchExternalities.createForPre071Accumulate({ entropy, operands }, this.chainSpec);
@@ -22887,11 +22983,28 @@ class Accumulate {
22887
22983
  */
22888
22984
  async accumulateSingleService(serviceId, transfers, operands, gasCost, slot, entropy, inputStateUpdate) {
22889
22985
  accumulate_logger.log `Accumulating service ${serviceId}, transfers: ${transfers.length} operands: ${operands.length} at slot: ${slot}.`;
22890
- const result = await this.pvmAccumulateInvocation(slot, serviceId, transfers, operands, gasCost, entropy, inputStateUpdate);
22986
+ const updatedState = new PartiallyUpdatedState(this.state, inputStateUpdate);
22987
+ // update service balance from incoming transfers
22988
+ if (Compatibility.isGreaterOrEqual(GpVersion.V0_7_1)) {
22989
+ const serviceInfo = updatedState.getServiceInfo(serviceId);
22990
+ if (serviceInfo !== null) {
22991
+ // update the balance from incoming tranfsers
22992
+ const newBalance = sumU64(serviceInfo.balance, ...transfers.map((item) => item.amount));
22993
+ if (newBalance.overflow) {
22994
+ accumulate_logger.log `Accumulation failed because of overflowing balance ${serviceId}.`;
22995
+ return { stateUpdate: null, consumedGas: 0n };
22996
+ }
22997
+ const newInfo = ServiceAccountInfo.create({ ...serviceInfo, balance: newBalance.value });
22998
+ updatedState.updateServiceInfo(serviceId, newInfo);
22999
+ }
23000
+ }
23001
+ const result = await this.pvmAccumulateInvocation(slot, serviceId, transfers, operands, gasCost, entropy, updatedState);
22891
23002
  if (result.isError) {
22892
23003
  // https://graypaper.fluffylabs.dev/#/7e6ff6a/2fb6012fb601?v=0.6.7
22893
23004
  accumulate_logger.log `Accumulation failed for ${serviceId}.`;
22894
- return { stateUpdate: null, consumedGas: 0n };
23005
+ // even though accumulation failed, we still need to make sure that
23006
+ // incoming transfers updated the balance, hence we pass state update here
23007
+ return { stateUpdate: updatedState.stateUpdate, consumedGas: 0n };
22895
23008
  }
22896
23009
  accumulate_logger.log `Accumulation successful for ${serviceId}. Consumed: ${result.ok.consumedGas}`;
22897
23010
  return result.ok;
@@ -22949,7 +23062,7 @@ class Accumulate {
22949
23062
  const accumulateData = new AccumulateData(reportsToAccumulateInParallel, transfers, autoAccumulateServices);
22950
23063
  const reportsToAccumulateSequentially = reports.subview(i);
22951
23064
  const { gasCost, state: stateAfterParallelAcc, ...rest } = await this.accumulateInParallel(accumulateData, slot, entropy, statistics, stateUpdate);
22952
- const newTransfers = stateAfterParallelAcc.transfers;
23065
+ const newTransfers = stateAfterParallelAcc.takeTransfers();
22953
23066
  assertEmpty(rest);
22954
23067
  // NOTE [ToDr] recursive invocation
22955
23068
  const { accumulatedReports, gasCost: seqGasCost, state, ...seqRest } = await this.accumulateSequentially(tryAsServiceGas(gasLimit - gasCost), reportsToAccumulateSequentially, newTransfers, slot, entropy, statistics, stateAfterParallelAcc, []);
@@ -22977,12 +23090,17 @@ class Accumulate {
22977
23090
  const currentManager = (inputStateUpdate.privilegedServices ?? this.state.privilegedServices).manager;
22978
23091
  for (const serviceId of serviceIds) {
22979
23092
  const checkpoint = AccumulationStateUpdate.copyFrom(currentState);
22980
- const { consumedGas, stateUpdate } = await this.accumulateSingleService(serviceId, accumulateData.getTransfers(serviceId), accumulateData.getOperands(serviceId), accumulateData.getGasCost(serviceId), slot, entropy, currentState);
23093
+ const operands = accumulateData.getOperands(serviceId);
23094
+ const { consumedGas, stateUpdate } = await this.accumulateSingleService(serviceId, accumulateData.getTransfers(serviceId), operands, accumulateData.getGasCost(serviceId), slot, entropy, currentState);
22981
23095
  gasCost = tryAsServiceGas(gasCost + consumedGas);
22982
- const serviceStatistics = statistics.get(serviceId) ?? { count: numbers_tryAsU32(0), gasUsed: tryAsServiceGas(0) };
22983
- serviceStatistics.count = numbers_tryAsU32(serviceStatistics.count + accumulateData.getReportsLength(serviceId));
22984
- serviceStatistics.gasUsed = tryAsServiceGas(serviceStatistics.gasUsed + consumedGas);
22985
- statistics.set(serviceId, serviceStatistics);
23096
+ // https://graypaper.fluffylabs.dev/#/ab2cdbd/193b05193b05?v=0.7.2
23097
+ // do not update statistics, if the service only had incoming transfers
23098
+ if (operands.length > 0) {
23099
+ const serviceStatistics = statistics.get(serviceId) ?? { count: numbers_tryAsU32(0), gasUsed: tryAsServiceGas(0) };
23100
+ serviceStatistics.count = numbers_tryAsU32(serviceStatistics.count + accumulateData.getReportsLength(serviceId));
23101
+ serviceStatistics.gasUsed = tryAsServiceGas(serviceStatistics.gasUsed + consumedGas);
23102
+ statistics.set(serviceId, serviceStatistics);
23103
+ }
22986
23104
  currentState = stateUpdate === null ? checkpoint : stateUpdate;
22987
23105
  if (Compatibility.is(GpVersion.V0_7_0) && serviceId === currentManager) {
22988
23106
  const newV = currentState.privilegedServices?.delegator;
@@ -23034,6 +23152,7 @@ class Accumulate {
23034
23152
  const info = partialStateUpdate.getServiceInfo(serviceId);
23035
23153
  if (info === null) {
23036
23154
  // NOTE If there is no service, we dont update it.
23155
+ accumulate_logger.log `Skipping update of ${serviceId}, because we have no service info.`;
23037
23156
  continue;
23038
23157
  }
23039
23158
  // δ‡
@@ -24746,6 +24865,9 @@ class OnChain {
24746
24865
  servicesUpdate = servicesUpdateFromDeferredTransfers;
24747
24866
  assertEmpty(deferredTransfersRest);
24748
24867
  }
24868
+ else {
24869
+ debug_check `${pendingTransfers.length === 0} All transfers should be already accumulated.`;
24870
+ }
24749
24871
  const accumulateRoot = await this.accumulateOutput.transition({ accumulationOutputLog });
24750
24872
  // recent history
24751
24873
  const recentHistoryUpdate = this.recentHistory.transition({