@typeberry/convert 0.1.2-ef67dce → 0.1.3-3f7b9cf

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.
Files changed (3) hide show
  1. package/index.js +351 -256
  2. package/index.js.map +1 -1
  3. package/package.json +1 -1
package/index.js CHANGED
@@ -5511,7 +5511,7 @@ function isResult(x) {
5511
5511
  var minimist = __nccwpck_require__(595);
5512
5512
  var minimist_default = /*#__PURE__*/__nccwpck_require__.n(minimist);
5513
5513
  ;// CONCATENATED MODULE: ./bin/convert/package.json
5514
- const package_namespaceObject = {"rE":"0.1.2"};
5514
+ const package_namespaceObject = {"rE":"0.1.3"};
5515
5515
  ;// CONCATENATED MODULE: ./packages/core/bytes/bitvec.ts
5516
5516
 
5517
5517
  /**
@@ -6867,13 +6867,15 @@ function validateLength(range, length, context) {
6867
6867
 
6868
6868
  /** A caching wrapper for either object or sequence item. */
6869
6869
  class ViewField {
6870
+ name;
6870
6871
  getView;
6871
6872
  getValue;
6872
6873
  getEncoded;
6873
6874
  cachedValue;
6874
6875
  cachedView;
6875
6876
  cachedBlob;
6876
- constructor(getView, getValue, getEncoded) {
6877
+ constructor(name, getView, getValue, getEncoded) {
6878
+ this.name = name;
6877
6879
  this.getView = getView;
6878
6880
  this.getValue = getValue;
6879
6881
  this.getEncoded = getEncoded;
@@ -6899,6 +6901,9 @@ class ViewField {
6899
6901
  }
6900
6902
  return this.cachedBlob;
6901
6903
  }
6904
+ toString() {
6905
+ return `ViewField<${this.name}>`;
6906
+ }
6902
6907
  }
6903
6908
  /**
6904
6909
  * A base class for all the lazy views.
@@ -6973,7 +6978,7 @@ class ObjectView {
6973
6978
  const fieldDecoder = skipper.decoder.clone();
6974
6979
  const field = this.descriptorsKeys[i];
6975
6980
  const type = this.descriptors[field];
6976
- lastItem = new ViewField(() => type.View.decode(fieldDecoder.clone()), () => type.decode(fieldDecoder.clone()), () => type.skipEncoded(fieldDecoder.clone()));
6981
+ lastItem = new ViewField(`${this.toString()}.${String(field)}`, () => type.View.decode(fieldDecoder.clone()), () => type.decode(fieldDecoder.clone()), () => type.skipEncoded(fieldDecoder.clone()));
6977
6982
  // skip the field
6978
6983
  type.skip(skipper);
6979
6984
  // cache data
@@ -6985,6 +6990,9 @@ class ObjectView {
6985
6990
  }
6986
6991
  return lastItem;
6987
6992
  }
6993
+ toString() {
6994
+ return `View<${this.materializedConstructor.name}>(cache: ${this.cache.size})`;
6995
+ }
6988
6996
  }
6989
6997
  /**
6990
6998
  * A lazy-evaluated decoder of a sequence.
@@ -7073,7 +7081,7 @@ class SequenceView {
7073
7081
  // create new cached prop
7074
7082
  const fieldDecoder = skipper.decoder.clone();
7075
7083
  const type = this.descriptor;
7076
- lastItem = new ViewField(() => type.View.decode(fieldDecoder.clone()), () => type.decode(fieldDecoder.clone()), () => type.skipEncoded(fieldDecoder.clone()));
7084
+ lastItem = new ViewField(`${this.toString()}[${index}]`, () => type.View.decode(fieldDecoder.clone()), () => type.decode(fieldDecoder.clone()), () => type.skipEncoded(fieldDecoder.clone()));
7077
7085
  // skip the field
7078
7086
  type.skip(skipper);
7079
7087
  // cache data
@@ -7085,6 +7093,9 @@ class SequenceView {
7085
7093
  }
7086
7094
  return lastItem;
7087
7095
  }
7096
+ toString() {
7097
+ return `SequenceView<${this.descriptor.name}>(cache: ${this.cache.size})`;
7098
+ }
7088
7099
  }
7089
7100
 
7090
7101
  ;// CONCATENATED MODULE: ./packages/core/codec/descriptors.ts
@@ -11498,15 +11509,12 @@ function loadConfig(configPath) {
11498
11509
 
11499
11510
 
11500
11511
 
11501
- ;// CONCATENATED MODULE: ./packages/extensions/ipc/fuzz/v0/types.ts
11512
+ ;// CONCATENATED MODULE: ./packages/jam/fuzz-proto/v1/types.ts
11502
11513
 
11503
11514
 
11504
11515
 
11505
11516
 
11506
11517
 
11507
- /**
11508
- * Reference: https://github.com/davxy/jam-conformance/blob/7c6a371a966c6446564f91676e7a2afdec5fa3da/fuzz-proto/fuzz.asn
11509
- */
11510
11518
  /**
11511
11519
  * Version ::= SEQUENCE {
11512
11520
  * major INTEGER (0..255),
@@ -11547,190 +11555,17 @@ class Version extends WithDebug {
11547
11555
  this.patch = patch;
11548
11556
  }
11549
11557
  }
11550
- /**
11551
- * PeerInfo ::= SEQUENCE {
11552
- * name UTF8String,
11553
- * app-version Version,
11554
- * jam-version Version
11555
- * }
11556
- */
11557
- class PeerInfo extends WithDebug {
11558
- name;
11559
- appVersion;
11560
- jamVersion;
11561
- static Codec = descriptors_codec.Class(PeerInfo, {
11562
- name: descriptors_codec.string,
11563
- appVersion: Version.Codec,
11564
- jamVersion: Version.Codec,
11565
- });
11566
- static create({ name, appVersion, jamVersion }) {
11567
- return new PeerInfo(name, appVersion, jamVersion);
11568
- }
11569
- constructor(name, appVersion, jamVersion) {
11570
- super();
11571
- this.name = name;
11572
- this.appVersion = appVersion;
11573
- this.jamVersion = jamVersion;
11574
- }
11575
- }
11576
- /**
11577
- * KeyValue ::= SEQUENCE {
11578
- * key TrieKey,
11579
- * value OCTET STRING
11580
- * }
11581
- */
11582
- class KeyValue extends WithDebug {
11583
- key;
11584
- value;
11585
- static Codec = descriptors_codec.Class(KeyValue, {
11586
- key: descriptors_codec.bytes(TRUNCATED_HASH_SIZE),
11587
- value: descriptors_codec.blob,
11588
- });
11589
- static create({ key, value }) {
11590
- return new KeyValue(key, value);
11591
- }
11592
- constructor(key, value) {
11593
- super();
11594
- this.key = key;
11595
- this.value = value;
11596
- }
11597
- }
11598
- /** State ::= SEQUENCE OF KeyValue */
11599
- const stateCodec = descriptors_codec.sequenceVarLen(KeyValue.Codec);
11600
- /**
11601
- * SetState ::= SEQUENCE {
11602
- * header Header,
11603
- * state State
11604
- * }
11605
- */
11606
- class SetState extends WithDebug {
11607
- header;
11608
- state;
11609
- static Codec = descriptors_codec.Class(SetState, {
11610
- header: header_Header.Codec,
11611
- state: descriptors_codec.sequenceVarLen(KeyValue.Codec),
11612
- });
11613
- static create({ header, state }) {
11614
- return new SetState(header, state);
11615
- }
11616
- constructor(header, state) {
11617
- super();
11618
- this.header = header;
11619
- this.state = state;
11620
- }
11621
- }
11622
- /** GetState ::= HeaderHash */
11623
- const getStateCodec = descriptors_codec.bytes(hash_HASH_SIZE).asOpaque();
11624
- /** StateRoot ::= StateRootHash */
11625
- const stateRootCodec = descriptors_codec.bytes(hash_HASH_SIZE).asOpaque();
11626
- /** Message choice type tags */
11627
- var MessageType;
11628
- (function (MessageType) {
11629
- MessageType[MessageType["PeerInfo"] = 0] = "PeerInfo";
11630
- MessageType[MessageType["ImportBlock"] = 1] = "ImportBlock";
11631
- MessageType[MessageType["SetState"] = 2] = "SetState";
11632
- MessageType[MessageType["GetState"] = 3] = "GetState";
11633
- MessageType[MessageType["State"] = 4] = "State";
11634
- MessageType[MessageType["StateRoot"] = 5] = "StateRoot";
11635
- })(MessageType || (MessageType = {}));
11636
- /**
11637
- * Message ::= CHOICE {
11638
- * peer-info [0] PeerInfo,
11639
- * import-block [1] ImportBlock,
11640
- * set-state [2] SetState,
11641
- * get-state [3] GetState,
11642
- * state [4] State,
11643
- * state-root [5] StateRoot
11644
- * }
11645
- */
11646
- const messageCodec = descriptors_codec.custom({
11647
- name: "Message",
11648
- sizeHint: { bytes: 1, isExact: false },
11649
- }, (e, msg) => {
11650
- e.i8(msg.type);
11651
- switch (msg.type) {
11652
- case MessageType.PeerInfo:
11653
- PeerInfo.Codec.encode(e, msg.value);
11654
- break;
11655
- case MessageType.ImportBlock:
11656
- block_Block.Codec.View.encode(e, msg.value);
11657
- break;
11658
- case MessageType.SetState:
11659
- SetState.Codec.encode(e, msg.value);
11660
- break;
11661
- case MessageType.GetState:
11662
- getStateCodec.encode(e, msg.value);
11663
- break;
11664
- case MessageType.State:
11665
- stateCodec.encode(e, msg.value);
11666
- break;
11667
- case MessageType.StateRoot:
11668
- stateRootCodec.encode(e, msg.value);
11669
- break;
11670
- default:
11671
- throw new Error(`Unknown message type: ${msg}`);
11672
- }
11673
- }, (d) => {
11674
- const type = d.u8();
11675
- switch (type) {
11676
- case MessageType.PeerInfo:
11677
- return { type: MessageType.PeerInfo, value: PeerInfo.Codec.decode(d) };
11678
- case MessageType.ImportBlock:
11679
- return { type: MessageType.ImportBlock, value: block_Block.Codec.View.decode(d) };
11680
- case MessageType.SetState:
11681
- return { type: MessageType.SetState, value: SetState.Codec.decode(d) };
11682
- case MessageType.GetState:
11683
- return { type: MessageType.GetState, value: getStateCodec.decode(d) };
11684
- case MessageType.State:
11685
- return { type: MessageType.State, value: stateCodec.decode(d) };
11686
- case MessageType.StateRoot:
11687
- return { type: MessageType.StateRoot, value: stateRootCodec.decode(d) };
11688
- default:
11689
- throw new Error(`Unknown message type: ${type}`);
11690
- }
11691
- }, (s) => {
11692
- const type = s.decoder.u8();
11693
- switch (type) {
11694
- case MessageType.PeerInfo:
11695
- PeerInfo.Codec.View.skip(s);
11696
- break;
11697
- case MessageType.ImportBlock:
11698
- block_Block.Codec.View.skip(s);
11699
- break;
11700
- case MessageType.SetState:
11701
- SetState.Codec.View.skip(s);
11702
- break;
11703
- case MessageType.GetState:
11704
- getStateCodec.View.skip(s);
11705
- break;
11706
- case MessageType.State:
11707
- stateCodec.View.skip(s);
11708
- break;
11709
- case MessageType.StateRoot:
11710
- stateRootCodec.View.skip(s);
11711
- break;
11712
- default:
11713
- throw new Error(`Unknown message type: ${type}`);
11714
- }
11715
- });
11716
-
11717
- ;// CONCATENATED MODULE: ./packages/extensions/ipc/fuzz/v1/types.ts
11718
-
11719
-
11720
-
11721
-
11722
-
11723
11558
  /**
11724
11559
  * Fuzzer Protocol V1
11725
11560
  * Reference: https://github.com/davxy/jam-conformance/blob/main/fuzz-proto/fuzz.asn
11726
11561
  */
11727
11562
  // Feature bit constants
11728
- var Features;
11563
+ var types_Features;
11729
11564
  (function (Features) {
11730
11565
  Features[Features["Ancestry"] = 1] = "Ancestry";
11731
11566
  Features[Features["Fork"] = 2] = "Fork";
11732
11567
  Features[Features["Reserved"] = 2147483648] = "Reserved";
11733
- })(Features || (Features = {}));
11568
+ })(types_Features || (types_Features = {}));
11734
11569
  /**
11735
11570
  * PeerInfo ::= SEQUENCE {
11736
11571
  * fuzz-version U8,
@@ -11740,13 +11575,13 @@ var Features;
11740
11575
  * name UTF8String
11741
11576
  * }
11742
11577
  */
11743
- class types_PeerInfo extends WithDebug {
11578
+ class PeerInfo extends WithDebug {
11744
11579
  fuzzVersion;
11745
11580
  features;
11746
11581
  jamVersion;
11747
11582
  appVersion;
11748
11583
  name;
11749
- static Codec = descriptors_codec.Class(types_PeerInfo, {
11584
+ static Codec = descriptors_codec.Class(PeerInfo, {
11750
11585
  fuzzVersion: descriptors_codec.u8,
11751
11586
  features: descriptors_codec.u32,
11752
11587
  jamVersion: Version.Codec,
@@ -11754,7 +11589,7 @@ class types_PeerInfo extends WithDebug {
11754
11589
  name: descriptors_codec.string,
11755
11590
  });
11756
11591
  static create({ fuzzVersion, features, appVersion, jamVersion, name }) {
11757
- return new types_PeerInfo(fuzzVersion, features, jamVersion, appVersion, name);
11592
+ return new PeerInfo(fuzzVersion, features, jamVersion, appVersion, name);
11758
11593
  }
11759
11594
  constructor(fuzzVersion, features, jamVersion, appVersion, name) {
11760
11595
  super();
@@ -11787,6 +11622,30 @@ class AncestryItem extends WithDebug {
11787
11622
  this.headerHash = headerHash;
11788
11623
  }
11789
11624
  }
11625
+ /**
11626
+ * KeyValue ::= SEQUENCE {
11627
+ * key TrieKey,
11628
+ * value OCTET STRING
11629
+ * }
11630
+ */
11631
+ class KeyValue extends WithDebug {
11632
+ key;
11633
+ value;
11634
+ static Codec = descriptors_codec.Class(KeyValue, {
11635
+ key: descriptors_codec.bytes(TRUNCATED_HASH_SIZE),
11636
+ value: descriptors_codec.blob,
11637
+ });
11638
+ static create({ key, value }) {
11639
+ return new KeyValue(key, value);
11640
+ }
11641
+ constructor(key, value) {
11642
+ super();
11643
+ this.key = key;
11644
+ this.value = value;
11645
+ }
11646
+ }
11647
+ /** State ::= SEQUENCE OF KeyValue */
11648
+ const stateCodec = descriptors_codec.sequenceVarLen(KeyValue.Codec);
11790
11649
  /**
11791
11650
  * Ancestry ::= SEQUENCE (SIZE(0..24)) OF AncestryItem
11792
11651
  * Empty when `feature-ancestry` is not supported by both parties
@@ -11822,9 +11681,9 @@ class Initialize extends WithDebug {
11822
11681
  }
11823
11682
  }
11824
11683
  /** GetState ::= HeaderHash */
11825
- const types_getStateCodec = descriptors_codec.bytes(hash_HASH_SIZE).asOpaque();
11684
+ const getStateCodec = descriptors_codec.bytes(hash_HASH_SIZE).asOpaque();
11826
11685
  /** StateRoot ::= StateRootHash */
11827
- const types_stateRootCodec = descriptors_codec.bytes(hash_HASH_SIZE).asOpaque();
11686
+ const stateRootCodec = descriptors_codec.bytes(hash_HASH_SIZE).asOpaque();
11828
11687
  /** Error ::= UTF8String */
11829
11688
  class ErrorMessage extends WithDebug {
11830
11689
  message;
@@ -11868,19 +11727,19 @@ const types_messageCodec = descriptors_codec.custom({
11868
11727
  e.i8(msg.type);
11869
11728
  switch (msg.type) {
11870
11729
  case types_MessageType.PeerInfo:
11871
- types_PeerInfo.Codec.encode(e, msg.value);
11730
+ PeerInfo.Codec.encode(e, msg.value);
11872
11731
  break;
11873
11732
  case types_MessageType.Initialize:
11874
11733
  Initialize.Codec.encode(e, msg.value);
11875
11734
  break;
11876
11735
  case types_MessageType.StateRoot:
11877
- types_stateRootCodec.encode(e, msg.value);
11736
+ stateRootCodec.encode(e, msg.value);
11878
11737
  break;
11879
11738
  case types_MessageType.ImportBlock:
11880
11739
  block_Block.Codec.View.encode(e, msg.value);
11881
11740
  break;
11882
11741
  case types_MessageType.GetState:
11883
- types_getStateCodec.encode(e, msg.value);
11742
+ getStateCodec.encode(e, msg.value);
11884
11743
  break;
11885
11744
  case types_MessageType.State:
11886
11745
  stateCodec.encode(e, msg.value);
@@ -11895,15 +11754,15 @@ const types_messageCodec = descriptors_codec.custom({
11895
11754
  const type = d.u8();
11896
11755
  switch (type) {
11897
11756
  case types_MessageType.PeerInfo:
11898
- return { type: types_MessageType.PeerInfo, value: types_PeerInfo.Codec.decode(d) };
11757
+ return { type: types_MessageType.PeerInfo, value: PeerInfo.Codec.decode(d) };
11899
11758
  case types_MessageType.Initialize:
11900
11759
  return { type: types_MessageType.Initialize, value: Initialize.Codec.decode(d) };
11901
11760
  case types_MessageType.StateRoot:
11902
- return { type: types_MessageType.StateRoot, value: types_stateRootCodec.decode(d) };
11761
+ return { type: types_MessageType.StateRoot, value: stateRootCodec.decode(d) };
11903
11762
  case types_MessageType.ImportBlock:
11904
11763
  return { type: types_MessageType.ImportBlock, value: block_Block.Codec.View.decode(d) };
11905
11764
  case types_MessageType.GetState:
11906
- return { type: types_MessageType.GetState, value: types_getStateCodec.decode(d) };
11765
+ return { type: types_MessageType.GetState, value: getStateCodec.decode(d) };
11907
11766
  case types_MessageType.State:
11908
11767
  return { type: types_MessageType.State, value: stateCodec.decode(d) };
11909
11768
  case types_MessageType.Error:
@@ -11915,19 +11774,19 @@ const types_messageCodec = descriptors_codec.custom({
11915
11774
  const type = s.decoder.u8();
11916
11775
  switch (type) {
11917
11776
  case types_MessageType.PeerInfo:
11918
- types_PeerInfo.Codec.View.skip(s);
11777
+ PeerInfo.Codec.View.skip(s);
11919
11778
  break;
11920
11779
  case types_MessageType.Initialize:
11921
11780
  Initialize.Codec.View.skip(s);
11922
11781
  break;
11923
11782
  case types_MessageType.StateRoot:
11924
- types_stateRootCodec.View.skip(s);
11783
+ stateRootCodec.View.skip(s);
11925
11784
  break;
11926
11785
  case types_MessageType.ImportBlock:
11927
11786
  block_Block.Codec.View.skip(s);
11928
11787
  break;
11929
11788
  case types_MessageType.GetState:
11930
- types_getStateCodec.View.skip(s);
11789
+ getStateCodec.View.skip(s);
11931
11790
  break;
11932
11791
  case types_MessageType.State:
11933
11792
  stateCodec.View.skip(s);
@@ -11940,6 +11799,145 @@ const types_messageCodec = descriptors_codec.custom({
11940
11799
  }
11941
11800
  });
11942
11801
 
11802
+ ;// CONCATENATED MODULE: ./packages/jam/fuzz-proto/v1/handler.ts
11803
+
11804
+
11805
+
11806
+
11807
+ const handler_logger = Logger.new(import.meta.filename, "ext-ipc-fuzz-v1");
11808
+ class FuzzTarget {
11809
+ msgHandler;
11810
+ sender;
11811
+ spec;
11812
+ sessionFeatures = 0;
11813
+ constructor(msgHandler, sender, spec) {
11814
+ this.msgHandler = msgHandler;
11815
+ this.sender = sender;
11816
+ this.spec = spec;
11817
+ }
11818
+ async onSocketMessage(msg) {
11819
+ // attempt to decode the messsage
11820
+ try {
11821
+ const message = Decoder.decodeObject(messageCodec, msg, this.spec);
11822
+ handler_logger.log `[${message.type}] incoming message`;
11823
+ await this.processAndRespond(message);
11824
+ }
11825
+ catch (e) {
11826
+ handler_logger.error `Error while processing fuzz v1 message: ${e}`;
11827
+ handler_logger.error `${e}`;
11828
+ if (e instanceof Error) {
11829
+ handler_logger.error `${e.stack ?? ""}`;
11830
+ }
11831
+ this.sender.close();
11832
+ }
11833
+ }
11834
+ async processAndRespond(message) {
11835
+ let response = null;
11836
+ switch (message.type) {
11837
+ case MessageType.PeerInfo: {
11838
+ // only support V1
11839
+ if (message.value.fuzzVersion !== 1) {
11840
+ handler_logger.warn `Unsupported fuzzer protocol version: ${message.value.fuzzVersion}. Closing`;
11841
+ this.sender.close();
11842
+ return;
11843
+ }
11844
+ // Handle handshake
11845
+ const ourPeerInfo = await this.msgHandler.getPeerInfo(message.value);
11846
+ // Calculate session features (intersection of both peer features)
11847
+ this.sessionFeatures = message.value.features & ourPeerInfo.features;
11848
+ handler_logger.info `Handshake completed. Shared features: 0b${this.sessionFeatures.toString(2)}`;
11849
+ handler_logger.log `Feature ancestry: ${(this.sessionFeatures & Features.Ancestry) !== 0}`;
11850
+ handler_logger.log `Feature fork: ${(this.sessionFeatures & Features.Fork) !== 0}`;
11851
+ response = {
11852
+ type: MessageType.PeerInfo,
11853
+ value: ourPeerInfo,
11854
+ };
11855
+ break;
11856
+ }
11857
+ case MessageType.Initialize: {
11858
+ const stateRoot = await this.msgHandler.initialize(message.value);
11859
+ response = {
11860
+ type: MessageType.StateRoot,
11861
+ value: stateRoot,
11862
+ };
11863
+ break;
11864
+ }
11865
+ case MessageType.ImportBlock: {
11866
+ const result = await this.msgHandler.importBlock(message.value);
11867
+ if (result.isOk) {
11868
+ response = {
11869
+ type: MessageType.StateRoot,
11870
+ value: result.ok,
11871
+ };
11872
+ }
11873
+ else {
11874
+ response = {
11875
+ type: MessageType.Error,
11876
+ value: result.error,
11877
+ };
11878
+ }
11879
+ break;
11880
+ }
11881
+ case MessageType.GetState: {
11882
+ const state = await this.msgHandler.getSerializedState(message.value);
11883
+ response = {
11884
+ type: MessageType.State,
11885
+ value: state,
11886
+ };
11887
+ break;
11888
+ }
11889
+ case MessageType.StateRoot: {
11890
+ handler_logger.log `--> Received unexpected 'StateRoot' message from the fuzzer. Closing.`;
11891
+ this.sender.close();
11892
+ return;
11893
+ }
11894
+ case MessageType.State: {
11895
+ handler_logger.log `--> Received unexpected 'State' message from the fuzzer. Closing.`;
11896
+ this.sender.close();
11897
+ return;
11898
+ }
11899
+ case MessageType.Error: {
11900
+ handler_logger.log `--> Received unexpected 'Error' message from the fuzzer. Closing.`;
11901
+ this.sender.close();
11902
+ return;
11903
+ }
11904
+ default: {
11905
+ handler_logger.log `--> Received unexpected message type ${JSON.stringify(message)} from the fuzzer. Closing.`;
11906
+ this.sender.close();
11907
+ try {
11908
+ assertNever(message);
11909
+ }
11910
+ catch {
11911
+ return;
11912
+ }
11913
+ }
11914
+ }
11915
+ if (response !== null) {
11916
+ handler_logger.trace `<-- responding with: ${response.type}`;
11917
+ const encoded = Encoder.encodeObject(messageCodec, response, this.spec);
11918
+ this.sender.send(encoded);
11919
+ }
11920
+ else {
11921
+ handler_logger.warn `<-- no response generated for: ${message.type}`;
11922
+ }
11923
+ }
11924
+ onClose({ error }) {
11925
+ handler_logger.log `Closing the v1 handler. Reason: ${error !== undefined ? error.message : "close"}.`;
11926
+ }
11927
+ /** Check if a specific feature is enabled in the session */
11928
+ hasFeature(feature) {
11929
+ return (this.sessionFeatures & feature) !== 0;
11930
+ }
11931
+ }
11932
+
11933
+ ;// CONCATENATED MODULE: ./packages/jam/fuzz-proto/v1/index.ts
11934
+
11935
+
11936
+
11937
+ ;// CONCATENATED MODULE: ./packages/jam/fuzz-proto/index.ts
11938
+
11939
+
11940
+
11943
11941
  ;// CONCATENATED MODULE: ./packages/core/pvm-spi-decoder/memory-conts.ts
11944
11942
  // GP reference: https://graypaper.fluffylabs.dev/#/7e6ff6a/2d32002d3200?v=0.6.7
11945
11943
  const memory_conts_PAGE_SIZE = 2 ** 12; // Z_P from GP
@@ -12192,6 +12190,10 @@ class disputes_DisputesRecords {
12192
12190
  static create({ goodSet, badSet, wonkySet, punishSet }) {
12193
12191
  return new disputes_DisputesRecords(goodSet, badSet, wonkySet, punishSet);
12194
12192
  }
12193
+ goodSetDict;
12194
+ badSetDict;
12195
+ wonkySetDict;
12196
+ punishSetDict;
12195
12197
  constructor(
12196
12198
  /** `goodSet`: all work-reports hashes which were judged to be correct */
12197
12199
  goodSet,
@@ -12205,6 +12207,18 @@ class disputes_DisputesRecords {
12205
12207
  this.badSet = badSet;
12206
12208
  this.wonkySet = wonkySet;
12207
12209
  this.punishSet = punishSet;
12210
+ this.goodSetDict = hash_set_HashSet.from(goodSet.array);
12211
+ this.badSetDict = hash_set_HashSet.from(badSet.array);
12212
+ this.wonkySetDict = hash_set_HashSet.from(wonkySet.array);
12213
+ this.punishSetDict = hash_set_HashSet.from(punishSet.array);
12214
+ }
12215
+ asDictionaries() {
12216
+ return {
12217
+ goodSet: this.goodSetDict,
12218
+ badSet: this.badSetDict,
12219
+ wonkySet: this.wonkySetDict,
12220
+ punishSet: this.punishSetDict,
12221
+ };
12208
12222
  }
12209
12223
  static fromSortedArrays({ goodSet, badSet, wonkySet, punishSet, }) {
12210
12224
  return new disputes_DisputesRecords(sorted_set_SortedSet.fromSortedArray(disputes_hashComparator, goodSet), sorted_set_SortedSet.fromSortedArray(disputes_hashComparator, badSet), sorted_set_SortedSet.fromSortedArray(disputes_hashComparator, wonkySet), sorted_set_SortedSet.fromSortedArray(disputes_hashComparator, punishSet));
@@ -16249,10 +16263,16 @@ function registers_signExtend32To64(value) {
16249
16263
 
16250
16264
  /** Attempt to convert a number into `HostCallIndex`. */
16251
16265
  const host_call_handler_tryAsHostCallIndex = (v) => opaque_asOpaqueType(numbers_tryAsU32(v));
16266
+ /**
16267
+ * Host-call exit reason.
16268
+ *
16269
+ * https://graypaper.fluffylabs.dev/#/ab2cdbd/24a30124a501?v=0.7.2
16270
+ */
16252
16271
  var host_call_handler_PvmExecution;
16253
16272
  (function (PvmExecution) {
16254
16273
  PvmExecution[PvmExecution["Halt"] = 0] = "Halt";
16255
16274
  PvmExecution[PvmExecution["Panic"] = 1] = "Panic";
16275
+ PvmExecution[PvmExecution["OOG"] = 2] = "OOG";
16256
16276
  })(host_call_handler_PvmExecution || (host_call_handler_PvmExecution = {}));
16257
16277
  /** A utility function to easily trace a bunch of registers. */
16258
16278
  function host_call_handler_traceRegisters(...regs) {
@@ -19869,8 +19889,9 @@ class host_calls_HostCalls {
19869
19889
  const index = tryAsHostCallIndex(hostCallIndex);
19870
19890
  const hostCall = this.hostCalls.get(index);
19871
19891
  const gasBefore = gas.get();
19872
- const gasCost = typeof hostCall.gasCost === "number" ? hostCall.gasCost : hostCall.gasCost(regs);
19873
- const underflow = gas.sub(gasCost);
19892
+ // NOTE: `basicGasCost(regs)` function is for compatibility reasons: pre GP 0.7.2
19893
+ const basicGasCost = typeof hostCall.basicGasCost === "number" ? hostCall.basicGasCost : hostCall.basicGasCost(regs);
19894
+ const underflow = gas.sub(basicGasCost);
19874
19895
  const pcLog = `[PC: ${pvmInstance.getPC()}]`;
19875
19896
  if (underflow) {
19876
19897
  this.hostCalls.traceHostCall(`${pcLog} OOG`, index, hostCall, regs, gas.get());
@@ -19887,6 +19908,10 @@ class host_calls_HostCalls {
19887
19908
  status = Status.PANIC;
19888
19909
  return this.getReturnValue(status, pvmInstance);
19889
19910
  }
19911
+ if (result === PvmExecution.OOG) {
19912
+ status = Status.OOG;
19913
+ return this.getReturnValue(status, pvmInstance);
19914
+ }
19890
19915
  if (result === undefined) {
19891
19916
  pvmInstance.runProgram();
19892
19917
  status = pvmInstance.getStatus();
@@ -19945,7 +19970,7 @@ class host_calls_manager_HostCallsManager {
19945
19970
  }
19946
19971
  class NoopMissing {
19947
19972
  index = tryAsHostCallIndex(2 ** 32 - 1);
19948
- gasCost = tryAsSmallGas(0);
19973
+ basicGasCost = tryAsSmallGas(0);
19949
19974
  currentServiceId = tryAsU32(0);
19950
19975
  tracedRegisters = [];
19951
19976
  async execute() {
@@ -20059,7 +20084,7 @@ function utils_clampU64ToU32(value) {
20059
20084
 
20060
20085
  class missing_Missing {
20061
20086
  index = tryAsHostCallIndex(2 ** 32 - 1);
20062
- gasCost = tryAsSmallGas(10);
20087
+ basicGasCost = tryAsSmallGas(10);
20063
20088
  currentServiceId = CURRENT_SERVICE_ID;
20064
20089
  tracedRegisters = traceRegisters(7);
20065
20090
  execute(_gas, regs, _memory) {
@@ -20436,7 +20461,7 @@ class disputes_Disputes {
20436
20461
  const { key, workReportHash } = disputes.culprits[i];
20437
20462
  // check if some offenders weren't reported earlier
20438
20463
  // https://graypaper.fluffylabs.dev/#/579bd12/125501125501
20439
- const isInPunishSet = this.state.disputesRecords.punishSet.findExact(key) !== undefined;
20464
+ const isInPunishSet = this.state.disputesRecords.asDictionaries().punishSet.has(key);
20440
20465
  if (isInPunishSet) {
20441
20466
  return Result.error(DisputesErrorCode.OffenderAlreadyReported);
20442
20467
  }
@@ -20447,8 +20472,8 @@ class disputes_Disputes {
20447
20472
  }
20448
20473
  // verify if the culprit will be in new bad set
20449
20474
  // https://graypaper.fluffylabs.dev/#/579bd12/124601124601
20450
- const isInNewBadSet = newItems.toAddToBadSet.findExact(workReportHash);
20451
- if (isInNewBadSet === undefined) {
20475
+ const isInNewBadSet = newItems.asDictionaries().badSet.has(workReportHash);
20476
+ if (!isInNewBadSet) {
20452
20477
  return Result.error(DisputesErrorCode.CulpritsVerdictNotBad);
20453
20478
  }
20454
20479
  // verify culprit signature
@@ -20471,7 +20496,7 @@ class disputes_Disputes {
20471
20496
  const { key, workReportHash, wasConsideredValid } = disputes.faults[i];
20472
20497
  // check if some offenders weren't reported earlier
20473
20498
  // https://graypaper.fluffylabs.dev/#/579bd12/12a20112a201
20474
- const isInPunishSet = this.state.disputesRecords.punishSet.findExact(key) !== undefined;
20499
+ const isInPunishSet = this.state.disputesRecords.asDictionaries().punishSet.has(key);
20475
20500
  if (isInPunishSet) {
20476
20501
  return Result.error(DisputesErrorCode.OffenderAlreadyReported);
20477
20502
  }
@@ -20486,9 +20511,10 @@ class disputes_Disputes {
20486
20511
  // but it does not pass the tests
20487
20512
  // https://graypaper.fluffylabs.dev/#/579bd12/128a01129601
20488
20513
  if (wasConsideredValid) {
20489
- const isInNewGoodSet = newItems.toAddToGoodSet.findExact(workReportHash);
20490
- const isInNewBadSet = newItems.toAddToBadSet.findExact(workReportHash);
20491
- if (isInNewGoodSet !== undefined || isInNewBadSet === undefined) {
20514
+ const { goodSet, badSet } = newItems.asDictionaries();
20515
+ const isInNewGoodSet = goodSet.has(workReportHash);
20516
+ const isInNewBadSet = badSet.has(workReportHash);
20517
+ if (isInNewGoodSet || !isInNewBadSet) {
20492
20518
  return Result.error(DisputesErrorCode.FaultVerdictWrong);
20493
20519
  }
20494
20520
  }
@@ -20541,10 +20567,11 @@ class disputes_Disputes {
20541
20567
  for (const verdict of disputes.verdicts) {
20542
20568
  // current verdicts should not be reported earlier
20543
20569
  // https://graypaper.fluffylabs.dev/#/579bd12/122202122202
20544
- const isInGoodSet = this.state.disputesRecords.goodSet.findExact(verdict.workReportHash);
20545
- const isInBadSet = this.state.disputesRecords.badSet.findExact(verdict.workReportHash);
20546
- const isInWonkySet = this.state.disputesRecords.wonkySet.findExact(verdict.workReportHash);
20547
- if (isInGoodSet !== undefined || isInBadSet !== undefined || isInWonkySet !== undefined) {
20570
+ const { goodSet, badSet, wonkySet } = this.state.disputesRecords.asDictionaries();
20571
+ const isInGoodSet = goodSet.has(verdict.workReportHash);
20572
+ const isInBadSet = badSet.has(verdict.workReportHash);
20573
+ const isInWonkySet = wonkySet.has(verdict.workReportHash);
20574
+ if (isInGoodSet || isInBadSet || isInWonkySet) {
20548
20575
  return Result.error(DisputesErrorCode.AlreadyJudged);
20549
20576
  }
20550
20577
  }
@@ -20614,11 +20641,12 @@ class disputes_Disputes {
20614
20641
  toAddToWonkySet.push(r);
20615
20642
  }
20616
20643
  }
20617
- return {
20618
- toAddToGoodSet: SortedSet.fromArrayUnique(hashComparator, toAddToGoodSet),
20619
- toAddToBadSet: SortedSet.fromArrayUnique(hashComparator, toAddToBadSet),
20620
- toAddToWonkySet: SortedSet.fromArrayUnique(hashComparator, toAddToWonkySet),
20621
- };
20644
+ return DisputesRecords.create({
20645
+ goodSet: SortedSet.fromArrayUnique(hashComparator, toAddToGoodSet),
20646
+ badSet: SortedSet.fromArrayUnique(hashComparator, toAddToBadSet),
20647
+ wonkySet: SortedSet.fromArrayUnique(hashComparator, toAddToWonkySet),
20648
+ punishSet: SortedSet.fromArray(hashComparator, []),
20649
+ });
20622
20650
  }
20623
20651
  getClearedCoreAssignment(v) {
20624
20652
  /**
@@ -20653,9 +20681,9 @@ class disputes_Disputes {
20653
20681
  const toAddToPunishSet = SortedArray.fromArray(hashComparator, Array.from(offenders));
20654
20682
  return DisputesRecords.create({
20655
20683
  // https://graypaper.fluffylabs.dev/#/579bd12/12690312bc03
20656
- goodSet: SortedSet.fromTwoSortedCollections(this.state.disputesRecords.goodSet, newItems.toAddToGoodSet),
20657
- badSet: SortedSet.fromTwoSortedCollections(this.state.disputesRecords.badSet, newItems.toAddToBadSet),
20658
- wonkySet: SortedSet.fromTwoSortedCollections(this.state.disputesRecords.wonkySet, newItems.toAddToWonkySet),
20684
+ goodSet: SortedSet.fromTwoSortedCollections(this.state.disputesRecords.goodSet, newItems.goodSet),
20685
+ badSet: SortedSet.fromTwoSortedCollections(this.state.disputesRecords.badSet, newItems.badSet),
20686
+ wonkySet: SortedSet.fromTwoSortedCollections(this.state.disputesRecords.wonkySet, newItems.wonkySet),
20659
20687
  punishSet: SortedSet.fromTwoSortedCollections(this.state.disputesRecords.punishSet, toAddToPunishSet),
20660
20688
  });
20661
20689
  }
@@ -20757,6 +20785,15 @@ var ResultValues;
20757
20785
  ResultValues[ResultValues["Ok"] = 0] = "Ok";
20758
20786
  ResultValues[ResultValues["Error"] = 1] = "Error";
20759
20787
  })(ResultValues || (ResultValues = {}));
20788
+ /**
20789
+ * Getting a ring commitment is pretty expensive (hundreds of ms),
20790
+ * yet the validators do not always change.
20791
+ * For current benchmarks, we get a huge hit every epoch, hence
20792
+ * to overcome that we cache the results of getting ring commitment.
20793
+ * Note we can also tentatively populate this cache, before we even
20794
+ * reach the epoch change block.
20795
+ */
20796
+ const ringCommitmentCache = [];
20760
20797
  // TODO [ToDr] We export the entire object to allow mocking in tests.
20761
20798
  // Ideally we would just export functions and figure out how to mock
20762
20799
  // properly in ESM.
@@ -20772,9 +20809,27 @@ async function verifySeal(bandersnatch, authorKey, signature, payload, encodedUn
20772
20809
  }
20773
20810
  return result_Result.ok(bytes_Bytes.fromBlob(sealResult.subarray(1), hash_HASH_SIZE).asOpaque());
20774
20811
  }
20775
- async function getRingCommitment(bandersnatch, validators) {
20776
- const keys = bytes_BytesBlob.blobFromParts(validators.map((x) => x.raw)).raw;
20777
- const commitmentResult = await bandersnatch.getRingCommitment(keys);
20812
+ function getRingCommitment(bandersnatch, validators) {
20813
+ const keys = bytes_BytesBlob.blobFromParts(validators.map((x) => x.raw));
20814
+ // We currently compare the large bytes blob, but the number of entries in the cache
20815
+ // must be low. If the cache ever grows larger, we should rather consider hashing the keys.
20816
+ const MAX_CACHE_ENTRIES = 3;
20817
+ const cacheEntry = ringCommitmentCache.find((v) => v.keys.isEqualTo(keys));
20818
+ if (cacheEntry !== undefined) {
20819
+ return cacheEntry.value;
20820
+ }
20821
+ const value = getRingCommitmentNoCache(bandersnatch, keys);
20822
+ ringCommitmentCache.push({
20823
+ keys,
20824
+ value,
20825
+ });
20826
+ if (ringCommitmentCache.length > MAX_CACHE_ENTRIES) {
20827
+ ringCommitmentCache.shift();
20828
+ }
20829
+ return value;
20830
+ }
20831
+ async function getRingCommitmentNoCache(bandersnatch, keys) {
20832
+ const commitmentResult = await bandersnatch.getRingCommitment(keys.raw);
20778
20833
  if (commitmentResult[RESULT_INDEX] === ResultValues.Error) {
20779
20834
  return result_Result.error(null);
20780
20835
  }
@@ -20900,6 +20955,18 @@ class safrole_Safrole {
20900
20955
  }
20901
20956
  return FixedSizeArray.new([newRandomnessAcc, ...rest], 4);
20902
20957
  }
20958
+ /**
20959
+ * Pre-populate cache for validator keys, and especially the ring commitment.
20960
+ *
20961
+ * NOTE the function is still doing quite some work, so it should only be used
20962
+ * once per epoch. The optimisation relies on the fact that the `bandersnatch.getRingCommitment`
20963
+ * call will be cached.
20964
+ */
20965
+ async prepareValidatorKeysForNextEpoch(postOffenders) {
20966
+ const stateEpoch = Math.floor(this.state.timeslot / this.chainSpec.epochLength);
20967
+ const nextEpochStart = (stateEpoch + 1) * this.chainSpec.epochLength;
20968
+ return await this.getValidatorKeys(tryAsTimeSlot(nextEpochStart), postOffenders);
20969
+ }
20903
20970
  async getValidatorKeys(timeslot, postOffenders) {
20904
20971
  /**
20905
20972
  * Epoch is not changed so the previous state is returned
@@ -23039,7 +23106,7 @@ class Assign {
23039
23106
  partialState;
23040
23107
  chainSpec;
23041
23108
  index = host_call_handler_tryAsHostCallIndex(15);
23042
- gasCost = gas_tryAsSmallGas(10);
23109
+ basicGasCost = gas_tryAsSmallGas(10);
23043
23110
  tracedRegisters = host_call_handler_traceRegisters(IN_OUT_REG, 8);
23044
23111
  constructor(currentServiceId, partialState, chainSpec) {
23045
23112
  this.currentServiceId = currentServiceId;
@@ -23117,7 +23184,7 @@ class Bless {
23117
23184
  partialState;
23118
23185
  chainSpec;
23119
23186
  index = host_call_handler_tryAsHostCallIndex(14);
23120
- gasCost = gas_tryAsSmallGas(10);
23187
+ basicGasCost = gas_tryAsSmallGas(10);
23121
23188
  tracedRegisters = host_call_handler_traceRegisters(bless_IN_OUT_REG, 8, 9, 10, 11);
23122
23189
  constructor(currentServiceId, partialState, chainSpec) {
23123
23190
  this.currentServiceId = currentServiceId;
@@ -23202,7 +23269,7 @@ class Bless {
23202
23269
  class gas_GasHostCall {
23203
23270
  currentServiceId;
23204
23271
  index = host_call_handler_tryAsHostCallIndex(0);
23205
- gasCost = gas_tryAsSmallGas(10);
23272
+ basicGasCost = gas_tryAsSmallGas(10);
23206
23273
  tracedRegisters = host_call_handler_traceRegisters(7);
23207
23274
  constructor(currentServiceId) {
23208
23275
  this.currentServiceId = currentServiceId;
@@ -23229,7 +23296,7 @@ class Checkpoint {
23229
23296
  currentServiceId;
23230
23297
  partialState;
23231
23298
  index = host_call_handler_tryAsHostCallIndex(17);
23232
- gasCost = gas_tryAsSmallGas(10);
23299
+ basicGasCost = gas_tryAsSmallGas(10);
23233
23300
  tracedRegisters;
23234
23301
  gasHostCall;
23235
23302
  constructor(currentServiceId, partialState) {
@@ -23266,7 +23333,7 @@ class Designate {
23266
23333
  partialState;
23267
23334
  chainSpec;
23268
23335
  index = host_call_handler_tryAsHostCallIndex(16);
23269
- gasCost = gas_tryAsSmallGas(10);
23336
+ basicGasCost = gas_tryAsSmallGas(10);
23270
23337
  tracedRegisters = host_call_handler_traceRegisters(designate_IN_OUT_REG);
23271
23338
  constructor(currentServiceId, partialState, chainSpec) {
23272
23339
  this.currentServiceId = currentServiceId;
@@ -23317,7 +23384,7 @@ class Eject {
23317
23384
  currentServiceId;
23318
23385
  partialState;
23319
23386
  index = host_call_handler_tryAsHostCallIndex(21);
23320
- gasCost = gas_tryAsSmallGas(10);
23387
+ basicGasCost = gas_tryAsSmallGas(10);
23321
23388
  tracedRegisters = host_call_handler_traceRegisters(eject_IN_OUT_REG, 8);
23322
23389
  constructor(currentServiceId, partialState) {
23323
23390
  this.currentServiceId = currentServiceId;
@@ -23379,7 +23446,7 @@ class Forget {
23379
23446
  currentServiceId;
23380
23447
  partialState;
23381
23448
  index = host_call_handler_tryAsHostCallIndex(24);
23382
- gasCost = gas_tryAsSmallGas(10);
23449
+ basicGasCost = gas_tryAsSmallGas(10);
23383
23450
  tracedRegisters = host_call_handler_traceRegisters(forget_IN_OUT_REG, 8);
23384
23451
  constructor(currentServiceId, partialState) {
23385
23452
  this.currentServiceId = currentServiceId;
@@ -23429,7 +23496,7 @@ class New {
23429
23496
  currentServiceId;
23430
23497
  partialState;
23431
23498
  index = host_call_handler_tryAsHostCallIndex(18);
23432
- gasCost = gas_tryAsSmallGas(10);
23499
+ basicGasCost = gas_tryAsSmallGas(10);
23433
23500
  tracedRegisters = host_call_handler_traceRegisters(new_IN_OUT_REG, 8, 9, 10, 11);
23434
23501
  constructor(currentServiceId, partialState) {
23435
23502
  this.currentServiceId = currentServiceId;
@@ -23492,7 +23559,7 @@ class Provide {
23492
23559
  currentServiceId;
23493
23560
  partialState;
23494
23561
  index = host_call_handler_tryAsHostCallIndex(26);
23495
- gasCost = gas_tryAsSmallGas(10);
23562
+ basicGasCost = gas_tryAsSmallGas(10);
23496
23563
  tracedRegisters = host_call_handler_traceRegisters(provide_IN_OUT_REG, 8, 9);
23497
23564
  constructor(currentServiceId, partialState) {
23498
23565
  this.currentServiceId = currentServiceId;
@@ -23553,7 +23620,7 @@ class Query {
23553
23620
  currentServiceId;
23554
23621
  partialState;
23555
23622
  index = host_call_handler_tryAsHostCallIndex(22);
23556
- gasCost = gas_tryAsSmallGas(10);
23623
+ basicGasCost = gas_tryAsSmallGas(10);
23557
23624
  tracedRegisters = host_call_handler_traceRegisters(IN_OUT_REG_1, IN_OUT_REG_2);
23558
23625
  constructor(currentServiceId, partialState) {
23559
23626
  this.currentServiceId = currentServiceId;
@@ -23619,7 +23686,7 @@ class Solicit {
23619
23686
  currentServiceId;
23620
23687
  partialState;
23621
23688
  index = host_call_handler_tryAsHostCallIndex(23);
23622
- gasCost = gas_tryAsSmallGas(10);
23689
+ basicGasCost = gas_tryAsSmallGas(10);
23623
23690
  tracedRegisters = host_call_handler_traceRegisters(solicit_IN_OUT_REG, 8);
23624
23691
  constructor(currentServiceId, partialState) {
23625
23692
  this.currentServiceId = currentServiceId;
@@ -23667,12 +23734,12 @@ class Solicit {
23667
23734
 
23668
23735
  const transfer_IN_OUT_REG = 7; // `d`
23669
23736
  const AMOUNT_REG = 8; // `a`
23670
- const ON_TRANSFER_GAS_REG = 9; // `l`
23737
+ const TRANSFER_GAS_FEE_REG = 9; // `l`
23671
23738
  const MEMO_START_REG = 10; // `o`
23672
23739
  /**
23673
23740
  * Transfer balance from one service account to another.
23674
23741
  *
23675
- * https://graypaper.fluffylabs.dev/#/7e6ff6a/373b00373b00?v=0.6.7
23742
+ * https://graypaper.fluffylabs.dev/#/ab2cdbd/373f00373f00?v=0.7.2
23676
23743
  */
23677
23744
  class Transfer {
23678
23745
  currentServiceId;
@@ -23684,38 +23751,50 @@ class Transfer {
23684
23751
  },
23685
23752
  }));
23686
23753
  /**
23687
- * `g = 10 + ω9`
23688
- * https://graypaper.fluffylabs.dev/#/7e6ff6a/373d00373d00?v=0.6.7
23754
+ * `g = 10 + t`
23755
+ *
23756
+ * `t` has positive value, only when status of a transfer is `OK`
23757
+ * `0` otherwise
23758
+ *
23759
+ * Pre0.7.2: `g = 10 + ω9`
23760
+ *
23761
+ * https://graypaper.fluffylabs.dev/#/ab2cdbd/373f00373f00?v=0.7.2
23689
23762
  */
23690
- gasCost = (regs) => {
23691
- const gas = 10n + regs.get(ON_TRANSFER_GAS_REG);
23692
- return gas_tryAsGas(gas);
23693
- };
23694
- tracedRegisters = host_call_handler_traceRegisters(transfer_IN_OUT_REG, AMOUNT_REG, ON_TRANSFER_GAS_REG, MEMO_START_REG);
23763
+ basicGasCost = compatibility_Compatibility.isGreaterOrEqual(compatibility_GpVersion.V0_7_2)
23764
+ ? gas_tryAsSmallGas(10)
23765
+ : (regs) => gas_tryAsGas(10n + regs.get(TRANSFER_GAS_FEE_REG));
23766
+ tracedRegisters = host_call_handler_traceRegisters(transfer_IN_OUT_REG, AMOUNT_REG, TRANSFER_GAS_FEE_REG, MEMO_START_REG);
23695
23767
  constructor(currentServiceId, partialState) {
23696
23768
  this.currentServiceId = currentServiceId;
23697
23769
  this.partialState = partialState;
23698
23770
  }
23699
- async execute(_gas, regs, memory) {
23771
+ async execute(gas, regs, memory) {
23700
23772
  // `d`: destination
23701
23773
  const destination = getServiceId(regs.get(transfer_IN_OUT_REG));
23702
23774
  // `a`: amount
23703
23775
  const amount = regs.get(AMOUNT_REG);
23704
23776
  // `l`: gas
23705
- const onTransferGas = common_tryAsServiceGas(regs.get(ON_TRANSFER_GAS_REG));
23777
+ const transferGasFee = common_tryAsServiceGas(regs.get(TRANSFER_GAS_FEE_REG));
23706
23778
  // `o`: transfer memo
23707
23779
  const memoStart = regs.get(MEMO_START_REG);
23708
23780
  const memo = bytes_Bytes.zero(TRANSFER_MEMO_BYTES);
23709
23781
  const memoryReadResult = memory.loadInto(memo.raw, memoStart);
23710
23782
  // page fault while reading the memory.
23711
23783
  if (memoryReadResult.isError) {
23712
- logger_logger.trace `TRANSFER(${destination}, ${amount}, ${onTransferGas}, ${memo}) <- PANIC`;
23784
+ logger_logger.trace `TRANSFER(${destination}, ${amount}, ${transferGasFee}, ${memo}) <- PANIC`;
23713
23785
  return host_call_handler_PvmExecution.Panic;
23714
23786
  }
23715
- const transferResult = this.partialState.transfer(destination, amount, onTransferGas, memo);
23716
- logger_logger.trace `TRANSFER(${destination}, ${amount}, ${onTransferGas}, ${memo}) <- ${result_resultToString(transferResult)}`;
23787
+ const transferResult = this.partialState.transfer(destination, amount, transferGasFee, memo);
23788
+ logger_logger.trace `TRANSFER(${destination}, ${amount}, ${transferGasFee}, ${memo}) <- ${result_resultToString(transferResult)}`;
23717
23789
  // All good!
23718
23790
  if (transferResult.isOk) {
23791
+ if (compatibility_Compatibility.isGreaterOrEqual(compatibility_GpVersion.V0_7_2)) {
23792
+ // substracting value `t`
23793
+ const underflow = gas.sub(gas_tryAsGas(transferGasFee));
23794
+ if (underflow) {
23795
+ return host_call_handler_PvmExecution.OOG;
23796
+ }
23797
+ }
23719
23798
  regs.set(transfer_IN_OUT_REG, results_HostCallResult.OK);
23720
23799
  return;
23721
23800
  }
@@ -23755,7 +23834,7 @@ class Upgrade {
23755
23834
  currentServiceId;
23756
23835
  partialState;
23757
23836
  index = host_call_handler_tryAsHostCallIndex(19);
23758
- gasCost = gas_tryAsSmallGas(10);
23837
+ basicGasCost = gas_tryAsSmallGas(10);
23759
23838
  tracedRegisters = host_call_handler_traceRegisters(upgrade_IN_OUT_REG, GAS_REG, ALLOWANCE_REG);
23760
23839
  constructor(currentServiceId, partialState) {
23761
23840
  this.currentServiceId = currentServiceId;
@@ -23798,7 +23877,7 @@ class Yield {
23798
23877
  currentServiceId;
23799
23878
  partialState;
23800
23879
  index = host_call_handler_tryAsHostCallIndex(25);
23801
- gasCost = gas_tryAsSmallGas(10);
23880
+ basicGasCost = gas_tryAsSmallGas(10);
23802
23881
  tracedRegisters = host_call_handler_traceRegisters(yield_IN_OUT_REG);
23803
23882
  constructor(currentServiceId, partialState) {
23804
23883
  this.currentServiceId = currentServiceId;
@@ -23834,7 +23913,7 @@ class fetch_Fetch {
23834
23913
  currentServiceId;
23835
23914
  fetch;
23836
23915
  index = tryAsHostCallIndex(1);
23837
- gasCost = tryAsSmallGas(10);
23916
+ basicGasCost = tryAsSmallGas(10);
23838
23917
  tracedRegisters = traceRegisters(fetch_IN_OUT_REG, 8, 9, 10, 11, 12);
23839
23918
  constructor(currentServiceId, fetch) {
23840
23919
  this.currentServiceId = currentServiceId;
@@ -23991,7 +24070,7 @@ class info_Info {
23991
24070
  currentServiceId;
23992
24071
  account;
23993
24072
  index = tryAsHostCallIndex(5);
23994
- gasCost = tryAsSmallGas(10);
24073
+ basicGasCost = tryAsSmallGas(10);
23995
24074
  tracedRegisters = traceRegisters(info_IN_OUT_REG, 8, OFFSET_REG, LEN_REG);
23996
24075
  constructor(currentServiceId, account) {
23997
24076
  this.currentServiceId = currentServiceId;
@@ -24066,7 +24145,7 @@ const decoder = new TextDecoder("utf8");
24066
24145
  class log_LogHostCall {
24067
24146
  currentServiceId;
24068
24147
  index = tryAsHostCallIndex(100);
24069
- gasCost = tryAsSmallGas(0);
24148
+ basicGasCost = tryAsSmallGas(0);
24070
24149
  // intentionally not tracing anything here, since the message will be printed anyway.
24071
24150
  tracedRegisters = traceRegisters();
24072
24151
  constructor(currentServiceId) {
@@ -24108,7 +24187,7 @@ class lookup_Lookup {
24108
24187
  currentServiceId;
24109
24188
  account;
24110
24189
  index = tryAsHostCallIndex(2);
24111
- gasCost = tryAsSmallGas(10);
24190
+ basicGasCost = tryAsSmallGas(10);
24112
24191
  tracedRegisters = traceRegisters(lookup_IN_OUT_REG, 8, 9, 10, 11);
24113
24192
  constructor(currentServiceId, account) {
24114
24193
  this.currentServiceId = currentServiceId;
@@ -24171,7 +24250,7 @@ class read_Read {
24171
24250
  currentServiceId;
24172
24251
  account;
24173
24252
  index = tryAsHostCallIndex(3);
24174
- gasCost = tryAsSmallGas(10);
24253
+ basicGasCost = tryAsSmallGas(10);
24175
24254
  tracedRegisters = traceRegisters(read_IN_OUT_REG, 8, 9, 10, 11, 12);
24176
24255
  constructor(currentServiceId, account) {
24177
24256
  this.currentServiceId = currentServiceId;
@@ -24241,7 +24320,7 @@ class write_Write {
24241
24320
  currentServiceId;
24242
24321
  account;
24243
24322
  index = tryAsHostCallIndex(4);
24244
- gasCost = tryAsSmallGas(10);
24323
+ basicGasCost = tryAsSmallGas(10);
24245
24324
  tracedRegisters = traceRegisters(write_IN_OUT_REG, 8, 9, 10);
24246
24325
  constructor(currentServiceId, account) {
24247
24326
  this.currentServiceId = currentServiceId;
@@ -26185,6 +26264,7 @@ class chain_stf_OnChain {
26185
26264
  authorization;
26186
26265
  // chapter 13: https://graypaper.fluffylabs.dev/#/68eaa1f/18b60118b601?v=0.6.4
26187
26266
  statistics;
26267
+ isReadyForNextEpoch = Promise.resolve(false);
26188
26268
  constructor(chainSpec, state, blocks, hasher) {
26189
26269
  this.chainSpec = chainSpec;
26190
26270
  this.state = state;
@@ -26203,6 +26283,14 @@ class chain_stf_OnChain {
26203
26283
  this.preimages = new Preimages(state);
26204
26284
  this.authorization = new Authorization(chainSpec, state);
26205
26285
  }
26286
+ /** Pre-populate things worth caching for the next epoch. */
26287
+ async prepareForNextEpoch() {
26288
+ if (await this.isReadyForNextEpoch) {
26289
+ return;
26290
+ }
26291
+ const ready = this.safrole.prepareValidatorKeysForNextEpoch(this.state.disputesRecords.punishSet);
26292
+ this.isReadyForNextEpoch = ready.then((_) => true);
26293
+ }
26206
26294
  async verifySeal(timeSlot, block) {
26207
26295
  const sealState = this.safrole.getSafroleSealState(timeSlot);
26208
26296
  return await this.safroleSeal.verifyHeaderSeal(block.header.view(), sealState);
@@ -26211,6 +26299,10 @@ class chain_stf_OnChain {
26211
26299
  const headerView = block.header.view();
26212
26300
  const header = block.header.materialize();
26213
26301
  const timeSlot = header.timeSlotIndex;
26302
+ // reset the epoch cache state
26303
+ if (headerView.epochMarker.view() !== null) {
26304
+ this.isReadyForNextEpoch = Promise.resolve(false);
26305
+ }
26214
26306
  // safrole seal
26215
26307
  let newEntropyHash;
26216
26308
  if (omitSealVerification) {
@@ -27367,6 +27459,9 @@ function toJson(data) {
27367
27459
  if (value instanceof Map) {
27368
27460
  return Object.fromEntries(value.entries());
27369
27461
  }
27462
+ if (value instanceof ObjectView) {
27463
+ return value.materialize();
27464
+ }
27370
27465
  return value;
27371
27466
  }, 2);
27372
27467
  }