@keetanetwork/keetanet-client 0.14.9 → 0.14.11

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 (108) hide show
  1. package/client/index-browser.js +251 -81
  2. package/client/index.js +234 -76
  3. package/docs/assets/hierarchy.js +1 -1
  4. package/docs/assets/navigation.js +1 -1
  5. package/docs/assets/search.js +1 -1
  6. package/docs/classes/KeetaNetSDK.Referenced.BaseSet.html +1 -1
  7. package/docs/classes/KeetaNetSDK.Referenced.BaseVoteBuilder.html +1 -1
  8. package/docs/classes/KeetaNetSDK.Referenced.BlockOperation.html +1 -1
  9. package/docs/classes/KeetaNetSDK.Referenced.BlockOperationCREATE_IDENTIFIER.html +1 -1
  10. package/docs/classes/KeetaNetSDK.Referenced.BlockOperationMANAGE_CERTIFICATE.html +1 -1
  11. package/docs/classes/KeetaNetSDK.Referenced.BlockOperationMODIFY_PERMISSIONS.html +1 -1
  12. package/docs/classes/KeetaNetSDK.Referenced.BlockOperationRECEIVE.html +1 -1
  13. package/docs/classes/KeetaNetSDK.Referenced.BlockOperationSEND.html +1 -1
  14. package/docs/classes/KeetaNetSDK.Referenced.BlockOperationSET_INFO.html +1 -1
  15. package/docs/classes/KeetaNetSDK.Referenced.BlockOperationSET_REP.html +1 -1
  16. package/docs/classes/KeetaNetSDK.Referenced.BlockOperationTOKEN_ADMIN_MODIFY_BALANCE.html +1 -1
  17. package/docs/classes/KeetaNetSDK.Referenced.BlockOperationTOKEN_ADMIN_SUPPLY.html +1 -1
  18. package/docs/classes/KeetaNetSDK.Referenced.ECDSAKeyPair.html +1 -1
  19. package/docs/classes/KeetaNetSDK.Referenced.ECDSASECP256K1KeyPair.html +1 -1
  20. package/docs/classes/KeetaNetSDK.Referenced.ECDSASECP256K1PrivateKey.html +1 -1
  21. package/docs/classes/KeetaNetSDK.Referenced.ECDSASECP256K1PublicKey.html +1 -1
  22. package/docs/classes/KeetaNetSDK.Referenced.ECDSASECP256K1Signature.html +1 -1
  23. package/docs/classes/KeetaNetSDK.Referenced.ECDSASECP256R1KeyPair.html +1 -1
  24. package/docs/classes/KeetaNetSDK.Referenced.ECDSASECP256R1PrivateKey.html +1 -1
  25. package/docs/classes/KeetaNetSDK.Referenced.ECDSASECP256R1PublicKey.html +1 -1
  26. package/docs/classes/KeetaNetSDK.Referenced.ECDSASECP256R1Signature.html +1 -1
  27. package/docs/classes/KeetaNetSDK.Referenced.ED25519KeyPair.html +1 -1
  28. package/docs/classes/KeetaNetSDK.Referenced.ED25519PrivateKey.html +1 -1
  29. package/docs/classes/KeetaNetSDK.Referenced.ED25519PublicKey.html +1 -1
  30. package/docs/classes/KeetaNetSDK.Referenced.ED25519Signature.html +1 -1
  31. package/docs/classes/KeetaNetSDK.Referenced.ExternalKeyPair.html +1 -1
  32. package/docs/classes/KeetaNetSDK.Referenced.ExternalSet.html +1 -1
  33. package/docs/classes/KeetaNetSDK.Referenced.IdempotentKey.html +1 -1
  34. package/docs/classes/KeetaNetSDK.Referenced.IdentifierKey.html +1 -1
  35. package/docs/classes/KeetaNetSDK.Referenced.IdentifierKeyPair.html +1 -1
  36. package/docs/classes/KeetaNetSDK.Referenced.KeetaNetError.html +1 -1
  37. package/docs/classes/KeetaNetSDK.Referenced.KeetaNetErrorBase.html +1 -1
  38. package/docs/classes/KeetaNetSDK.Referenced.KeetaNetLedgerError.html +2 -2
  39. package/docs/classes/KeetaNetSDK.Referenced.KeetaNetLedgerIdempotentKeyError.html +1 -1
  40. package/docs/classes/KeetaNetSDK.Referenced.KeetaNetLedgerVoteError.html +1 -1
  41. package/docs/classes/KeetaNetSDK.Referenced.KeyInterface.html +1 -1
  42. package/docs/classes/KeetaNetSDK.Referenced.KeyStorage.html +1 -1
  43. package/docs/classes/KeetaNetSDK.Referenced.PermissionSetHolder.html +1 -1
  44. package/docs/classes/KeetaNetSDK.Referenced.PossiblyExpiredVote.html +1 -1
  45. package/docs/classes/KeetaNetSDK.Referenced.SignatureStorage.html +1 -1
  46. package/docs/classes/KeetaNetSDK.Referenced.StatsPending.html +1 -1
  47. package/docs/classes/KeetaNetSDK.Referenced.VoteBlockBundle.html +1 -1
  48. package/docs/classes/KeetaNetSDK.Referenced.VoteBuilder.html +1 -1
  49. package/docs/classes/KeetaNetSDK.Referenced.VoteHash.html +1 -1
  50. package/docs/classes/KeetaNetSDK.Referenced.VoteLikeBase.html +1 -1
  51. package/docs/classes/KeetaNetSDK.Referenced.VoteQuoteBuilder.html +1 -1
  52. package/docs/classes/KeetaNetSDK.Referenced.VoteStapleHash.html +1 -1
  53. package/docs/hierarchy.html +1 -1
  54. package/docs/interfaces/KeetaNetSDK.Referenced.ACLEntry.html +1 -1
  55. package/docs/interfaces/KeetaNetSDK.Referenced.ACLUpdate.html +1 -1
  56. package/docs/interfaces/KeetaNetSDK.Referenced.ASN1ExplicitContextTag.html +1 -1
  57. package/docs/interfaces/KeetaNetSDK.Referenced.ASN1ImplicitContextTag.html +1 -1
  58. package/docs/interfaces/KeetaNetSDK.Referenced.ASN1Object.html +1 -1
  59. package/docs/interfaces/KeetaNetSDK.Referenced.BaseExternalKeyPairFunctions.html +1 -1
  60. package/docs/interfaces/KeetaNetSDK.Referenced.BaseGenerationConfig.html +1 -1
  61. package/docs/interfaces/KeetaNetSDK.Referenced.BaseIdentifierCreateArguments.html +1 -1
  62. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperation.html +1 -1
  63. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationCREATE_IDENTIFIER.html +1 -1
  64. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationMANAGE_CERTIFICATE.html +1 -1
  65. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationMANAGE_CERTIFICATESerializable.html +1 -1
  66. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationMODIFY_PERMISSIONS.html +1 -1
  67. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationRECEIVE.html +1 -1
  68. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationSEND.html +1 -1
  69. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationSET_INFO.html +1 -1
  70. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationSET_REP.html +1 -1
  71. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationTOKEN_ADMIN_MODIFY_BALANCE.html +1 -1
  72. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationTOKEN_ADMIN_SUPPLY.html +1 -1
  73. package/docs/interfaces/KeetaNetSDK.Referenced.BlockV1Canonical.html +1 -1
  74. package/docs/interfaces/KeetaNetSDK.Referenced.BlockV2Canonical.html +1 -1
  75. package/docs/interfaces/KeetaNetSDK.Referenced.Constructor.html +1 -1
  76. package/docs/interfaces/KeetaNetSDK.Referenced.DisposableTimingHandle.html +1 -1
  77. package/docs/interfaces/KeetaNetSDK.Referenced.ExternalKeyPairFunctionsNoEncryption.html +1 -1
  78. package/docs/interfaces/KeetaNetSDK.Referenced.ExternalKeyPairFunctionsSupportsEncryption.html +1 -1
  79. package/docs/interfaces/KeetaNetSDK.Referenced.InitialConfigSupply.html +1 -1
  80. package/docs/interfaces/KeetaNetSDK.Referenced.InstanceSet.html +1 -1
  81. package/docs/interfaces/KeetaNetSDK.Referenced.KVGenericOptionsType.html +1 -1
  82. package/docs/interfaces/KeetaNetSDK.Referenced.KVSetOptionsType.html +1 -1
  83. package/docs/interfaces/KeetaNetSDK.Referenced.ModifyTokenBalanceEntry.html +1 -1
  84. package/docs/interfaces/KeetaNetSDK.Referenced.MultiSigIdentifierCreateArguments.html +1 -1
  85. package/docs/interfaces/KeetaNetSDK.Referenced.MultisigConfig.html +1 -1
  86. package/docs/interfaces/KeetaNetSDK.Referenced.NumericValueEntry.html +1 -1
  87. package/docs/interfaces/KeetaNetSDK.Referenced.P2PPeerBase.html +1 -1
  88. package/docs/interfaces/KeetaNetSDK.Referenced.P2PPeerListener.html +1 -1
  89. package/docs/interfaces/KeetaNetSDK.Referenced.P2PPeerRepBase.html +1 -1
  90. package/docs/interfaces/KeetaNetSDK.Referenced.PublicKeyStorage.html +1 -1
  91. package/docs/interfaces/KeetaNetSDK.Referenced.RequestTokenReceiveEntry.html +1 -1
  92. package/docs/interfaces/KeetaNetSDK.Referenced.TokenNumericEntry.html +1 -1
  93. package/docs/interfaces/KeetaNetSDK.Referenced.WithIsInstance.html +1 -1
  94. package/docs/modules/KeetaNetSDK.Referenced.html +1 -1
  95. package/docs/modules/KeetaNetSDK.Referenced.src_lib_utils_helper.html +1 -1
  96. package/docs/types/KeetaNetSDK.Referenced.VoteOrQuoteOptions.html +3 -0
  97. package/docs/variables/KeetaNetSDK.Referenced.FullLedgerBaseErrorCode.html +1 -1
  98. package/docs/variables/KeetaNetSDK.Referenced.allFullErrorCodes.html +1 -1
  99. package/docs/variables/KeetaNetSDK.Referenced.src_lib_utils_helper.crypto.html +1 -1
  100. package/docs/variables/KeetaNetSDK.Referenced.src_lib_utils_helper.util.html +1 -0
  101. package/lib/error/index.d.ts +1 -1
  102. package/lib/error/ledger.d.ts +3 -3
  103. package/lib/ledger/db_spanner_helper.d.ts +1 -0
  104. package/lib/log/index.d.ts +2 -2
  105. package/lib/utils/helper.d.ts +7 -0
  106. package/npm-shrinkwrap.json +2 -2
  107. package/package.json +1 -1
  108. package/version.d.ts +1 -1
@@ -101243,6 +101243,7 @@ __webpack_require__.d(client_helper_namespaceObject, {
101243
101243
  randomInt: () => (client_randomInt),
101244
101244
  randomString: () => (client_randomString),
101245
101245
  setGenerator: () => (client_setGenerator),
101246
+ util: () => (client_helper_util),
101246
101247
  validateBase64ToBuffer: () => (client_validateBase64ToBuffer),
101247
101248
  waitTicks: () => (client_waitTicks)
101248
101249
  });
@@ -105947,7 +105948,13 @@ const client_helper_crypto = {
105947
105948
  randomUUID: client_helper_randomUUID,
105948
105949
  randomBytes: client_helper_randomBytes,
105949
105950
  createCipheriv: client_crypto_default().createCipheriv.bind((client_crypto_default())),
105950
- createDecipheriv: client_crypto_default().createDecipheriv.bind((client_crypto_default()))
105951
+ createDecipheriv: client_crypto_default().createDecipheriv.bind((client_crypto_default())),
105952
+ createHash: client_crypto_default().createHash.bind((client_crypto_default())),
105953
+ createHmac: client_crypto_default().createHmac.bind((client_crypto_default()))
105954
+ };
105955
+ const client_helper_util = {
105956
+ inspect: client_util.inspect,
105957
+ types: client_util.types
105951
105958
  };
105952
105959
  ;// ./node_modules/rfc4648/lib/rfc4648.js
105953
105960
  /* eslint-disable @typescript-eslint/strict-boolean-expressions */
@@ -116912,9 +116919,9 @@ function client_ledger_toPrimitive(t, r) { if ("object" != typeof t || !t) retur
116912
116919
 
116913
116920
 
116914
116921
  const client_LedgerErrorType = 'LEDGER';
116915
- const client_LedgerBaseErrorCodes = ['BLOCK_ALREADY_EXISTS', 'TRANSACTION_ABORTED', 'INVALID_CHAIN', 'INVALID_NETWORK', 'INVALID_SUBNET', 'INVALID_PERMISSIONS', 'INVALID_OWNER_COUNT', 'INVALID_BALANCE', 'INVALID_SET_REP', 'OPERATION_NOT_SUPPORTED', 'NOT_EMPTY', 'PREVIOUS_ALREADY_USED', 'PREVIOUS_NOT_SEEN', 'SUCCESSOR_VOTE_EXISTS', 'INSUFFICIENT_VOTING_WEIGHT', 'INVALID_ACCOUNT_INFO_KEY', 'RECEIVE_NOT_MET', 'DUPLICATE_VOTE_FOUND', 'CANNOT_EXCHANGE_PERM_VOTE', 'BLOCKS_DIFFER_FROM_VOTED_ON', 'NO_PERM_WITHOUT_SELF_TEMP', 'DUPLICATE_VOTE_ISSUER_FOUND', 'OTHER', 'MISSING_BLOCKS',
116922
+ const client_LedgerBaseErrorCodes = ['BLOCK_ALREADY_EXISTS', 'BLOCK_EXPIRED', 'TRANSACTION_ABORTED', 'INVALID_CHAIN', 'INVALID_NETWORK', 'INVALID_SUBNET', 'INVALID_PERMISSIONS', 'INVALID_OWNER_COUNT', 'INVALID_BALANCE', 'INVALID_SET_REP', 'OPERATION_NOT_SUPPORTED', 'NOT_EMPTY', 'PREVIOUS_ALREADY_USED', 'PREVIOUS_NOT_SEEN', 'SUCCESSOR_VOTE_EXISTS', 'INSUFFICIENT_VOTING_WEIGHT', 'INVALID_ACCOUNT_INFO_KEY', 'RECEIVE_NOT_MET', 'DUPLICATE_VOTE_FOUND', 'CANNOT_EXCHANGE_PERM_VOTE', 'TEMP_VOTE_INCLUDES_SELF', 'BLOCKS_DIFFER_FROM_VOTED_ON', 'NO_PERM_WITHOUT_SELF_TEMP', 'DUPLICATE_VOTE_ISSUER_FOUND', 'OTHER', 'MISSING_BLOCKS',
116916
116923
  // Fee Errors
116917
- 'FEE_AMOUNT_MISMATCH', 'FEE_TOKEN_MISMATCH', 'FEE_MISSING', 'MISSING_REQUIRED_FEE_BLOCK', 'PERM_VOTE_WITH_QUOTE', 'QUOTE_MISMATCH', 'REQUIRED_FEE_MISMATCH'];
116924
+ 'FEE_AMOUNT_MISMATCH', 'FEE_TOKEN_MISMATCH', 'FEE_MISSING', 'MISSING_REQUIRED_FEE_BLOCK', 'MULTIPLE_FEE_BLOCK', 'VOTE_WITH_QUOTE', 'QUOTE_MISMATCH', 'REQUIRED_FEE_MISMATCH'];
116918
116925
 
116919
116926
  // Errors that can trigger rep sync
116920
116927
  const client_LedgerVoteErrorCodes = ['NOT_SUCCESSOR', 'NOT_OPENING'];
@@ -126409,6 +126416,7 @@ function client_lib_ledger_toPrimitive(t, r) { if ("object" != typeof t || !t) r
126409
126416
 
126410
126417
 
126411
126418
 
126419
+
126412
126420
  /**
126413
126421
  * Kind of ledger
126414
126422
  */
@@ -126487,6 +126495,10 @@ class client_LedgerStorageTransactionBase {
126487
126495
  }
126488
126496
  }
126489
126497
 
126498
+ /**
126499
+ * Options for the LedgerStorageAPI.voteOrQuoteWithFees function
126500
+ */
126501
+
126490
126502
  /**
126491
126503
  * Each Ledger Storage backend must implement this interface
126492
126504
  */
@@ -126559,6 +126571,9 @@ class client_LedgerAtomicInterface {
126559
126571
  if (blocks.length === 0) {
126560
126572
  throw new client_ledger_KeetaNetLedgerError('LEDGER_MISSING_BLOCKS', 'At least one block is required to issue a vote');
126561
126573
  }
126574
+ if (blocks[0].purpose === src_client_Block.Purpose.FEE) {
126575
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_MISSING_BLOCKS', 'First block cannot be a fee block');
126576
+ }
126562
126577
  if (!client_ledger_classPrivateFieldGet(client_ledger_privateKey, this)) {
126563
126578
  throw new Error('Cannot vote on block, no private key loaded');
126564
126579
  }
@@ -126567,36 +126582,71 @@ class client_LedgerAtomicInterface {
126567
126582
  }
126568
126583
  const privateKey = client_ledger_classPrivateFieldGet(client_ledger_privateKey, this);
126569
126584
  const ledgerPubKey = privateKey.publicKeyString.get();
126585
+ const transaction = client_ledger_assertClassBrand(client_LedgerAtomicInterface_brand, this, client_assertTransaction).call(this);
126586
+
126587
+ /**
126588
+ * If there are other votes, if all of them are permanent then
126589
+ * we are requesting a temporary vote with a minority of permanent
126590
+ * votes to disable the block timestamp checking; otherwise if
126591
+ * any are temporary we are requesting a permanent vote
126592
+ *
126593
+ * If there are no other votes, we need to produce a temporary
126594
+ * vote.
126595
+ */
126596
+ let outcome = 'temporary';
126597
+ let requireBlockTimestampCheck = true;
126598
+ if (otherVotes !== undefined) {
126599
+ const foundTemporary = otherVotes.some(function (checkVote) {
126600
+ return !checkVote.$permanent;
126601
+ });
126602
+ if (foundTemporary) {
126603
+ outcome = 'permanent';
126604
+ } else {
126605
+ outcome = 'temporary';
126606
+ requireBlockTimestampCheck = false;
126607
+ }
126608
+ }
126609
+
126610
+ /*
126611
+ * If we have a quote, ensure it is valid for this ledger and outcome
126612
+ */
126570
126613
  if (quote !== undefined) {
126571
- if (otherVotes !== undefined) {
126572
- throw new client_ledger_KeetaNetLedgerError('LEDGER_PERM_VOTE_WITH_QUOTE', 'Quote should not be included when requesting permanent votes');
126614
+ if (outcome === 'permanent') {
126615
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_VOTE_WITH_QUOTE', 'Quote should not be included when requesting permanent votes');
126573
126616
  }
126574
126617
  if (!quote.issuer.comparePublicKey(ledgerPubKey)) {
126575
126618
  throw new client_ledger_KeetaNetLedgerError('LEDGER_QUOTE_MISMATCH', 'Provided quote does not match issuer public key');
126576
126619
  }
126577
126620
  }
126578
- const transaction = client_ledger_assertClassBrand(client_LedgerAtomicInterface_brand, this, client_assertTransaction).call(this);
126579
126621
 
126580
126622
  /**
126581
- * If there are other votes, ensure one of them was issued by
126582
- * us and the blocks are in the same order as the set of
126583
- * blocks we are voting on now
126623
+ * Verify some attributes about the other votes if they are provided
126584
126624
  */
126585
126625
  let hasFeeBlock = false;
126586
- if (otherVotes !== undefined) {
126587
- let foundOurVote = false;
126626
+ let foundOurVote;
126627
+ if (otherVotes) {
126628
+ foundOurVote = false;
126588
126629
  const seenVoteUIDs = new Set();
126589
126630
  const seenVoteIssuers = new client_lib_account.Set();
126590
126631
  let blockCount = blocks.length;
126591
126632
  const possibleFeeBlock = blocks.at(-1);
126592
126633
  if ((possibleFeeBlock === null || possibleFeeBlock === void 0 ? void 0 : possibleFeeBlock.purpose) === client_BlockPurpose.FEE) {
126593
126634
  hasFeeBlock = true;
126594
- blockCount--;
126635
+ /**
126636
+ * If permanent votes were provided then all votes should include the fee block
126637
+ * So only decrement block count if otherVotes are all temporary votes
126638
+ */
126639
+ const otherVotesAllTemporary = !otherVotes.some(function (checkVote) {
126640
+ return checkVote.$permanent;
126641
+ });
126642
+ if (otherVotesAllTemporary) {
126643
+ blockCount--;
126644
+ }
126595
126645
  }
126596
126646
  const requiredFees = new Map();
126597
126647
  for (const checkVote of otherVotes) {
126598
126648
  if (checkVote.quote === true) {
126599
- throw new client_ledger_KeetaNetLedgerError('LEDGER_PERM_VOTE_WITH_QUOTE', 'Cannot request permanent votes with quotes');
126649
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_VOTE_WITH_QUOTE', 'Cannot request votes with quote as supporting votes');
126600
126650
  }
126601
126651
  if (seenVoteUIDs.has(checkVote.$id)) {
126602
126652
  throw new client_ledger_KeetaNetLedgerError('LEDGER_DUPLICATE_VOTE_FOUND', 'Duplicate vote UID found');
@@ -126609,11 +126659,16 @@ class client_LedgerAtomicInterface {
126609
126659
  if (checkVote.fee !== undefined) {
126610
126660
  requiredFees.set(checkVote.issuer, checkVote.fee);
126611
126661
  }
126612
- if (checkVote.$permanent) {
126613
- throw new client_ledger_KeetaNetLedgerError('LEDGER_CANNOT_EXCHANGE_PERM_VOTE', 'Asked to exchange a permanent vote for a permanent vote');
126662
+
126663
+ /*
126664
+ * Handle errors specific to requesting a permanent vote
126665
+ */
126666
+ if (outcome === 'permanent') {
126667
+ if (checkVote.$permanent && checkVote.issuer.comparePublicKey(ledgerPubKey)) {
126668
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_CANNOT_EXCHANGE_PERM_VOTE', 'Asked to exchange a permanent vote from us for a permanent vote from us');
126669
+ }
126614
126670
  }
126615
126671
  let blocksDifferFromVoteBlocks = checkVote.blocks.length !== blockCount;
126616
-
126617
126672
  /* If they do not differ from length alone, compare block hashes */
126618
126673
  if (!blocksDifferFromVoteBlocks) {
126619
126674
  for (let blockIndex = 0; blockIndex < blockCount; blockIndex++) {
@@ -126630,38 +126685,82 @@ class client_LedgerAtomicInterface {
126630
126685
  foundOurVote = true;
126631
126686
  }
126632
126687
  }
126633
- if (requiredFees.size > 0) {
126634
- if (!hasFeeBlock) {
126635
- throw new client_ledger_KeetaNetLedgerError('LEDGER_MISSING_REQUIRED_FEE_BLOCK', 'Missing fee block but votes require it');
126636
- }
126637
- if (requiredFees.size !== (possibleFeeBlock === null || possibleFeeBlock === void 0 ? void 0 : possibleFeeBlock.operations.length)) {
126638
- throw new client_ledger_KeetaNetLedgerError('LEDGER_REQUIRED_FEE_MISMATCH', 'Fee Block Operations do not match required fees');
126688
+
126689
+ /*
126690
+ * We only care about fees if we are issuing a permanent vote,
126691
+ * if we are issuing a temporary vote the fees will be checked
126692
+ * when the permanent vote is requested
126693
+ */
126694
+ if (outcome === 'permanent') {
126695
+ if (requiredFees.size > 0) {
126696
+ if (!hasFeeBlock) {
126697
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_MISSING_REQUIRED_FEE_BLOCK', 'Missing fee block but votes require it');
126698
+ }
126699
+ if (requiredFees.size !== (possibleFeeBlock === null || possibleFeeBlock === void 0 ? void 0 : possibleFeeBlock.operations.length)) {
126700
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_REQUIRED_FEE_MISMATCH', 'Fee Block Operations do not match required fees');
126701
+ }
126639
126702
  }
126640
- }
126641
126703
 
126642
- // Verify that all required fees have been included in the fee block
126643
- for (const [issuer, fee] of requiredFees) {
126644
- const foundFee = possibleFeeBlock === null || possibleFeeBlock === void 0 ? void 0 : possibleFeeBlock.operations.find(operation => {
126645
- var _fee$payTo, _fee$token;
126646
- const expectedPayTo = (_fee$payTo = fee.payTo) !== null && _fee$payTo !== void 0 ? _fee$payTo : issuer;
126647
- const expectedToken = (_fee$token = fee.token) !== null && _fee$token !== void 0 ? _fee$token : client_ledger_classPrivateFieldGet(client_ledger, this).baseToken;
126648
- if (operation.type === client_OperationType.SEND && operation.to.comparePublicKey(expectedPayTo)) {
126649
- if (operation.amount !== fee.amount) {
126650
- throw new client_ledger_KeetaNetLedgerError('LEDGER_FEE_AMOUNT_MISMATCH', `Fee Amount Mismatch, found: ${operation.amount} expected: ${fee.amount}`);
126651
- }
126652
- if (!operation.token.comparePublicKey(expectedToken)) {
126653
- throw new client_ledger_KeetaNetLedgerError('LEDGER_FEE_TOKEN_MISMATCH', `Fee Token Mismatch, found: ${operation.token.publicKeyString.get()} expected: ${expectedToken.publicKeyString.get()}`);
126704
+ // Verify that all required fees have been included in the fee block
126705
+ for (const [issuer, fee] of requiredFees) {
126706
+ const foundFee = possibleFeeBlock === null || possibleFeeBlock === void 0 ? void 0 : possibleFeeBlock.operations.find(operation => {
126707
+ var _fee$payTo, _fee$token;
126708
+ const expectedPayTo = (_fee$payTo = fee.payTo) !== null && _fee$payTo !== void 0 ? _fee$payTo : issuer;
126709
+ const expectedToken = (_fee$token = fee.token) !== null && _fee$token !== void 0 ? _fee$token : client_ledger_classPrivateFieldGet(client_ledger, this).baseToken;
126710
+ if (operation.type === client_OperationType.SEND && operation.to.comparePublicKey(expectedPayTo)) {
126711
+ if (operation.amount !== fee.amount) {
126712
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_FEE_AMOUNT_MISMATCH', `Fee Amount Mismatch, found: ${operation.amount} expected: ${fee.amount}`);
126713
+ }
126714
+ if (!operation.token.comparePublicKey(expectedToken)) {
126715
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_FEE_TOKEN_MISMATCH', `Fee Token Mismatch, found: ${operation.token.publicKeyString.get()} expected: ${expectedToken.publicKeyString.get()}`);
126716
+ }
126717
+ return true;
126654
126718
  }
126655
- return true;
126719
+ return false;
126720
+ });
126721
+ if (foundFee === undefined) {
126722
+ var _fee$payTo$publicKeyS, _fee$payTo2;
126723
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_FEE_MISSING', `Missing Required Fee for ${(_fee$payTo$publicKeyS = (_fee$payTo2 = fee.payTo) === null || _fee$payTo2 === void 0 ? void 0 : _fee$payTo2.publicKeyString.get()) !== null && _fee$payTo$publicKeyS !== void 0 ? _fee$payTo$publicKeyS : issuer.publicKeyString.get()}`);
126656
126724
  }
126657
- return false;
126658
- });
126659
- if (foundFee === undefined) {
126660
- var _fee$payTo$publicKeyS, _fee$payTo2;
126661
- throw new client_ledger_KeetaNetLedgerError('LEDGER_FEE_MISSING', `Missing Required Fee for ${(_fee$payTo$publicKeyS = (_fee$payTo2 = fee.payTo) === null || _fee$payTo2 === void 0 ? void 0 : _fee$payTo2.publicKeyString.get()) !== null && _fee$payTo$publicKeyS !== void 0 ? _fee$payTo$publicKeyS : issuer.publicKeyString.get()}`);
126662
126725
  }
126726
+ } else if (outcome === 'temporary') {
126727
+ if (foundOurVote) {
126728
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_TEMP_VOTE_INCLUDES_SELF', 'Temporary vote request cannot include a vote from self');
126729
+ }
126730
+ /* XXX:TODO: We need to check the fee block to find out the fee paid to us and include that in our temporary vote so that it can be verified later */
126731
+ } else {
126732
+ client_assertNever(outcome);
126733
+ }
126734
+ }
126735
+
126736
+ /**
126737
+ * If the outcome is a temporary vote and the are other votes
126738
+ * ensure that the temporary votes represent a minority of
126739
+ * the voting weight and do not include a vote from us
126740
+ */
126741
+ if (outcome === 'temporary' && otherVotes !== undefined) {
126742
+ const totalVotingPower = await this.votingPower();
126743
+ const minVotingWeight = totalVotingPower / 4n;
126744
+ const combinedVotingPower = (await Promise.all(otherVotes.map(async vote => {
126745
+ return await this.votingPower(vote.issuer);
126746
+ }))).reduce(function (sum, value) {
126747
+ return sum + value;
126748
+ }, 0n);
126749
+ if (combinedVotingPower <= minVotingWeight) {
126750
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_INSUFFICIENT_VOTING_WEIGHT', 'Temporary vote must represent at least a minority of the voting weight');
126663
126751
  }
126664
- if (!foundOurVote) {
126752
+ }
126753
+
126754
+ /**
126755
+ * If there are other votes, ensure one of them was issued by
126756
+ * us and the blocks are in the same order as the set of
126757
+ * blocks we are voting on now
126758
+ */
126759
+ if (outcome === 'permanent') {
126760
+ if (otherVotes === undefined) {
126761
+ throw new Error('internal error: Outcome permanent but otherVotes is undefined');
126762
+ }
126763
+ if (foundOurVote !== true) {
126665
126764
  throw new client_ledger_KeetaNetLedgerError('LEDGER_NO_PERM_WITHOUT_SELF_TEMP', 'Asked to give a permanent vote without a temporary vote from us');
126666
126765
  }
126667
126766
  }
@@ -126710,7 +126809,13 @@ class client_LedgerAtomicInterface {
126710
126809
  */
126711
126810
 
126712
126811
  let mayReplace = false;
126713
- if (previousVotes.length === 1 && otherVotes !== undefined && otherVotes.length !== 0) {
126812
+ if (previousVotes.length === 1 && outcome === 'permanent') {
126813
+ var _otherVotes$length;
126814
+ const otherVotesCount = (_otherVotes$length = otherVotes === null || otherVotes === void 0 ? void 0 : otherVotes.length) !== null && _otherVotes$length !== void 0 ? _otherVotes$length : 0;
126815
+ if (otherVotesCount < 1) {
126816
+ throw new Error('internal error: outcome permanent but otherVotes is empty or undefined');
126817
+ }
126818
+ ;
126714
126819
  const ourVote = previousVotes[0];
126715
126820
  mayReplace = !ourVote.$permanent && ourVote.issuer.comparePublicKey(ledgerPubKey);
126716
126821
  }
@@ -126721,15 +126826,25 @@ class client_LedgerAtomicInterface {
126721
126826
  }
126722
126827
 
126723
126828
  /**
126724
- * If no other votes have been supplied, validate that the blocks are valid, and issue a short vote
126829
+ * If we are producing a temporary vote, do it now and return
126725
126830
  */
126726
- if (otherVotes === undefined) {
126727
- const vote = await client_ledger_assertClassBrand(client_LedgerAtomicInterface_brand, this, client_voteOrQuoteWithFees).call(this, blocks, 'VOTE', quote);
126831
+ if (outcome === 'temporary') {
126832
+ const vote = await client_ledger_assertClassBrand(client_LedgerAtomicInterface_brand, this, client_voteOrQuoteWithFees).call(this, blocks, 'VOTE', quote, {
126833
+ requireBlockTimestampCheck
126834
+ });
126728
126835
  const blocksAndVote = src_client_VoteStaple.fromVotesAndBlocks([vote], blocks);
126729
126836
  await client_ledger_classPrivateFieldGet(client_ledger_storage, this).addPendingVote(transaction, blocksAndVote);
126730
126837
  return vote;
126731
126838
  }
126732
126839
 
126840
+ /**
126841
+ * From here on we are producing a permanent vote but we need
126842
+ * to narrow some types for TypeScript
126843
+ */
126844
+ if (otherVotes === undefined) {
126845
+ throw new Error('internal error: Outcome permanent but otherVotes is undefined');
126846
+ }
126847
+
126733
126848
  /**
126734
126849
  * Validate ledger outcome again before permanent votes if blocks includes a fee block
126735
126850
  */
@@ -127484,7 +127599,15 @@ async function client_validateBlocksForVote(blocks) {
127484
127599
  const allLedgerHeads = new Map();
127485
127600
  const allLedgerIdempotentKeys = new Map();
127486
127601
  const allLedgerIdempotentKeysReverse = new Map();
127602
+ let foundFeeBlock = false;
127487
127603
  for (const block of blocks) {
127604
+ if (block.purpose === src_client_Block.Purpose.FEE) {
127605
+ if (foundFeeBlock) {
127606
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_MULTIPLE_FEE_BLOCK', 'Should only contain 1 fee block');
127607
+ } else {
127608
+ foundFeeBlock = true;
127609
+ }
127610
+ }
127488
127611
  const prevBlockHash = block.previous;
127489
127612
  seenBlockHashes.add(block.hash);
127490
127613
  if (block.network !== client_ledger_classPrivateFieldGet(client_network, this)) {
@@ -127540,8 +127663,8 @@ async function client_validateBlocksForVote(blocks) {
127540
127663
  allLedgerIdempotentKeys
127541
127664
  };
127542
127665
  }
127543
- async function client_voteOrQuoteWithFees(blocks, type, quote) {
127544
- var _quote$fee;
127666
+ async function client_voteOrQuoteWithFees(blocks, type, quote, options) {
127667
+ var _options$requireBlock;
127545
127668
  if (client_ledger_classPrivateFieldGet(client_ledger, this).ledgerWriteMode !== 'read-write') {
127546
127669
  throw new Error(`May not issue votes in read-only mode, in ${client_ledger_classPrivateFieldGet(client_ledger, this).ledgerWriteMode} mode`);
127547
127670
  }
@@ -127550,16 +127673,26 @@ async function client_voteOrQuoteWithFees(blocks, type, quote) {
127550
127673
  }
127551
127674
  client_ledger_assertClassBrand(client_LedgerAtomicInterface_brand, this, client_assertTransaction).call(this);
127552
127675
  const effects = await client_ledger_assertClassBrand(client_LedgerAtomicInterface_brand, this, client_validateLedgerOutcome).call(this, blocks);
127553
- const now = Date.now();
127554
- for (const block of blocks) {
127555
- const blockDate = block.date.valueOf();
127556
- const timeOffset = 5 /* m */ * 60 /* s */ * 1000 /* ms */;
127557
127676
 
127558
- /**
127559
- * Do not allow short votes on blocks from the distant past
127560
- */
127561
- if (blockDate < now - timeOffset || blockDate > now + timeOffset) {
127562
- throw new Error(`Refusing to issue vote for block dated ${block.date.toISOString()}`);
127677
+ /*
127678
+ * Ensure the block is relatively recent, otherwise a found
127679
+ * block for an account could be used to indefinitely delay voting
127680
+ * by continuously requesting votes on old blocks
127681
+ */
127682
+ const requireBlockTimestampCheck = (_options$requireBlock = options === null || options === void 0 ? void 0 : options.requireBlockTimestampCheck) !== null && _options$requireBlock !== void 0 ? _options$requireBlock : true;
127683
+ if (requireBlockTimestampCheck) {
127684
+ var _classPrivateFieldGet0, _classPrivateFieldGet1;
127685
+ const now = (_classPrivateFieldGet0 = (_classPrivateFieldGet1 = client_ledger_classPrivateFieldGet(client_transaction, this)) === null || _classPrivateFieldGet1 === void 0 ? void 0 : _classPrivateFieldGet1.moment.valueOf()) !== null && _classPrivateFieldGet0 !== void 0 ? _classPrivateFieldGet0 : Date.now();
127686
+ for (const block of blocks) {
127687
+ const blockDate = block.date.valueOf();
127688
+ const timeOffset = 5 /* m */ * 60 /* s */ * 1000 /* ms */;
127689
+
127690
+ /**
127691
+ * Do not allow short votes on blocks from the distant past
127692
+ */
127693
+ if (blockDate < now - timeOffset || blockDate > now + timeOffset) {
127694
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_BLOCK_EXPIRED', `Refusing to issue vote for block dated ${block.date.toISOString()}`);
127695
+ }
127563
127696
  }
127564
127697
  }
127565
127698
 
@@ -127581,10 +127714,15 @@ async function client_voteOrQuoteWithFees(blocks, type, quote) {
127581
127714
 
127582
127715
  /**
127583
127716
  * If a quote was provided use it as the fee, otherwise generate new fee
127717
+ * If we are creating a vote with permanent `otherVotes` then do not include the fee.
127718
+ * TODO - considering changing how fees are handled when recovering
127584
127719
  */
127585
- const fee = (_quote$fee = quote === null || quote === void 0 ? void 0 : quote.fee) !== null && _quote$fee !== void 0 ? _quote$fee : await this.getFee(blocks, effects);
127586
- if (fee !== null) {
127587
- builder.addFee(fee);
127720
+ if (requireBlockTimestampCheck) {
127721
+ var _quote$fee;
127722
+ const fee = (_quote$fee = quote === null || quote === void 0 ? void 0 : quote.fee) !== null && _quote$fee !== void 0 ? _quote$fee : await this.getFee(blocks, effects);
127723
+ if (fee !== null) {
127724
+ builder.addFee(fee);
127725
+ }
127588
127726
  }
127589
127727
  const voteOrQuote = await builder.seal(serial, pendingVoteExpiry);
127590
127728
  return voteOrQuote;
@@ -128012,7 +128150,7 @@ client_lib_ledger_defineProperty(src_client_Ledger, "isInstance", client_checkab
128012
128150
  // EXTERNAL MODULE: ws (ignored)
128013
128151
  var client_ws_ignored_ = __webpack_require__(4708);
128014
128152
  ;// ./src/version.ts
128015
- const client_version = '0.14.9+gdb1185935886a43e4feda1919fa65830dc656174';
128153
+ const client_version = '0.14.11+gfb27e304d06f586fd5f3532fae4f1504a46d359b';
128016
128154
  /* harmony default export */ const client_src_version = ((/* unused pure expression or super */ null && (client_version)));
128017
128155
  ;// ./src/lib/p2p.ts
128018
128156
  /* provided dependency */ var client_p2p_Buffer = __webpack_require__(8287)["Buffer"];
@@ -132800,21 +132938,31 @@ class src_client_Client {
132800
132938
  if (!successorBlock) {
132801
132939
  return null;
132802
132940
  }
132803
- const getVotes = async (rep, hash) => {
132941
+ const getVote = async (rep, hash) => {
132942
+ var _votes$;
132804
132943
  let votes = null;
132805
132944
  try {
132806
132945
  votes = await client_client_assertClassBrand(client_Client_brand, this, client_getVotes).call(this, hash, 'side', rep);
132807
132946
  } catch {
132808
132947
  /* Ignore */
132809
132948
  }
132949
+ if (votes === null) {
132950
+ return {
132951
+ rep,
132952
+ vote: null
132953
+ };
132954
+ }
132955
+
132956
+ // Favor using permanent votes over short votes if the rep returns both
132957
+ votes.sort((voteA, voteB) => voteB.validityTo.valueOf() - voteA.validityTo.valueOf());
132810
132958
  return {
132811
132959
  rep: rep,
132812
- votes: votes
132960
+ vote: (_votes$ = votes[0]) !== null && _votes$ !== void 0 ? _votes$ : null
132813
132961
  };
132814
132962
  };
132815
132963
  const votePromises = [];
132816
132964
  for (const rep of client_client_classPrivateFieldGet(client_reps, this)) {
132817
- votePromises.push(getVotes(rep, successorBlock.hash));
132965
+ votePromises.push(getVote(rep, successorBlock.hash));
132818
132966
  }
132819
132967
  const votesInfo = await Promise.all(votePromises);
132820
132968
  if (votesInfo.length === 0) {
@@ -132832,18 +132980,16 @@ class src_client_Client {
132832
132980
  /* Any reps that did not generate any vote */
132833
132981
  const missingReps = [];
132834
132982
  for (const repInfo of votesInfo) {
132835
- const repVotes = repInfo.votes;
132836
- if (repVotes === null) {
132983
+ const repVote = repInfo.vote;
132984
+ if (repVote === null) {
132837
132985
  missingReps.push(repInfo.rep);
132838
132986
  } else {
132839
- for (const vote of repVotes) {
132840
- if (vote.$permanent === true) {
132841
- permVotes.push(vote);
132842
- permReps.push(repInfo.rep);
132843
- } else {
132844
- tempVotes.push(vote);
132845
- tempReps.push(repInfo.rep);
132846
- }
132987
+ if (repVote.$permanent === true) {
132988
+ permVotes.push(repVote);
132989
+ permReps.push(repInfo.rep);
132990
+ } else {
132991
+ tempVotes.push(repVote);
132992
+ tempReps.push(repInfo.rep);
132847
132993
  }
132848
132994
  }
132849
132995
  }
@@ -132893,7 +133039,12 @@ class src_client_Client {
132893
133039
  let newTempVotes = [];
132894
133040
  if (tempVotes.length !== client_client_classPrivateFieldGet(client_reps, this).length) {
132895
133041
  try {
132896
- newTempVotes = await client_client_assertClassBrand(client_Client_brand, this, client_requestVotes).call(this, votedOnBlocks, undefined, missingReps, options === null || options === void 0 ? void 0 : options.quotes);
133042
+ /**
133043
+ * If we are trying to recover an old block that has some permanent votes, send those votes in the request
133044
+ * Otherwise the rep will reject the old block and won't issue a vote
133045
+ */
133046
+ const otherVotes = permVotes.length > 0 ? permVotes : undefined;
133047
+ newTempVotes = await client_client_assertClassBrand(client_Client_brand, this, client_requestVotes).call(this, votedOnBlocks, otherVotes, missingReps, options === null || options === void 0 ? void 0 : options.quotes);
132897
133048
  } catch {
132898
133049
  /* Ignore */
132899
133050
  }
@@ -132918,7 +133069,7 @@ class src_client_Client {
132918
133069
  votedOnBlocks.push(feeBlock);
132919
133070
  }
132920
133071
  try {
132921
- const newPermVotes = await client_client_assertClassBrand(client_Client_brand, this, client_requestVotes).call(this, votedOnBlocks, tempVotes, missingPermReps);
133072
+ const newPermVotes = await client_client_assertClassBrand(client_Client_brand, this, client_requestVotes).call(this, votedOnBlocks, [...tempVotes, ...permVotes], missingPermReps);
132922
133073
  permVotes = [...permVotes, ...newPermVotes];
132923
133074
  } catch {
132924
133075
  /* Ignore */
@@ -132945,7 +133096,7 @@ class src_client_Client {
132945
133096
  * @param publish Publish the synced staple to the network (default is true)
132946
133097
  */
132947
133098
  async syncAccount(account) {
132948
- var _accountInfoSorted$0$, _accountInfoSorted$in, _accountInfoSorted$0$2, _accountInfoSorted$0$3;
133099
+ var _accountInfoSorted$in, _accountInfoSorted$0$;
132949
133100
  let publish = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
132950
133101
  let reps = arguments.length > 2 ? arguments[2] : undefined;
132951
133102
  await client_client_classPrivateFieldGet(client_updateRepsPromise, this);
@@ -132973,11 +133124,12 @@ class src_client_Client {
132973
133124
  var _a$info$height, _a$info, _b$info$height, _b$info;
132974
133125
  return Number(BigInt((_a$info$height = (_a$info = a.info) === null || _a$info === void 0 ? void 0 : _a$info.height) !== null && _a$info$height !== void 0 ? _a$info$height : -1) - BigInt((_b$info$height = (_b$info = b.info) === null || _b$info === void 0 ? void 0 : _b$info.height) !== null && _b$info$height !== void 0 ? _b$info$height : -1));
132975
133126
  });
132976
- if (((_accountInfoSorted$0$ = accountInfoSorted[0].info) === null || _accountInfoSorted$0$ === void 0 ? void 0 : _accountInfoSorted$0$.height) === ((_accountInfoSorted$in = accountInfoSorted[accountInfoSorted.length - 1].info) === null || _accountInfoSorted$in === void 0 ? void 0 : _accountInfoSorted$in.height)) {
133127
+ const lowestInfo = accountInfoSorted[0].info;
133128
+ if ((lowestInfo === null || lowestInfo === void 0 ? void 0 : lowestInfo.height) === ((_accountInfoSorted$in = accountInfoSorted[accountInfoSorted.length - 1].info) === null || _accountInfoSorted$in === void 0 ? void 0 : _accountInfoSorted$in.height)) {
132977
133129
  // Block Heights match so return
132978
133130
  return null;
132979
133131
  }
132980
- let lowestHead = (_accountInfoSorted$0$2 = accountInfoSorted[0].info) === null || _accountInfoSorted$0$2 === void 0 ? void 0 : _accountInfoSorted$0$2.block.hash;
133132
+ let lowestHead = lowestInfo === null || lowestInfo === void 0 ? void 0 : lowestInfo.block.hash;
132981
133133
  if (lowestHead === null || lowestHead === undefined) {
132982
133134
  lowestHead = client_lib_block.getAccountOpeningHash(account);
132983
133135
  }
@@ -132992,10 +133144,28 @@ class src_client_Client {
132992
133144
  return null;
132993
133145
  }
132994
133146
  if (publish === true) {
132995
- await this.transmitStaple(successorStaple, [accountInfoSorted[0].rep]);
133147
+ const allLowestReps = [];
133148
+ for (const accountInfo of accountInfoSorted) {
133149
+ var _accountInfo$info;
133150
+ // All lowest reps could be missing the opening block and info would be null so make sure we send to all of them
133151
+ if (((_accountInfo$info = accountInfo.info) === null || _accountInfo$info === void 0 ? void 0 : _accountInfo$info.height) === (lowestInfo === null || lowestInfo === void 0 ? void 0 : lowestInfo.height)) {
133152
+ allLowestReps.push(accountInfo.rep);
133153
+ }
133154
+ }
133155
+ for (const rep of allLowestReps) {
133156
+ // we publish these serially to avoid transaction conflicts, but publish to all to ensure that every missing rep sees the staple
133157
+ try {
133158
+ await this.transmitStaple(successorStaple, [rep]);
133159
+ } catch {
133160
+ /**
133161
+ * Ignore transmit errors like LEDGER_BLOCK_ALREADY_EXISTS
133162
+ * We will check block heights after to see if sync was performed
133163
+ */
133164
+ }
133165
+ }
132996
133166
  }
132997
133167
  const updatedAccountInfo = await this.getAccountHeadInfo(account, accountInfoSorted[0].rep);
132998
- if ((updatedAccountInfo === null || updatedAccountInfo === void 0 ? void 0 : updatedAccountInfo.height) === ((_accountInfoSorted$0$3 = accountInfoSorted[0].info) === null || _accountInfoSorted$0$3 === void 0 ? void 0 : _accountInfoSorted$0$3.height)) {
133168
+ if ((updatedAccountInfo === null || updatedAccountInfo === void 0 ? void 0 : updatedAccountInfo.height) === ((_accountInfoSorted$0$ = accountInfoSorted[0].info) === null || _accountInfoSorted$0$ === void 0 ? void 0 : _accountInfoSorted$0$.height)) {
132999
133169
  throw new src_client_KeetaNetClientError('CLIENT_SYNC_PUBLISH_FAILED', `Client sync found a missing staple: ${successorStaple.blocksHash}, but it could not be published to rep: ${accountInfoSorted[0].rep.key.publicKeyString.get()}`);
133000
133170
  }
133001
133171
  return successorStaple;