From 06674b19fe9e146fa547d94b9ef67bd2425ad71b Mon Sep 17 00:00:00 2001 From: junderw Date: Wed, 15 Jan 2020 10:50:33 +0900 Subject: [PATCH] Add BufferReader to Transaction and fix tests --- src/transaction.js | 67 +++++++++------------------------ test/buffer_writer.spec.ts | 2 +- ts_src/bufferutils.ts | 4 +- ts_src/transaction.ts | 76 +++++++++----------------------------- types/bufferutils.d.ts | 4 +- 5 files changed, 40 insertions(+), 113 deletions(-) diff --git a/src/transaction.js b/src/transaction.js index ef97900..b47cfe9 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -1,6 +1,5 @@ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); -const bufferutils = require('./bufferutils'); const bufferutils_1 = require('./bufferutils'); const bcrypto = require('./crypto'); const bscript = require('./script'); @@ -47,80 +46,48 @@ class Transaction { this.outs = []; } static fromBuffer(buffer, _NO_STRICT) { - let offset = 0; - 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 bufferReader = new bufferutils_1.BufferReader(buffer); const tx = new Transaction(); - tx.version = readInt32(); - const marker = buffer.readUInt8(offset); - const flag = buffer.readUInt8(offset + 1); + tx.version = bufferReader.readInt32(); + const marker = bufferReader.readUInt8(); + const flag = bufferReader.readUInt8(); let hasWitnesses = false; if ( marker === Transaction.ADVANCED_TRANSACTION_MARKER && flag === Transaction.ADVANCED_TRANSACTION_FLAG ) { - offset += 2; hasWitnesses = true; + } else { + bufferReader.offset -= 2; } - const vinLen = readVarInt(); + const vinLen = bufferReader.readVarInt(); for (let i = 0; i < vinLen; ++i) { tx.ins.push({ - hash: readSlice(32), - index: readUInt32(), - script: readVarSlice(), - sequence: readUInt32(), + hash: bufferReader.readSlice(32), + index: bufferReader.readUInt32(), + script: bufferReader.readVarSlice(), + sequence: bufferReader.readUInt32(), witness: EMPTY_WITNESS, }); } - const voutLen = readVarInt(); + const voutLen = bufferReader.readVarInt(); for (let i = 0; i < voutLen; ++i) { tx.outs.push({ - value: readUInt64(), - script: readVarSlice(), + value: bufferReader.readUInt64(), + script: bufferReader.readVarSlice(), }); } if (hasWitnesses) { for (let i = 0; i < vinLen; ++i) { - tx.ins[i].witness = readVector(); + tx.ins[i].witness = bufferReader.readVector(); } // was this pointless? if (!tx.hasWitnesses()) throw new Error('Transaction has superfluous witness data'); } - tx.locktime = readUInt32(); + tx.locktime = bufferReader.readUInt32(); if (_NO_STRICT) return tx; - if (offset !== buffer.length) + if (bufferReader.offset !== buffer.length) throw new Error('Transaction has unexpected data'); return tx; } diff --git a/test/buffer_writer.spec.ts b/test/buffer_writer.spec.ts index 8b33e2e..af35cba 100644 --- a/test/buffer_writer.spec.ts +++ b/test/buffer_writer.spec.ts @@ -1,6 +1,6 @@ import * as assert from 'assert'; import { describe, it } from 'mocha'; -import { BufferWriter } from '../src/buffer_writer'; +import { BufferWriter } from '../src/bufferutils'; const varuint = require('varuint-bitcoin'); diff --git a/ts_src/bufferutils.ts b/ts_src/bufferutils.ts index 6904b73..8a5c839 100644 --- a/ts_src/bufferutils.ts +++ b/ts_src/bufferutils.ts @@ -52,7 +52,7 @@ export function reverseBuffer(buffer: Buffer): Buffer { * Helper class for serialization of bitcoin data types into a pre-allocated buffer. */ 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]); } @@ -96,7 +96,7 @@ export class BufferWriter { * Helper class for serialization of bitcoin data types into a pre-allocated buffer. */ 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]); } diff --git a/ts_src/transaction.ts b/ts_src/transaction.ts index 3b792ec..561ee8a 100644 --- a/ts_src/transaction.ts +++ b/ts_src/transaction.ts @@ -1,5 +1,4 @@ -import * as bufferutils from './bufferutils'; -import { BufferWriter, reverseBuffer } from './bufferutils'; +import { BufferReader, BufferWriter, reverseBuffer } from './bufferutils'; import * as bcrypto from './crypto'; import * as bscript from './script'; import { OPS as opcodes } from './script'; @@ -68,85 +67,46 @@ export class Transaction { static readonly ADVANCED_TRANSACTION_FLAG = 0x01; static fromBuffer(buffer: Buffer, _NO_STRICT?: boolean): Transaction { - let offset: number = 0; - - 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 bufferReader = new BufferReader(buffer); const tx = new Transaction(); - tx.version = readInt32(); + tx.version = bufferReader.readInt32(); - const marker = buffer.readUInt8(offset); - const flag = buffer.readUInt8(offset + 1); + const marker = bufferReader.readUInt8(); + const flag = bufferReader.readUInt8(); let hasWitnesses = false; if ( marker === Transaction.ADVANCED_TRANSACTION_MARKER && flag === Transaction.ADVANCED_TRANSACTION_FLAG ) { - offset += 2; hasWitnesses = true; + } else { + bufferReader.offset -= 2; } - const vinLen = readVarInt(); + const vinLen = bufferReader.readVarInt(); for (let i = 0; i < vinLen; ++i) { tx.ins.push({ - hash: readSlice(32), - index: readUInt32(), - script: readVarSlice(), - sequence: readUInt32(), + hash: bufferReader.readSlice(32), + index: bufferReader.readUInt32(), + script: bufferReader.readVarSlice(), + sequence: bufferReader.readUInt32(), witness: EMPTY_WITNESS, }); } - const voutLen = readVarInt(); + const voutLen = bufferReader.readVarInt(); for (let i = 0; i < voutLen; ++i) { tx.outs.push({ - value: readUInt64(), - script: readVarSlice(), + value: bufferReader.readUInt64(), + script: bufferReader.readVarSlice(), }); } if (hasWitnesses) { for (let i = 0; i < vinLen; ++i) { - tx.ins[i].witness = readVector(); + tx.ins[i].witness = bufferReader.readVector(); } // was this pointless? @@ -154,10 +114,10 @@ export class Transaction { throw new Error('Transaction has superfluous witness data'); } - tx.locktime = readUInt32(); + tx.locktime = bufferReader.readUInt32(); if (_NO_STRICT) return tx; - if (offset !== buffer.length) + if (bufferReader.offset !== buffer.length) throw new Error('Transaction has unexpected data'); return tx; diff --git a/types/bufferutils.d.ts b/types/bufferutils.d.ts index d9e6dc0..424bbaf 100644 --- a/types/bufferutils.d.ts +++ b/types/bufferutils.d.ts @@ -5,7 +5,7 @@ export declare function reverseBuffer(buffer: Buffer): Buffer; * Helper class for serialization of bitcoin data types into a pre-allocated buffer. */ export declare class BufferWriter { - private buffer; + buffer: Buffer; offset: number; constructor(buffer: Buffer, offset?: number); 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. */ export declare class BufferReader { - private buffer; + buffer: Buffer; offset: number; constructor(buffer: Buffer, offset?: number); readUInt8(): number;