@keetanetwork/keetanet-client 0.14.9 → 0.14.10

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 (68) hide show
  1. package/client/index-browser.js +217 -75
  2. package/client/index.js +200 -70
  3. package/docs/assets/hierarchy.js +1 -1
  4. package/docs/assets/search.js +1 -1
  5. package/docs/classes/KeetaNetSDK.Referenced.BaseVoteBuilder.html +1 -1
  6. package/docs/classes/KeetaNetSDK.Referenced.BlockOperation.html +1 -1
  7. package/docs/classes/KeetaNetSDK.Referenced.ECDSAKeyPair.html +1 -1
  8. package/docs/classes/KeetaNetSDK.Referenced.ECDSASECP256K1KeyPair.html +1 -1
  9. package/docs/classes/KeetaNetSDK.Referenced.ECDSASECP256R1KeyPair.html +1 -1
  10. package/docs/classes/KeetaNetSDK.Referenced.ED25519KeyPair.html +1 -1
  11. package/docs/classes/KeetaNetSDK.Referenced.IdempotentKey.html +1 -1
  12. package/docs/classes/KeetaNetSDK.Referenced.IdentifierKeyPair.html +1 -1
  13. package/docs/classes/KeetaNetSDK.Referenced.KeetaNetError.html +1 -1
  14. package/docs/classes/KeetaNetSDK.Referenced.KeetaNetLedgerError.html +1 -1
  15. package/docs/classes/KeetaNetSDK.Referenced.KeyInterface.html +1 -1
  16. package/docs/classes/KeetaNetSDK.Referenced.KeyStorage.html +1 -1
  17. package/docs/classes/KeetaNetSDK.Referenced.PermissionSetHolder.html +1 -1
  18. package/docs/classes/KeetaNetSDK.Referenced.SignatureStorage.html +1 -1
  19. package/docs/classes/KeetaNetSDK.Referenced.StatsPending.html +1 -1
  20. package/docs/hierarchy.html +1 -1
  21. package/docs/interfaces/KeetaNetSDK.Referenced.ACLEntry.html +1 -1
  22. package/docs/interfaces/KeetaNetSDK.Referenced.ACLUpdate.html +1 -1
  23. package/docs/interfaces/KeetaNetSDK.Referenced.ASN1ExplicitContextTag.html +1 -1
  24. package/docs/interfaces/KeetaNetSDK.Referenced.ASN1ImplicitContextTag.html +1 -1
  25. package/docs/interfaces/KeetaNetSDK.Referenced.ASN1Object.html +1 -1
  26. package/docs/interfaces/KeetaNetSDK.Referenced.BaseExternalKeyPairFunctions.html +1 -1
  27. package/docs/interfaces/KeetaNetSDK.Referenced.BaseGenerationConfig.html +1 -1
  28. package/docs/interfaces/KeetaNetSDK.Referenced.BaseIdentifierCreateArguments.html +1 -1
  29. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperation.html +1 -1
  30. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationCREATE_IDENTIFIER.html +1 -1
  31. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationMANAGE_CERTIFICATE.html +1 -1
  32. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationMANAGE_CERTIFICATESerializable.html +1 -1
  33. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationMODIFY_PERMISSIONS.html +1 -1
  34. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationRECEIVE.html +1 -1
  35. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationSEND.html +1 -1
  36. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationSET_INFO.html +1 -1
  37. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationSET_REP.html +1 -1
  38. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationTOKEN_ADMIN_MODIFY_BALANCE.html +1 -1
  39. package/docs/interfaces/KeetaNetSDK.Referenced.BlockJSONOperationTOKEN_ADMIN_SUPPLY.html +1 -1
  40. package/docs/interfaces/KeetaNetSDK.Referenced.Constructor.html +1 -1
  41. package/docs/interfaces/KeetaNetSDK.Referenced.DisposableTimingHandle.html +1 -1
  42. package/docs/interfaces/KeetaNetSDK.Referenced.ExternalKeyPairFunctionsNoEncryption.html +1 -1
  43. package/docs/interfaces/KeetaNetSDK.Referenced.ExternalKeyPairFunctionsSupportsEncryption.html +1 -1
  44. package/docs/interfaces/KeetaNetSDK.Referenced.InitialConfigSupply.html +1 -1
  45. package/docs/interfaces/KeetaNetSDK.Referenced.InstanceSet.html +1 -1
  46. package/docs/interfaces/KeetaNetSDK.Referenced.KVGenericOptionsType.html +1 -1
  47. package/docs/interfaces/KeetaNetSDK.Referenced.KVSetOptionsType.html +1 -1
  48. package/docs/interfaces/KeetaNetSDK.Referenced.ModifyTokenBalanceEntry.html +1 -1
  49. package/docs/interfaces/KeetaNetSDK.Referenced.MultiSigIdentifierCreateArguments.html +1 -1
  50. package/docs/interfaces/KeetaNetSDK.Referenced.MultisigConfig.html +1 -1
  51. package/docs/interfaces/KeetaNetSDK.Referenced.NumericValueEntry.html +1 -1
  52. package/docs/interfaces/KeetaNetSDK.Referenced.P2PPeerBase.html +1 -1
  53. package/docs/interfaces/KeetaNetSDK.Referenced.P2PPeerListener.html +1 -1
  54. package/docs/interfaces/KeetaNetSDK.Referenced.P2PPeerRepBase.html +1 -1
  55. package/docs/interfaces/KeetaNetSDK.Referenced.PublicKeyStorage.html +1 -1
  56. package/docs/interfaces/KeetaNetSDK.Referenced.RequestTokenReceiveEntry.html +1 -1
  57. package/docs/interfaces/KeetaNetSDK.Referenced.TokenNumericEntry.html +1 -1
  58. package/docs/interfaces/KeetaNetSDK.Referenced.WithIsInstance.html +1 -1
  59. package/docs/modules/KeetaNetSDK.Referenced.html +1 -1
  60. package/docs/types/KeetaNetSDK.Referenced.VoteOrQuoteOptions.html +3 -0
  61. package/docs/variables/KeetaNetSDK.Referenced.FullLedgerBaseErrorCode.html +1 -1
  62. package/docs/variables/KeetaNetSDK.Referenced.allFullErrorCodes.html +1 -1
  63. package/lib/error/index.d.ts +1 -1
  64. package/lib/error/ledger.d.ts +3 -3
  65. package/lib/ledger/db_spanner_helper.d.ts +1 -0
  66. package/npm-shrinkwrap.json +2 -2
  67. package/package.json +1 -1
  68. package/version.d.ts +1 -1
@@ -116912,9 +116912,9 @@ function client_ledger_toPrimitive(t, r) { if ("object" != typeof t || !t) retur
116912
116912
 
116913
116913
 
116914
116914
  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',
116915
+ 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
116916
  // Fee Errors
116917
- 'FEE_AMOUNT_MISMATCH', 'FEE_TOKEN_MISMATCH', 'FEE_MISSING', 'MISSING_REQUIRED_FEE_BLOCK', 'PERM_VOTE_WITH_QUOTE', 'QUOTE_MISMATCH', 'REQUIRED_FEE_MISMATCH'];
116917
+ 'FEE_AMOUNT_MISMATCH', 'FEE_TOKEN_MISMATCH', 'FEE_MISSING', 'MISSING_REQUIRED_FEE_BLOCK', 'VOTE_WITH_QUOTE', 'QUOTE_MISMATCH', 'REQUIRED_FEE_MISMATCH'];
116918
116918
 
116919
116919
  // Errors that can trigger rep sync
116920
116920
  const client_LedgerVoteErrorCodes = ['NOT_SUCCESSOR', 'NOT_OPENING'];
@@ -126409,6 +126409,7 @@ function client_lib_ledger_toPrimitive(t, r) { if ("object" != typeof t || !t) r
126409
126409
 
126410
126410
 
126411
126411
 
126412
+
126412
126413
  /**
126413
126414
  * Kind of ledger
126414
126415
  */
@@ -126487,6 +126488,10 @@ class client_LedgerStorageTransactionBase {
126487
126488
  }
126488
126489
  }
126489
126490
 
126491
+ /**
126492
+ * Options for the LedgerStorageAPI.voteOrQuoteWithFees function
126493
+ */
126494
+
126490
126495
  /**
126491
126496
  * Each Ledger Storage backend must implement this interface
126492
126497
  */
@@ -126567,24 +126572,50 @@ class client_LedgerAtomicInterface {
126567
126572
  }
126568
126573
  const privateKey = client_ledger_classPrivateFieldGet(client_ledger_privateKey, this);
126569
126574
  const ledgerPubKey = privateKey.publicKeyString.get();
126575
+ const transaction = client_ledger_assertClassBrand(client_LedgerAtomicInterface_brand, this, client_assertTransaction).call(this);
126576
+
126577
+ /**
126578
+ * If there are other votes, if all of them are permanent then
126579
+ * we are requesting a temporary vote with a minority of permanent
126580
+ * votes to disable the block timestamp checking; otherwise if
126581
+ * any are temporary we are requesting a permanent vote
126582
+ *
126583
+ * If there are no other votes, we need to produce a temporary
126584
+ * vote.
126585
+ */
126586
+ let outcome = 'temporary';
126587
+ let requireBlockTimestampCheck = true;
126588
+ if (otherVotes !== undefined) {
126589
+ const foundTemporary = otherVotes.some(function (checkVote) {
126590
+ return !checkVote.$permanent;
126591
+ });
126592
+ if (foundTemporary) {
126593
+ outcome = 'permanent';
126594
+ } else {
126595
+ outcome = 'temporary';
126596
+ requireBlockTimestampCheck = false;
126597
+ }
126598
+ }
126599
+
126600
+ /*
126601
+ * If we have a quote, ensure it is valid for this ledger and outcome
126602
+ */
126570
126603
  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');
126604
+ if (outcome === 'permanent') {
126605
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_VOTE_WITH_QUOTE', 'Quote should not be included when requesting permanent votes');
126573
126606
  }
126574
126607
  if (!quote.issuer.comparePublicKey(ledgerPubKey)) {
126575
126608
  throw new client_ledger_KeetaNetLedgerError('LEDGER_QUOTE_MISMATCH', 'Provided quote does not match issuer public key');
126576
126609
  }
126577
126610
  }
126578
- const transaction = client_ledger_assertClassBrand(client_LedgerAtomicInterface_brand, this, client_assertTransaction).call(this);
126579
126611
 
126580
126612
  /**
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
126613
+ * Verify some attributes about the other votes if they are provided
126584
126614
  */
126585
126615
  let hasFeeBlock = false;
126586
- if (otherVotes !== undefined) {
126587
- let foundOurVote = false;
126616
+ let foundOurVote;
126617
+ if (otherVotes) {
126618
+ foundOurVote = false;
126588
126619
  const seenVoteUIDs = new Set();
126589
126620
  const seenVoteIssuers = new client_lib_account.Set();
126590
126621
  let blockCount = blocks.length;
@@ -126596,7 +126627,7 @@ class client_LedgerAtomicInterface {
126596
126627
  const requiredFees = new Map();
126597
126628
  for (const checkVote of otherVotes) {
126598
126629
  if (checkVote.quote === true) {
126599
- throw new client_ledger_KeetaNetLedgerError('LEDGER_PERM_VOTE_WITH_QUOTE', 'Cannot request permanent votes with quotes');
126630
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_VOTE_WITH_QUOTE', 'Cannot request votes with quote as supporting votes');
126600
126631
  }
126601
126632
  if (seenVoteUIDs.has(checkVote.$id)) {
126602
126633
  throw new client_ledger_KeetaNetLedgerError('LEDGER_DUPLICATE_VOTE_FOUND', 'Duplicate vote UID found');
@@ -126609,13 +126640,22 @@ class client_LedgerAtomicInterface {
126609
126640
  if (checkVote.fee !== undefined) {
126610
126641
  requiredFees.set(checkVote.issuer, checkVote.fee);
126611
126642
  }
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');
126643
+
126644
+ /*
126645
+ * Handle errors specific to requesting a permanent vote
126646
+ */
126647
+ if (outcome === 'permanent') {
126648
+ if (checkVote.$permanent && checkVote.issuer.comparePublicKey(ledgerPubKey)) {
126649
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_CANNOT_EXCHANGE_PERM_VOTE', 'Asked to exchange a permanent vote from us for a permanent vote from us');
126650
+ }
126614
126651
  }
126652
+
126653
+ /* XXX:TODO: Need to account for fee blocks if the input is a permanent vote */
126615
126654
  let blocksDifferFromVoteBlocks = checkVote.blocks.length !== blockCount;
126616
126655
 
126617
126656
  /* If they do not differ from length alone, compare block hashes */
126618
126657
  if (!blocksDifferFromVoteBlocks) {
126658
+ /* XXX:TODO: Need to account for fee blocks if the input is a permanent vote */
126619
126659
  for (let blockIndex = 0; blockIndex < blockCount; blockIndex++) {
126620
126660
  if (!blocks[blockIndex].hash.compareHexString(checkVote.blocks[blockIndex])) {
126621
126661
  blocksDifferFromVoteBlocks = true;
@@ -126630,38 +126670,82 @@ class client_LedgerAtomicInterface {
126630
126670
  foundOurVote = true;
126631
126671
  }
126632
126672
  }
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');
126673
+
126674
+ /*
126675
+ * We only care about fees if we are issuing a permanent vote,
126676
+ * if we are issuing a temporary vote the fees will be checked
126677
+ * when the permanent vote is requested
126678
+ */
126679
+ if (outcome === 'permanent') {
126680
+ if (requiredFees.size > 0) {
126681
+ if (!hasFeeBlock) {
126682
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_MISSING_REQUIRED_FEE_BLOCK', 'Missing fee block but votes require it');
126683
+ }
126684
+ if (requiredFees.size !== (possibleFeeBlock === null || possibleFeeBlock === void 0 ? void 0 : possibleFeeBlock.operations.length)) {
126685
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_REQUIRED_FEE_MISMATCH', 'Fee Block Operations do not match required fees');
126686
+ }
126639
126687
  }
126640
- }
126641
126688
 
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()}`);
126689
+ // Verify that all required fees have been included in the fee block
126690
+ for (const [issuer, fee] of requiredFees) {
126691
+ const foundFee = possibleFeeBlock === null || possibleFeeBlock === void 0 ? void 0 : possibleFeeBlock.operations.find(operation => {
126692
+ var _fee$payTo, _fee$token;
126693
+ const expectedPayTo = (_fee$payTo = fee.payTo) !== null && _fee$payTo !== void 0 ? _fee$payTo : issuer;
126694
+ const expectedToken = (_fee$token = fee.token) !== null && _fee$token !== void 0 ? _fee$token : client_ledger_classPrivateFieldGet(client_ledger, this).baseToken;
126695
+ if (operation.type === client_OperationType.SEND && operation.to.comparePublicKey(expectedPayTo)) {
126696
+ if (operation.amount !== fee.amount) {
126697
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_FEE_AMOUNT_MISMATCH', `Fee Amount Mismatch, found: ${operation.amount} expected: ${fee.amount}`);
126698
+ }
126699
+ if (!operation.token.comparePublicKey(expectedToken)) {
126700
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_FEE_TOKEN_MISMATCH', `Fee Token Mismatch, found: ${operation.token.publicKeyString.get()} expected: ${expectedToken.publicKeyString.get()}`);
126701
+ }
126702
+ return true;
126654
126703
  }
126655
- return true;
126704
+ return false;
126705
+ });
126706
+ if (foundFee === undefined) {
126707
+ var _fee$payTo$publicKeyS, _fee$payTo2;
126708
+ 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
126709
  }
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
126710
  }
126711
+ } else if (outcome === 'temporary') {
126712
+ if (foundOurVote) {
126713
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_TEMP_VOTE_INCLUDES_SELF', 'Temporary vote request cannot include a vote from self');
126714
+ }
126715
+ /* 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 */
126716
+ } else {
126717
+ client_assertNever(outcome);
126718
+ }
126719
+ }
126720
+
126721
+ /**
126722
+ * If the outcome is a temporary vote and the are other votes
126723
+ * ensure that the temporary votes represent a minority of
126724
+ * the voting weight and do not include a vote from us
126725
+ */
126726
+ if (outcome === 'temporary' && otherVotes !== undefined) {
126727
+ const totalVotingPower = await this.votingPower();
126728
+ const minVotingWeight = totalVotingPower / 4n;
126729
+ const combinedVotingPower = (await Promise.all(otherVotes.map(async vote => {
126730
+ return await this.votingPower(vote.issuer);
126731
+ }))).reduce(function (sum, value) {
126732
+ return sum + value;
126733
+ }, 0n);
126734
+ if (combinedVotingPower <= minVotingWeight) {
126735
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_INSUFFICIENT_VOTING_WEIGHT', 'Temporary vote must represent at least a minority of the voting weight');
126736
+ }
126737
+ }
126738
+
126739
+ /**
126740
+ * If there are other votes, ensure one of them was issued by
126741
+ * us and the blocks are in the same order as the set of
126742
+ * blocks we are voting on now
126743
+ */
126744
+ if (outcome === 'permanent') {
126745
+ if (otherVotes === undefined) {
126746
+ throw new Error('internal error: Outcome permanent but otherVotes is undefined');
126663
126747
  }
126664
- if (!foundOurVote) {
126748
+ if (foundOurVote !== true) {
126665
126749
  throw new client_ledger_KeetaNetLedgerError('LEDGER_NO_PERM_WITHOUT_SELF_TEMP', 'Asked to give a permanent vote without a temporary vote from us');
126666
126750
  }
126667
126751
  }
@@ -126710,7 +126794,13 @@ class client_LedgerAtomicInterface {
126710
126794
  */
126711
126795
 
126712
126796
  let mayReplace = false;
126713
- if (previousVotes.length === 1 && otherVotes !== undefined && otherVotes.length !== 0) {
126797
+ if (previousVotes.length === 1 && outcome === 'permanent') {
126798
+ var _otherVotes$length;
126799
+ const otherVotesCount = (_otherVotes$length = otherVotes === null || otherVotes === void 0 ? void 0 : otherVotes.length) !== null && _otherVotes$length !== void 0 ? _otherVotes$length : 0;
126800
+ if (otherVotesCount < 1) {
126801
+ throw new Error('internal error: outcome permanent but otherVotes is empty or undefined');
126802
+ }
126803
+ ;
126714
126804
  const ourVote = previousVotes[0];
126715
126805
  mayReplace = !ourVote.$permanent && ourVote.issuer.comparePublicKey(ledgerPubKey);
126716
126806
  }
@@ -126721,15 +126811,25 @@ class client_LedgerAtomicInterface {
126721
126811
  }
126722
126812
 
126723
126813
  /**
126724
- * If no other votes have been supplied, validate that the blocks are valid, and issue a short vote
126814
+ * If we are producing a temporary vote, do it now and return
126725
126815
  */
126726
- if (otherVotes === undefined) {
126727
- const vote = await client_ledger_assertClassBrand(client_LedgerAtomicInterface_brand, this, client_voteOrQuoteWithFees).call(this, blocks, 'VOTE', quote);
126816
+ if (outcome === 'temporary') {
126817
+ const vote = await client_ledger_assertClassBrand(client_LedgerAtomicInterface_brand, this, client_voteOrQuoteWithFees).call(this, blocks, 'VOTE', quote, {
126818
+ requireBlockTimestampCheck
126819
+ });
126728
126820
  const blocksAndVote = src_client_VoteStaple.fromVotesAndBlocks([vote], blocks);
126729
126821
  await client_ledger_classPrivateFieldGet(client_ledger_storage, this).addPendingVote(transaction, blocksAndVote);
126730
126822
  return vote;
126731
126823
  }
126732
126824
 
126825
+ /**
126826
+ * From here on we are producing a permanent vote but we need
126827
+ * to narrow some types for TypeScript
126828
+ */
126829
+ if (otherVotes === undefined) {
126830
+ throw new Error('internal error: Outcome permanent but otherVotes is undefined');
126831
+ }
126832
+
126733
126833
  /**
126734
126834
  * Validate ledger outcome again before permanent votes if blocks includes a fee block
126735
126835
  */
@@ -127540,8 +127640,8 @@ async function client_validateBlocksForVote(blocks) {
127540
127640
  allLedgerIdempotentKeys
127541
127641
  };
127542
127642
  }
127543
- async function client_voteOrQuoteWithFees(blocks, type, quote) {
127544
- var _quote$fee;
127643
+ async function client_voteOrQuoteWithFees(blocks, type, quote, options) {
127644
+ var _options$requireBlock, _quote$fee;
127545
127645
  if (client_ledger_classPrivateFieldGet(client_ledger, this).ledgerWriteMode !== 'read-write') {
127546
127646
  throw new Error(`May not issue votes in read-only mode, in ${client_ledger_classPrivateFieldGet(client_ledger, this).ledgerWriteMode} mode`);
127547
127647
  }
@@ -127550,16 +127650,26 @@ async function client_voteOrQuoteWithFees(blocks, type, quote) {
127550
127650
  }
127551
127651
  client_ledger_assertClassBrand(client_LedgerAtomicInterface_brand, this, client_assertTransaction).call(this);
127552
127652
  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
127653
 
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()}`);
127654
+ /*
127655
+ * Ensure the block is relatively recent, otherwise a found
127656
+ * block for an account could be used to indefinitely delay voting
127657
+ * by continuously requesting votes on old blocks
127658
+ */
127659
+ const requireBlockTimestampCheck = (_options$requireBlock = options === null || options === void 0 ? void 0 : options.requireBlockTimestampCheck) !== null && _options$requireBlock !== void 0 ? _options$requireBlock : true;
127660
+ if (requireBlockTimestampCheck) {
127661
+ var _classPrivateFieldGet0, _classPrivateFieldGet1;
127662
+ 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();
127663
+ for (const block of blocks) {
127664
+ const blockDate = block.date.valueOf();
127665
+ const timeOffset = 5 /* m */ * 60 /* s */ * 1000 /* ms */;
127666
+
127667
+ /**
127668
+ * Do not allow short votes on blocks from the distant past
127669
+ */
127670
+ if (blockDate < now - timeOffset || blockDate > now + timeOffset) {
127671
+ throw new client_ledger_KeetaNetLedgerError('LEDGER_BLOCK_EXPIRED', `Refusing to issue vote for block dated ${block.date.toISOString()}`);
127672
+ }
127563
127673
  }
127564
127674
  }
127565
127675
 
@@ -128012,7 +128122,7 @@ client_lib_ledger_defineProperty(src_client_Ledger, "isInstance", client_checkab
128012
128122
  // EXTERNAL MODULE: ws (ignored)
128013
128123
  var client_ws_ignored_ = __webpack_require__(4708);
128014
128124
  ;// ./src/version.ts
128015
- const client_version = '0.14.9+gdb1185935886a43e4feda1919fa65830dc656174';
128125
+ const client_version = '0.14.10+g915d941de2a9b7990a6a140496a0e142eafaa9b7';
128016
128126
  /* harmony default export */ const client_src_version = ((/* unused pure expression or super */ null && (client_version)));
128017
128127
  ;// ./src/lib/p2p.ts
128018
128128
  /* provided dependency */ var client_p2p_Buffer = __webpack_require__(8287)["Buffer"];
@@ -132800,21 +132910,31 @@ class src_client_Client {
132800
132910
  if (!successorBlock) {
132801
132911
  return null;
132802
132912
  }
132803
- const getVotes = async (rep, hash) => {
132913
+ const getVote = async (rep, hash) => {
132914
+ var _votes$;
132804
132915
  let votes = null;
132805
132916
  try {
132806
132917
  votes = await client_client_assertClassBrand(client_Client_brand, this, client_getVotes).call(this, hash, 'side', rep);
132807
132918
  } catch {
132808
132919
  /* Ignore */
132809
132920
  }
132921
+ if (votes === null) {
132922
+ return {
132923
+ rep,
132924
+ vote: null
132925
+ };
132926
+ }
132927
+
132928
+ // Favor using permanent votes over short votes if the rep returns both
132929
+ votes.sort((voteA, voteB) => voteB.validityTo.valueOf() - voteA.validityTo.valueOf());
132810
132930
  return {
132811
132931
  rep: rep,
132812
- votes: votes
132932
+ vote: (_votes$ = votes[0]) !== null && _votes$ !== void 0 ? _votes$ : null
132813
132933
  };
132814
132934
  };
132815
132935
  const votePromises = [];
132816
132936
  for (const rep of client_client_classPrivateFieldGet(client_reps, this)) {
132817
- votePromises.push(getVotes(rep, successorBlock.hash));
132937
+ votePromises.push(getVote(rep, successorBlock.hash));
132818
132938
  }
132819
132939
  const votesInfo = await Promise.all(votePromises);
132820
132940
  if (votesInfo.length === 0) {
@@ -132832,18 +132952,16 @@ class src_client_Client {
132832
132952
  /* Any reps that did not generate any vote */
132833
132953
  const missingReps = [];
132834
132954
  for (const repInfo of votesInfo) {
132835
- const repVotes = repInfo.votes;
132836
- if (repVotes === null) {
132955
+ const repVote = repInfo.vote;
132956
+ if (repVote === null) {
132837
132957
  missingReps.push(repInfo.rep);
132838
132958
  } 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
- }
132959
+ if (repVote.$permanent === true) {
132960
+ permVotes.push(repVote);
132961
+ permReps.push(repInfo.rep);
132962
+ } else {
132963
+ tempVotes.push(repVote);
132964
+ tempReps.push(repInfo.rep);
132847
132965
  }
132848
132966
  }
132849
132967
  }
@@ -132893,7 +133011,12 @@ class src_client_Client {
132893
133011
  let newTempVotes = [];
132894
133012
  if (tempVotes.length !== client_client_classPrivateFieldGet(client_reps, this).length) {
132895
133013
  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);
133014
+ /**
133015
+ * If we are trying to recover an old block that has some permanent votes, send those votes in the request
133016
+ * Otherwise the rep will reject the old block and won't issue a vote
133017
+ */
133018
+ const otherVotes = permVotes.length > 0 ? permVotes : undefined;
133019
+ 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
133020
  } catch {
132898
133021
  /* Ignore */
132899
133022
  }
@@ -132918,7 +133041,7 @@ class src_client_Client {
132918
133041
  votedOnBlocks.push(feeBlock);
132919
133042
  }
132920
133043
  try {
132921
- const newPermVotes = await client_client_assertClassBrand(client_Client_brand, this, client_requestVotes).call(this, votedOnBlocks, tempVotes, missingPermReps);
133044
+ const newPermVotes = await client_client_assertClassBrand(client_Client_brand, this, client_requestVotes).call(this, votedOnBlocks, [...tempVotes, ...permVotes], missingPermReps);
132922
133045
  permVotes = [...permVotes, ...newPermVotes];
132923
133046
  } catch {
132924
133047
  /* Ignore */
@@ -132945,7 +133068,7 @@ class src_client_Client {
132945
133068
  * @param publish Publish the synced staple to the network (default is true)
132946
133069
  */
132947
133070
  async syncAccount(account) {
132948
- var _accountInfoSorted$0$, _accountInfoSorted$in, _accountInfoSorted$0$2, _accountInfoSorted$0$3;
133071
+ var _accountInfoSorted$in, _accountInfoSorted$0$;
132949
133072
  let publish = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
132950
133073
  let reps = arguments.length > 2 ? arguments[2] : undefined;
132951
133074
  await client_client_classPrivateFieldGet(client_updateRepsPromise, this);
@@ -132973,11 +133096,12 @@ class src_client_Client {
132973
133096
  var _a$info$height, _a$info, _b$info$height, _b$info;
132974
133097
  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
133098
  });
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)) {
133099
+ const lowestInfo = accountInfoSorted[0].info;
133100
+ 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
133101
  // Block Heights match so return
132978
133102
  return null;
132979
133103
  }
132980
- let lowestHead = (_accountInfoSorted$0$2 = accountInfoSorted[0].info) === null || _accountInfoSorted$0$2 === void 0 ? void 0 : _accountInfoSorted$0$2.block.hash;
133104
+ let lowestHead = lowestInfo === null || lowestInfo === void 0 ? void 0 : lowestInfo.block.hash;
132981
133105
  if (lowestHead === null || lowestHead === undefined) {
132982
133106
  lowestHead = client_lib_block.getAccountOpeningHash(account);
132983
133107
  }
@@ -132992,10 +133116,28 @@ class src_client_Client {
132992
133116
  return null;
132993
133117
  }
132994
133118
  if (publish === true) {
132995
- await this.transmitStaple(successorStaple, [accountInfoSorted[0].rep]);
133119
+ const allLowestReps = [];
133120
+ for (const accountInfo of accountInfoSorted) {
133121
+ var _accountInfo$info;
133122
+ // All lowest reps could be missing the opening block and info would be null so make sure we send to all of them
133123
+ if (((_accountInfo$info = accountInfo.info) === null || _accountInfo$info === void 0 ? void 0 : _accountInfo$info.height) === (lowestInfo === null || lowestInfo === void 0 ? void 0 : lowestInfo.height)) {
133124
+ allLowestReps.push(accountInfo.rep);
133125
+ }
133126
+ }
133127
+ for (const rep of allLowestReps) {
133128
+ // we publish these serially to avoid transaction conflicts, but publish to all to ensure that every missing rep sees the staple
133129
+ try {
133130
+ await this.transmitStaple(successorStaple, [rep]);
133131
+ } catch {
133132
+ /**
133133
+ * Ignore transmit errors like LEDGER_BLOCK_ALREADY_EXISTS
133134
+ * We will check block heights after to see if sync was performed
133135
+ */
133136
+ }
133137
+ }
132996
133138
  }
132997
133139
  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)) {
133140
+ 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
133141
  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
133142
  }
133001
133143
  return successorStaple;