@leofcoin/chain 1.10.16 → 1.10.18

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 (31) hide show
  1. package/exports/beacon-envelope.js +6 -6
  2. package/exports/beacon-epoch.js +1 -1
  3. package/exports/beacon-lifecycle.js +1 -1
  4. package/exports/beacon-round.js +1 -1
  5. package/exports/beacon.js +15 -14
  6. package/exports/browser/_commonjsHelpers-B85MJLTf.js +5 -0
  7. package/exports/browser/beacon-envelope.js +61 -150
  8. package/exports/browser/beacon-epoch.js +2 -2
  9. package/exports/browser/beacon-lifecycle.js +3 -3
  10. package/exports/browser/beacon-round.js +2 -2
  11. package/exports/browser/beacon-wire.js +3 -3
  12. package/exports/browser/beacon.js +2483 -1228
  13. package/exports/browser/{browser-CCfR9KOM-CvhDZrGu.js → browser-CCfR9KOM-CpStHgTj.js} +4 -4
  14. package/exports/browser/{browser-crypto-CeE-yId5.js → browser-crypto-CH0ua22L.js} +1 -1
  15. package/exports/browser/chain.js +151 -81
  16. package/exports/browser/{client-CAC7RVMf-Dmz_2A_5.js → client-C_pBoi1g-_pfKzCvX.js} +256 -80
  17. package/exports/browser/{connection-monitor-Cmv00mwl.js → connection-monitor-D-krNiRH.js} +1 -1
  18. package/exports/browser/{hkdf-CnZvwpZ9.js → hkdf-BUHINPFj.js} +2 -94
  19. package/exports/browser/{index-BC-KRBgE.js → index-DmuI-29u.js} +1 -1
  20. package/exports/browser/{index-dTQVgkpf-CuHJWO2l.js → index-dTQVgkpf-BbdshWB0.js} +4 -4
  21. package/exports/browser/index.browser-CFfJpgKV.js +857 -0
  22. package/exports/browser/{messages-Dw86z0zq-DrPw_nlZ.js → messages-BGHaihSi-eHZVl0y9.js} +4 -4
  23. package/exports/browser/{node-browser-DWSdi-XP.js → node-browser-BNe-en1l.js} +5 -5
  24. package/exports/browser/node-browser.js +4 -4
  25. package/exports/browser/{sha2-piimb6xL.js → sha2-BKcEJzgd.js} +144 -3
  26. package/exports/browser/weierstrass-BVfhtHbl.js +3596 -0
  27. package/exports/browser/workers/machine-worker.js +61 -19
  28. package/exports/chain.js +146 -73
  29. package/exports/workers/machine-worker.js +61 -19
  30. package/package.json +14 -13
  31. package/exports/browser/weierstrass-Q0QND1ZT.js +0 -2156
@@ -1,8 +1,8 @@
1
- import { g as getDefaultExportFromCjs } from './node-browser-DWSdi-XP.js';
2
- import './browser-crypto-CeE-yId5.js';
1
+ import { g as getDefaultExportFromCjs } from './node-browser-BNe-en1l.js';
2
+ import './browser-crypto-CH0ua22L.js';
3
3
  import './index-CvKt4UDE.js';
4
- import './sha2-piimb6xL.js';
5
- import './connection-monitor-Cmv00mwl.js';
4
+ import './sha2-BKcEJzgd.js';
5
+ import './connection-monitor-D-krNiRH.js';
6
6
 
7
7
  function _mergeNamespaces$1(n, m) {
8
8
  m.forEach(function (e) {
@@ -1,5 +1,5 @@
1
1
  import { a as index$3, b as base58$1, i as index$4, f as fromBase58, c as fromHex, d as fromArrayLike, e as toBase32, t as toBase58, g as toHex } from './index-CvKt4UDE.js';
2
- import { s as sha256 } from './sha2-piimb6xL.js';
2
+ import { s as sha256 } from './sha2-BKcEJzgd.js';
3
3
 
4
4
  var isHex = string => /^[A-F0-9]+$/i.test(
5
5
  string.startsWith('0x') ?
@@ -1,9 +1,10 @@
1
- import { F as FormatInterface, p as proto, a as proto$1, b as proto$2, T as TransactionMessage, j as jsonStringifyBigInt, c as jsonParseBigInt, C as ContractMessage, d as Codec } from './browser-crypto-CeE-yId5.js';
2
- import { B as BlockMessage, L as LastBlockMessage, P as PROTOCOL_VERSION, R as REACHED_ONE_ZERO_ZERO, C as ConnectionMonitor, a as BWMessage, S as StateMessage } from './connection-monitor-Cmv00mwl.js';
3
- import { M as MAX_TRANSACTION_BYTES, a as MAX_BLOCK_TRANSACTION_BYTES, b as MAX_BLOCK_TRANSACTIONS, c as MultiWallet, d as createTransactionHash, e as calculateFee, f as createContractMessage, s as signTransaction, r as randombytes, g as distributeTransactionFee, h as supportsTransactionFees, i as supportsMonetaryPolicy, v as validateBlockResourceLimits, j as calculateMonetaryPolicy, k as distributeAmount, l as aggregateValidatorFees, m as MONETARY_POLICY_AUTHORITY, n as contractFactoryMessage, o as nativeTokenMessage, p as validatorsMessage, q as nameServiceMessage, t as parseUnits, u as formatUnits } from './index-BC-KRBgE.js';
1
+ import { F as FormatInterface, p as proto, a as proto$1, b as proto$2, T as TransactionMessage, j as jsonStringifyBigInt, c as jsonParseBigInt, C as ContractMessage, d as Codec } from './browser-crypto-CH0ua22L.js';
2
+ import { B as BlockMessage, L as LastBlockMessage, P as PROTOCOL_VERSION, R as REACHED_ONE_ZERO_ZERO, C as ConnectionMonitor, a as BWMessage, S as StateMessage } from './connection-monitor-D-krNiRH.js';
3
+ import { M as MAX_TRANSACTION_BYTES, a as MAX_BLOCK_TRANSACTION_BYTES, b as MAX_BLOCK_TRANSACTIONS, c as MultiWallet, d as createTransactionHash, e as calculateFee, f as createContractMessage, s as signTransaction, r as randombytes, g as distributeTransactionFee, h as supportsTransactionFees, i as supportsMonetaryPolicy, v as validateBlockResourceLimits, j as calculateMonetaryPolicy, k as distributeAmount, l as aggregateValidatorFees, m as MONETARY_POLICY_AUTHORITY, n as contractFactoryMessage, o as nativeTokenMessage, p as validatorsMessage, q as nameServiceMessage, t as parseUnits, u as formatUnits } from './index-DmuI-29u.js';
4
4
  import { f as fromBase58 } from './index-CvKt4UDE.js';
5
+ import { g as getDefaultExportFromCjs } from './_commonjsHelpers-B85MJLTf.js';
5
6
  import { q as quorumThreshold } from './quorum-S_qdgiAY.js';
6
- import './sha2-piimb6xL.js';
7
+ import './sha2-BKcEJzgd.js';
7
8
 
8
9
  const getTargets = () => Array.from([]);
9
10
  const isEnabled = (target) => {
@@ -98,10 +99,6 @@ var addresses = {
98
99
  validators
99
100
  };
100
101
 
101
- function getDefaultExportFromCjs (x) {
102
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
103
- }
104
-
105
102
  var re = {exports: {}};
106
103
 
107
104
  var constants;
@@ -3699,6 +3696,12 @@ class Machine {
3699
3696
  pubsub.publish(data.id, { error: data.message });
3700
3697
  break;
3701
3698
  }
3699
+ case "addLoadedBlockError":
3700
+ case "collectFeeError":
3701
+ case "settleRewardsError": {
3702
+ pubsub.publish(data.id, { error: new Error(data.message) });
3703
+ break;
3704
+ }
3702
3705
  case "debug": {
3703
3706
  if (data.message.includes("loaded transactions for block:")) {
3704
3707
  pubsub.publish("block-loaded", data.message.replace("loaded transactions for block: ", "").split(" @")[0]);
@@ -3748,9 +3751,9 @@ class Machine {
3748
3751
  }
3749
3752
  }
3750
3753
  }
3751
- async updateState() {
3754
+ async updateState(strict = false) {
3752
3755
  try {
3753
- const lastBlock = await this.lastBlock;
3756
+ const lastBlock = strict ? await this.getCanonicalTip() : await this.lastBlock;
3754
3757
  const lastBlockIndex = Number(lastBlock.index);
3755
3758
  const statesLastBlockIndex = Number(this.states.lastBlock.index);
3756
3759
  if (lastBlockIndex > statesLastBlockIndex || lastBlock.hash !== this.states.lastBlock.hash && Number(lastBlockIndex) === 0) {
@@ -3809,7 +3812,7 @@ class Machine {
3809
3812
  return JSON.stringify(sorted, replacer);
3810
3813
  };
3811
3814
  const tasks = [
3812
- stateStore.put("lastBlock", sortedStringify(await this.lastBlock, jsonStringifyBigInt)),
3815
+ stateStore.put("lastBlock", sortedStringify(lastBlock, jsonStringifyBigInt)),
3813
3816
  stateStore.put("states", sortedStringify(state, jsonStringifyBigInt)),
3814
3817
  stateStore.put("accounts", sortedStringify(accounts, jsonStringifyBigInt)),
3815
3818
  stateStore.put(
@@ -3836,6 +3839,7 @@ class Machine {
3836
3839
  }
3837
3840
  } catch (error) {
3838
3841
  console.error(error);
3842
+ if (strict) throw error;
3839
3843
  }
3840
3844
  }
3841
3845
  async #init(blocks) {
@@ -4102,6 +4106,9 @@ ${error.message}`);
4102
4106
  return this.states.lastBlock;
4103
4107
  });
4104
4108
  }
4109
+ getCanonicalTip() {
4110
+ return this.#askWorker("lastBlock");
4111
+ }
4105
4112
  get lastBlockHeight() {
4106
4113
  return this.#askWorker("lastBlockHeight").catch((error) => {
4107
4114
  debug$2("lastBlockHeight fallback after worker timeout:", error?.message ?? error);
@@ -4246,6 +4253,56 @@ const decodeResponsePayload = async (result, depth = 0) => {
4246
4253
  return result;
4247
4254
  };
4248
4255
 
4256
+ class CanonicalStateQueue {
4257
+ #tail = Promise.resolve();
4258
+ #failed = false;
4259
+ #failure;
4260
+ run(operation) {
4261
+ const result = this.#tail.then(async () => {
4262
+ if (this.#failed) {
4263
+ throw new Error("Canonical state application halted after a failed mutation; restart and recover state", {
4264
+ cause: this.#failure
4265
+ });
4266
+ }
4267
+ let mutating = false;
4268
+ try {
4269
+ return await operation({ markMutating: () => {
4270
+ mutating = true;
4271
+ } });
4272
+ } catch (error) {
4273
+ if (mutating) {
4274
+ this.#failed = true;
4275
+ this.#failure = error;
4276
+ }
4277
+ throw error;
4278
+ }
4279
+ });
4280
+ this.#tail = result.then(() => void 0, () => void 0);
4281
+ return result;
4282
+ }
4283
+ }
4284
+
4285
+ const validateChainLink = (localTip, incoming) => {
4286
+ const localHash = localTip?.hash || "0x0";
4287
+ const localIndex = Number(localTip?.index ?? -1);
4288
+ const hasCanonicalTip = localHash !== "0x0";
4289
+ if (hasCanonicalTip && incoming.index < localIndex) return "stale";
4290
+ if (hasCanonicalTip && incoming.index === localIndex) {
4291
+ if (incoming.hash === localHash) return "duplicate";
4292
+ throw new Error(`Block conflict detected at index ${incoming.index}`);
4293
+ }
4294
+ const expectedIndex = hasCanonicalTip ? localIndex + 1 : 0;
4295
+ if (incoming.index !== expectedIndex) {
4296
+ throw new Error(`Unexpected block index ${incoming.index}; expected ${expectedIndex}`);
4297
+ }
4298
+ if (incoming.previousHash !== localHash) {
4299
+ throw new Error(
4300
+ `previousHash mismatch at index ${incoming.index}: expected ${localHash}, got ${incoming.previousHash}`
4301
+ );
4302
+ }
4303
+ return "append";
4304
+ };
4305
+
4249
4306
  const debug$1 = createDebugger("leofcoin/state");
4250
4307
  class State extends Contract {
4251
4308
  constructor(config) {
@@ -4260,6 +4317,7 @@ class State extends Contract {
4260
4317
  this.#blocks = [];
4261
4318
  this.knownBlocks = [];
4262
4319
  this.#totalSize = 0;
4320
+ this.#canonicalStateQueue = new CanonicalStateQueue();
4263
4321
  this.#loaded = false;
4264
4322
  this.#resolvingHashes = /* @__PURE__ */ new Set();
4265
4323
  this._wantList = [];
@@ -4302,6 +4360,13 @@ class State extends Contract {
4302
4360
  #blocks;
4303
4361
  #totalSize;
4304
4362
  #machine;
4363
+ #canonicalStateQueue;
4364
+ withCanonicalState(operation) {
4365
+ return this.#canonicalStateQueue.run(operation);
4366
+ }
4367
+ canonicalTip() {
4368
+ return this.#machine ? this.#machine.getCanonicalTip() : Promise.resolve({ index: -1, hash: "0x0", previousHash: "0x0" });
4369
+ }
4305
4370
  #loaded;
4306
4371
  #resolvingHashes;
4307
4372
  /**
@@ -4454,7 +4519,7 @@ class State extends Contract {
4454
4519
  this.#machine = machine;
4455
4520
  const lastBlock = await this.#machine.lastBlock;
4456
4521
  if (lastBlock.hash !== "0x0") {
4457
- this.updateState(new BlockMessage(lastBlock));
4522
+ await this.updateState(new BlockMessage(lastBlock));
4458
4523
  }
4459
4524
  this.#loaded = true;
4460
4525
  this.#chainState = "loaded";
@@ -4477,9 +4542,10 @@ class State extends Contract {
4477
4542
  await machine.ready;
4478
4543
  this.#machine = machine;
4479
4544
  }
4480
- await this.#machine.updateState();
4545
+ await this.#machine.updateState(true);
4481
4546
  } catch (error) {
4482
4547
  console.error(error);
4548
+ throw error;
4483
4549
  }
4484
4550
  }
4485
4551
  getLatestBlock() {
@@ -4668,11 +4734,16 @@ class State extends Contract {
4668
4734
  console.error(error);
4669
4735
  }
4670
4736
  if (!lastBlock) lastBlock = await this.#getLatestBlock();
4671
- if (globalThis.peernet.peers.length === 0) return "connectionless";
4737
+ if (globalThis.peernet.peers.length === 0) {
4738
+ this.#chainSyncing = false;
4739
+ this.#syncState = "connectionless";
4740
+ return this.#syncState;
4741
+ }
4672
4742
  try {
4673
- await this.#syncChain(lastBlock);
4743
+ await this.withCanonicalState((transition) => this.#syncChain(lastBlock, transition));
4674
4744
  } catch (error) {
4675
4745
  this.#syncErrorCount += 1;
4746
+ this.#chainSyncing = false;
4676
4747
  if (this.#syncErrorCount < 3) return this.syncChain(lastBlock);
4677
4748
  this.#syncErrorCount = 0;
4678
4749
  this.#chainSyncing = false;
@@ -4686,9 +4757,9 @@ class State extends Contract {
4686
4757
  this.#syncState = "synced";
4687
4758
  return this.#syncState;
4688
4759
  }
4689
- async #syncChain(lastBlock) {
4760
+ async #syncChain(lastBlock, transition) {
4690
4761
  try {
4691
- const localBlock = await this.lastBlock;
4762
+ const localBlock = await this.canonicalTip();
4692
4763
  const localIndex = localBlock ? Number(localBlock.index) : -1;
4693
4764
  const remoteIndex = Number(lastBlock.index);
4694
4765
  const remoteBlockHash = lastBlock.hash;
@@ -4710,6 +4781,9 @@ class State extends Contract {
4710
4781
  debug$1(`Remote block hash is 0x0, skipping sync`);
4711
4782
  return;
4712
4783
  }
4784
+ if (localBlock?.hash !== "0x0" && localIndex === remoteIndex && localBlock.hash !== remoteBlockHash) {
4785
+ throw new Error(`Block conflict detected at index ${remoteIndex}`);
4786
+ }
4713
4787
  if (localIndex > remoteIndex) {
4714
4788
  const MAX_REORG_DEPTH = 6;
4715
4789
  const reorgDepth = localIndex - remoteIndex;
@@ -4749,9 +4823,14 @@ class State extends Contract {
4749
4823
  debug$1(`Loading blocks from index ${localIndex + 1} to ${remoteIndex}`);
4750
4824
  const start = localIndex + 1;
4751
4825
  if (this.#machine && blocks.length > start) {
4752
- await this.#loadBlocks(blocks.slice(start));
4826
+ await this.#loadBlocks(blocks.slice(start), transition);
4753
4827
  }
4754
4828
  if (blocks.length > 0) {
4829
+ const appliedTip = await this.canonicalTip();
4830
+ if (appliedTip.hash !== remoteBlockHash || Number(appliedTip.index) !== remoteIndex) {
4831
+ throw new Error(`Sync did not apply canonical target ${remoteBlockHash} at index ${remoteIndex}`);
4832
+ }
4833
+ transition.markMutating();
4755
4834
  await this.updateState(new BlockMessage(blocks[blocks.length - 1]));
4756
4835
  }
4757
4836
  } else {
@@ -4871,14 +4950,14 @@ class State extends Contract {
4871
4950
  console.log(error);
4872
4951
  }
4873
4952
  console.log(error);
4874
- return false;
4953
+ throw error;
4875
4954
  }
4876
4955
  }
4877
4956
  /**
4878
4957
  *
4879
4958
  * @param {Block[]} blocks
4880
4959
  */
4881
- async #loadBlocks(blocks) {
4960
+ async #loadBlocks(blocks, transition) {
4882
4961
  this.#chainState = "loading";
4883
4962
  if (blocks.some((block) => !block)) {
4884
4963
  throw new Error("missing block data during load; chain resolution incomplete");
@@ -4889,10 +4968,21 @@ class State extends Contract {
4889
4968
  for (const block of blocks) {
4890
4969
  if (block && !block.loaded) {
4891
4970
  try {
4971
+ const link = validateChainLink(await this.canonicalTip(), {
4972
+ index: Number(block.index),
4973
+ hash: block.hash,
4974
+ previousHash: String(block.previousHash)
4975
+ });
4976
+ if (link !== "append") {
4977
+ this.#blocks[block.index].loaded = true;
4978
+ debug$1(`Ignoring ${link} loaded block ${block.hash} at height ${block.index}`);
4979
+ continue;
4980
+ }
4892
4981
  debug$1(`loading block: ${Number(block.index)} ${block.hash}`);
4893
4982
  let transactions = await this.#loadBlockTransactions(block.transactions || []);
4894
4983
  const validators = block.validators.map(({ address }) => address);
4895
4984
  debug$1(`loading transactions: ${transactions.length} for block ${block.index}`);
4985
+ transition.markMutating();
4896
4986
  for (const transaction of transactions) {
4897
4987
  const hash = await transaction.hash();
4898
4988
  if (poolTransactionKeys.has(hash)) await globalThis.transactionPoolStore.delete(hash);
@@ -4925,10 +5015,11 @@ class State extends Contract {
4925
5015
  ...distributeAmount(policy.subsidy, validators, Number(block.index) % validators.length)
4926
5016
  ]);
4927
5017
  }
4928
- this.#blocks[block.index].loaded = true;
4929
5018
  debug$1(`executed transactions for block ${block.index}`);
5019
+ const registered = await this.#machine.addLoadedBlock({ ...block, loaded: true });
5020
+ if (registered !== true) throw new Error(`Loaded block registration failed after execution: ${block.hash}`);
5021
+ this.#blocks[block.index].loaded = true;
4930
5022
  if (Number(block.index) === 0) this.#loaded = true;
4931
- await this.#machine.addLoadedBlock(block);
4932
5023
  debug$1(`loaded block: ${block.hash} @${Number(block.index)}`);
4933
5024
  globalThis.pubsub.publish("block-loaded", { ...block });
4934
5025
  } catch (error) {
@@ -4936,6 +5027,7 @@ class State extends Contract {
4936
5027
  for (const transaction of block.transactions) {
4937
5028
  this.wantList.push(transaction);
4938
5029
  }
5030
+ throw error;
4939
5031
  }
4940
5032
  }
4941
5033
  }
@@ -5049,27 +5141,6 @@ class VersionControl extends State {
5049
5141
  }
5050
5142
  }
5051
5143
 
5052
- const validateChainLink = (localTip, incoming) => {
5053
- const localHash = localTip?.hash || "0x0";
5054
- const localIndex = Number(localTip?.index ?? -1);
5055
- const hasCanonicalTip = localHash !== "0x0";
5056
- if (hasCanonicalTip && incoming.index < localIndex) return "stale";
5057
- if (hasCanonicalTip && incoming.index === localIndex) {
5058
- if (incoming.hash === localHash) return "duplicate";
5059
- throw new Error(`Block conflict detected at index ${incoming.index}`);
5060
- }
5061
- const expectedIndex = hasCanonicalTip ? localIndex + 1 : 0;
5062
- if (incoming.index !== expectedIndex) {
5063
- throw new Error(`Unexpected block index ${incoming.index}; expected ${expectedIndex}`);
5064
- }
5065
- if (incoming.previousHash !== localHash) {
5066
- throw new Error(
5067
- `previousHash mismatch at index ${incoming.index}: expected ${localHash}, got ${incoming.previousHash}`
5068
- );
5069
- }
5070
- return "append";
5071
- };
5072
-
5073
5144
  const validateCanonicalValidatorSet = (blockIndex, expectedValidators, validators) => {
5074
5145
  const actualValidators = validators.map(({ address }) => address);
5075
5146
  const canonicalExpected = [...new Set(expectedValidators)].sort();
@@ -5645,7 +5716,9 @@ class Chain extends VersionControl {
5645
5716
  `[consensus] Epoch boundary at block ${blockHeight}: new epoch starts at height ${this.#currentEpochStartHeight}`
5646
5717
  );
5647
5718
  if (this.#participating && !this.#runningEpoch) {
5648
- await this.#runEpoch();
5719
+ void this.#runEpoch().catch((error) => {
5720
+ debug(`epoch scheduling failed: ${error?.message ?? error}`);
5721
+ });
5649
5722
  }
5650
5723
  }
5651
5724
  async #runEpoch() {
@@ -6114,11 +6187,14 @@ class Chain extends VersionControl {
6114
6187
  }
6115
6188
  }
6116
6189
  async #addBlock(block) {
6190
+ return this.withCanonicalState((transition) => this.#applyBlock(block, transition));
6191
+ }
6192
+ async #applyBlock(block, transition) {
6117
6193
  const receivedEncoded = block instanceof BlockMessage ? block.encoded : block;
6118
6194
  const blockMessage = await new BlockMessage(block);
6119
6195
  const hash = await blockMessage.hash();
6120
6196
  const blockIndex = Number(blockMessage.decoded.index);
6121
- const linkResult = validateChainLink(await this.lastBlock, {
6197
+ const linkResult = validateChainLink(await this.canonicalTip(), {
6122
6198
  index: blockIndex,
6123
6199
  hash,
6124
6200
  previousHash: String(blockMessage.decoded.previousHash)
@@ -6147,6 +6223,7 @@ class Chain extends VersionControl {
6147
6223
  console.log(`[chain] \u2705 Block data integrity verified: ${hash}`);
6148
6224
  await this.#validateBlockValidators(blockMessage);
6149
6225
  const transactions = await this.#resolveBlockTransactions(blockMessage);
6226
+ transition.markMutating();
6150
6227
  await Promise.all(
6151
6228
  blockMessage.decoded.transactions.map(async (transactionHash) => {
6152
6229
  if (await transactionPoolStore.has(transactionHash)) await transactionPoolStore.delete(transactionHash);
@@ -6157,9 +6234,6 @@ class Chain extends VersionControl {
6157
6234
  hash,
6158
6235
  ...blockMessage.decoded
6159
6236
  };
6160
- debug(`added block: ${hash}`);
6161
- let promises = [];
6162
- let contracts = [];
6163
6237
  const allTransactions = transactions.sort((a, b) => {
6164
6238
  if (a.decoded.priority !== b.decoded.priority) {
6165
6239
  return (b.decoded.priority ? 1 : 0) - (a.decoded.priority ? 1 : 0);
@@ -6170,7 +6244,6 @@ class Chain extends VersionControl {
6170
6244
  });
6171
6245
  const monetaryPolicy = await this.#monetaryPolicy(blockMessage.decoded.protocolVersion);
6172
6246
  for (const transaction of allTransactions) {
6173
- if (!contracts.includes(transaction.decoded.to)) contracts.push(transaction.decoded.to);
6174
6247
  this.removePendingNonce(transaction.decoded.from, transaction.decoded.nonce);
6175
6248
  const transactionHash = await transaction.hash();
6176
6249
  const validatorAddresses = blockMessage.decoded.validators.map(({ address }) => address);
@@ -6188,36 +6261,36 @@ class Chain extends VersionControl {
6188
6261
  ...distributeAmount(monetaryPolicy.subsidy, validators, blockIndex % validators.length)
6189
6262
  ]);
6190
6263
  }
6191
- try {
6192
- promises = await Promise.allSettled(promises);
6193
- const noncesByAddress = {};
6194
- for (let transaction of transactions) {
6195
- globalThis.pubsub.publish("transaction-processed", transaction.encoded);
6196
- if (transaction.decoded.to === globalThis.peernet.selectedAccount)
6197
- globalThis.pubsub.publish("account-transaction-processed", transaction.encoded);
6198
- if (!noncesByAddress[transaction.decoded.from] || noncesByAddress?.[transaction.decoded.from] < transaction.decoded.nonce) {
6199
- noncesByAddress[transaction.decoded.from] = transaction.decoded.nonce;
6200
- }
6201
- }
6202
- await Promise.all(
6203
- Object.entries(noncesByAddress).map(([from, nonce]) => globalThis.accountsStore.put(from, String(nonce)))
6204
- );
6205
- if ((await this.lastBlock).index < Number(blockMessage.decoded.index)) {
6206
- await this.machine.addLoadedBlock({ ...blockMessage.decoded, loaded: true, hash: await blockMessage.hash() });
6207
- try {
6208
- await this.call(addresses.validators, "recordValidatorSnapshot", [blockMessage.decoded.index]);
6209
- } catch (snapshotError) {
6210
- debug(`failed to record validator snapshot: ${snapshotError?.message ?? snapshotError}`);
6211
- }
6212
- await this.#handleEpochBoundary(Number(blockMessage.decoded.index));
6213
- await this.updateState(blockMessage);
6264
+ const noncesByAddress = {};
6265
+ for (let transaction of transactions) {
6266
+ globalThis.pubsub.publish("transaction-processed", transaction.encoded);
6267
+ if (transaction.decoded.to === globalThis.peernet.selectedAccount)
6268
+ globalThis.pubsub.publish("account-transaction-processed", transaction.encoded);
6269
+ if (!noncesByAddress[transaction.decoded.from] || noncesByAddress?.[transaction.decoded.from] < transaction.decoded.nonce) {
6270
+ noncesByAddress[transaction.decoded.from] = transaction.decoded.nonce;
6214
6271
  }
6215
- globalThis.pubsub.publish("block-processed", blockMessage.decoded);
6216
- } catch (error) {
6217
- console.log(error.hash);
6218
- console.log("errrrr");
6219
- await transactionPoolStore.delete(error.hash);
6220
6272
  }
6273
+ await Promise.all(
6274
+ Object.entries(noncesByAddress).map(([from, nonce]) => globalThis.accountsStore.put(from, String(nonce)))
6275
+ );
6276
+ if (validateChainLink(await this.canonicalTip(), {
6277
+ index: blockIndex,
6278
+ hash,
6279
+ previousHash: String(blockMessage.decoded.previousHash)
6280
+ }) !== "append") {
6281
+ throw new Error(`Canonical tip changed during block application: ${hash}`);
6282
+ }
6283
+ const registered = await this.machine.addLoadedBlock({ ...blockMessage.decoded, loaded: true, hash });
6284
+ if (registered !== true) throw new Error(`Block registration failed after execution: ${hash}`);
6285
+ try {
6286
+ await this.call(addresses.validators, "recordValidatorSnapshot", [blockMessage.decoded.index]);
6287
+ } catch (snapshotError) {
6288
+ debug(`failed to record validator snapshot: ${snapshotError?.message ?? snapshotError}`);
6289
+ }
6290
+ await this.updateState(blockMessage);
6291
+ debug(`added block: ${hash}`);
6292
+ globalThis.pubsub.publish("block-processed", blockMessage.decoded);
6293
+ await this.#handleEpochBoundary(blockIndex);
6221
6294
  }
6222
6295
  async participate(address) {
6223
6296
  try {
@@ -6281,10 +6354,6 @@ class Chain extends VersionControl {
6281
6354
  executionTimestamp: block?.timestamp ?? transaction.decoded.timestamp,
6282
6355
  feePayments
6283
6356
  });
6284
- if (block) {
6285
- block.transactions.push(hash);
6286
- block.fees = block.fees += await calculateFee(transaction.decoded);
6287
- }
6288
6357
  await globalThis.accountsStore.put(
6289
6358
  transaction.decoded.from,
6290
6359
  new TextEncoder().encode(String(transaction.decoded.nonce))
@@ -6296,6 +6365,7 @@ class Chain extends VersionControl {
6296
6365
  console.log(hash);
6297
6366
  peernet.publish("invalid-transaction", hash);
6298
6367
  await globalThis.transactionPoolStore.delete(e.hash);
6368
+ if (block) throw e;
6299
6369
  }
6300
6370
  }
6301
6371
  // todo filter tx that need to wait on prev nonce