@typeberry/jam 0.1.3-3344df0 → 0.1.3-47d06ae

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;
@@ -19895,24 +19918,78 @@ class AccumulateExternalities {
19895
19918
  this.updatedState.stateUpdate.authorizationQueues.set(coreIndex, authQueue);
19896
19919
  return result_Result.ok(result_OK);
19897
19920
  }
19921
+ updatePrivilegedServiceId(
19922
+ // The id that privileged service wants to be updated to
19923
+ newId,
19924
+ // Current id of privileged service (updated state)
19925
+ currentId, {
19926
+ // is current service id a manager (can update anything)
19927
+ isManager,
19928
+ // is current service attempting to update itself (privileged are owned)
19929
+ isSelf,
19930
+ // is the service id already changed in this block
19931
+ isAlreadyChanged, }) {
19932
+ if (isManager) {
19933
+ return newId;
19934
+ }
19935
+ // current service can update itself, only if it was a privileged
19936
+ // service at the start of the block. I.e. owned privileges cannot
19937
+ // be transfered multiple times in a block.
19938
+ if (isSelf && !isAlreadyChanged) {
19939
+ return newId;
19940
+ }
19941
+ return currentId;
19942
+ }
19898
19943
  updatePrivilegedServices(manager, authorizers, delegator, registrar, autoAccumulate) {
19899
19944
  /** 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.");
19945
+ const current = this.updatedState.getPrivilegedServices();
19946
+ const isManager = current.manager === this.currentServiceId;
19947
+ if (Compatibility.isLessThan(GpVersion.V0_7_1)) {
19948
+ if (!isManager) {
19949
+ return result_Result.error(UpdatePrivilegesError.UnprivilegedService);
19950
+ }
19951
+ if (manager === null || delegator === null) {
19952
+ return result_Result.error(UpdatePrivilegesError.InvalidServiceId, "Either manager or delegator is not a valid service id.");
19953
+ }
19954
+ this.updatedState.stateUpdate.privilegedServices = PrivilegedServices.create({
19955
+ manager,
19956
+ assigners: authorizers,
19957
+ delegator: delegator,
19958
+ registrar: registrar ?? tryAsServiceId(0),
19959
+ autoAccumulateServices: autoAccumulate.map(([service, gasLimit]) => AutoAccumulate.create({ service, gasLimit })),
19960
+ });
19961
+ return result_Result.ok(result_OK);
19906
19962
  }
19907
- if (Compatibility.isGreaterOrEqual(GpVersion.V0_7_1) && registrar === null) {
19908
- return result_Result.error(UpdatePrivilegesError.InvalidServiceId, "Register manager is not valid service id.");
19963
+ const original = this.updatedState.state.privilegedServices;
19964
+ if (manager === null || delegator === null || registrar === null) {
19965
+ return result_Result.error(UpdatePrivilegesError.InvalidServiceId, "Either manager or delegator or registrar is not a valid service id.");
19909
19966
  }
19967
+ const newDelegator = this.updatePrivilegedServiceId(delegator, current.delegator, {
19968
+ isManager,
19969
+ isSelf: this.currentServiceId === current.delegator,
19970
+ isAlreadyChanged: current.delegator !== original.delegator,
19971
+ });
19972
+ const newRegistrar = this.updatePrivilegedServiceId(registrar, current.registrar, {
19973
+ isManager,
19974
+ isSelf: this.currentServiceId === current.registrar,
19975
+ isAlreadyChanged: current.registrar !== original.registrar,
19976
+ });
19977
+ const newAssigners = current.assigners.map((currentAssigner, index) => this.updatePrivilegedServiceId(authorizers[index], currentAssigner, {
19978
+ isManager,
19979
+ isSelf: this.currentServiceId === currentAssigner,
19980
+ isAlreadyChanged: currentAssigner !== original.assigners[index],
19981
+ }));
19982
+ const newManager = isManager ? manager : current.manager;
19983
+ const newAutoAccumulateServices = isManager
19984
+ ? autoAccumulate.map(([service, gasLimit]) => AutoAccumulate.create({ service, gasLimit }))
19985
+ : current.autoAccumulateServices;
19986
+ // finally update the privileges
19910
19987
  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 })),
19988
+ manager: newManager,
19989
+ assigners: tryAsPerCore(newAssigners, this.chainSpec),
19990
+ delegator: newDelegator,
19991
+ registrar: newRegistrar,
19992
+ autoAccumulateServices: newAutoAccumulateServices,
19916
19993
  });
19917
19994
  return result_Result.ok(result_OK);
19918
19995
  }
@@ -21271,6 +21348,7 @@ class Bless {
21271
21348
  return;
21272
21349
  }
21273
21350
  const e = updateResult.error;
21351
+ // NOTE: `UpdatePrivilegesError.UnprivilegedService` won't happen in 0.7.1+
21274
21352
  if (e === UpdatePrivilegesError.UnprivilegedService) {
21275
21353
  logger_logger.trace `BLESS(${manager}, ${authorizers}, ${delegator}, ${registrar}, ${autoAccumulateEntries}) <- HUH`;
21276
21354
  regs.set(bless_IN_OUT_REG, HostCallResult.HUH);
@@ -22265,7 +22343,7 @@ class Lookup {
22265
22343
  }
22266
22344
  // v
22267
22345
  const preImage = this.account.lookup(serviceId, preImageHash);
22268
- logger_logger.trace `LOOKUP(${serviceId}, ${preImageHash}) <- ${preImage?.toStringTruncated()}...`;
22346
+ logger_logger.trace `LOOKUP(${serviceId}, ${preImageHash}) <- ${preImage?.toStringTruncated() ?? "<missing>"}...`;
22269
22347
  const preImageLength = preImage === null ? numbers_tryAsU64(0) : numbers_tryAsU64(preImage.raw.length);
22270
22348
  const preimageBlobOffset = regs.get(10);
22271
22349
  const lengthToWrite = regs.get(11);
@@ -22815,15 +22893,15 @@ class Accumulate {
22815
22893
  *
22816
22894
  * https://graypaper.fluffylabs.dev/#/7e6ff6a/2fdb012fdb01?v=0.6.7
22817
22895
  */
22818
- async pvmAccumulateInvocation(slot, serviceId, transfers, operands, gas, entropy, inputStateUpdate) {
22819
- const service = this.state.getService(serviceId);
22820
- if (service === null) {
22896
+ async pvmAccumulateInvocation(slot, serviceId, transfers, operands, gas, entropy, updatedState) {
22897
+ const serviceInfo = updatedState.getServiceInfo(serviceId);
22898
+ if (serviceInfo === null) {
22821
22899
  accumulate_logger.log `Service with id ${serviceId} not found.`;
22822
22900
  return result_Result.error(PvmInvocationError.NoService);
22823
22901
  }
22824
- const codeHash = service.getInfo().codeHash;
22902
+ const codeHash = serviceInfo.codeHash;
22825
22903
  // TODO [ToDr] Should we check that the preimage is still available?
22826
- const code = service.getPreimage(codeHash.asOpaque());
22904
+ const code = updatedState.getPreimage(serviceId, codeHash.asOpaque());
22827
22905
  if (code === null) {
22828
22906
  accumulate_logger.log `Code with hash ${codeHash} not found for service ${serviceId}.`;
22829
22907
  return result_Result.error(PvmInvocationError.NoPreimage);
@@ -22833,7 +22911,7 @@ class Accumulate {
22833
22911
  return result_Result.error(PvmInvocationError.PreimageTooLong);
22834
22912
  }
22835
22913
  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);
22914
+ const partialState = new AccumulateExternalities(this.chainSpec, this.blake2b, updatedState, serviceId, nextServiceId, slot);
22837
22915
  const fetchExternalities = Compatibility.isGreaterOrEqual(GpVersion.V0_7_1)
22838
22916
  ? FetchExternalities.createForAccumulate({ entropy, transfers, operands }, this.chainSpec)
22839
22917
  : FetchExternalities.createForPre071Accumulate({ entropy, operands }, this.chainSpec);
@@ -22887,11 +22965,28 @@ class Accumulate {
22887
22965
  */
22888
22966
  async accumulateSingleService(serviceId, transfers, operands, gasCost, slot, entropy, inputStateUpdate) {
22889
22967
  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);
22968
+ const updatedState = new PartiallyUpdatedState(this.state, inputStateUpdate);
22969
+ // update service balance from incoming transfers
22970
+ if (Compatibility.isGreaterOrEqual(GpVersion.V0_7_1)) {
22971
+ const serviceInfo = updatedState.getServiceInfo(serviceId);
22972
+ if (serviceInfo !== null) {
22973
+ // update the balance from incoming tranfsers
22974
+ const newBalance = sumU64(serviceInfo.balance, ...transfers.map((item) => item.amount));
22975
+ if (newBalance.overflow) {
22976
+ accumulate_logger.log `Accumulation failed because of overflowing balance ${serviceId}.`;
22977
+ return { stateUpdate: null, consumedGas: 0n };
22978
+ }
22979
+ const newInfo = ServiceAccountInfo.create({ ...serviceInfo, balance: newBalance.value });
22980
+ updatedState.updateServiceInfo(serviceId, newInfo);
22981
+ }
22982
+ }
22983
+ const result = await this.pvmAccumulateInvocation(slot, serviceId, transfers, operands, gasCost, entropy, updatedState);
22891
22984
  if (result.isError) {
22892
22985
  // https://graypaper.fluffylabs.dev/#/7e6ff6a/2fb6012fb601?v=0.6.7
22893
22986
  accumulate_logger.log `Accumulation failed for ${serviceId}.`;
22894
- return { stateUpdate: null, consumedGas: 0n };
22987
+ // even though accumulation failed, we still need to make sure that
22988
+ // incoming transfers updated the balance, hence we pass state update here
22989
+ return { stateUpdate: updatedState.stateUpdate, consumedGas: 0n };
22895
22990
  }
22896
22991
  accumulate_logger.log `Accumulation successful for ${serviceId}. Consumed: ${result.ok.consumedGas}`;
22897
22992
  return result.ok;
@@ -22949,7 +23044,7 @@ class Accumulate {
22949
23044
  const accumulateData = new AccumulateData(reportsToAccumulateInParallel, transfers, autoAccumulateServices);
22950
23045
  const reportsToAccumulateSequentially = reports.subview(i);
22951
23046
  const { gasCost, state: stateAfterParallelAcc, ...rest } = await this.accumulateInParallel(accumulateData, slot, entropy, statistics, stateUpdate);
22952
- const newTransfers = stateAfterParallelAcc.transfers;
23047
+ const newTransfers = stateAfterParallelAcc.takeTransfers();
22953
23048
  assertEmpty(rest);
22954
23049
  // NOTE [ToDr] recursive invocation
22955
23050
  const { accumulatedReports, gasCost: seqGasCost, state, ...seqRest } = await this.accumulateSequentially(tryAsServiceGas(gasLimit - gasCost), reportsToAccumulateSequentially, newTransfers, slot, entropy, statistics, stateAfterParallelAcc, []);
@@ -22977,12 +23072,17 @@ class Accumulate {
22977
23072
  const currentManager = (inputStateUpdate.privilegedServices ?? this.state.privilegedServices).manager;
22978
23073
  for (const serviceId of serviceIds) {
22979
23074
  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);
23075
+ const operands = accumulateData.getOperands(serviceId);
23076
+ const { consumedGas, stateUpdate } = await this.accumulateSingleService(serviceId, accumulateData.getTransfers(serviceId), operands, accumulateData.getGasCost(serviceId), slot, entropy, currentState);
22981
23077
  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);
23078
+ // https://graypaper.fluffylabs.dev/#/ab2cdbd/193b05193b05?v=0.7.2
23079
+ // do not update statistics, if the service only had incoming transfers
23080
+ if (operands.length > 0) {
23081
+ const serviceStatistics = statistics.get(serviceId) ?? { count: numbers_tryAsU32(0), gasUsed: tryAsServiceGas(0) };
23082
+ serviceStatistics.count = numbers_tryAsU32(serviceStatistics.count + accumulateData.getReportsLength(serviceId));
23083
+ serviceStatistics.gasUsed = tryAsServiceGas(serviceStatistics.gasUsed + consumedGas);
23084
+ statistics.set(serviceId, serviceStatistics);
23085
+ }
22986
23086
  currentState = stateUpdate === null ? checkpoint : stateUpdate;
22987
23087
  if (Compatibility.is(GpVersion.V0_7_0) && serviceId === currentManager) {
22988
23088
  const newV = currentState.privilegedServices?.delegator;
@@ -23034,6 +23134,7 @@ class Accumulate {
23034
23134
  const info = partialStateUpdate.getServiceInfo(serviceId);
23035
23135
  if (info === null) {
23036
23136
  // NOTE If there is no service, we dont update it.
23137
+ accumulate_logger.log `Skipping update of ${serviceId}, because we have no service info.`;
23037
23138
  continue;
23038
23139
  }
23039
23140
  // δ‡
@@ -24746,6 +24847,9 @@ class OnChain {
24746
24847
  servicesUpdate = servicesUpdateFromDeferredTransfers;
24747
24848
  assertEmpty(deferredTransfersRest);
24748
24849
  }
24850
+ else {
24851
+ debug_check `${pendingTransfers.length === 0} All transfers should be already accumulated.`;
24852
+ }
24749
24853
  const accumulateRoot = await this.accumulateOutput.transition({ accumulationOutputLog });
24750
24854
  // recent history
24751
24855
  const recentHistoryUpdate = this.recentHistory.transition({