Skip to content

Commit 06674b1

Browse files
committed
Add BufferReader to Transaction and fix tests
1 parent 91e6c8a commit 06674b1

File tree

5 files changed

+40
-113
lines changed

5 files changed

+40
-113
lines changed

src/transaction.js

+17-50
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
'use strict';
22
Object.defineProperty(exports, '__esModule', { value: true });
3-
const bufferutils = require('./bufferutils');
43
const bufferutils_1 = require('./bufferutils');
54
const bcrypto = require('./crypto');
65
const bscript = require('./script');
@@ -47,80 +46,48 @@ class Transaction {
4746
this.outs = [];
4847
}
4948
static fromBuffer(buffer, _NO_STRICT) {
50-
let offset = 0;
51-
function readSlice(n) {
52-
offset += n;
53-
return buffer.slice(offset - n, offset);
54-
}
55-
function readUInt32() {
56-
const i = buffer.readUInt32LE(offset);
57-
offset += 4;
58-
return i;
59-
}
60-
function readInt32() {
61-
const i = buffer.readInt32LE(offset);
62-
offset += 4;
63-
return i;
64-
}
65-
function readUInt64() {
66-
const i = bufferutils.readUInt64LE(buffer, offset);
67-
offset += 8;
68-
return i;
69-
}
70-
function readVarInt() {
71-
const vi = varuint.decode(buffer, offset);
72-
offset += varuint.decode.bytes;
73-
return vi;
74-
}
75-
function readVarSlice() {
76-
return readSlice(readVarInt());
77-
}
78-
function readVector() {
79-
const count = readVarInt();
80-
const vector = [];
81-
for (let i = 0; i < count; i++) vector.push(readVarSlice());
82-
return vector;
83-
}
49+
const bufferReader = new bufferutils_1.BufferReader(buffer);
8450
const tx = new Transaction();
85-
tx.version = readInt32();
86-
const marker = buffer.readUInt8(offset);
87-
const flag = buffer.readUInt8(offset + 1);
51+
tx.version = bufferReader.readInt32();
52+
const marker = bufferReader.readUInt8();
53+
const flag = bufferReader.readUInt8();
8854
let hasWitnesses = false;
8955
if (
9056
marker === Transaction.ADVANCED_TRANSACTION_MARKER &&
9157
flag === Transaction.ADVANCED_TRANSACTION_FLAG
9258
) {
93-
offset += 2;
9459
hasWitnesses = true;
60+
} else {
61+
bufferReader.offset -= 2;
9562
}
96-
const vinLen = readVarInt();
63+
const vinLen = bufferReader.readVarInt();
9764
for (let i = 0; i < vinLen; ++i) {
9865
tx.ins.push({
99-
hash: readSlice(32),
100-
index: readUInt32(),
101-
script: readVarSlice(),
102-
sequence: readUInt32(),
66+
hash: bufferReader.readSlice(32),
67+
index: bufferReader.readUInt32(),
68+
script: bufferReader.readVarSlice(),
69+
sequence: bufferReader.readUInt32(),
10370
witness: EMPTY_WITNESS,
10471
});
10572
}
106-
const voutLen = readVarInt();
73+
const voutLen = bufferReader.readVarInt();
10774
for (let i = 0; i < voutLen; ++i) {
10875
tx.outs.push({
109-
value: readUInt64(),
110-
script: readVarSlice(),
76+
value: bufferReader.readUInt64(),
77+
script: bufferReader.readVarSlice(),
11178
});
11279
}
11380
if (hasWitnesses) {
11481
for (let i = 0; i < vinLen; ++i) {
115-
tx.ins[i].witness = readVector();
82+
tx.ins[i].witness = bufferReader.readVector();
11683
}
11784
// was this pointless?
11885
if (!tx.hasWitnesses())
11986
throw new Error('Transaction has superfluous witness data');
12087
}
121-
tx.locktime = readUInt32();
88+
tx.locktime = bufferReader.readUInt32();
12289
if (_NO_STRICT) return tx;
123-
if (offset !== buffer.length)
90+
if (bufferReader.offset !== buffer.length)
12491
throw new Error('Transaction has unexpected data');
12592
return tx;
12693
}

test/buffer_writer.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as assert from 'assert';
22
import { describe, it } from 'mocha';
3-
import { BufferWriter } from '../src/buffer_writer';
3+
import { BufferWriter } from '../src/bufferutils';
44

55
const varuint = require('varuint-bitcoin');
66

ts_src/bufferutils.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export function reverseBuffer(buffer: Buffer): Buffer {
5252
* Helper class for serialization of bitcoin data types into a pre-allocated buffer.
5353
*/
5454
export class BufferWriter {
55-
constructor(private buffer: Buffer, public offset: number = 0) {
55+
constructor(public buffer: Buffer, public offset: number = 0) {
5656
typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]);
5757
}
5858

@@ -96,7 +96,7 @@ export class BufferWriter {
9696
* Helper class for serialization of bitcoin data types into a pre-allocated buffer.
9797
*/
9898
export class BufferReader {
99-
constructor(private buffer: Buffer, public offset: number = 0) {
99+
constructor(public buffer: Buffer, public offset: number = 0) {
100100
typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]);
101101
}
102102

ts_src/transaction.ts

+18-58
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import * as bufferutils from './bufferutils';
2-
import { BufferWriter, reverseBuffer } from './bufferutils';
1+
import { BufferReader, BufferWriter, reverseBuffer } from './bufferutils';
32
import * as bcrypto from './crypto';
43
import * as bscript from './script';
54
import { OPS as opcodes } from './script';
@@ -68,96 +67,57 @@ export class Transaction {
6867
static readonly ADVANCED_TRANSACTION_FLAG = 0x01;
6968

7069
static fromBuffer(buffer: Buffer, _NO_STRICT?: boolean): Transaction {
71-
let offset: number = 0;
72-
73-
function readSlice(n: number): Buffer {
74-
offset += n;
75-
return buffer.slice(offset - n, offset);
76-
}
77-
78-
function readUInt32(): number {
79-
const i = buffer.readUInt32LE(offset);
80-
offset += 4;
81-
return i;
82-
}
83-
84-
function readInt32(): number {
85-
const i = buffer.readInt32LE(offset);
86-
offset += 4;
87-
return i;
88-
}
89-
90-
function readUInt64(): number {
91-
const i = bufferutils.readUInt64LE(buffer, offset);
92-
offset += 8;
93-
return i;
94-
}
95-
96-
function readVarInt(): number {
97-
const vi = varuint.decode(buffer, offset);
98-
offset += varuint.decode.bytes;
99-
return vi;
100-
}
101-
102-
function readVarSlice(): Buffer {
103-
return readSlice(readVarInt());
104-
}
105-
106-
function readVector(): Buffer[] {
107-
const count = readVarInt();
108-
const vector: Buffer[] = [];
109-
for (let i = 0; i < count; i++) vector.push(readVarSlice());
110-
return vector;
111-
}
70+
const bufferReader = new BufferReader(buffer);
11271

11372
const tx = new Transaction();
114-
tx.version = readInt32();
73+
tx.version = bufferReader.readInt32();
11574

116-
const marker = buffer.readUInt8(offset);
117-
const flag = buffer.readUInt8(offset + 1);
75+
const marker = bufferReader.readUInt8();
76+
const flag = bufferReader.readUInt8();
11877

11978
let hasWitnesses = false;
12079
if (
12180
marker === Transaction.ADVANCED_TRANSACTION_MARKER &&
12281
flag === Transaction.ADVANCED_TRANSACTION_FLAG
12382
) {
124-
offset += 2;
12583
hasWitnesses = true;
84+
} else {
85+
bufferReader.offset -= 2;
12686
}
12787

128-
const vinLen = readVarInt();
88+
const vinLen = bufferReader.readVarInt();
12989
for (let i = 0; i < vinLen; ++i) {
13090
tx.ins.push({
131-
hash: readSlice(32),
132-
index: readUInt32(),
133-
script: readVarSlice(),
134-
sequence: readUInt32(),
91+
hash: bufferReader.readSlice(32),
92+
index: bufferReader.readUInt32(),
93+
script: bufferReader.readVarSlice(),
94+
sequence: bufferReader.readUInt32(),
13595
witness: EMPTY_WITNESS,
13696
});
13797
}
13898

139-
const voutLen = readVarInt();
99+
const voutLen = bufferReader.readVarInt();
140100
for (let i = 0; i < voutLen; ++i) {
141101
tx.outs.push({
142-
value: readUInt64(),
143-
script: readVarSlice(),
102+
value: bufferReader.readUInt64(),
103+
script: bufferReader.readVarSlice(),
144104
});
145105
}
146106

147107
if (hasWitnesses) {
148108
for (let i = 0; i < vinLen; ++i) {
149-
tx.ins[i].witness = readVector();
109+
tx.ins[i].witness = bufferReader.readVector();
150110
}
151111

152112
// was this pointless?
153113
if (!tx.hasWitnesses())
154114
throw new Error('Transaction has superfluous witness data');
155115
}
156116

157-
tx.locktime = readUInt32();
117+
tx.locktime = bufferReader.readUInt32();
158118

159119
if (_NO_STRICT) return tx;
160-
if (offset !== buffer.length)
120+
if (bufferReader.offset !== buffer.length)
161121
throw new Error('Transaction has unexpected data');
162122

163123
return tx;

types/bufferutils.d.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export declare function reverseBuffer(buffer: Buffer): Buffer;
55
* Helper class for serialization of bitcoin data types into a pre-allocated buffer.
66
*/
77
export declare class BufferWriter {
8-
private buffer;
8+
buffer: Buffer;
99
offset: number;
1010
constructor(buffer: Buffer, offset?: number);
1111
writeUInt8(i: number): void;
@@ -21,7 +21,7 @@ export declare class BufferWriter {
2121
* Helper class for serialization of bitcoin data types into a pre-allocated buffer.
2222
*/
2323
export declare class BufferReader {
24-
private buffer;
24+
buffer: Buffer;
2525
offset: number;
2626
constructor(buffer: Buffer, offset?: number);
2727
readUInt8(): number;

0 commit comments

Comments
 (0)