@bsv/sdk 1.7.5 → 1.7.7

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/sdk",
3
- "version": "1.7.5",
3
+ "version": "1.7.7",
4
4
  "type": "module",
5
5
  "description": "BSV Blockchain Software Development Kit",
6
6
  "main": "dist/cjs/mod.js",
@@ -55,6 +55,7 @@ export class AuthFetch {
55
55
  this.wallet = wallet
56
56
  this.requestedCertificates = requestedCertificates
57
57
  this.sessionManager = sessionManager ?? new SessionManager()
58
+ this.originator = originator
58
59
  }
59
60
 
60
61
  /**
@@ -77,6 +77,7 @@ export class Beef {
77
77
  txs: BeefTx[] = []
78
78
  version: number = BEEF_V2
79
79
  atomicTxid: string | undefined = undefined
80
+ private txidIndex: Map<string, BeefTx> | undefined = undefined
80
81
 
81
82
  constructor (version: number = BEEF_V2) {
82
83
  this.version = version
@@ -87,7 +88,25 @@ export class Beef {
87
88
  * @returns `BeefTx` in `txs` with `txid`.
88
89
  */
89
90
  findTxid (txid: string): BeefTx | undefined {
90
- return this.txs.find((tx) => tx.txid === txid)
91
+ return this.ensureTxidIndex().get(txid)
92
+ }
93
+
94
+ private ensureTxidIndex (): Map<string, BeefTx> {
95
+ if (this.txidIndex == null) {
96
+ this.txidIndex = new Map<string, BeefTx>()
97
+ for (const tx of this.txs) {
98
+ this.txidIndex.set(tx.txid, tx)
99
+ }
100
+ }
101
+ return this.txidIndex
102
+ }
103
+
104
+ private deleteFromIndex (txid: string): void {
105
+ this.txidIndex?.delete(txid)
106
+ }
107
+
108
+ private addToIndex (tx: BeefTx): void {
109
+ this.txidIndex?.set(tx.txid, tx)
91
110
  }
92
111
 
93
112
  /**
@@ -107,6 +126,7 @@ export class Beef {
107
126
  if (btx.isTxidOnly) {
108
127
  return btx
109
128
  }
129
+ this.deleteFromIndex(txid)
110
130
  this.txs.splice(i, 1)
111
131
  btx = this.mergeTxidOnly(txid)
112
132
  return btx
@@ -254,6 +274,7 @@ export class Beef {
254
274
  const newTx: BeefTx = new BeefTx(rawTx, bumpIndex)
255
275
  this.removeExistingTxid(newTx.txid)
256
276
  this.txs.push(newTx)
277
+ this.addToIndex(newTx)
257
278
  this.tryToValidateBumpIndex(newTx)
258
279
  return newTx
259
280
  }
@@ -277,6 +298,7 @@ export class Beef {
277
298
  }
278
299
  const newTx = new BeefTx(tx, bumpIndex)
279
300
  this.txs.push(newTx)
301
+ this.addToIndex(newTx)
280
302
  this.tryToValidateBumpIndex(newTx)
281
303
  bumpIndex = newTx.bumpIndex
282
304
  if (bumpIndex === undefined) {
@@ -296,15 +318,17 @@ export class Beef {
296
318
  removeExistingTxid (txid: string): void {
297
319
  const existingTxIndex = this.txs.findIndex((t) => t.txid === txid)
298
320
  if (existingTxIndex >= 0) {
321
+ this.deleteFromIndex(txid)
299
322
  this.txs.splice(existingTxIndex, 1)
300
323
  }
301
324
  }
302
325
 
303
326
  mergeTxidOnly (txid: string): BeefTx {
304
- let tx = this.txs.find((t) => t.txid === txid)
327
+ let tx = this.findTxid(txid)
305
328
  if (tx == null) {
306
329
  tx = new BeefTx(txid)
307
330
  this.txs.push(tx)
331
+ this.addToIndex(tx)
308
332
  this.tryToValidateBumpIndex(tx)
309
333
  }
310
334
  return tx
@@ -743,6 +767,7 @@ export class Beef {
743
767
  c.version = this.version
744
768
  c.bumps = Array.from(this.bumps)
745
769
  c.txs = Array.from(this.txs)
770
+ c.txidIndex = undefined
746
771
  return c
747
772
  }
748
773
 
@@ -754,6 +779,7 @@ export class Beef {
754
779
  for (let i = 0; i < this.txs.length;) {
755
780
  const tx = this.txs[i]
756
781
  if (tx.isTxidOnly && knownTxids.includes(tx.txid)) {
782
+ this.deleteFromIndex(tx.txid)
757
783
  this.txs.splice(i, 1)
758
784
  } else {
759
785
  i++
@@ -912,49 +912,49 @@ export default class Transaction {
912
912
  const writer = new Writer()
913
913
  writer.writeUInt32LE(BEEF_V1)
914
914
  const BUMPs: MerklePath[] = []
915
+ const bumpIndexByInstance = new Map<MerklePath, number>()
916
+ const bumpIndexByRoot = new Map<string, number>()
915
917
  const txs: Array<{ tx: Transaction, pathIndex?: number }> = []
918
+ const seenTxids = new Set<string>()
919
+
920
+ const getBumpIndex = (merklePath: MerklePath): number => {
921
+ const existingByInstance = bumpIndexByInstance.get(merklePath)
922
+ if (existingByInstance !== undefined) {
923
+ return existingByInstance
924
+ }
925
+
926
+ const key = `${merklePath.blockHeight}:${merklePath.computeRoot()}`
927
+ const existingByRoot = bumpIndexByRoot.get(key)
928
+ if (existingByRoot !== undefined) {
929
+ BUMPs[existingByRoot].combine(merklePath)
930
+ bumpIndexByInstance.set(merklePath, existingByRoot)
931
+ return existingByRoot
932
+ }
933
+
934
+ const newIndex = BUMPs.length
935
+ BUMPs.push(merklePath)
936
+ bumpIndexByInstance.set(merklePath, newIndex)
937
+ bumpIndexByRoot.set(key, newIndex)
938
+ return newIndex
939
+ }
916
940
 
917
941
  // Recursive function to add paths and input transactions for a TX
918
942
  const addPathsAndInputs = (tx: Transaction): void => {
919
- const obj: { tx: Transaction, pathIndex?: number } = { tx }
920
- const hasProof = typeof tx.merklePath === 'object'
921
- if (hasProof) {
922
- let added = false
923
- // If this proof is identical to another one previously added, we use that first. Otherwise, we try to merge it with proofs from the same block.
924
- for (let i = 0; i < BUMPs.length; i++) {
925
- if (BUMPs[i] === tx.merklePath) {
926
- // Literally the same
927
- obj.pathIndex = i
928
- added = true
929
- break
930
- }
931
- if (tx.merklePath !== null && tx.merklePath !== undefined && BUMPs[i].blockHeight === tx.merklePath.blockHeight) {
932
- // Probably the same...
933
- const rootA = BUMPs[i].computeRoot()
934
- const rootB = tx.merklePath.computeRoot()
935
- if (rootA === rootB) {
936
- // Definitely the same... combine them to save space
937
- BUMPs[i].combine(tx.merklePath)
938
- obj.pathIndex = i
939
- added = true
940
- break
941
- }
942
- }
943
- }
944
- // Finally, if the proof is not yet added, add a new path.
945
- if (!added) {
946
- obj.pathIndex = BUMPs.length
947
- if (tx.merklePath !== null && tx.merklePath !== undefined) {
948
- BUMPs.push(tx.merklePath)
949
- }
950
- }
943
+ const txid = tx.id('hex')
944
+ if (seenTxids.has(txid)) {
945
+ return
951
946
  }
952
- const duplicate = txs.some((x) => x.tx.id('hex') === tx.id('hex'))
953
- if (!duplicate) {
954
- txs.unshift(obj)
947
+
948
+ const obj: { tx: Transaction, pathIndex?: number } = { tx }
949
+ const merklePath = tx.merklePath
950
+ const hasProof = typeof merklePath === 'object'
951
+
952
+ if (hasProof && merklePath != null) {
953
+ obj.pathIndex = getBumpIndex(merklePath)
955
954
  }
955
+
956
956
  if (!hasProof) {
957
- for (let i = 0; i < tx.inputs.length; i++) {
957
+ for (let i = tx.inputs.length - 1; i >= 0; i--) {
958
958
  const input = tx.inputs[i]
959
959
  if (typeof input.sourceTransaction === 'object') {
960
960
  addPathsAndInputs(input.sourceTransaction)
@@ -963,6 +963,9 @@ export default class Transaction {
963
963
  }
964
964
  }
965
965
  }
966
+
967
+ seenTxids.add(txid)
968
+ txs.push(obj)
966
969
  }
967
970
 
968
971
  addPathsAndInputs(this)