Add BufferReader to Transaction and fix tests

This commit is contained in:
junderw 2020-01-15 10:50:33 +09:00
parent 91e6c8abc3
commit 06674b19fe
No known key found for this signature in database
GPG key ID: B256185D3A971908
5 changed files with 40 additions and 113 deletions

View file

@ -1,6 +1,5 @@
'use strict'; 'use strict';
Object.defineProperty(exports, '__esModule', { value: true }); Object.defineProperty(exports, '__esModule', { value: true });
const bufferutils = require('./bufferutils');
const bufferutils_1 = require('./bufferutils'); const bufferutils_1 = require('./bufferutils');
const bcrypto = require('./crypto'); const bcrypto = require('./crypto');
const bscript = require('./script'); const bscript = require('./script');
@ -47,80 +46,48 @@ class Transaction {
this.outs = []; this.outs = [];
} }
static fromBuffer(buffer, _NO_STRICT) { static fromBuffer(buffer, _NO_STRICT) {
let offset = 0; const bufferReader = new bufferutils_1.BufferReader(buffer);
function readSlice(n) {
offset += n;
return buffer.slice(offset - n, offset);
}
function readUInt32() {
const i = buffer.readUInt32LE(offset);
offset += 4;
return i;
}
function readInt32() {
const i = buffer.readInt32LE(offset);
offset += 4;
return i;
}
function readUInt64() {
const i = bufferutils.readUInt64LE(buffer, offset);
offset += 8;
return i;
}
function readVarInt() {
const vi = varuint.decode(buffer, offset);
offset += varuint.decode.bytes;
return vi;
}
function readVarSlice() {
return readSlice(readVarInt());
}
function readVector() {
const count = readVarInt();
const vector = [];
for (let i = 0; i < count; i++) vector.push(readVarSlice());
return vector;
}
const tx = new Transaction(); const tx = new Transaction();
tx.version = readInt32(); tx.version = bufferReader.readInt32();
const marker = buffer.readUInt8(offset); const marker = bufferReader.readUInt8();
const flag = buffer.readUInt8(offset + 1); const flag = bufferReader.readUInt8();
let hasWitnesses = false; let hasWitnesses = false;
if ( if (
marker === Transaction.ADVANCED_TRANSACTION_MARKER && marker === Transaction.ADVANCED_TRANSACTION_MARKER &&
flag === Transaction.ADVANCED_TRANSACTION_FLAG flag === Transaction.ADVANCED_TRANSACTION_FLAG
) { ) {
offset += 2;
hasWitnesses = true; hasWitnesses = true;
} else {
bufferReader.offset -= 2;
} }
const vinLen = readVarInt(); const vinLen = bufferReader.readVarInt();
for (let i = 0; i < vinLen; ++i) { for (let i = 0; i < vinLen; ++i) {
tx.ins.push({ tx.ins.push({
hash: readSlice(32), hash: bufferReader.readSlice(32),
index: readUInt32(), index: bufferReader.readUInt32(),
script: readVarSlice(), script: bufferReader.readVarSlice(),
sequence: readUInt32(), sequence: bufferReader.readUInt32(),
witness: EMPTY_WITNESS, witness: EMPTY_WITNESS,
}); });
} }
const voutLen = readVarInt(); const voutLen = bufferReader.readVarInt();
for (let i = 0; i < voutLen; ++i) { for (let i = 0; i < voutLen; ++i) {
tx.outs.push({ tx.outs.push({
value: readUInt64(), value: bufferReader.readUInt64(),
script: readVarSlice(), script: bufferReader.readVarSlice(),
}); });
} }
if (hasWitnesses) { if (hasWitnesses) {
for (let i = 0; i < vinLen; ++i) { for (let i = 0; i < vinLen; ++i) {
tx.ins[i].witness = readVector(); tx.ins[i].witness = bufferReader.readVector();
} }
// was this pointless? // was this pointless?
if (!tx.hasWitnesses()) if (!tx.hasWitnesses())
throw new Error('Transaction has superfluous witness data'); throw new Error('Transaction has superfluous witness data');
} }
tx.locktime = readUInt32(); tx.locktime = bufferReader.readUInt32();
if (_NO_STRICT) return tx; if (_NO_STRICT) return tx;
if (offset !== buffer.length) if (bufferReader.offset !== buffer.length)
throw new Error('Transaction has unexpected data'); throw new Error('Transaction has unexpected data');
return tx; return tx;
} }

View file

@ -1,6 +1,6 @@
import * as assert from 'assert'; import * as assert from 'assert';
import { describe, it } from 'mocha'; import { describe, it } from 'mocha';
import { BufferWriter } from '../src/buffer_writer'; import { BufferWriter } from '../src/bufferutils';
const varuint = require('varuint-bitcoin'); const varuint = require('varuint-bitcoin');

View file

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

View file

@ -1,5 +1,4 @@
import * as bufferutils from './bufferutils'; import { BufferReader, BufferWriter, reverseBuffer } from './bufferutils';
import { BufferWriter, reverseBuffer } from './bufferutils';
import * as bcrypto from './crypto'; import * as bcrypto from './crypto';
import * as bscript from './script'; import * as bscript from './script';
import { OPS as opcodes } from './script'; import { OPS as opcodes } from './script';
@ -68,85 +67,46 @@ export class Transaction {
static readonly ADVANCED_TRANSACTION_FLAG = 0x01; static readonly ADVANCED_TRANSACTION_FLAG = 0x01;
static fromBuffer(buffer: Buffer, _NO_STRICT?: boolean): Transaction { static fromBuffer(buffer: Buffer, _NO_STRICT?: boolean): Transaction {
let offset: number = 0; const bufferReader = new BufferReader(buffer);
function readSlice(n: number): Buffer {
offset += n;
return buffer.slice(offset - n, offset);
}
function readUInt32(): number {
const i = buffer.readUInt32LE(offset);
offset += 4;
return i;
}
function readInt32(): number {
const i = buffer.readInt32LE(offset);
offset += 4;
return i;
}
function readUInt64(): number {
const i = bufferutils.readUInt64LE(buffer, offset);
offset += 8;
return i;
}
function readVarInt(): number {
const vi = varuint.decode(buffer, offset);
offset += varuint.decode.bytes;
return vi;
}
function readVarSlice(): Buffer {
return readSlice(readVarInt());
}
function readVector(): Buffer[] {
const count = readVarInt();
const vector: Buffer[] = [];
for (let i = 0; i < count; i++) vector.push(readVarSlice());
return vector;
}
const tx = new Transaction(); const tx = new Transaction();
tx.version = readInt32(); tx.version = bufferReader.readInt32();
const marker = buffer.readUInt8(offset); const marker = bufferReader.readUInt8();
const flag = buffer.readUInt8(offset + 1); const flag = bufferReader.readUInt8();
let hasWitnesses = false; let hasWitnesses = false;
if ( if (
marker === Transaction.ADVANCED_TRANSACTION_MARKER && marker === Transaction.ADVANCED_TRANSACTION_MARKER &&
flag === Transaction.ADVANCED_TRANSACTION_FLAG flag === Transaction.ADVANCED_TRANSACTION_FLAG
) { ) {
offset += 2;
hasWitnesses = true; hasWitnesses = true;
} else {
bufferReader.offset -= 2;
} }
const vinLen = readVarInt(); const vinLen = bufferReader.readVarInt();
for (let i = 0; i < vinLen; ++i) { for (let i = 0; i < vinLen; ++i) {
tx.ins.push({ tx.ins.push({
hash: readSlice(32), hash: bufferReader.readSlice(32),
index: readUInt32(), index: bufferReader.readUInt32(),
script: readVarSlice(), script: bufferReader.readVarSlice(),
sequence: readUInt32(), sequence: bufferReader.readUInt32(),
witness: EMPTY_WITNESS, witness: EMPTY_WITNESS,
}); });
} }
const voutLen = readVarInt(); const voutLen = bufferReader.readVarInt();
for (let i = 0; i < voutLen; ++i) { for (let i = 0; i < voutLen; ++i) {
tx.outs.push({ tx.outs.push({
value: readUInt64(), value: bufferReader.readUInt64(),
script: readVarSlice(), script: bufferReader.readVarSlice(),
}); });
} }
if (hasWitnesses) { if (hasWitnesses) {
for (let i = 0; i < vinLen; ++i) { for (let i = 0; i < vinLen; ++i) {
tx.ins[i].witness = readVector(); tx.ins[i].witness = bufferReader.readVector();
} }
// was this pointless? // was this pointless?
@ -154,10 +114,10 @@ export class Transaction {
throw new Error('Transaction has superfluous witness data'); throw new Error('Transaction has superfluous witness data');
} }
tx.locktime = readUInt32(); tx.locktime = bufferReader.readUInt32();
if (_NO_STRICT) return tx; if (_NO_STRICT) return tx;
if (offset !== buffer.length) if (bufferReader.offset !== buffer.length)
throw new Error('Transaction has unexpected data'); throw new Error('Transaction has unexpected data');
return tx; return tx;

View file

@ -5,7 +5,7 @@ export declare function reverseBuffer(buffer: Buffer): Buffer;
* Helper class for serialization of bitcoin data types into a pre-allocated buffer. * Helper class for serialization of bitcoin data types into a pre-allocated buffer.
*/ */
export declare class BufferWriter { export declare class BufferWriter {
private buffer; buffer: Buffer;
offset: number; offset: number;
constructor(buffer: Buffer, offset?: number); constructor(buffer: Buffer, offset?: number);
writeUInt8(i: number): void; writeUInt8(i: number): void;
@ -21,7 +21,7 @@ export declare class BufferWriter {
* Helper class for serialization of bitcoin data types into a pre-allocated buffer. * Helper class for serialization of bitcoin data types into a pre-allocated buffer.
*/ */
export declare class BufferReader { export declare class BufferReader {
private buffer; buffer: Buffer;
offset: number; offset: number;
constructor(buffer: Buffer, offset?: number); constructor(buffer: Buffer, offset?: number);
readUInt8(): number; readUInt8(): number;