Skip to content

Commit f703435

Browse files
committed
Clone transaction data more efficiently
1 parent 5d81b94 commit f703435

File tree

6 files changed

+50
-22
lines changed

6 files changed

+50
-22
lines changed

src/bufferutils.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ function reverseBuffer(buffer) {
4141
return buffer;
4242
}
4343
exports.reverseBuffer = reverseBuffer;
44+
function cloneBuffer(buffer) {
45+
const clone = Buffer.alloc(buffer.length);
46+
buffer.copy(clone);
47+
return buffer;
48+
}
49+
exports.cloneBuffer = cloneBuffer;
4450
/**
4551
* Helper class for serialization of bitcoin data types into a pre-allocated buffer.
4652
*/

src/psbt.js

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,23 @@ class Psbt {
104104
return this.__CACHE.__TX.locktime;
105105
}
106106
get txInputs() {
107-
return deepClone(this.__CACHE.__TX.ins);
107+
return this.__CACHE.__TX.ins.map(input => {
108+
return {
109+
hash: bufferutils_1.cloneBuffer(input.hash),
110+
index: input.index,
111+
script: bufferutils_1.cloneBuffer(input.script),
112+
sequence: input.sequence,
113+
witness: input.witness.map(buffer => bufferutils_1.cloneBuffer(buffer)),
114+
};
115+
});
108116
}
109117
get txOutputs() {
110-
return deepClone(this.__CACHE.__TX.outs);
118+
return this.__CACHE.__TX.outs.map(output => {
119+
return {
120+
script: bufferutils_1.cloneBuffer(output.script),
121+
value: output.value,
122+
};
123+
});
111124
}
112125
combine(...those) {
113126
this.data.combine(...those.map(o => o.data));
@@ -591,11 +604,6 @@ class PsbtTransaction {
591604
return this.tx.toBuffer();
592605
}
593606
}
594-
function deepClone(obj) {
595-
return JSON.parse(JSON.stringify(obj), (_, value) =>
596-
value.type === 'Buffer' ? Buffer.from(value.data) : value,
597-
);
598-
}
599607
function canFinalize(input, script, scriptType) {
600608
switch (scriptType) {
601609
case 'pubkey':

ts_src/bufferutils.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ export function reverseBuffer(buffer: Buffer): Buffer {
4848
return buffer;
4949
}
5050

51+
export function cloneBuffer(buffer: Buffer): Buffer {
52+
const clone = Buffer.alloc(buffer.length);
53+
buffer.copy(clone);
54+
return buffer;
55+
}
56+
5157
/**
5258
* Helper class for serialization of bitcoin data types into a pre-allocated buffer.
5359
*/

ts_src/psbt.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
} from 'bip174/src/lib/interfaces';
1515
import { checkForInput } from 'bip174/src/lib/utils';
1616
import { toOutputScript } from './address';
17-
import { reverseBuffer } from './bufferutils';
17+
import { cloneBuffer, reverseBuffer } from './bufferutils';
1818
import { hash160 } from './crypto';
1919
import {
2020
fromPublicKey as ecPairFromPublicKey,
@@ -24,7 +24,7 @@ import {
2424
import { bitcoin as btcNetwork, Network } from './networks';
2525
import * as payments from './payments';
2626
import * as bscript from './script';
27-
import { Output, Transaction } from './transaction';
27+
import { Input, Output, Transaction } from './transaction';
2828

2929
/**
3030
* These are the default arguments for a Psbt instance.
@@ -137,12 +137,25 @@ export class Psbt {
137137
return this.__CACHE.__TX.locktime;
138138
}
139139

140-
get txInputs(): TransactionInput[] {
141-
return deepClone(this.__CACHE.__TX.ins);
140+
get txInputs(): Input[] {
141+
return this.__CACHE.__TX.ins.map(input => {
142+
return {
143+
hash: cloneBuffer(input.hash),
144+
index: input.index,
145+
script: cloneBuffer(input.script),
146+
sequence: input.sequence,
147+
witness: input.witness.map(buffer => cloneBuffer(buffer)),
148+
};
149+
});
142150
}
143151

144-
get txOutputs(): TransactionInput[] {
145-
return deepClone(this.__CACHE.__TX.outs);
152+
get txOutputs(): Output[] {
153+
return this.__CACHE.__TX.outs.map(output => {
154+
return {
155+
script: cloneBuffer(output.script),
156+
value: output.value,
157+
};
158+
});
146159
}
147160

148161
combine(...those: Psbt[]): this {
@@ -773,12 +786,6 @@ class PsbtTransaction implements ITransaction {
773786
}
774787
}
775788

776-
function deepClone(obj: any): any {
777-
return JSON.parse(JSON.stringify(obj), (_, value) =>
778-
value.type === 'Buffer' ? Buffer.from(value.data) : value,
779-
);
780-
}
781-
782789
function canFinalize(
783790
input: PsbtInput,
784791
script: Buffer,

types/bufferutils.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export declare function readUInt64LE(buffer: Buffer, offset: number): number;
22
export declare function writeUInt64LE(buffer: Buffer, value: number, offset: number): number;
33
export declare function reverseBuffer(buffer: Buffer): Buffer;
4+
export declare function cloneBuffer(buffer: Buffer): Buffer;
45
/**
56
* Helper class for serialization of bitcoin data types into a pre-allocated buffer.
67
*/

types/psbt.d.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Psbt as PsbtBase } from 'bip174';
22
import { KeyValue, PsbtGlobalUpdate, PsbtInput, PsbtInputUpdate, PsbtOutput, PsbtOutputUpdate, TransactionInput } from 'bip174/src/lib/interfaces';
33
import { Signer, SignerAsync } from './ecpair';
44
import { Network } from './networks';
5-
import { Transaction } from './transaction';
5+
import { Input, Output, Transaction } from './transaction';
66
/**
77
* Psbt class can parse and generate a PSBT binary based off of the BIP174.
88
* There are 6 roles that this class fulfills. (Explained in BIP174)
@@ -46,8 +46,8 @@ export declare class Psbt {
4646
readonly inputCount: number;
4747
readonly txVersion: number;
4848
readonly txLocktime: number;
49-
readonly txInputs: TransactionInput[];
50-
readonly txOutputs: TransactionInput[];
49+
readonly txInputs: Input[];
50+
readonly txOutputs: Output[];
5151
combine(...those: Psbt[]): this;
5252
clone(): Psbt;
5353
setMaximumFeeRate(satoshiPerByte: number): void;

0 commit comments

Comments
 (0)