@bsv/sdk 1.1.29 → 1.1.32
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/dist/cjs/package.json +1 -1
- package/dist/cjs/src/primitives/Schnorr.js +92 -0
- package/dist/cjs/src/primitives/Schnorr.js.map +1 -0
- package/dist/cjs/src/primitives/index.js +3 -1
- package/dist/cjs/src/primitives/index.js.map +1 -1
- package/dist/cjs/src/totp/totp.js +1 -1
- package/dist/cjs/src/totp/totp.js.map +1 -1
- package/dist/cjs/src/transaction/Beef.js +292 -155
- package/dist/cjs/src/transaction/Beef.js.map +1 -1
- package/dist/cjs/src/transaction/BeefParty.js +46 -26
- package/dist/cjs/src/transaction/BeefParty.js.map +1 -1
- package/dist/cjs/src/transaction/BeefTx.js +31 -16
- package/dist/cjs/src/transaction/BeefTx.js.map +1 -1
- package/dist/cjs/src/transaction/MerklePath.js.map +1 -1
- package/dist/cjs/src/transaction/Transaction.js +12 -6
- package/dist/cjs/src/transaction/Transaction.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/primitives/Schnorr.js +87 -0
- package/dist/esm/src/primitives/Schnorr.js.map +1 -0
- package/dist/esm/src/primitives/index.js +1 -0
- package/dist/esm/src/primitives/index.js.map +1 -1
- package/dist/esm/src/totp/totp.js +1 -1
- package/dist/esm/src/totp/totp.js.map +1 -1
- package/dist/esm/src/transaction/Beef.js +294 -157
- package/dist/esm/src/transaction/Beef.js.map +1 -1
- package/dist/esm/src/transaction/BeefParty.js +47 -27
- package/dist/esm/src/transaction/BeefParty.js.map +1 -1
- package/dist/esm/src/transaction/BeefTx.js +35 -20
- package/dist/esm/src/transaction/BeefTx.js.map +1 -1
- package/dist/esm/src/transaction/MerklePath.js.map +1 -1
- package/dist/esm/src/transaction/Transaction.js +12 -6
- package/dist/esm/src/transaction/Transaction.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/primitives/Schnorr.d.ts +65 -0
- package/dist/types/src/primitives/Schnorr.d.ts.map +1 -0
- package/dist/types/src/primitives/index.d.ts +1 -0
- package/dist/types/src/primitives/index.d.ts.map +1 -1
- package/dist/types/src/transaction/Beef.d.ts +131 -90
- package/dist/types/src/transaction/Beef.d.ts.map +1 -1
- package/dist/types/src/transaction/BeefParty.d.ts +34 -23
- package/dist/types/src/transaction/BeefParty.d.ts.map +1 -1
- package/dist/types/src/transaction/BeefTx.d.ts +11 -6
- package/dist/types/src/transaction/BeefTx.d.ts.map +1 -1
- package/dist/types/src/transaction/MerklePath.d.ts.map +1 -1
- package/dist/types/src/transaction/Transaction.d.ts +8 -2
- package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +1 -1
- package/docs/primitives.md +120 -9
- package/docs/transaction.md +141 -9
- package/package.json +1 -1
- package/src/primitives/Schnorr.ts +95 -0
- package/src/primitives/__tests/Schnorr.test.ts +272 -0
- package/src/primitives/index.ts +1 -0
- package/src/totp/totp.ts +1 -1
- package/src/transaction/Beef.ts +493 -378
- package/src/transaction/BeefParty.ts +71 -58
- package/src/transaction/BeefTx.ts +133 -143
- package/src/transaction/MerklePath.ts +11 -11
- package/src/transaction/Transaction.ts +42 -36
- package/src/transaction/__tests/Beef.test.ts +55 -10
|
@@ -1,100 +1,113 @@
|
|
|
1
|
-
import { Beef } from
|
|
1
|
+
import { Beef } from './Beef.js'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Extends `Beef` that is used to exchange transaction validity data with more than one external party.
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
6
|
* Use `addKnownTxidsForParty` to keep track of who knows what to reduce re-transmission of potentially large transactions.
|
|
7
|
-
*
|
|
7
|
+
*
|
|
8
8
|
* Use `getTrimmedBeefForParty` to obtain a `Beef` trimmed of transaction validity data known to a specific party.
|
|
9
|
-
*
|
|
9
|
+
*
|
|
10
10
|
* Typical usage scenario:
|
|
11
|
-
*
|
|
11
|
+
*
|
|
12
12
|
* 1. Query a wallet storage provider for spendable outputs.
|
|
13
13
|
* 2. The provider replies with a Beef validating the returned outputs.
|
|
14
14
|
* 3. Construct a new transaction using some of the queried outputs as inputs, including Beef validating all the inputs.
|
|
15
15
|
* 4. Receive new valid raw transaction after processing and Beef validating change outputs added to original inputs.
|
|
16
16
|
* 5. Return to step 1, continuing to build on old and new spendable outputs.
|
|
17
|
-
*
|
|
17
|
+
*
|
|
18
18
|
* By default, each Beef is required to be complete and valid: All transactions appear as full serialized bitcoin transactions and
|
|
19
19
|
* each transaction either has a merkle path proof (it has been mined) or all of its input transactions are included.
|
|
20
|
-
*
|
|
20
|
+
*
|
|
21
21
|
* The size and redundancy of these Beefs becomes a problem when chained transaction creation out-paces the block mining rate.
|
|
22
|
-
*
|
|
22
|
+
*
|
|
23
23
|
*/
|
|
24
24
|
export class BeefParty extends Beef {
|
|
25
|
-
|
|
25
|
+
/**
|
|
26
26
|
* keys are party identifiers.
|
|
27
27
|
* values are records of txids with truthy value for which the party already has validity proof.
|
|
28
28
|
*/
|
|
29
|
-
|
|
29
|
+
knownTo: Record<string, Record<string, boolean>> = {}
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
*
|
|
31
|
+
/**
|
|
32
|
+
*
|
|
33
33
|
* @param parties Optional array of initial unique party identifiers.
|
|
34
34
|
*/
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
this.addParty(party)
|
|
40
|
-
}
|
|
35
|
+
constructor (parties?: string[]) {
|
|
36
|
+
super()
|
|
37
|
+
if (parties) {
|
|
38
|
+
for (const party of parties) { this.addParty(party) }
|
|
41
39
|
}
|
|
40
|
+
}
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
* @param party
|
|
42
|
+
/**
|
|
43
|
+
* @param party
|
|
45
44
|
* @returns `true` if `party` has already beed added to this `BeefParty`.
|
|
46
45
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
isParty (party: string) {
|
|
47
|
+
const r = Object.keys(this.knownTo).includes(party)
|
|
48
|
+
return r
|
|
49
|
+
}
|
|
51
50
|
|
|
52
|
-
|
|
51
|
+
/**
|
|
53
52
|
* Adds a new unique party identifier to this `BeefParty`.
|
|
54
|
-
* @param party
|
|
53
|
+
* @param party
|
|
55
54
|
*/
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
55
|
+
addParty (party: string) {
|
|
56
|
+
if (this.isParty(party)) { throw new Error(`Party ${party} already exists.`) }
|
|
57
|
+
this.knownTo[party] = {}
|
|
58
|
+
}
|
|
61
59
|
|
|
62
|
-
|
|
63
|
-
* @param party
|
|
60
|
+
/**
|
|
61
|
+
* @param party
|
|
64
62
|
* @returns Array of txids "known" to `party`.
|
|
65
63
|
*/
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
64
|
+
getKnownTxidsForParty (party: string): string[] {
|
|
65
|
+
const knownTxids = this.knownTo[party]
|
|
66
|
+
if (!knownTxids) { throw new Error(`Party ${party} is unknown.`) }
|
|
67
|
+
return Object.keys(knownTxids)
|
|
68
|
+
}
|
|
72
69
|
|
|
73
|
-
|
|
74
|
-
* @param party
|
|
70
|
+
/**
|
|
71
|
+
* @param party
|
|
75
72
|
* @returns trimmed beef of unknown transactions and proofs for `party`
|
|
76
73
|
*/
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
74
|
+
getTrimmedBeefForParty (party: string): Beef {
|
|
75
|
+
const knownTxids = this.getKnownTxidsForParty(party)
|
|
76
|
+
const prunedBeef = this.clone()
|
|
77
|
+
prunedBeef.trimKnownTxids(knownTxids)
|
|
78
|
+
return prunedBeef
|
|
79
|
+
}
|
|
83
80
|
|
|
84
|
-
|
|
81
|
+
/**
|
|
85
82
|
* Make note of additional txids "known" to `party`.
|
|
86
83
|
* @param party unique identifier, added if new.
|
|
87
|
-
* @param knownTxids
|
|
84
|
+
* @param knownTxids
|
|
88
85
|
*/
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
this.mergeTxidOnly(txid)
|
|
96
|
-
}
|
|
86
|
+
addKnownTxidsForParty (party: string, knownTxids: string[]) {
|
|
87
|
+
if (!this.isParty(party)) { this.addParty(party) }
|
|
88
|
+
const kts = this.knownTo[party]
|
|
89
|
+
for (const txid of knownTxids) {
|
|
90
|
+
kts[txid] = true
|
|
91
|
+
this.mergeTxidOnly(txid)
|
|
97
92
|
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Merge a `beef` received from a specific `party`.
|
|
97
|
+
*
|
|
98
|
+
* Updates this `BeefParty` to track all the txids
|
|
99
|
+
* corresponding to transactions for which `party`
|
|
100
|
+
* has raw transaction and validity proof data.
|
|
101
|
+
*
|
|
102
|
+
* @param party
|
|
103
|
+
* @param beef
|
|
104
|
+
*/
|
|
105
|
+
mergeBeefFromParty (party: string, beef: number[] | Beef) {
|
|
106
|
+
const b: Beef = Array.isArray(beef) ? Beef.fromBinary(beef) : beef
|
|
107
|
+
const knownTxids = b.getValidTxids()
|
|
108
|
+
this.mergeBeef(b)
|
|
109
|
+
this.addKnownTxidsForParty(party, knownTxids)
|
|
110
|
+
}
|
|
98
111
|
}
|
|
99
112
|
|
|
100
|
-
export default BeefParty
|
|
113
|
+
export default BeefParty
|
|
@@ -1,162 +1,152 @@
|
|
|
1
|
-
import { hash256 } from
|
|
2
|
-
import { Reader, Writer, toHex, toArray } from
|
|
3
|
-
import Transaction from
|
|
4
|
-
import { BEEF_MAGIC, BEEF_MAGIC_TXID_ONLY_EXTENSION } from
|
|
1
|
+
import { hash256 } from '../primitives/Hash.js'
|
|
2
|
+
import { Reader, Writer, toHex, toArray } from '../primitives/utils.js'
|
|
3
|
+
import Transaction from './Transaction.js'
|
|
4
|
+
import { BEEF_MAGIC, BEEF_MAGIC_TXID_ONLY_EXTENSION } from './Beef.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* A single bitcoin transaction associated with a `Beef` validity proof set.
|
|
8
|
-
*
|
|
8
|
+
*
|
|
9
9
|
* Simple case is transaction data included directly, either as raw bytes or fully parsed data, or both.
|
|
10
|
-
*
|
|
10
|
+
*
|
|
11
11
|
* Supports 'known' transactions which are represented by just their txid.
|
|
12
12
|
* It is assumed that intended consumer of this beef already has validity proof for such a transaction,
|
|
13
13
|
* which they can merge if necessary to create a valid beef.
|
|
14
14
|
*/
|
|
15
15
|
export default class BeefTx {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
16
|
+
_bumpIndex?: number
|
|
17
|
+
_tx?: Transaction
|
|
18
|
+
_rawTx?: number[]
|
|
19
|
+
_txid?: string
|
|
20
|
+
inputTxids: string[] = []
|
|
21
|
+
/**
|
|
22
|
+
* true if `hasProof` or all inputs chain to `hasProof`.
|
|
23
|
+
*
|
|
24
|
+
* Typically set by sorting transactions by proven dependency chains.
|
|
25
|
+
*/
|
|
26
|
+
isValid?: boolean = undefined
|
|
27
|
+
|
|
28
|
+
get bumpIndex (): number | undefined { return this._bumpIndex }
|
|
29
|
+
|
|
30
|
+
set bumpIndex (v: number | undefined) {
|
|
31
|
+
this._bumpIndex = v
|
|
32
|
+
this.updateInputTxids()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get hasProof (): boolean {
|
|
36
|
+
return this._bumpIndex !== undefined
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get isTxidOnly (): boolean {
|
|
40
|
+
return !!this._txid && !this._rawTx && !this._tx
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get txid () {
|
|
44
|
+
if (this._txid) return this._txid
|
|
45
|
+
if (this._tx) return this._txid = this._tx.id('hex')
|
|
46
|
+
if (this._rawTx) return this._txid = toHex(hash256(this._rawTx))
|
|
47
|
+
throw new Error('Internal')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get tx () {
|
|
51
|
+
if (this._tx) return this._tx
|
|
52
|
+
if (this._rawTx) return this._tx = Transaction.fromBinary(this._rawTx)
|
|
53
|
+
return undefined
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
get rawTx () {
|
|
57
|
+
if (this._rawTx) return this._rawTx
|
|
58
|
+
if (this._tx) return this._rawTx = this._tx.toBinary()
|
|
59
|
+
return undefined
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
58
63
|
* @param tx If string, must be a valid txid. If `number[]` must be a valid serialized transaction.
|
|
59
64
|
* @param bumpIndex If transaction already has a proof in the beef to which it will be added.
|
|
60
65
|
*/
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
this.bumpIndex = bumpIndex
|
|
72
|
-
this.updateInputTxids()
|
|
66
|
+
constructor (tx: Transaction | number[] | string, bumpIndex?: number) {
|
|
67
|
+
if (typeof tx === 'string') {
|
|
68
|
+
this._txid = tx
|
|
69
|
+
} else {
|
|
70
|
+
if (Array.isArray(tx)) {
|
|
71
|
+
this._rawTx = tx
|
|
72
|
+
} else {
|
|
73
|
+
this._tx = tx
|
|
74
|
+
}
|
|
73
75
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
76
|
+
this.bumpIndex = bumpIndex
|
|
77
|
+
this.updateInputTxids()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private updateInputTxids () {
|
|
81
|
+
if (this.hasProof || !this.tx)
|
|
82
|
+
// If we have a proof, or don't have a parsed transaction
|
|
83
|
+
{ this.inputTxids = [] } else {
|
|
84
|
+
const inputTxids = {}
|
|
85
|
+
for (const input of this.tx.inputs) { inputTxids[input.sourceTXID] = true }
|
|
86
|
+
this.inputTxids = Object.keys(inputTxids)
|
|
85
87
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
toWriter (writer: Writer, magic: number): void {
|
|
91
|
+
if (magic === BEEF_MAGIC) {
|
|
92
|
+
// V1
|
|
93
|
+
if (this.isTxidOnly) {
|
|
94
|
+
// Encode just the txid of a known transaction using the txid
|
|
95
|
+
writer.writeUInt32LE(BEEF_MAGIC_TXID_ONLY_EXTENSION)
|
|
96
|
+
writer.writeReverse(toArray(this._txid, 'hex'))
|
|
97
|
+
} else if (this._rawTx) { writer.write(this._rawTx) } else if (this._tx) { writer.write(this._tx.toBinary()) } else { throw new Error('a valid serialized Transaction is expected') }
|
|
98
|
+
if (this.bumpIndex === undefined) {
|
|
99
|
+
writer.writeUInt8(0)
|
|
100
|
+
} else {
|
|
101
|
+
writer.writeUInt8(1)
|
|
102
|
+
writer.writeVarIntNum(this.bumpIndex)
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
// V2
|
|
106
|
+
if (this.isTxidOnly) {
|
|
107
|
+
// Encode just the txid of a known transaction using the txid
|
|
108
|
+
writer.writeUInt8(2)
|
|
109
|
+
writer.writeReverse(toArray(this._txid, 'hex'))
|
|
110
|
+
} else {
|
|
111
|
+
if (this.bumpIndex === undefined) {
|
|
112
|
+
writer.writeUInt8(0)
|
|
106
113
|
} else {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
// Encode just the txid of a known transaction using the txid
|
|
110
|
-
writer.writeUInt8(2)
|
|
111
|
-
writer.writeReverse(toArray(this._txid, 'hex'))
|
|
112
|
-
} else {
|
|
113
|
-
if (this.bumpIndex === undefined) {
|
|
114
|
-
writer.writeUInt8(0)
|
|
115
|
-
} else {
|
|
116
|
-
writer.writeUInt8(1)
|
|
117
|
-
writer.writeVarIntNum(this.bumpIndex)
|
|
118
|
-
}
|
|
119
|
-
if (this._rawTx)
|
|
120
|
-
writer.write(this._rawTx)
|
|
121
|
-
else if (this._tx)
|
|
122
|
-
writer.write(this._tx.toBinary())
|
|
123
|
-
else
|
|
124
|
-
throw new Error('a valid serialized Transaction is expected')
|
|
125
|
-
}
|
|
114
|
+
writer.writeUInt8(1)
|
|
115
|
+
writer.writeVarIntNum(this.bumpIndex)
|
|
126
116
|
}
|
|
117
|
+
if (this._rawTx) { writer.write(this._rawTx) } else if (this._tx) { writer.write(this._tx.toBinary()) } else { throw new Error('a valid serialized Transaction is expected') }
|
|
118
|
+
}
|
|
127
119
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const beefTx = new BeefTx(tx, bumpIndex)
|
|
159
|
-
return beefTx
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
static fromReader (br: Reader, magic: number): BeefTx {
|
|
123
|
+
let tx: Transaction | number[] | string | undefined
|
|
124
|
+
let bumpIndex: number | undefined
|
|
125
|
+
|
|
126
|
+
if (magic === BEEF_MAGIC) {
|
|
127
|
+
// V1
|
|
128
|
+
const version = br.readUInt32LE()
|
|
129
|
+
if (version === BEEF_MAGIC_TXID_ONLY_EXTENSION) {
|
|
130
|
+
// This is the extension to support known transactions
|
|
131
|
+
tx = toHex(br.readReverse(32))
|
|
132
|
+
} else {
|
|
133
|
+
br.pos -= 4 // Unread the version...
|
|
134
|
+
tx = Transaction.fromReader(br)
|
|
135
|
+
}
|
|
136
|
+
bumpIndex = br.readUInt8() ? br.readVarIntNum() : undefined
|
|
137
|
+
} else {
|
|
138
|
+
// V2
|
|
139
|
+
const format = br.readUInt8()
|
|
140
|
+
if (format === 2) {
|
|
141
|
+
// txid only
|
|
142
|
+
tx = toHex(br.readReverse(32))
|
|
143
|
+
} else {
|
|
144
|
+
if (format === 1) { bumpIndex = br.readVarIntNum() }
|
|
145
|
+
tx = Transaction.fromReader(br)
|
|
146
|
+
}
|
|
160
147
|
}
|
|
161
148
|
|
|
162
|
-
|
|
149
|
+
const beefTx = new BeefTx(tx, bumpIndex)
|
|
150
|
+
return beefTx
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -46,11 +46,11 @@ export default class MerklePath {
|
|
|
46
46
|
* @param {string} hex - The hexadecimal string representation of the Merkle Path.
|
|
47
47
|
* @returns {MerklePath} - A new MerklePath instance.
|
|
48
48
|
*/
|
|
49
|
-
static fromHex(hex: string): MerklePath {
|
|
49
|
+
static fromHex (hex: string): MerklePath {
|
|
50
50
|
return MerklePath.fromBinary(toArray(hex, 'hex'))
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
static fromReader(reader: Reader): MerklePath {
|
|
53
|
+
static fromReader (reader: Reader): MerklePath {
|
|
54
54
|
const blockHeight = reader.readVarIntNum()
|
|
55
55
|
const treeHeight = reader.readUInt8()
|
|
56
56
|
const path = Array(treeHeight).fill(0).map(() => ([]))
|
|
@@ -89,12 +89,12 @@ export default class MerklePath {
|
|
|
89
89
|
* @param {number[]} bump - The binary array representation of the Merkle Path.
|
|
90
90
|
* @returns {MerklePath} - A new MerklePath instance.
|
|
91
91
|
*/
|
|
92
|
-
static fromBinary(bump: number[]): MerklePath {
|
|
92
|
+
static fromBinary (bump: number[]): MerklePath {
|
|
93
93
|
const reader = new Reader(bump)
|
|
94
94
|
return MerklePath.fromReader(reader)
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
constructor(blockHeight: number, path: Array<Array<{
|
|
97
|
+
constructor (blockHeight: number, path: Array<Array<{
|
|
98
98
|
offset: number
|
|
99
99
|
hash?: string
|
|
100
100
|
txid?: boolean
|
|
@@ -142,7 +142,7 @@ export default class MerklePath {
|
|
|
142
142
|
*
|
|
143
143
|
* @returns {number[]} - The binary array representation of the Merkle Path.
|
|
144
144
|
*/
|
|
145
|
-
toBinary(): number[] {
|
|
145
|
+
toBinary (): number[] {
|
|
146
146
|
const writer = new Writer()
|
|
147
147
|
writer.writeVarIntNum(this.blockHeight)
|
|
148
148
|
const treeHeight = this.path.length
|
|
@@ -173,7 +173,7 @@ export default class MerklePath {
|
|
|
173
173
|
*
|
|
174
174
|
* @returns {string} - The hexadecimal string representation of the Merkle Path.
|
|
175
175
|
*/
|
|
176
|
-
toHex(): string {
|
|
176
|
+
toHex (): string {
|
|
177
177
|
return toHex(this.toBinary())
|
|
178
178
|
}
|
|
179
179
|
|
|
@@ -184,7 +184,7 @@ export default class MerklePath {
|
|
|
184
184
|
* @returns {string} - The computed Merkle root as a hexadecimal string.
|
|
185
185
|
* @throws {Error} - If the transaction ID is not part of the Merkle Path.
|
|
186
186
|
*/
|
|
187
|
-
computeRoot(txid?: string): string {
|
|
187
|
+
computeRoot (txid?: string): string {
|
|
188
188
|
if (typeof txid !== 'string') {
|
|
189
189
|
txid = this.path[0].find(leaf => Boolean(leaf?.hash)).hash
|
|
190
190
|
}
|
|
@@ -224,7 +224,7 @@ export default class MerklePath {
|
|
|
224
224
|
* @param height
|
|
225
225
|
* @param offset
|
|
226
226
|
*/
|
|
227
|
-
findOrComputeLeaf(height: number, offset: number): MerklePathLeaf | undefined {
|
|
227
|
+
findOrComputeLeaf (height: number, offset: number): MerklePathLeaf | undefined {
|
|
228
228
|
const hash = (m: string): string => toHex((
|
|
229
229
|
hash256(toArray(m, 'hex').reverse())
|
|
230
230
|
).reverse())
|
|
@@ -261,7 +261,7 @@ export default class MerklePath {
|
|
|
261
261
|
* @param {ChainTracker} chainTracker - The ChainTracker instance used to verify the Merkle root.
|
|
262
262
|
* @returns {boolean} - True if the transaction ID is valid within the Merkle Path at the specified block height.
|
|
263
263
|
*/
|
|
264
|
-
async verify(txid: string, chainTracker: ChainTracker): Promise<boolean> {
|
|
264
|
+
async verify (txid: string, chainTracker: ChainTracker): Promise<boolean> {
|
|
265
265
|
const root = this.computeRoot(txid)
|
|
266
266
|
// Use the chain tracker to determine whether this is a valid merkle root at the given block height
|
|
267
267
|
return await chainTracker.isValidRootForHeight(root, this.blockHeight)
|
|
@@ -273,7 +273,7 @@ export default class MerklePath {
|
|
|
273
273
|
* @param {MerklePath} other - Another MerklePath to combine with this path.
|
|
274
274
|
* @throws {Error} - If the paths have different block heights or roots.
|
|
275
275
|
*/
|
|
276
|
-
combine(other: MerklePath): void {
|
|
276
|
+
combine (other: MerklePath): void {
|
|
277
277
|
if (this.blockHeight !== other.blockHeight) {
|
|
278
278
|
throw new Error('You cannot combine paths which do not have the same block height.')
|
|
279
279
|
}
|
|
@@ -309,7 +309,7 @@ export default class MerklePath {
|
|
|
309
309
|
* Assumes that at least all required nodes are present.
|
|
310
310
|
* Leaves all levels sorted by increasing offset.
|
|
311
311
|
*/
|
|
312
|
-
trim() {
|
|
312
|
+
trim () {
|
|
313
313
|
const pushIfNew = (v: number, a: number[]) => {
|
|
314
314
|
if (a.length === 0 || a.slice(-1)[0] !== v) { a.push(v) }
|
|
315
315
|
}
|