From 8e1200c728d43722bb8a17e532ec470828cc6f69 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 2 Aug 2013 14:33:50 -0400 Subject: [PATCH 1/3] Block, Transaction: de-serialize via BinaryParser --- Block.js | 36 +++++++++++++++++++----------------- Transaction.js | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 17 deletions(-) diff --git a/Block.js b/Block.js index 9feaa06..5cae78b 100644 --- a/Block.js +++ b/Block.js @@ -48,25 +48,27 @@ function spec(b) { return buf; }; - Block.prototype.parseHeader = function parseHeader(buf) { - if (buf.length != 80) - throw new VerificationError('Block header length invalid'); + Block.prototype.parse = function parse(parser, headerOnly) { + this.version = parser.word32le(); + this.prev_hash = parser.buffer(32); + this.merkle_root = parser.buffer(32); + this.timestamp = parser.word32le(); + this.bits = parser.word32le(); + this.nonce = parser.word32le(); - var vars = Binary.parse(buf) - .word32lu('version') - .buffer('prev_hash', 32) - .buffer('merkle_root', 32) - .word32lu('timestamp') - .word32lu('bits') - .word32lu('nonce') - .vars; + this.txs = []; + this.size = 0; - this.version = vars.version; - this.prev_hash = vars.prev_hash; - this.merkle_root = vars.merkle_root; - this.timestamp = vars.timestamp; - this.bits = vars.bits; - this.nonce = vars.nonce; + if (headerOnly) + return; + + var txCount = parser.varInt(); + + for (i = 0; i < txCount; i++) { + var tx = new Transaction(); + tx.parse(parser); + this.txs.push(tx); + } }; Block.prototype.calcHash = function calcHash() { diff --git a/Transaction.js b/Transaction.js index fd758b1..28fbd98 100644 --- a/Transaction.js +++ b/Transaction.js @@ -575,6 +575,40 @@ function spec(b) { return this; }; + Transaction.prototype.parse = function (parser) { + if (Buffer.isBuffer(parser)) { + parser = new Parser(parser); + } + + var i, sLen, startPos = parser.pos; + + this.version = parser.word32le(); + + var txinCount = parser.varInt(); + + this.ins = []; + for (j = 0; j < txinCount; j++) { + var txin = new TransactionIn(); + txin.o = parser.buffer(36); // outpoint + sLen = parser.varInt(); // script_len + txin.s = parser.buffer(sLen); // script + txin.q = parser.word32le(); // sequence + this.ins.push(txin); + } + + var txoutCount = parser.varInt(); + + this.outs = []; + for (j = 0; j < txoutCount; j++) { + var txout = new TransactionOut(); + txout.v = parser.buffer(8); // value + sLen = parser.varInt(); // script_len + txout.s = parser.buffer(sLen); // script + this.outs.push(txout); + } + + this.lock_time = parser.word32le(); + }; var TransactionInputsCache = exports.TransactionInputsCache = function TransactionInputsCache(tx) From 420773ac3903b23b78db0e15a43514ecd1da773f Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 2 Aug 2013 14:47:44 -0400 Subject: [PATCH 2/3] Connection: parse TXs, blocks via their object parsers. --- Connection.js | 76 +++++++++++++-------------------------------------- 1 file changed, 19 insertions(+), 57 deletions(-) diff --git a/Connection.js b/Connection.js index e94aab6..61786f5 100644 --- a/Connection.js +++ b/Connection.js @@ -13,6 +13,8 @@ function spec(b) { var Buffers = b.Buffers || require('buffers'); require('./Buffers.monkey').patch(Buffers); var noop = function() {}; + var Block = require('./Block').class(); + var Transaction = require('./Transaction').class(); var util = b.util || require('./util/util'); var Parser = b.Parser || require('./util/BinaryParser').class(); var doubleSha256 = b.doubleSha256 || util.twoSha256; @@ -431,31 +433,32 @@ function spec(b) { break; case 'block': - data.version = parser.word32le(); - data.prev_hash = parser.buffer(32); - data.merkle_root = parser.buffer(32); - data.timestamp = parser.word32le(); - data.bits = parser.word32le(); - data.nonce = parser.word32le(); + var block = new Block(); + block.parse(parser); - var txCount = parser.varInt(); + data.block = block; + data.version = block.version; + data.prev_hash = block.prev_hash; + data.merkle_root = block.merkle_root; + data.timestamp = block.timestamp; + data.bits = block.bits; + data.nonce = block.nonce; - data.txs = []; - for (i = 0; i < txCount; i++) { - data.txs.push(Connection.parseTx(parser)); - } + data.txs = block.txs; data.size = payload.length; break; case 'tx': - var txData = Connection.parseTx(parser); + var tx = new Transaction(); + tx.parse(parser); return { command: command, - version: txData.version, - lock_time: txData.lock_time, - ins: txData.ins, - outs: txData.outs + version: tx.version, + lock_time: tx.lock_time, + ins: tx.ins, + outs: tx.outs, + tx: tx, }; case 'getblocks': @@ -521,47 +524,6 @@ function spec(b) { return data; }; - Connection.parseTx = function (parser) { - if (Buffer.isBuffer(parser)) { - parser = new Parser(parser); - } - - var data = {}, i, sLen, startPos = parser.pos; - - data.version = parser.word32le(); - - var txinCount = parser.varInt(); - - data.ins = []; - for (j = 0; j < txinCount; j++) { - var txin = {}; - txin.o = parser.buffer(36); // outpoint - sLen = parser.varInt(); // script_len - txin.s = parser.buffer(sLen); // script - txin.q = parser.word32le(); // sequence - data.ins.push(txin); - } - - var txoutCount = parser.varInt(); - - data.outs = []; - for (j = 0; j < txoutCount; j++) { - var txout = {}; - txout.v = parser.buffer(8); // value - sLen = parser.varInt(); // script_len - txout.s = parser.buffer(sLen); // script - data.outs.push(txout); - } - - data.lock_time = parser.word32le(); - - var endPos = parser.pos; - - data.buffer = parser.subject.slice(startPos, endPos); - - return data; - }; - return Connection; }; module.defineClass(spec); From 5b69342356aaa4a2bdf5170ee8db5fa9c634720d Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 2 Aug 2013 15:02:45 -0400 Subject: [PATCH 3/3] Connection, const: add bits necessary for getheaders/headers --- Connection.js | 22 ++++++++++++++++++++-- const.js | 7 +++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 const.js diff --git a/Connection.js b/Connection.js index 61786f5..f7078ee 100644 --- a/Connection.js +++ b/Connection.js @@ -187,7 +187,7 @@ function spec(b) { this.sendMessage('version', put.buffer()); }; - Connection.prototype.sendGetBlocks = function (starts, stop) { + Connection.prototype.sendGetBlocks = function (starts, stop, wantHeaders) { var put = new Put(); put.word32le(this.sendVer); @@ -207,7 +207,14 @@ function spec(b) { put.put(stopBuffer); - this.sendMessage('getblocks', put.buffer()); + var command = 'getblocks'; + if (wantHeaders) + command = 'getheaders'; + this.sendMessage(command, put.buffer()); + }; + + Connection.prototype.sendGetHeaders = function(starts, stop) { + this.sendGetBlocks(starts, stop, true); }; Connection.prototype.sendGetData = function (invs) { @@ -432,6 +439,17 @@ function spec(b) { } break; + case 'headers': + data.count = parser.varInt(); + + data.headers = []; + for (i = 0; i < data.count; i++) { + var header = new Block(); + header.parse(parser); + data.headers.push(header); + } + break; + case 'block': var block = new Block(); block.parse(parser); diff --git a/const.js b/const.js new file mode 100644 index 0000000..cd6a77e --- /dev/null +++ b/const.js @@ -0,0 +1,7 @@ + +exports.MSG = { + TX: 1, + BLOCK: 2, + FILTERED_BLOCK: 3, +}; +