@alexbosworth/blockchain 3.0.0 → 3.2.0

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 (33) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +132 -0
  3. package/addresses/bech32_type.js +52 -0
  4. package/addresses/decode_bech32.js +79 -0
  5. package/addresses/decode_bech32_address.js +86 -0
  6. package/addresses/index.js +2 -1
  7. package/addresses/modify_bech32_accumulator.js +24 -0
  8. package/hashes/id_for_transaction_components.js +2 -0
  9. package/index.js +16 -0
  10. package/package.json +1 -1
  11. package/script/index.js +14 -1
  12. package/script/p2pkh_output_script.js +37 -0
  13. package/script/p2sh_output_script.js +35 -0
  14. package/script/p2tr_output_script.js +32 -0
  15. package/script/p2wpkh_output_script.js +32 -0
  16. package/script/p2wsh_output_script.js +32 -0
  17. package/script/script_elements_as_output.js +41 -0
  18. package/script/script_elements_as_script.js +3 -22
  19. package/test/addresses/test_bech32_type.js +29 -0
  20. package/test/addresses/test_decode_bech32.js +49 -0
  21. package/test/addresses/test_decode_bech32_address.js +188 -0
  22. package/test/script/test_p2pkh_output_script.js +41 -0
  23. package/test/script/test_p2sh_output_script.js +41 -0
  24. package/test/script/test_p2tr_output_script.js +43 -0
  25. package/test/script/test_p2wpkh_output_script.js +41 -0
  26. package/test/script/test_p2wsh_output_script.js +43 -0
  27. package/test/transactions/test_id_for_transaction.js +72 -0
  28. package/test/transactions/test_unsigned_tx_from_psbt.js +72 -0
  29. package/transactions/id_for_transaction.js +39 -0
  30. package/transactions/index.js +4 -0
  31. package/transactions/parse_transaction.js +9 -11
  32. package/transactions/unsigned_tx_from_psbt.js +47 -0
  33. /package/test/addresses/{decode_base58_address.js → test_decode_base58_address.js} +0 -0
@@ -0,0 +1,72 @@
1
+ const {deepStrictEqual} = require('node:assert').strict;
2
+ const {throws} = require('node:assert').strict;
3
+ const test = require('node:test');
4
+
5
+ const {unsignedTxFromPsbt} = require('./../../');
6
+
7
+ const hexAsBuffer = hex => Buffer.from(hex, 'hex');
8
+
9
+ const tests = [
10
+ {
11
+ args: {},
12
+ description: 'A psbt is required',
13
+ error: 'ExpectedPsbtToGetUnsignedTransaction',
14
+ },
15
+ {
16
+ args: {
17
+ psbt: '0200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf6000000006a473044022070b2245123e6bf474d60c5b50c043d4c691a5d2435f09a34a7662a9dc251790a022001329ca9dacf280bdf30740ec0390422422c81cb45839457aeb76fc12edd95b3012102657d118d3357b8e0f4c2cd46db7b39f6d9c38d9a70abcb9b2de5dc8dbfe4ce31feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300',
18
+ },
19
+ description: 'A valid psbt is required',
20
+ error: 'ExpectedKnownPsbtStartBytesToGetUnsignedTransaction',
21
+ },
22
+ {
23
+ args: {
24
+ psbt: '70736274ff0100fd630102000000030146055816a5ce735defea7c69abb584946fadb54befc4ce55eb039f9ccfdda10000000000ffffffff16d3dad203d4d016ede6ffef29ed24b1bce4ba8efbe4ad8482bacf65d92ed57e0000000000ffffffff01e7e7e51596634dbccb27ee5031276293f2765084b72a889d5bb0aa84425ad80000000000ffffffff06a0860100000000002200203a291e21dee6c814294f159dcf259e9e82ffa3881fd09b22537400b8c5a8d0c8c76a042a01000000160014ca4be4a08bbd2acc8431e920a41f7ccfcd8fc8ada086010000000000220020f21b761d396210ba5cfd796db936bef36432f13d20afe55b57872a090415ce98c76a042a010000001600148b25e25be092a33e4524a9b2da5046fcc6e27e05a086010000000000220020eed63c2f9175915a94ad626ba35dcbf876a72116ea6fbd50b094b08b347e8688c76a042a010000001600147e5b3b51cc3217ac8f384a665285f90a4dd6826a0000000000000100a9020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401680101ffffffff0200f2052a01000000160014fb9ae43f439741acb5d4f2813b4177adb09a52950000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf9012000000000000000000000000000000000000000000000000000000000000000000000000001011f00f2052a01000000160014fb9ae43f439741acb5d4f2813b4177adb09a52952202025008f4d43049ea3ff9e71bca9b96402cc92c1c911adebcf5722d94e5bc84b48f47304402202e7f867ac0647b7c659d8742a0dae894437354106c98413a4b7beea2758e973502205787be7f941ecdda56cc099b297d4f71dfca5e859c6f5709852a1efd9d6995cc01010304010000002206025008f4d43049ea3ff9e71bca9b96402cc92c1c911adebcf5722d94e5bc84b48f180000000054000080000000800000008000000000010000000000000000000000',
25
+ },
26
+ description: 'An unsigned tx with empty inputs is pulled out of the PSBT',
27
+ expected: {
28
+ transaction: hexAsBuffer('02000000030146055816a5ce735defea7c69abb584946fadb54befc4ce55eb039f9ccfdda10000000000ffffffff16d3dad203d4d016ede6ffef29ed24b1bce4ba8efbe4ad8482bacf65d92ed57e0000000000ffffffff01e7e7e51596634dbccb27ee5031276293f2765084b72a889d5bb0aa84425ad80000000000ffffffff06a0860100000000002200203a291e21dee6c814294f159dcf259e9e82ffa3881fd09b22537400b8c5a8d0c8c76a042a01000000160014ca4be4a08bbd2acc8431e920a41f7ccfcd8fc8ada086010000000000220020f21b761d396210ba5cfd796db936bef36432f13d20afe55b57872a090415ce98c76a042a010000001600148b25e25be092a33e4524a9b2da5046fcc6e27e05a086010000000000220020eed63c2f9175915a94ad626ba35dcbf876a72116ea6fbd50b094b08b347e8688c76a042a010000001600147e5b3b51cc3217ac8f384a665285f90a4dd6826a00000000'),
29
+ },
30
+ },
31
+ {
32
+ args: {
33
+ psbt: '70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000',
34
+ },
35
+ description: 'An blank tx is pulled out of the PSBT',
36
+ expected: {
37
+ transaction: hexAsBuffer('020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000'),
38
+ },
39
+ },
40
+ {
41
+ args: {
42
+ psbt: '70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac000000000001076a47304402204759661797c01b036b25928948686218347d89864b719e1f7fcf57d1e511658702205309eabf56aa4d8891ffd111fdf1336f3a29da866d7f8486d75546ceedaf93190121035cdc61fc7ba971c0b501a646a2a83b102cb43881217ca682dc86e2d73fa882920001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb82308000000',
43
+ },
44
+ description: 'An tx with varied inputs is pulled out of the PSBT',
45
+ expected: {
46
+ transaction: hexAsBuffer('0200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac00000000'),
47
+ },
48
+ },
49
+ {
50
+ args: {
51
+ psbt: '70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab300000000000000',
52
+ },
53
+ description: 'A simple transaction is pulled out of the PSBT',
54
+ expected: {
55
+ transaction: hexAsBuffer('0200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300'),
56
+ },
57
+ },
58
+ ];
59
+
60
+ tests.forEach(({args, description, error, expected}) => {
61
+ return test(description, (t, end) => {
62
+ if (!!error) {
63
+ throws(() => unsignedTxFromPsbt(args), new Error(error), 'Got err');
64
+ } else {
65
+ const res = unsignedTxFromPsbt(args);
66
+
67
+ deepStrictEqual(res, expected, 'Got expected result');
68
+ }
69
+
70
+ return end();
71
+ });
72
+ });
@@ -0,0 +1,39 @@
1
+ const componentsOfTransaction = require('./components_of_transaction');
2
+ const {idForTransactionComponents} = require('./../hashes');
3
+
4
+ const hexAsBuffer = hex => Buffer.from(hex, 'hex');
5
+
6
+ /** Derive the standard transaction id for a raw serialized tx
7
+
8
+ {
9
+ transaction: <Hex Encoded Transaction String>
10
+ }
11
+
12
+ @throws
13
+ <Error>
14
+
15
+ @returns
16
+ {
17
+ id: <Transaction Id Hex Encoded String>
18
+ }
19
+ */
20
+ module.exports = ({transaction}) => {
21
+ const tx = componentsOfTransaction({transaction});
22
+
23
+ const {id} = idForTransactionComponents({
24
+ inputs: tx.inputs.map(({id, script, sequence, vout}) => ({
25
+ sequence,
26
+ vout,
27
+ hash: hexAsBuffer(id).reverse(),
28
+ script: hexAsBuffer(script),
29
+ })),
30
+ locktime: tx.locktime,
31
+ outputs: tx.outputs.map(({script, tokens}) => ({
32
+ tokens,
33
+ script: hexAsBuffer(script),
34
+ })),
35
+ version: tx.version,
36
+ });
37
+
38
+ return {id};
39
+ };
@@ -1,11 +1,15 @@
1
1
  const componentsOfTransaction = require('./components_of_transaction');
2
+ const idForTransaction = require('./id_for_transaction');
2
3
  const noLocktimeIdForTransaction = require('./no_locktime_id_for_transaction');
3
4
  const parseTransaction = require('./parse_transaction');
4
5
  const queryTransactions = require('./query_transactions');
6
+ const unsignedTxFromPsbt = require('./unsigned_tx_from_psbt');
5
7
 
6
8
  module.exports = {
7
9
  componentsOfTransaction,
10
+ idForTransaction,
8
11
  noLocktimeIdForTransaction,
9
12
  parseTransaction,
10
13
  queryTransactions,
14
+ unsignedTxFromPsbt,
11
15
  };
@@ -11,8 +11,6 @@ const defaultLocktime = 0;
11
11
  const defaultStartIndex = 0;
12
12
  const defaultWitnessCount = 0;
13
13
  const {isBuffer} = Buffer;
14
- const segWitV0Marker = 0;
15
- const segWitV0Flag = 1;
16
14
  const times = n => [...Array(n).keys()];
17
15
 
18
16
  /** Parse a raw transaction out of a buffer at a specific offset start
@@ -51,19 +49,19 @@ module.exports = args => {
51
49
  let offset = start;
52
50
 
53
51
  // Transaction version is a signed 4 byte integer
54
- const version = args.buffer.readInt32LE(offset, offset + byteCountInt32);
52
+ const version = args.buffer.readInt32LE(offset);
55
53
 
56
54
  offset += byteCountInt32;
57
55
 
58
56
  // For SegWit transactions, the next 2 bytes would be a marker and flag
59
57
  const flagSplit = offset + byteCountInt8;
60
58
 
61
- const marker = args.buffer.readUInt8(offset, flagSplit);
59
+ const marker = args.buffer.readUInt8(offset);
62
60
 
63
- const flag = args.buffer.readUInt8(flagSplit, offset + byteCountMarkerFlag);
61
+ const flag = args.buffer.readUInt8(flagSplit);
64
62
 
65
63
  // The presence of the marker and flag indicates SegWit tx encoding
66
- const isSegWit = !marker && flag === segWitV0Flag;
64
+ const isSegWit = !marker && !!flag;
67
65
 
68
66
  // When tx isn't SegWit though, the bytes are not marker and flag
69
67
  offset += isSegWit ? byteCountMarkerFlag : byteCountNoMarkerFlag;
@@ -83,7 +81,7 @@ module.exports = args => {
83
81
  offset += byteCountHash;
84
82
 
85
83
  // The vout is the 4 byte output index of the tx being spent in this input
86
- const vout = args.buffer.readUInt32LE(offset, offset + byteCountInt32);
84
+ const vout = args.buffer.readUInt32LE(offset);
87
85
 
88
86
  offset += byteCountInt32;
89
87
 
@@ -98,7 +96,7 @@ module.exports = args => {
98
96
  offset += scriptLength.number;
99
97
 
100
98
  // Sequence is a 4 byte unsigned number for an input, used for CSV mainly
101
- const sequence = args.buffer.readUInt32LE(offset, offset + byteCountInt32);
99
+ const sequence = args.buffer.readUInt32LE(offset);
102
100
 
103
101
  offset += byteCountInt32;
104
102
 
@@ -112,7 +110,7 @@ module.exports = args => {
112
110
  // Read in the outputs of the transaction
113
111
  const outputs = times(outputsCount.number).map(i => {
114
112
  // The value being spent
115
- const value = args.buffer.readBigUInt64LE(offset, offset + byteCountInt64);
113
+ const value = args.buffer.readBigUInt64LE(offset);
116
114
 
117
115
  offset += byteCountInt64;
118
116
 
@@ -165,7 +163,7 @@ module.exports = args => {
165
163
  });
166
164
 
167
165
  // The final element is the 4 byte transaction nLockTime
168
- const locktime = args.buffer.readUInt32LE(offset, offset + byteCountInt32);
166
+ const locktime = args.buffer.readUInt32LE(offset);
169
167
 
170
168
  offset += byteCountInt32;
171
169
 
@@ -173,4 +171,4 @@ module.exports = args => {
173
171
  const bytes = args.buffer.subarray(start, offset);
174
172
 
175
173
  return {bytes, inputs, locktime, outputs, version};
176
- };
174
+ };
@@ -0,0 +1,47 @@
1
+ const {compactIntAsNumber} = require('./../numbers');
2
+ const parseTransaction = require('./parse_transaction');
3
+
4
+ const decodeCompactInt = (b, o) => compactIntAsNumber({encoded: b, start: o});
5
+ const hexAsBuffer = hex => Buffer.from(hex, 'hex');
6
+ const psbtStartBytes = Buffer.from([0x70, 0x73, 0x62, 0x74, 0xff, 0x01]);
7
+
8
+ /** Get the unsigned transaction out of a PSBT
9
+
10
+ {
11
+ psbt: <PSBT Hex String>
12
+ }
13
+
14
+ @throws
15
+ <Error>
16
+
17
+ @returns
18
+ {
19
+ transaction: <Unsigned Transaction Buffer Object>
20
+ }
21
+ */
22
+ module.exports = ({psbt}) => {
23
+ if (!psbt) {
24
+ throw new Error('ExpectedPsbtToGetUnsignedTransaction');
25
+ }
26
+
27
+ const psbtData = hexAsBuffer(psbt);
28
+
29
+ // Start reading - beginning with magic bytes, separator, unsigned tx type
30
+ const startBytes = psbtData.slice(0, psbtStartBytes.length);
31
+
32
+ // The magic bytes, separator, and tx type of a PSBT must always be set
33
+ if (!startBytes.equals(psbtStartBytes)) {
34
+ throw new Error('ExpectedKnownPsbtStartBytesToGetUnsignedTransaction');
35
+ }
36
+
37
+ // The next byte will be a compact int number that describes the tx length
38
+ const keySize = decodeCompactInt(psbtData, psbtStartBytes.length + 1).bytes;
39
+
40
+ // Read in the transaction from the global value bytes
41
+ const {bytes} = parseTransaction({
42
+ buffer: psbtData,
43
+ start: psbtStartBytes.length + keySize + 1,
44
+ });
45
+
46
+ return {transaction: bytes};
47
+ };