@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.
- package/CHANGELOG.md +14 -0
- package/README.md +132 -0
- package/addresses/bech32_type.js +52 -0
- package/addresses/decode_bech32.js +79 -0
- package/addresses/decode_bech32_address.js +86 -0
- package/addresses/index.js +2 -1
- package/addresses/modify_bech32_accumulator.js +24 -0
- package/hashes/id_for_transaction_components.js +2 -0
- package/index.js +16 -0
- package/package.json +1 -1
- package/script/index.js +14 -1
- package/script/p2pkh_output_script.js +37 -0
- package/script/p2sh_output_script.js +35 -0
- package/script/p2tr_output_script.js +32 -0
- package/script/p2wpkh_output_script.js +32 -0
- package/script/p2wsh_output_script.js +32 -0
- package/script/script_elements_as_output.js +41 -0
- package/script/script_elements_as_script.js +3 -22
- package/test/addresses/test_bech32_type.js +29 -0
- package/test/addresses/test_decode_bech32.js +49 -0
- package/test/addresses/test_decode_bech32_address.js +188 -0
- package/test/script/test_p2pkh_output_script.js +41 -0
- package/test/script/test_p2sh_output_script.js +41 -0
- package/test/script/test_p2tr_output_script.js +43 -0
- package/test/script/test_p2wpkh_output_script.js +41 -0
- package/test/script/test_p2wsh_output_script.js +43 -0
- package/test/transactions/test_id_for_transaction.js +72 -0
- package/test/transactions/test_unsigned_tx_from_psbt.js +72 -0
- package/transactions/id_for_transaction.js +39 -0
- package/transactions/index.js +4 -0
- package/transactions/parse_transaction.js +9 -11
- package/transactions/unsigned_tx_from_psbt.js +47 -0
- /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
|
+
};
|
package/transactions/index.js
CHANGED
|
@@ -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
|
|
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
|
|
59
|
+
const marker = args.buffer.readUInt8(offset);
|
|
62
60
|
|
|
63
|
-
const flag = args.buffer.readUInt8(flagSplit
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
+
};
|
|
File without changes
|