@vbyte/btc-dev 1.0.6 → 1.0.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.
@@ -1,6 +1,6 @@
1
1
  import type { LocktimeData, SequenceData } from './meta.js';
2
2
  import type { TxOutput, TxOutputType, TxSize, TxValue } from './txdata.js';
3
- import type { WitnessType, WitnessVersion } from './witness.js';
3
+ import type { WitnessSize, WitnessType, WitnessVersion } from './witness.js';
4
4
  export interface LocktimeField {
5
5
  hex: string;
6
6
  data: LocktimeData | null;
@@ -32,11 +32,10 @@ export interface WitnessField {
32
32
  cblock: string | null;
33
33
  params: string[];
34
34
  script: ScriptField | null;
35
- size: number;
35
+ size: WitnessSize;
36
36
  stack: string[];
37
37
  type: WitnessType;
38
38
  version: WitnessVersion;
39
- vsize: number;
40
39
  }
41
40
  export interface TransactionInputData {
42
41
  coinbase?: string | null;
@@ -55,7 +55,7 @@ export interface TxData {
55
55
  }
56
56
  export interface TxSize {
57
57
  base: number;
58
- real: number;
58
+ total: number;
59
59
  weight: number;
60
60
  vsize: number;
61
61
  }
@@ -1,11 +1,11 @@
1
- export type WitnessContext = WitnessInfo | TaprootScript | SegwitScript | TaprootSpend | SegwitSpend;
1
+ export type WitnessContext = WitnessData | TaprootScript | SegwitScript | TaprootSpend | SegwitSpend;
2
2
  export type WitnessVersion = number | null;
3
3
  export type WitnessType = 'p2w-pkh' | 'p2w-sh' | 'p2tr-pk' | 'p2tr-ts' | 'unknown';
4
4
  export interface WitnessSize {
5
- size: number;
5
+ total: number;
6
6
  vsize: number;
7
7
  }
8
- export interface WitnessInfo {
8
+ export interface WitnessData {
9
9
  annex: string | null;
10
10
  cblock: string | null;
11
11
  params: string[];
@@ -13,22 +13,22 @@ export interface WitnessInfo {
13
13
  type: WitnessType;
14
14
  version: WitnessVersion;
15
15
  }
16
- export interface TaprootScript extends WitnessInfo {
16
+ export interface TaprootScript extends WitnessData {
17
17
  cblock: string;
18
18
  script: string;
19
19
  type: 'p2tr-ts';
20
20
  version: 1;
21
21
  }
22
- export interface SegwitScript extends WitnessInfo {
22
+ export interface SegwitScript extends WitnessData {
23
23
  script: string;
24
24
  type: 'p2w-sh';
25
25
  version: 0;
26
26
  }
27
- export interface TaprootSpend extends WitnessInfo {
27
+ export interface TaprootSpend extends WitnessData {
28
28
  type: 'p2tr-pk';
29
29
  version: 1;
30
30
  }
31
- export interface SegwitSpend extends WitnessInfo {
31
+ export interface SegwitSpend extends WitnessData {
32
32
  type: 'p2w-pkh';
33
33
  version: 0;
34
34
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vbyte/btc-dev",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "Batteries-included toolset for plebian bitcoin development",
5
5
  "type": "module",
6
6
  "keywords": [
package/src/class/tx.ts CHANGED
@@ -1,3 +1,5 @@
1
+
2
+ import { Assert } from '@vbyte/micro-lib'
1
3
  import { LocktimeUtil } from '@/lib/meta/index.js'
2
4
  import { TransactionInput } from './txin.js'
3
5
  import { TransactionOutput } from './txout.js'
@@ -16,31 +18,34 @@ import {
16
18
  import type {
17
19
  TxData,
18
20
  TxTemplate,
21
+ TransactionData,
22
+ TxInput,
23
+ TxOutput,
19
24
  TxSize,
20
- TxValue,
21
- TransactionData
25
+ TxValue
22
26
  } from '@/types/index.js'
23
27
 
24
28
  export class Transaction {
25
29
 
26
- private readonly _size : TxSize
27
- private readonly _tx : TxData
28
- private readonly _hash : string
29
- private readonly _value : TxValue
30
- private readonly _vin : TransactionInput[]
31
- private readonly _vout : TransactionOutput[]
30
+ private readonly _tx : TxData
31
+
32
+ private _size : TxSize & { segwit : number }
33
+ private _hash : string
34
+ private _txid : string
35
+ private _value : TxValue
36
+ private _vin : TransactionInput[]
37
+ private _vout : TransactionOutput[]
32
38
 
33
39
  constructor (txdata : string | TxData | TxTemplate) {
34
40
  this._tx = (typeof txdata !== 'string')
35
41
  ? parse_tx(txdata)
36
42
  : decode_tx(txdata)
37
-
38
- this._vin = this._tx.vin.map(txin => new TransactionInput(txin))
39
- this._vout = this._tx.vout.map(txout => new TransactionOutput(txout))
40
-
41
- this._size = get_txsize(this._tx)
43
+ this._size = this._get_size()
42
44
  this._hash = get_txhash(this._tx)
45
+ this._txid = get_txid(this._tx)
43
46
  this._value = get_tx_value(this._tx)
47
+ this._vin = this._tx.vin.map(txin => new TransactionInput(txin))
48
+ this._vout = this._tx.vout.map(txout => new TransactionOutput(txout))
44
49
  }
45
50
 
46
51
  get data () : TransactionData {
@@ -75,13 +80,7 @@ export class Transaction {
75
80
  }
76
81
 
77
82
  get size () {
78
- return {
79
- ...this._size,
80
- segwit : this._vin.reduce((acc, txin) => acc + (txin.witness?.vsize ?? 0), 0),
81
- vin : this._vin.reduce((acc, txin) => acc + txin.size, 0),
82
- vout : this._vout.reduce((acc, txout) => acc + txout.size, 0),
83
- witness : this._vin.reduce((acc, txin) => acc + (txin.witness?.size ?? 0), 0)
84
- }
83
+ return this._size
85
84
  }
86
85
 
87
86
  get spends () : TransactionOutput[] {
@@ -91,7 +90,7 @@ export class Transaction {
91
90
  }
92
91
 
93
92
  get txid () : string {
94
- return get_txid(this._tx)
93
+ return this._txid
95
94
  }
96
95
 
97
96
  get value () {
@@ -110,9 +109,75 @@ export class Transaction {
110
109
  return this._vout
111
110
  }
112
111
 
113
- toJSON () { return this.data }
114
- toString () { return JSON.stringify(this.data) }
115
- }
112
+ add_vin (txin : TxInput) {
113
+ this._tx.vin.push(txin)
114
+ this._update_vin()
115
+ }
116
+
117
+ add_vout (txout : TxOutput) {
118
+ this._tx.vout.push(txout)
119
+ this._update_vout()
120
+ }
116
121
 
122
+ insert_vin (index : number, txin : TxInput) {
123
+ Assert.ok(index >= 0 && index <= this._tx.vin.length, 'input goes out of bounds')
124
+ if (index === this._tx.vin.length) {
125
+ this._tx.vin.push(txin)
126
+ } else {
127
+ this._tx.vin.splice(index, 0, txin)
128
+ }
129
+ this._update_vin()
130
+ }
117
131
 
132
+ insert_vout (index : number, txout : TxOutput) {
133
+ Assert.ok(index >= 0 && index <= this._tx.vout.length, 'output goes out of bounds')
134
+ if (index === this._tx.vout.length) {
135
+ this._tx.vout.push(txout)
136
+ } else {
137
+ this._tx.vout.splice(index, 0, txout)
138
+ }
139
+ this._update_vout()
140
+ }
141
+
142
+ remove_vin (index : number) {
143
+ Assert.ok(this._tx.vin.at(index) !== undefined, 'input does not exist at index')
144
+ this._tx.vin.splice(index, 1)
145
+ this._update_vin()
146
+ }
118
147
 
148
+ remove_vout (index : number) {
149
+ Assert.ok(this._tx.vout.at(index) !== undefined, 'output does not exist at index')
150
+ this._tx.vout.splice(index, 1)
151
+ this._update_vout()
152
+ }
153
+
154
+ _get_size () {
155
+ return {
156
+ ...get_txsize(this._tx),
157
+ segwit : this.vin.reduce((acc, txin) => acc + (txin.witness?.size.vsize ?? 0), 0),
158
+ vin : this.vin.reduce((acc, txin) => acc + txin.size, 0),
159
+ vout : this.vout.reduce((acc, txout) => acc + txout.size, 0),
160
+ witness : this.vin.reduce((acc, txin) => acc + (txin.witness?.size.total ?? 0), 0)
161
+ }
162
+ }
163
+
164
+ _update_tx () {
165
+ this._size = this._get_size()
166
+ this._hash = get_txhash(this._tx)
167
+ this._txid = get_txid(this._tx)
168
+ this._value = get_tx_value(this._tx)
169
+ }
170
+
171
+ _update_vin () {
172
+ this._vin = this._tx.vin.map(txin => new TransactionInput(txin))
173
+ this._update_tx()
174
+ }
175
+
176
+ _update_vout () {
177
+ this._vout = this._tx.vout.map(txout => new TransactionOutput(txout))
178
+ this._update_tx()
179
+ }
180
+
181
+ toJSON () { return this.data }
182
+ toString () { return JSON.stringify(this.data) }
183
+ }
package/src/class/txin.ts CHANGED
@@ -15,16 +15,10 @@ import type {
15
15
 
16
16
  export class TransactionInput {
17
17
 
18
- private readonly _size : number
19
- private readonly _txin : TxInput
20
- private readonly _witness : TransactionWitness | null
18
+ private readonly _txin : TxInput
21
19
 
22
20
  constructor (txin : TxInput) {
23
- this._size = get_txin_size(txin)
24
- this._txin = txin
25
- this._witness = txin.witness.length > 0
26
- ? new TransactionWitness(txin.witness)
27
- : null
21
+ this._txin = txin
28
22
  }
29
23
 
30
24
  get coinbase () : string | null {
@@ -75,7 +69,7 @@ export class TransactionInput {
75
69
  }
76
70
 
77
71
  get size () {
78
- return this._size
72
+ return get_txin_size(this._txin)
79
73
  }
80
74
 
81
75
  get txid () : string {
@@ -87,7 +81,9 @@ export class TransactionInput {
87
81
  }
88
82
 
89
83
  get witness () {
90
- return this._witness
84
+ return this._txin.witness.length > 0
85
+ ? new TransactionWitness(this._txin.witness)
86
+ : null
91
87
  }
92
88
 
93
89
  toJSON () { return this.data }
@@ -2,20 +2,17 @@ import { decode_script } from '@/lib/script/index.js'
2
2
 
3
3
  import {
4
4
  get_txout_size,
5
- get_vout_info
5
+ get_vout_type,
6
+ get_vout_version
6
7
  } from '@/lib/tx/index.js'
7
8
 
8
- import type { TxOutput, TransactionOutputData, TxOutputInfo } from '@/types/index.js'
9
+ import type { TxOutput, TransactionOutputData } from '@/types/index.js'
9
10
 
10
11
  export class TransactionOutput {
11
12
 
12
- private readonly _info : TxOutputInfo
13
- private readonly _size : number
14
13
  private readonly _txout : TxOutput
15
14
 
16
15
  constructor (txout : TxOutput) {
17
- this._info = get_vout_info(txout)
18
- this._size = get_txout_size(txout)
19
16
  this._txout = txout
20
17
  }
21
18
 
@@ -37,11 +34,11 @@ export class TransactionOutput {
37
34
  }
38
35
 
39
36
  get size () {
40
- return this._size
37
+ return get_txout_size(this._txout)
41
38
  }
42
39
 
43
40
  get type () {
44
- return this._info.type
41
+ return get_vout_type(this._txout.script_pk)
45
42
  }
46
43
 
47
44
  get value () : bigint {
@@ -49,7 +46,7 @@ export class TransactionOutput {
49
46
  }
50
47
 
51
48
  get version () {
52
- return this._info.version
49
+ return get_vout_version(this._txout.script_pk)
53
50
  }
54
51
 
55
52
  toJSON () { return this.data }
@@ -1,37 +1,39 @@
1
1
  import { Buff, Bytes } from '@vbyte/buff'
2
+ import { Assert } from '@vbyte/micro-lib'
2
3
  import { decode_script } from '@/lib/script/index.js'
3
4
 
4
5
  import {
5
- parse_witness_data,
6
+ parse_witness,
6
7
  get_witness_size,
7
8
  } from '@/lib/witness/index.js'
8
9
 
9
10
  import type {
10
11
  ScriptField,
11
12
  WitnessField,
12
- WitnessInfo,
13
+ WitnessData,
13
14
  WitnessSize,
14
15
  WitnessType
15
16
  } from '@/types/index.js'
16
17
 
17
18
  export class TransactionWitness {
18
19
 
19
- private readonly _data : Buff[]
20
- private readonly _meta : WitnessInfo
21
- private readonly _size : WitnessSize
20
+ private readonly _elems : Buff[]
21
+
22
+ private _data : WitnessData
23
+ private _size : WitnessSize
22
24
 
23
25
  constructor (witness : Bytes[]) {
24
- this._data = witness.map(e => Buff.bytes(e))
25
- this._meta = parse_witness_data(witness)
26
- this._size = get_witness_size(witness)
26
+ this._elems = witness.map(e => Buff.bytes(e))
27
+ this._data = parse_witness(this._elems)
28
+ this._size = get_witness_size(this._elems)
27
29
  }
28
30
 
29
31
  get annex () : string | null {
30
- return this._meta.annex
32
+ return this._data.annex
31
33
  }
32
34
 
33
35
  get cblock () : string | null {
34
- return this._meta.cblock
36
+ return this._data.cblock
35
37
  }
36
38
 
37
39
  get data () : WitnessField {
@@ -43,41 +45,61 @@ export class TransactionWitness {
43
45
  size : this.size,
44
46
  stack : this.stack,
45
47
  type : this.type,
46
- version : this.version,
47
- vsize : this.vsize
48
+ version : this.version
48
49
  }
49
50
  }
50
51
 
51
52
  get params () : string[] {
52
- return this._meta.params
53
+ return this._data.params
53
54
  }
54
55
 
55
56
  get script () : ScriptField | null {
56
- if (this._meta.script === null) return null
57
+ if (this._data.script === null) return null
57
58
  return {
58
- hex : this._meta.script,
59
- asm : decode_script(this._meta.script)
59
+ hex : this._data.script,
60
+ asm : decode_script(this._data.script)
60
61
  }
61
62
  }
62
63
 
63
- get size () : number {
64
- return this._size.size
64
+ get size () : WitnessSize {
65
+ return this._size
65
66
  }
66
67
 
67
68
  get stack () : string[] {
68
- return this._data.map(e => e.hex)
69
+ return this._elems.map(e => e.hex)
69
70
  }
70
71
 
71
72
  get type () : WitnessType {
72
- return this._meta.type
73
+ return this._data.type
73
74
  }
74
75
 
75
76
  get version () : number | null {
76
- return this._meta.version
77
+ return this._data.version
78
+ }
79
+
80
+ _update () {
81
+ this._data = parse_witness(this._elems)
82
+ this._size = get_witness_size(this._elems)
83
+ }
84
+
85
+ add (elem : Bytes) {
86
+ this._elems.push(Buff.bytes(elem))
87
+ this._update()
88
+ }
89
+
90
+ insert (index : number, elem : Bytes) {
91
+ Assert.ok(index >= 0 && index <= this._elems.length, 'index out of bounds')
92
+ if (index === this._elems.length) {
93
+ this._elems.push(Buff.bytes(elem))
94
+ } else {
95
+ this._elems.splice(index, 0, Buff.bytes(elem))
96
+ }
97
+ this._update()
77
98
  }
78
99
 
79
- get vsize () : number {
80
- return this._size.vsize
100
+ remove (index : number) {
101
+ this._elems.splice(index, 1)
102
+ this._update()
81
103
  }
82
104
 
83
105
  toJSON () { return this.data }
@@ -1,6 +1,6 @@
1
1
  import { Buff, Stream } from '@vbyte/buff'
2
2
  import { Assert, ECC } from '@vbyte/micro-lib'
3
- import { parse_witness_data } from '@/lib/witness/parse.js'
3
+ import { parse_witness } from '@/lib/witness/parse.js'
4
4
 
5
5
  import {
6
6
  encode_tapbranch,
@@ -11,7 +11,7 @@ import {
11
11
  import type { ControlBlock } from '@/types/index.js'
12
12
 
13
13
  export function parse_taproot_witness (witness : string[]) {
14
- const { cblock, params, script } = parse_witness_data(witness)
14
+ const { cblock, params, script } = parse_witness(witness)
15
15
 
16
16
  Assert.exists(cblock, 'cblock is null')
17
17
  Assert.exists(script, 'script is null')
@@ -32,11 +32,11 @@ export function get_txsize (
32
32
  ) : TxSize {
33
33
  const json = parse_tx(txdata)
34
34
  const base = encode_tx(json, false).length
35
- const size = encode_tx(json, true).length
36
- const weight = base * 3 + size
35
+ const total = encode_tx(json, true).length
36
+ const weight = base * 3 + total
37
37
  const remain = (weight % 4 > 0) ? 1 : 0
38
38
  const vsize = Math.floor(weight / 4) + remain
39
- return { base, real: size, vsize, weight }
39
+ return { base, total, vsize, weight }
40
40
  }
41
41
 
42
42
  export function get_vin_size (vin : TxInput[]) : number {
@@ -3,13 +3,13 @@ import { is_valid_script } from '@/lib/script/decode.js'
3
3
  import { TAPLEAF_VERSIONS } from '@/const.js'
4
4
 
5
5
  import type {
6
- WitnessInfo,
6
+ WitnessData,
7
7
  WitnessType
8
8
  } from '@/types/index.js'
9
9
 
10
- export function parse_witness_data (
10
+ export function parse_witness (
11
11
  witness : Bytes[]
12
- ) : WitnessInfo {
12
+ ) : WitnessData {
13
13
  // Parse the witness data.
14
14
  const elems = witness.map(e => Buff.bytes(e))
15
15
  const annex = parse_annex_data(elems)
@@ -8,5 +8,5 @@ export function get_witness_size (witness : Bytes[]) : WitnessSize {
8
8
  const stack = witness.map(e => Buff.bytes(e))
9
9
  const size = stack.reduce((prev, next) => prev + next.length, 0)
10
10
  const vsize = Math.ceil(WIT_LENGTH_BYTE + size / 4)
11
- return { size, vsize }
11
+ return { total: size, vsize }
12
12
  }
@@ -1,6 +1,6 @@
1
- import type { LocktimeData, SequenceData } from './meta.js'
2
- import type { TxOutput, TxOutputType, TxSize, TxValue } from './txdata.js'
3
- import type { WitnessType, WitnessVersion } from './witness.js'
1
+ import type { LocktimeData, SequenceData } from './meta.js'
2
+ import type { TxOutput, TxOutputType, TxSize, TxValue } from './txdata.js'
3
+ import type { WitnessSize, WitnessType, WitnessVersion } from './witness.js'
4
4
 
5
5
  export interface LocktimeField {
6
6
  hex : string
@@ -37,11 +37,10 @@ export interface WitnessField {
37
37
  cblock : string | null
38
38
  params : string[]
39
39
  script : ScriptField | null
40
- size : number
40
+ size : WitnessSize
41
41
  stack : string[]
42
42
  type : WitnessType
43
43
  version : WitnessVersion
44
- vsize : number
45
44
  }
46
45
 
47
46
  export interface TransactionInputData {
@@ -67,7 +67,7 @@ export interface TxData {
67
67
 
68
68
  export interface TxSize {
69
69
  base : number
70
- real : number
70
+ total : number
71
71
  weight : number
72
72
  vsize : number
73
73
  }
@@ -1,13 +1,13 @@
1
- export type WitnessContext = WitnessInfo | TaprootScript | SegwitScript | TaprootSpend | SegwitSpend
1
+ export type WitnessContext = WitnessData | TaprootScript | SegwitScript | TaprootSpend | SegwitSpend
2
2
  export type WitnessVersion = number | null
3
3
  export type WitnessType = 'p2w-pkh' | 'p2w-sh' | 'p2tr-pk' | 'p2tr-ts' | 'unknown'
4
4
 
5
5
  export interface WitnessSize {
6
- size : number
6
+ total : number
7
7
  vsize : number
8
8
  }
9
9
 
10
- export interface WitnessInfo {
10
+ export interface WitnessData {
11
11
  annex : string | null
12
12
  cblock : string | null
13
13
  params : string[]
@@ -16,25 +16,25 @@ export interface WitnessInfo {
16
16
  version : WitnessVersion
17
17
  }
18
18
 
19
- export interface TaprootScript extends WitnessInfo {
19
+ export interface TaprootScript extends WitnessData {
20
20
  cblock : string
21
21
  script : string
22
22
  type : 'p2tr-ts'
23
23
  version : 1
24
24
  }
25
25
 
26
- export interface SegwitScript extends WitnessInfo {
26
+ export interface SegwitScript extends WitnessData {
27
27
  script : string
28
28
  type : 'p2w-sh'
29
29
  version : 0
30
30
  }
31
31
 
32
- export interface TaprootSpend extends WitnessInfo {
32
+ export interface TaprootSpend extends WitnessData {
33
33
  type : 'p2tr-pk'
34
34
  version : 1
35
35
  }
36
36
 
37
- export interface SegwitSpend extends WitnessInfo {
37
+ export interface SegwitSpend extends WitnessData {
38
38
  type : 'p2w-pkh'
39
39
  version : 0
40
40
  }