Browse Source

Merge pull request #1205 from maraoz/fix/block-parser

Fix block parsing
patch-2
Manuel Aráoz 10 years ago
parent
commit
a11b916be7
  1. 7
      lib/block/block.js
  2. 11
      lib/encoding/bufferreader.js
  3. 9
      lib/script/script.js
  4. 18
      lib/transaction/input/input.js
  5. 2
      lib/transaction/transaction.js
  6. 8
      test/block.js
  7. 6
      test/encoding/bufferreader.js
  8. 11
      test/script/interpreter.js
  9. 12
      test/script/script.js
  10. 1
      test/transaction/input/input.js

7
lib/block/block.js

@ -68,8 +68,8 @@ Block._fromJSON = function _fromJSON(data) {
*/ */
Block._fromObject = function _fromObject(data) { Block._fromObject = function _fromObject(data) {
var transactions = []; var transactions = [];
data.transactions.forEach(function(data) { data.transactions.forEach(function(tx) {
transactions.push(Transaction().fromJSON(data)); transactions.push(Transaction().fromJSON(tx));
}); });
var info = { var info = {
header: BlockHeader.fromObject(data.header), header: BlockHeader.fromObject(data.header),
@ -118,6 +118,7 @@ Block._fromBufferReader = function _fromBufferReader(br) {
* @returns {Block} - An instance of block * @returns {Block} - An instance of block
*/ */
Block.fromBufferReader = function fromBufferReader(br) { Block.fromBufferReader = function fromBufferReader(br) {
$.checkArgument(br, 'br is required');
var info = Block._fromBufferReader(br); var info = Block._fromBufferReader(br);
return new Block(info); return new Block(info);
}; };
@ -127,7 +128,7 @@ Block.fromBufferReader = function fromBufferReader(br) {
* @returns {Block} - An instance of block * @returns {Block} - An instance of block
*/ */
Block.fromBuffer = function fromBuffer(buf) { Block.fromBuffer = function fromBuffer(buf) {
return Block.fromBufferReader(BufferReader(buf)); return Block.fromBufferReader(new BufferReader(buf));
}; };
/** /**

11
lib/encoding/bufferreader.js

@ -9,13 +9,22 @@ var BufferReader = function BufferReader(buf) {
if (!(this instanceof BufferReader)) { if (!(this instanceof BufferReader)) {
return new BufferReader(buf); return new BufferReader(buf);
} }
if (_.isUndefined(buf)) {
return;
}
if (Buffer.isBuffer(buf)) { if (Buffer.isBuffer(buf)) {
this.set({ this.set({
buf: buf buf: buf
}); });
} else if (buf) { } else if (_.isString(buf)) {
this.set({
buf: new Buffer(buf, 'hex'),
});
} else if (_.isObject(buf)) {
var obj = buf; var obj = buf;
this.set(obj); this.set(obj);
} else {
throw new TypeError('Unrecognized argument for BufferReader');
} }
}; };

9
lib/script/script.js

@ -99,7 +99,7 @@ Script.fromBuffer = function(buffer) {
} }
} catch (e) { } catch (e) {
if (e instanceof RangeError) { if (e instanceof RangeError) {
throw new errors.Script.InvalidBuffer(buffer); throw new errors.Script.InvalidBuffer(buffer.toString('hex'));
} }
throw e; throw e;
} }
@ -778,13 +778,6 @@ Script.prototype.toAddress = function(network) {
return new Address(info); return new Address(info);
}; };
/**
* @return {Script}
*/
Script.prototype.toScriptHashOut = function() {
return Script.buildScriptHashOut(this);
};
/** /**
* Analagous to bitcoind's FindAndDelete. Find and delete equivalent chunks, * Analagous to bitcoind's FindAndDelete. Find and delete equivalent chunks,
* typically used with push data chunks. Note that this will find and delete * typically used with push data chunks. Note that this will find and delete

18
lib/transaction/input/input.js

@ -30,6 +30,9 @@ Object.defineProperty(Input.prototype, 'script', {
writeable: false, writeable: false,
enumerable: true, enumerable: true,
get: function() { get: function() {
if (this.isNull()) {
return null;
}
if (!this._script) { if (!this._script) {
this._script = new Script(this._scriptBuffer); this._script = new Script(this._scriptBuffer);
} }
@ -59,8 +62,12 @@ Input.prototype.toObject = function toObject() {
prevTxId: this.prevTxId.toString('hex'), prevTxId: this.prevTxId.toString('hex'),
outputIndex: this.outputIndex, outputIndex: this.outputIndex,
sequenceNumber: this.sequenceNumber, sequenceNumber: this.sequenceNumber,
script: this.script.toString(), script: this._scriptBuffer.toString('hex'),
}; };
// add human readable form if input contains valid script
if (this.script) {
obj.scriptString = this.script.toString();
}
if (this.output) { if (this.output) {
obj.output = this.output.toObject(); obj.output = this.output.toObject();
} }
@ -88,6 +95,8 @@ Input.fromBufferReader = function(br) {
input.outputIndex = br.readUInt32LE(); input.outputIndex = br.readUInt32LE();
input._scriptBuffer = br.readVarLengthBuffer(); input._scriptBuffer = br.readVarLengthBuffer();
input.sequenceNumber = br.readUInt32LE(); input.sequenceNumber = br.readUInt32LE();
// TODO: return different classes according to which input it is
// e.g: CoinbaseInput, PublicKeyHashInput, MultiSigScriptHashInput, etc.
return input; return input;
}; };
@ -105,14 +114,19 @@ Input.prototype.toBufferWriter = function(writer) {
}; };
Input.prototype.setScript = function(script) { Input.prototype.setScript = function(script) {
this._script = null;
if (script instanceof Script) { if (script instanceof Script) {
this._script = script; this._script = script;
this._scriptBuffer = script.toBuffer(); this._scriptBuffer = script.toBuffer();
} else if (JSUtil.isHexa(script)) {
// hex string script
this._scriptBuffer = new Buffer(script, 'hex');
} else if (_.isString(script)) { } else if (_.isString(script)) {
// human readable string script
this._script = new Script(script); this._script = new Script(script);
this._scriptBuffer = this._script.toBuffer(); this._scriptBuffer = this._script.toBuffer();
} else if (BufferUtil.isBuffer(script)) { } else if (BufferUtil.isBuffer(script)) {
this._script = null; // buffer script
this._scriptBuffer = new buffer.Buffer(script); this._scriptBuffer = new buffer.Buffer(script);
} else { } else {
throw new TypeError('Invalid argument type: script'); throw new TypeError('Invalid argument type: script');

2
lib/transaction/transaction.js

@ -1017,7 +1017,7 @@ Transaction.prototype.verify = function() {
var isCoinbase = this.isCoinbase(); var isCoinbase = this.isCoinbase();
if (isCoinbase) { if (isCoinbase) {
var buf = this.inputs[0]._script.toBuffer(); var buf = this.inputs[0]._scriptBuffer;
if (buf.length < 2 || buf.length > 100) { if (buf.length < 2 || buf.length > 100) {
return 'coinbase transaction script size invalid'; return 'coinbase transaction script size invalid';
} }

8
test/block.js

File diff suppressed because one or more lines are too long

6
test/encoding/bufferreader.js

@ -21,6 +21,12 @@ describe('BufferReader', function() {
should.exist(br); should.exist(br);
Buffer.isBuffer(br.buf).should.equal(true); Buffer.isBuffer(br.buf).should.equal(true);
}); });
it('should fail for invalid object', function() {
var fail = function() {
return new BufferReader(5);
};
fail.should.throw('Unrecognized argument for BufferReader');
});
describe('#set', function() { describe('#set', function() {

11
test/script/interpreter.js

@ -196,9 +196,6 @@ describe('Interpreter', function() {
var scriptPubkey = Script.fromBitcoindString(vector[1]); var scriptPubkey = Script.fromBitcoindString(vector[1]);
var flags = getFlags(vector[2]); var flags = getFlags(vector[2]);
//testToFromString(scriptSig);
//testToFromString(scriptPubkey);
var hashbuf = new Buffer(32); var hashbuf = new Buffer(32);
hashbuf.fill(0); hashbuf.fill(0);
var credtx = new Transaction(); var credtx = new Transaction();
@ -242,7 +239,8 @@ describe('Interpreter', function() {
var fullScriptString = vector[0] + ' ' + vector[1]; var fullScriptString = vector[0] + ' ' + vector[1];
var comment = descstr ? (' (' + descstr + ')') : ''; var comment = descstr ? (' (' + descstr + ')') : '';
it('should pass script_' + (expected ? '' : 'in') + 'valid ' + it('should pass script_' + (expected ? '' : 'in') + 'valid ' +
'vector #' + c + ': ' + fullScriptString + comment, function() { 'vector #' + c + ': ' + fullScriptString + comment,
function() {
testFixture(vector, expected); testFixture(vector, expected);
}); });
}); });
@ -279,12 +277,15 @@ describe('Interpreter', function() {
var tx = new Transaction(txhex); var tx = new Transaction(txhex);
var allInputsVerified = true; var allInputsVerified = true;
tx.inputs.forEach(function(txin, j) { tx.inputs.forEach(function(txin, j) {
if (txin.isNull()) {
return;
}
var scriptSig = txin.script; var scriptSig = txin.script;
var txidhex = txin.prevTxId.toString('hex'); var txidhex = txin.prevTxId.toString('hex');
var txoutnum = txin.outputIndex; var txoutnum = txin.outputIndex;
var scriptPubkey = map[txidhex + ':' + txoutnum]; var scriptPubkey = map[txidhex + ':' + txoutnum];
should.exist(scriptPubkey); should.exist(scriptPubkey);
should.exist(scriptSig); (scriptSig !== undefined).should.equal(true);
var interp = new Interpreter(); var interp = new Interpreter();
var verified = interp.verify(scriptSig, scriptPubkey, tx, j, flags); var verified = interp.verify(scriptSig, scriptPubkey, tx, j, flags);
if (!verified) { if (!verified) {

12
test/script/script.js

@ -11,8 +11,6 @@ var Opcode = bitcore.Opcode;
var PublicKey = bitcore.PublicKey; var PublicKey = bitcore.PublicKey;
var Address = bitcore.Address; var Address = bitcore.Address;
var script_valid = require('../data/bitcoind/script_valid');
describe('Script', function() { describe('Script', function() {
it('should make a new script', function() { it('should make a new script', function() {
@ -328,11 +326,16 @@ describe('Script', function() {
describe('#isScripthashOut', function() { describe('#isScripthashOut', function() {
it('should identify this known pubkeyhashout as pubkeyhashout', function() { it('should identify this known p2shout as p2shout', function() {
Script('OP_HASH160 20 0x0000000000000000000000000000000000000000 OP_EQUAL').isScriptHashOut().should.equal(true); Script('OP_HASH160 20 0x0000000000000000000000000000000000000000 OP_EQUAL').isScriptHashOut().should.equal(true);
}); });
it('should identify these known non-pubkeyhashout as not pubkeyhashout', function() { it('should identify result of .isScriptHashOut() as p2sh', function() {
Script('OP_DUP OP_HASH160 20 0x0000000000000000000000000000000000000000 OP_EQUALVERIFY OP_CHECKSIG')
.toScriptHashOut().isScriptHashOut().should.equal(true);
});
it('should identify these known non-p2shout as not p2shout', function() {
Script('OP_HASH160 20 0x0000000000000000000000000000000000000000 OP_EQUAL OP_EQUAL').isScriptHashOut().should.equal(false); Script('OP_HASH160 20 0x0000000000000000000000000000000000000000 OP_EQUAL OP_EQUAL').isScriptHashOut().should.equal(false);
Script('OP_HASH160 21 0x000000000000000000000000000000000000000000 OP_EQUAL').isScriptHashOut().should.equal(false); Script('OP_HASH160 21 0x000000000000000000000000000000000000000000 OP_EQUAL').isScriptHashOut().should.equal(false);
}); });
@ -755,4 +758,5 @@ describe('Script', function() {
}); });
}); });
}); });

1
test/transaction/input/input.js

@ -73,7 +73,6 @@ describe('Transaction.Input', function() {
it('fromObject should work', function() { it('fromObject should work', function() {
var input = Input.fromJSON(coinbaseJSON); var input = Input.fromJSON(coinbaseJSON);
var obj = input.toObject(); var obj = input.toObject();
obj.script = new Buffer(obj.script, 'hex');
Input.fromObject(obj).should.deep.equal(input); Input.fromObject(obj).should.deep.equal(input);
obj.script = 42; obj.script = 42;
Input.fromObject.bind(null, obj).should.throw('Invalid argument type: script'); Input.fromObject.bind(null, obj).should.throw('Invalid argument type: script');

Loading…
Cancel
Save