serialization... again.
This commit is contained in:
parent
f494762a67
commit
16404a03ba
@ -37,6 +37,28 @@ function AbstractBlock(data) {
|
||||
if (!(this instanceof AbstractBlock))
|
||||
return new AbstractBlock(data);
|
||||
|
||||
this.version = 1;
|
||||
this.prevBlock = null;
|
||||
this.merkleRoot = null;
|
||||
this.ts = 0;
|
||||
this.bits = 0;
|
||||
this.nonce = 0;
|
||||
this.totalTX = 0;
|
||||
this.height = -1;
|
||||
|
||||
this.txs = null;
|
||||
this.mutable = false;
|
||||
|
||||
this._valid = null;
|
||||
this._hash = null;
|
||||
this._size = null;
|
||||
this._witnessSize = null;
|
||||
|
||||
if (data)
|
||||
this.parseOptions(data);
|
||||
}
|
||||
|
||||
AbstractBlock.prototype.parseOptions = function parseOptions(data) {
|
||||
assert(data, 'Block data is required.');
|
||||
assert(typeof data.version === 'number');
|
||||
assert(typeof data.prevBlock === 'string');
|
||||
@ -61,7 +83,7 @@ function AbstractBlock(data) {
|
||||
this._hash = null;
|
||||
this._size = null;
|
||||
this._witnessSize = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hash the block headers.
|
||||
@ -86,8 +108,20 @@ AbstractBlock.prototype.hash = function hash(enc) {
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
AbstractBlock.prototype.abbr = function abbr() {
|
||||
return bcoin.protocol.framer.blockHeaders(this);
|
||||
AbstractBlock.prototype.abbr = function abbr(writer) {
|
||||
var p = bcoin.writer(writer);
|
||||
|
||||
p.write32(this.version);
|
||||
p.writeHash(this.prevBlock);
|
||||
p.writeHash(this.merkleRoot);
|
||||
p.writeU32(this.ts);
|
||||
p.writeU32(this.bits);
|
||||
p.writeU32(this.nonce);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -37,8 +37,6 @@ var constants = bcoin.protocol.constants;
|
||||
*/
|
||||
|
||||
function Block(data) {
|
||||
var i;
|
||||
|
||||
if (!(this instanceof Block))
|
||||
return new Block(data);
|
||||
|
||||
@ -49,6 +47,24 @@ function Block(data) {
|
||||
this._cbHeight = null;
|
||||
this._commitmentHash = null;
|
||||
|
||||
this._raw = null;
|
||||
this._size = null;
|
||||
this._witnessSize = null;
|
||||
|
||||
if (data)
|
||||
this.fromOptions(data);
|
||||
}
|
||||
|
||||
utils.inherits(Block, bcoin.abstractblock);
|
||||
|
||||
Block.prototype.fromOptions = function fromOptions(data) {
|
||||
var i;
|
||||
|
||||
this.txs = [];
|
||||
|
||||
this._cbHeight = null;
|
||||
this._commitmentHash = null;
|
||||
|
||||
this._raw = data._raw || null;
|
||||
this._size = data._size || null;
|
||||
this._witnessSize = data._witnessSize != null ? data._witnessSize : null;
|
||||
@ -57,17 +73,19 @@ function Block(data) {
|
||||
for (i = 0; i < data.txs.length; i++)
|
||||
this.addTX(data.txs[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
utils.inherits(Block, bcoin.abstractblock);
|
||||
Block.fromOptions = function fromOptions(data) {
|
||||
return new Block().fromOptions(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize the block. Include witnesses if present.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
Block.prototype.render = function render() {
|
||||
return this.getRaw();
|
||||
Block.prototype.render = function render(writer) {
|
||||
return this.getRaw(writer);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -75,10 +93,10 @@ Block.prototype.render = function render() {
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
Block.prototype.renderNormal = function renderNormal() {
|
||||
Block.prototype.renderNormal = function renderNormal(writer) {
|
||||
if (!this.hasWitness())
|
||||
return this.getRaw();
|
||||
return bcoin.protocol.framer.block(this);
|
||||
return this.getRaw(writer);
|
||||
return this.frameNormal(writer);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -86,10 +104,10 @@ Block.prototype.renderNormal = function renderNormal() {
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
Block.prototype.renderWitness = function renderWitness() {
|
||||
Block.prototype.renderWitness = function renderWitness(writer) {
|
||||
if (this.hasWitness())
|
||||
return this.getRaw();
|
||||
return bcoin.protocol.framer.witnessBlock(this);
|
||||
return this.getRaw(writer);
|
||||
return this.frameWitness(writer);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -98,19 +116,25 @@ Block.prototype.renderWitness = function renderWitness() {
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
Block.prototype.getRaw = function getRaw() {
|
||||
Block.prototype.getRaw = function getRaw(writer) {
|
||||
var raw;
|
||||
|
||||
if (this._raw) {
|
||||
assert(this._size > 0);
|
||||
assert(this._witnessSize >= 0);
|
||||
if (writer) {
|
||||
writer.writeBytes(this._raw);
|
||||
writer._witnessSize = this._raw._witnessSize;
|
||||
return writer;
|
||||
}
|
||||
return this._raw;
|
||||
}
|
||||
|
||||
if (this.hasWitness())
|
||||
raw = bcoin.protocol.framer.witnessBlock(this);
|
||||
else
|
||||
raw = bcoin.protocol.framer.block(this);
|
||||
raw = this.frameWitness();
|
||||
// if (this.hasWitness())
|
||||
// raw = this.frameWitness();
|
||||
// else
|
||||
// raw = this.frameNormal();
|
||||
|
||||
if (!this.mutable) {
|
||||
this._size = raw.length;
|
||||
@ -118,6 +142,12 @@ Block.prototype.getRaw = function getRaw() {
|
||||
this._raw = raw;
|
||||
}
|
||||
|
||||
if (writer) {
|
||||
writer.writeBytes(raw);
|
||||
writer._witnessSize = raw._witnessSize;
|
||||
return writer;
|
||||
}
|
||||
|
||||
return raw;
|
||||
};
|
||||
|
||||
@ -127,6 +157,8 @@ Block.prototype.getRaw = function getRaw() {
|
||||
*/
|
||||
|
||||
Block.prototype.getSizes = function getSizes() {
|
||||
var writer;
|
||||
|
||||
if (this._size != null) {
|
||||
return {
|
||||
size: this._size,
|
||||
@ -142,7 +174,13 @@ Block.prototype.getSizes = function getSizes() {
|
||||
};
|
||||
}
|
||||
|
||||
return bcoin.protocol.framer.block.sizes(this);
|
||||
writer = new bcoin.writer();
|
||||
this.render(writer);
|
||||
|
||||
return {
|
||||
size: writer.written,
|
||||
witnessSize: writer._witnessSize
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@ -619,7 +657,7 @@ Block.parseJSON = function parseJSON(json) {
|
||||
json.prevBlock = utils.revHex(json.prevBlock);
|
||||
json.merkleRoot = utils.revHex(json.merkleRoot);
|
||||
json.txs = json.txs.map(function(tx) {
|
||||
return bcoin.tx.parseJSON(tx);
|
||||
return bcoin.tx.fromJSON(tx);
|
||||
});
|
||||
return json;
|
||||
};
|
||||
@ -657,11 +695,34 @@ Block.prototype.toRaw = function toRaw(enc) {
|
||||
* @returns {Object} A "naked" block object.
|
||||
*/
|
||||
|
||||
Block.parseRaw = function parseRaw(data, enc) {
|
||||
if (enc === 'hex')
|
||||
data = new Buffer(data, 'hex');
|
||||
Block.prototype.fromRaw = function fromRaw(data) {
|
||||
var p = bcoin.reader(data);
|
||||
var i, tx;
|
||||
|
||||
return bcoin.protocol.parser.parseBlock(data);
|
||||
p.start();
|
||||
|
||||
this.version = p.readU32(); // Technically signed
|
||||
this.prevBlock = p.readHash('hex');
|
||||
this.merkleRoot = p.readHash('hex');
|
||||
this.ts = p.readU32();
|
||||
this.bits = p.readU32();
|
||||
this.nonce = p.readU32();
|
||||
this.totalTX = p.readVarint();
|
||||
|
||||
this._witnessSize = 0;
|
||||
|
||||
this.txs = [];
|
||||
|
||||
for (i = 0; i < this.totalTX; i++) {
|
||||
tx = bcoin.tx.fromRaw(p);
|
||||
this._witnessSize += tx._witnessSize;
|
||||
this.txs.push(tx);
|
||||
}
|
||||
|
||||
this._raw = p.endData();
|
||||
this._size = this._raw.length;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -672,7 +733,9 @@ Block.parseRaw = function parseRaw(data, enc) {
|
||||
*/
|
||||
|
||||
Block.fromRaw = function fromRaw(data, enc) {
|
||||
return new Block(Block.parseRaw(data, enc));
|
||||
if (typeof data === 'string')
|
||||
data = new Buffer(data, enc);
|
||||
return new Block().fromRaw(data);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -687,6 +750,43 @@ Block.prototype.toMerkle = function toMerkle(filter) {
|
||||
return bcoin.merkleblock.fromBlock(this, filter);
|
||||
};
|
||||
|
||||
Block.prototype.frame = function frame(witness, writer) {
|
||||
var p = bcoin.writer(writer);
|
||||
var witnessSize = 0;
|
||||
var i;
|
||||
|
||||
p.write32(this.version);
|
||||
p.writeHash(this.prevBlock);
|
||||
p.writeHash(this.merkleRoot);
|
||||
p.writeU32(this.ts);
|
||||
p.writeU32(this.bits);
|
||||
p.writeU32(this.nonce);
|
||||
p.writeVarint(this.txs.length);
|
||||
|
||||
for (i = 0; i < this.txs.length; i++) {
|
||||
if (witness)
|
||||
this.txs[i].render(p);
|
||||
else
|
||||
this.txs[i].renderNormal(p);
|
||||
witnessSize += p._witnessSize;
|
||||
}
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
p._witnessSize = witnessSize;
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
Block.prototype.frameNormal = function frameNormal(writer) {
|
||||
return this.frame(false, writer);
|
||||
};
|
||||
|
||||
Block.prototype.frameWitness = function frameWitness(writer) {
|
||||
return this.frame(true, writer);
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether an object is a Block.
|
||||
* @param {Object} obj
|
||||
|
||||
@ -670,7 +670,6 @@ Iterator.prototype.next = function(callback) {
|
||||
|
||||
Iterator.prototype.seek = function seek(key) {
|
||||
var self = this;
|
||||
var item;
|
||||
|
||||
assert(!this.ended, 'Already ended.');
|
||||
|
||||
|
||||
@ -301,10 +301,19 @@ Chain.prototype._preload = function _preload(callback) {
|
||||
|
||||
bcoin.debug('Loading %s.', url);
|
||||
|
||||
function parseHeader(buf) {
|
||||
var headers = bcoin.protocol.parser.parseBlockHeaders(buf);
|
||||
headers.hash = utils.dsha256(buf.slice(0, 80)).toString('hex');
|
||||
return headers;
|
||||
function parseHeader(data) {
|
||||
var p = bcoin.reader(data, true);
|
||||
var hash = utils.dsha256(p.readBytes(80)).toString('hex');
|
||||
p.seek(-80);
|
||||
return {
|
||||
hash: hash,
|
||||
version: p.readU32(), // Technically signed
|
||||
prevBlock: p.readHash('hex'),
|
||||
merkleRoot: p.readHash('hex'),
|
||||
ts: p.readU32(),
|
||||
bits: p.readU32(),
|
||||
nonce: p.readU32()
|
||||
};
|
||||
}
|
||||
|
||||
function save(entry, header) {
|
||||
|
||||
@ -15,8 +15,6 @@ var assert = utils.assert;
|
||||
var DUMMY = new Buffer([0]);
|
||||
var BufferWriter = require('./writer');
|
||||
var BufferReader = require('./reader');
|
||||
var Framer = bcoin.protocol.framer;
|
||||
var Parser = bcoin.protocol.parser;
|
||||
|
||||
/*
|
||||
* Database Layout:
|
||||
@ -886,7 +884,7 @@ ChainDB.prototype.connectBlock = function connectBlock(block, view, batch, callb
|
||||
}
|
||||
}
|
||||
|
||||
Framer.coin(input.coin, false, undo);
|
||||
input.coin.toRaw(undo);
|
||||
}
|
||||
|
||||
for (j = 0; j < tx.outputs.length; j++) {
|
||||
@ -1368,12 +1366,9 @@ ChainDB.prototype.getUndoCoins = function getUndoCoins(hash, callback) {
|
||||
return this.db.fetch(layout.u(hash), function(data) {
|
||||
var p = new BufferReader(data);
|
||||
var coins = [];
|
||||
var coin;
|
||||
|
||||
while (p.left()) {
|
||||
coin = Parser.parseCoin(p, false);
|
||||
coins.push(new bcoin.coin(coin));
|
||||
}
|
||||
while (p.left())
|
||||
coins.push(bcoin.coin.fromRaw(p));
|
||||
|
||||
return coins;
|
||||
}, callback);
|
||||
|
||||
@ -34,12 +34,27 @@ function Coin(options) {
|
||||
if (!(this instanceof Coin))
|
||||
return new Coin(options);
|
||||
|
||||
this.version = null;
|
||||
this.height = null;
|
||||
this.value = null;
|
||||
this.script = null;
|
||||
this.coinbase = null;
|
||||
this.hash = null;
|
||||
this.index = null;
|
||||
|
||||
if (options)
|
||||
this.fromOptions(options);
|
||||
}
|
||||
|
||||
utils.inherits(Coin, bcoin.output);
|
||||
|
||||
Coin.prototype.fromOptions = function fromOptions(options) {
|
||||
assert(options, 'Coin data is required.');
|
||||
|
||||
this.version = options.version;
|
||||
this.height = options.height;
|
||||
this.value = options.value;
|
||||
this.script = bcoin.script(options.script, false);
|
||||
this.script = bcoin.script(options.script);
|
||||
this.coinbase = options.coinbase;
|
||||
this.hash = options.hash;
|
||||
this.index = options.index;
|
||||
@ -51,9 +66,15 @@ function Coin(options) {
|
||||
assert(typeof this.coinbase === 'boolean');
|
||||
assert(!this.hash || typeof this.hash === 'string');
|
||||
assert(!this.index || typeof this.index === 'number');
|
||||
}
|
||||
|
||||
utils.inherits(Coin, bcoin.output);
|
||||
return this;
|
||||
};
|
||||
|
||||
Coin.fromOptions = function fromOptions(options) {
|
||||
if (options instanceof Coin)
|
||||
return options;
|
||||
return new Coin().fromOptions(options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate number of confirmations since coin was created.
|
||||
@ -129,32 +150,13 @@ Coin.prototype.toJSON = function toJSON() {
|
||||
version: this.version,
|
||||
height: this.height,
|
||||
value: utils.btc(this.value),
|
||||
script: this.script.toRaw('hex'),
|
||||
script: this.script.toRaw().toString('hex'),
|
||||
coinbase: this.coinbase,
|
||||
hash: this.hash ? utils.revHex(this.hash) : null,
|
||||
index: this.index
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle a deserialized JSON coin object.
|
||||
* @returns {NakedCoin} A "naked" coin (a
|
||||
* plain javascript object which is suitable
|
||||
* for passing to the Coin constructor).
|
||||
*/
|
||||
|
||||
Coin.parseJSON = function parseJSON(json) {
|
||||
return {
|
||||
version: json.version,
|
||||
height: json.height,
|
||||
value: utils.satoshi(json.value),
|
||||
script: bcoin.script.parseRaw(json.script, 'hex'),
|
||||
coinbase: json.coinbase,
|
||||
hash: json.hash ? utils.revHex(json.hash) : null,
|
||||
index: json.index
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate an Coin from a jsonified coin object.
|
||||
* @param {Object} json - The jsonified coin object.
|
||||
@ -162,7 +164,15 @@ Coin.parseJSON = function parseJSON(json) {
|
||||
*/
|
||||
|
||||
Coin.fromJSON = function fromJSON(json) {
|
||||
return new Coin(Coin.parseJSON(json));
|
||||
return Coin.fromOptions({
|
||||
version: json.version,
|
||||
height: json.height,
|
||||
value: utils.satoshi(json.value),
|
||||
script: bcoin.script.fromRaw(new Buffer(json.script, 'hex')),
|
||||
coinbase: json.coinbase,
|
||||
hash: json.hash ? utils.revHex(json.hash) : null,
|
||||
index: json.index
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -171,27 +181,38 @@ Coin.fromJSON = function fromJSON(json) {
|
||||
* @returns {Buffer|String}
|
||||
*/
|
||||
|
||||
Coin.prototype.toRaw = function toRaw(enc) {
|
||||
var data = bcoin.protocol.framer.coin(this, false);
|
||||
Coin.prototype.toRaw = function toRaw(writer) {
|
||||
var p = bcoin.writer(writer);
|
||||
var height = this.height;
|
||||
|
||||
if (enc === 'hex')
|
||||
data = data.toString('hex');
|
||||
if (height === -1)
|
||||
height = 0x7fffffff;
|
||||
|
||||
return data;
|
||||
p.writeU32(this.version);
|
||||
p.writeU32(height);
|
||||
p.write64(this.value);
|
||||
p.writeVarBytes(this.script.toRaw());
|
||||
p.writeU8(this.coinbase ? 1 : 0);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a serialized coin.
|
||||
* @param {Buffer} data
|
||||
* @param {String?} enc - Encoding, can be `'hex'` or null.
|
||||
* @returns {NakedCoin} A "naked" coin object.
|
||||
*/
|
||||
Coin.prototype.fromRaw = function fromRaw(data) {
|
||||
var p = bcoin.reader(data);
|
||||
|
||||
Coin.parseRaw = function parseRaw(data, enc) {
|
||||
if (enc === 'hex')
|
||||
data = new Buffer(data, 'hex');
|
||||
this.version = p.readU32();
|
||||
this.height = p.readU32();
|
||||
this.value = p.read64N();
|
||||
this.script = bcoin.script.fromRaw(p.readVarBytes());
|
||||
this.coinbase = p.readU8() === 1;
|
||||
|
||||
return bcoin.protocol.parser.parseCoin(data, false);
|
||||
if (this.height === 0x7fffffff)
|
||||
this.height = -1;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -202,7 +223,9 @@ Coin.parseRaw = function parseRaw(data, enc) {
|
||||
*/
|
||||
|
||||
Coin.fromRaw = function fromRaw(data, enc) {
|
||||
return new Coin(Coin.parseRaw(data, enc));
|
||||
if (typeof data === 'string')
|
||||
data = new Buffer(data, enc);
|
||||
return new Coin().fromRaw(data);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -212,27 +235,25 @@ Coin.fromRaw = function fromRaw(data, enc) {
|
||||
* @returns {Buffer|String}
|
||||
*/
|
||||
|
||||
Coin.prototype.toExtended = function toExtended(enc) {
|
||||
var data = bcoin.protocol.framer.coin(this, true);
|
||||
Coin.prototype.toExtended = function toExtended(writer) {
|
||||
var p = bcoin.writer(writer);
|
||||
|
||||
if (enc === 'hex')
|
||||
data = data.toString('hex');
|
||||
this.toRaw(p);
|
||||
p.writeHash(this.hash);
|
||||
p.writeU32(this.index);
|
||||
|
||||
return data;
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse an coin in "extended" serialization format.
|
||||
* @param {Buffer} data
|
||||
* @param {String?} enc - Encoding, can be `'hex'` or null.
|
||||
* @returns {NakedCoin} - A "naked" coin object.
|
||||
*/
|
||||
|
||||
Coin.parseExtended = function parseExtended(data, enc) {
|
||||
if (enc === 'hex')
|
||||
data = new Buffer(data, 'hex');
|
||||
|
||||
return bcoin.protocol.parser.parseCoin(data, true);
|
||||
Coin.prototype.fromExtended = function fromExtended(data) {
|
||||
var p = bcoin.reader(data);
|
||||
this.fromRaw(p);
|
||||
this.hash = p.readHash('hex');
|
||||
this.index = p.readU32();
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -244,7 +265,9 @@ Coin.parseExtended = function parseExtended(data, enc) {
|
||||
*/
|
||||
|
||||
Coin.fromExtended = function fromExtended(data, enc) {
|
||||
return new Coin(Coin.parseExtended(data, enc));
|
||||
if (typeof data === 'string')
|
||||
data = new Buffer(data, enc);
|
||||
return new Coin().fromExtended(data);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -254,16 +277,19 @@ Coin.fromExtended = function fromExtended(data, enc) {
|
||||
* @returns {Coin}
|
||||
*/
|
||||
|
||||
Coin.prototype.fromTX = function fromTX(tx, index) {
|
||||
this.version = tx.version;
|
||||
this.height = tx.height;
|
||||
this.value = tx.outputs[index].value;
|
||||
this.script = tx.outputs[index].script;
|
||||
this.coinbase = tx.isCoinbase();
|
||||
this.hash = tx.hash('hex');
|
||||
this.index = index;
|
||||
return this;
|
||||
};
|
||||
|
||||
Coin.fromTX = function fromTX(tx, index) {
|
||||
return new Coin({
|
||||
version: tx.version,
|
||||
height: tx.height,
|
||||
value: tx.outputs[index].value,
|
||||
script: tx.outputs[index].script,
|
||||
coinbase: tx.isCoinbase(),
|
||||
hash: tx.hash('hex'),
|
||||
index: index
|
||||
});
|
||||
return new Coin().fromTX(tx, index);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -30,15 +30,28 @@ function Coins(options) {
|
||||
if (!(this instanceof Coins))
|
||||
return new Coins(options);
|
||||
|
||||
if (!options)
|
||||
options = {};
|
||||
this.version = -1;
|
||||
this.hash = null;
|
||||
this.height = -1;
|
||||
this.coinbase = false;
|
||||
this.outputs = [];
|
||||
|
||||
if (options)
|
||||
this.fromOptions(options);
|
||||
}
|
||||
|
||||
Coins.prototype.fromOptions = function fromOptions(options) {
|
||||
this.version = options.version != null ? options.version : -1;
|
||||
this.hash = options.hash || null;
|
||||
this.height = options.height != null ? options.height : -1;
|
||||
this.coinbase = options.coinbase || false;
|
||||
this.outputs = options.outputs || [];
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Coins.fromOptions = function fromOptions(options) {
|
||||
return new Coins().fromOptions(options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a single coin to the collection.
|
||||
@ -167,7 +180,7 @@ Coins.prototype.toRaw = function toRaw(writer) {
|
||||
if (prefix)
|
||||
p.writeBytes(hash);
|
||||
else
|
||||
bcoin.protocol.framer.script(output.script, p);
|
||||
p.writeVarBytes(output.script.toRaw());
|
||||
|
||||
p.writeVarint(output.value);
|
||||
}
|
||||
@ -185,24 +198,22 @@ Coins.prototype.toRaw = function toRaw(writer) {
|
||||
* @returns {Object} A "naked" coins object.
|
||||
*/
|
||||
|
||||
Coins.parseRaw = function parseRaw(data, hash, index) {
|
||||
Coins.prototype.fromRaw = function fromRaw(data, hash, index) {
|
||||
var p = new BufferReader(data);
|
||||
var i = 0;
|
||||
var version, height, coin, coins, mask, prefix, offset, size;
|
||||
var version, height, coin, mask, prefix, offset, size;
|
||||
|
||||
version = p.readVarint();
|
||||
height = p.readU32();
|
||||
|
||||
coins = {
|
||||
version: version,
|
||||
height: height >>> 1,
|
||||
hash: hash,
|
||||
coinbase: (height & 1) !== 0,
|
||||
outputs: []
|
||||
};
|
||||
this.version = version;
|
||||
this.height = height >>> 1;
|
||||
this.hash = hash;
|
||||
this.coinbase = (height & 1) !== 0;
|
||||
this.outputs = [];
|
||||
|
||||
if (coins.height === 0x7fffffff)
|
||||
coins.height = -1;
|
||||
if (this.height === 0x7fffffff)
|
||||
this.height = -1;
|
||||
|
||||
while (p.left()) {
|
||||
offset = p.start();
|
||||
@ -215,7 +226,7 @@ Coins.parseRaw = function parseRaw(data, hash, index) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
coins.outputs.push(null);
|
||||
this.outputs.push(null);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
@ -241,16 +252,16 @@ Coins.parseRaw = function parseRaw(data, hash, index) {
|
||||
coin = new DeferredCoin(offset, size, data);
|
||||
|
||||
if (index != null)
|
||||
return coin.toCoin(coins, i);
|
||||
return coin.toCoin(this, i);
|
||||
|
||||
coins.outputs.push(coin);
|
||||
this.outputs.push(coin);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
assert(index == null, 'Bad coin index.');
|
||||
|
||||
return coins;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -263,7 +274,7 @@ Coins.parseRaw = function parseRaw(data, hash, index) {
|
||||
|
||||
Coins.parseCoin = function parseCoin(data, hash, index) {
|
||||
assert(index != null, 'Bad coin index.');
|
||||
return Coins.parseRaw(data, hash, index);
|
||||
return new Coins().fromRaw(data, hash, index);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -274,7 +285,7 @@ Coins.parseCoin = function parseCoin(data, hash, index) {
|
||||
*/
|
||||
|
||||
Coins.fromRaw = function fromRaw(data, hash) {
|
||||
return new Coins(Coins.parseRaw(data, hash));
|
||||
return new Coins().fromRaw(data, hash);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -283,25 +294,27 @@ Coins.fromRaw = function fromRaw(data, hash) {
|
||||
* @returns {Coins}
|
||||
*/
|
||||
|
||||
Coins.fromTX = function fromTX(tx) {
|
||||
var outputs = [];
|
||||
Coins.prototype.fromTX = function fromTX(tx) {
|
||||
var i;
|
||||
|
||||
this.version = tx.version;
|
||||
this.hash = tx.hash('hex');
|
||||
this.height = tx.height;
|
||||
this.coinbase = tx.isCoinbase();
|
||||
|
||||
for (i = 0; i < tx.outputs.length; i++) {
|
||||
if (tx.outputs[i].script.isUnspendable()) {
|
||||
outputs.push(null);
|
||||
this.outputs.push(null);
|
||||
continue;
|
||||
}
|
||||
outputs.push(bcoin.coin.fromTX(tx, i));
|
||||
this.outputs.push(bcoin.coin.fromTX(tx, i));
|
||||
}
|
||||
|
||||
return new Coins({
|
||||
version: tx.version,
|
||||
hash: tx.hash('hex'),
|
||||
height: tx.height,
|
||||
coinbase: tx.isCoinbase(),
|
||||
outputs: outputs
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
Coins.fromTX = function fromTX(tx) {
|
||||
return new Coins().fromTX(tx);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -349,7 +362,7 @@ DeferredCoin.prototype.toCoin = function toCoin(coins, index) {
|
||||
prefix = p.readU8() & 3;
|
||||
|
||||
if (prefix === 0)
|
||||
script = new bcoin.script(bcoin.protocol.parser.parseScript(p));
|
||||
script = bcoin.script.fromRaw(p.readVarBytes());
|
||||
else if (prefix === 1)
|
||||
script = bcoin.script.createPubkeyhash(p.readBytes(20));
|
||||
else if (prefix === 2)
|
||||
|
||||
@ -153,6 +153,7 @@ function Environment(options) {
|
||||
this.witness = this.script.Witness;
|
||||
this.address = require('./address');
|
||||
this.input = require('./input');
|
||||
this.outpoint = this.input.Outpoint;
|
||||
this.output = require('./output');
|
||||
this.coin = require('./coin');
|
||||
this.coins = require('./coins');
|
||||
|
||||
@ -44,8 +44,8 @@ utils.inherits(Headers, bcoin.abstractblock);
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
Headers.prototype.render = function render() {
|
||||
return this.getRaw();
|
||||
Headers.prototype.render = function render(writer) {
|
||||
return this.getRaw(writer);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -66,16 +66,9 @@ Headers.prototype._verify = function _verify(ret) {
|
||||
*/
|
||||
|
||||
Headers.prototype.getSize = function getSize() {
|
||||
return 80;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the raw headers serialization.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
Headers.prototype.getRaw = function getRaw() {
|
||||
return this.abbr();
|
||||
var writer = new bcoin.writer();
|
||||
this.toRaw(writer);
|
||||
return writer.written;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -107,15 +100,21 @@ Headers.prototype.inspect = function inspect() {
|
||||
* @returns {Buffer|String}
|
||||
*/
|
||||
|
||||
Headers.prototype.toRaw = function toRaw(enc) {
|
||||
var data;
|
||||
Headers.prototype.toRaw = function toRaw(writer) {
|
||||
var p = bcoin.writer(writer);
|
||||
|
||||
data = this.render();
|
||||
p.write32(this.version);
|
||||
p.writeHash(this.prevBlock);
|
||||
p.writeHash(this.merkleRoot);
|
||||
p.writeU32(this.ts);
|
||||
p.writeU32(this.bits);
|
||||
p.writeU32(this.nonce);
|
||||
p.writeVarint(this.totalTX);
|
||||
|
||||
if (enc === 'hex')
|
||||
data = data.toString('hex');
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
return data;
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -125,11 +124,18 @@ Headers.prototype.toRaw = function toRaw(enc) {
|
||||
* @returns {NakedBlock} A "naked" headers object.
|
||||
*/
|
||||
|
||||
Headers.parseRaw = function parseRaw(data, enc) {
|
||||
if (enc === 'hex')
|
||||
data = new Buffer(data, 'hex');
|
||||
Headers.prototype.fromRaw = function fromRaw(data) {
|
||||
var p = bcoin.reader(data);
|
||||
|
||||
return bcoin.protocol.parser.parseBlockHeaders(data);
|
||||
this.version = p.readU32(); // Technically signed
|
||||
this.prevBlock = p.readHash('hex');
|
||||
this.merkleRoot = p.readHash('hex');
|
||||
this.ts = p.readU32();
|
||||
this.bits = p.readU32();
|
||||
this.nonce = p.readU32();
|
||||
this.totalTX = p.readVarint();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -140,7 +146,9 @@ Headers.parseRaw = function parseRaw(data, enc) {
|
||||
*/
|
||||
|
||||
Headers.fromRaw = function fromRaw(data, enc) {
|
||||
return new Headers(Headers.parseRaw(data, enc));
|
||||
if (typeof data === 'string')
|
||||
data = new Buffer(data, enc);
|
||||
return new Headers().fromRaw(data);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -772,7 +772,7 @@ HTTPClient.prototype.getBlock = function getBlock(hash, callback) {
|
||||
*/
|
||||
|
||||
HTTPClient.prototype.broadcast = function broadcast(tx, callback) {
|
||||
var body = { tx: tx.toRaw('hex') };
|
||||
var body = { tx: tx.toRaw().toString('hex') };
|
||||
|
||||
callback = utils.ensure(callback);
|
||||
|
||||
@ -808,7 +808,7 @@ HTTPClient.prototype.walletSend = function walletSend(id, options, callback) {
|
||||
address: output.address && output.address.toBase58
|
||||
? output.address.toBase58()
|
||||
: output.address,
|
||||
script: output.script ? output.script.toRaw('hex') : null
|
||||
script: output.script ? output.script.toRaw().toString('hex') : null
|
||||
};
|
||||
});
|
||||
|
||||
@ -855,7 +855,7 @@ HTTPClient.prototype.walletCreate = function walletCreate(id, options, outputs,
|
||||
address: output.address && output.address.toBase58
|
||||
? output.address.toBase58()
|
||||
: output.address,
|
||||
script: output.script ? output.script.toRaw('hex') : null
|
||||
script: output.script ? output.script.toRaw().toString('hex') : null
|
||||
};
|
||||
});
|
||||
|
||||
@ -892,7 +892,7 @@ HTTPClient.prototype.walletSign = function walletCreate(id, tx, options, callbac
|
||||
}
|
||||
|
||||
body = utils.merge({}, options || {}, {
|
||||
tx: tx.toRaw('hex')
|
||||
tx: tx.toRaw().toString('hex')
|
||||
});
|
||||
|
||||
callback = utils.ensure(callback);
|
||||
@ -918,7 +918,7 @@ HTTPClient.prototype.walletSign = function walletCreate(id, tx, options, callbac
|
||||
*/
|
||||
|
||||
HTTPClient.prototype.walletFill = function walletFill(tx, callback) {
|
||||
var body = { tx: tx.toRaw('hex') };
|
||||
var body = { tx: tx.toRaw().toString('hex') };
|
||||
|
||||
callback = utils.ensure(callback);
|
||||
|
||||
|
||||
@ -11,8 +11,78 @@ var bcoin = require('./env');
|
||||
var utils = require('./utils');
|
||||
var assert = utils.assert;
|
||||
var constants = bcoin.protocol.constants;
|
||||
var BufferReader = require('./reader');
|
||||
var BufferWriter = require('./writer');
|
||||
|
||||
function Outpoint(hash, index) {
|
||||
if (!(this instanceof Outpoint))
|
||||
return new Outpoint(hash, index);
|
||||
|
||||
this.hash = hash || null;
|
||||
this.index = index || 0;
|
||||
}
|
||||
|
||||
Outpoint.prototype.fromOptions = function fromOptions(data) {
|
||||
this.hash = data.hash;
|
||||
this.index = data.index;
|
||||
assert(typeof this.hash === 'string');
|
||||
assert(typeof this.index === 'number');
|
||||
return this;
|
||||
};
|
||||
|
||||
Outpoint.fromOptions = function fromOptions(data) {
|
||||
if (data instanceof Outpoint)
|
||||
return data;
|
||||
return new Outpoint().fromOptions(data);
|
||||
};
|
||||
|
||||
Outpoint.prototype.fromRaw = function fromRaw(data) {
|
||||
var p = bcoin.reader(data);
|
||||
this.hash = p.readHash('hex');
|
||||
this.index = p.readU32();
|
||||
return this;
|
||||
};
|
||||
|
||||
Outpoint.fromRaw = function fromRaw(data) {
|
||||
return new Outpoint().fromRaw(data);
|
||||
};
|
||||
|
||||
Outpoint.prototype.toRaw = function toRaw(writer) {
|
||||
var p = bcoin.writer(writer);
|
||||
|
||||
p.writeHash(this.hash);
|
||||
p.writeU32(this.index);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
Outpoint.prototype.fromJSON = function fromJSON(json) {
|
||||
this.hash = utils.revHex(json.hash);
|
||||
this.index = json.index;
|
||||
return this;
|
||||
};
|
||||
|
||||
Outpoint.fromJSON = function fromJSON(json) {
|
||||
return Outpoint().fromJSON(json);
|
||||
};
|
||||
|
||||
Outpoint.prototype.fromTX = function fromTX(tx, i) {
|
||||
this.hash = tx.hash('hex');
|
||||
this.index = i;
|
||||
return this;
|
||||
};
|
||||
|
||||
Outpoint.fromTX = function fromTX(tx, i) {
|
||||
return Outpoint().fromTX(tx, i);
|
||||
};
|
||||
|
||||
Outpoint.prototype.toJSON = function toJSON() {
|
||||
return {
|
||||
hash: utils.revHex(this.hash),
|
||||
index: this.index
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a transaction input.
|
||||
@ -36,10 +106,22 @@ function Input(options, mutable) {
|
||||
if (!(this instanceof Input))
|
||||
return new Input(options, mutable);
|
||||
|
||||
this.mutable = false;
|
||||
this.prevout = null;
|
||||
this.script = null;
|
||||
this.sequence = null;
|
||||
this.witness = null;
|
||||
this.coin = null;
|
||||
|
||||
if (options)
|
||||
this.fromOptions(options, mutable);
|
||||
}
|
||||
|
||||
Input.prototype.fromOptions = function fromOptions(options, mutable) {
|
||||
assert(options, 'Input data is required.');
|
||||
|
||||
this.mutable = !!mutable;
|
||||
this.prevout = options.prevout;
|
||||
this.prevout = Outpoint.fromOptions(options.prevout);
|
||||
this.script = bcoin.script(options.script);
|
||||
this.sequence = options.sequence == null ? 0xffffffff : options.sequence;
|
||||
this.witness = bcoin.witness(options.witness);
|
||||
@ -52,7 +134,13 @@ function Input(options, mutable) {
|
||||
assert(typeof this.prevout.hash === 'string');
|
||||
assert(typeof this.prevout.index === 'number');
|
||||
assert(typeof this.sequence === 'number');
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Input.fromOptions = function fromOptions(options) {
|
||||
return new Input().fromOptions(options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the previous output script type. Will "guess"
|
||||
@ -268,6 +356,7 @@ Input.prototype.inspect = function inspect() {
|
||||
witness: this.witness,
|
||||
redeem: this.getRedeem(),
|
||||
sequence: this.sequence,
|
||||
prevout: this.prevout,
|
||||
coin: coin
|
||||
};
|
||||
};
|
||||
@ -282,35 +371,21 @@ Input.prototype.inspect = function inspect() {
|
||||
|
||||
Input.prototype.toJSON = function toJSON() {
|
||||
return {
|
||||
prevout: {
|
||||
hash: utils.revHex(this.prevout.hash),
|
||||
index: this.prevout.index
|
||||
},
|
||||
prevout: this.prevout.toJSON(),
|
||||
coin: this.coin ? this.coin.toJSON() : null,
|
||||
script: this.script.toRaw('hex'),
|
||||
witness: this.witness.toRaw('hex'),
|
||||
script: this.script.toRaw().toString('hex'),
|
||||
witness: this.witness.toRaw().toString('hex'),
|
||||
sequence: this.sequence
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle a deserialized JSON input object.
|
||||
* @returns {NakedInput} A "naked" input (a
|
||||
* plain javascript object which is suitable
|
||||
* for passing to the Input constructor).
|
||||
*/
|
||||
|
||||
Input.parseJSON = function parseJSON(json) {
|
||||
return {
|
||||
prevout: {
|
||||
hash: utils.revHex(json.prevout.hash),
|
||||
index: json.prevout.index
|
||||
},
|
||||
coin: json.coin ? bcoin.coin.parseJSON(json.coin) : null,
|
||||
script: bcoin.script.parseRaw(json.script, 'hex'),
|
||||
witness: bcoin.witness.parseRaw(json.witness, 'hex'),
|
||||
sequence: json.sequence
|
||||
};
|
||||
Input.prototype.fromJSON = function fromJSON(json) {
|
||||
this.prevout = Outpoint.fromJSON(json.prevout);
|
||||
this.coin = json.coin ? bcoin.coin.fromJSON(json.coin) : null;
|
||||
this.script = bcoin.script.fromRaw(json.script, 'hex');
|
||||
this.witness = bcoin.witness.fromRaw(json.witness, 'hex');
|
||||
this.sequence = json.sequence;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -320,7 +395,7 @@ Input.parseJSON = function parseJSON(json) {
|
||||
*/
|
||||
|
||||
Input.fromJSON = function fromJSON(json) {
|
||||
return new Input(Input.parseJSON(json));
|
||||
return new Input().fromJSON(json);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -329,29 +404,17 @@ Input.fromJSON = function fromJSON(json) {
|
||||
* @returns {Buffer|String}
|
||||
*/
|
||||
|
||||
Input.prototype.toRaw = function toRaw(enc) {
|
||||
var data = bcoin.protocol.framer.input(this);
|
||||
Input.prototype.toRaw = function toRaw(writer) {
|
||||
var p = bcoin.writer(writer);
|
||||
|
||||
if (enc === 'hex')
|
||||
data = data.toString('hex');
|
||||
this.prevout.toRaw(p);
|
||||
p.writeVarBytes(this.script.toRaw());
|
||||
p.writeU32(this.sequence);
|
||||
|
||||
return data;
|
||||
};
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
/**
|
||||
* Parse a serialized input.
|
||||
* @param {Buffer} data
|
||||
* @param {String?} enc - Encoding, can be `'hex'` or null.
|
||||
* @returns {NakedInput} A "naked" input object.
|
||||
*/
|
||||
|
||||
Input.parseRaw = function parseRaw(data, enc) {
|
||||
if (enc === 'hex')
|
||||
data = new Buffer(data, 'hex');
|
||||
|
||||
data = bcoin.protocol.parser.parseInput(data);
|
||||
|
||||
return data;
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -361,8 +424,20 @@ Input.parseRaw = function parseRaw(data, enc) {
|
||||
* @returns {Input}
|
||||
*/
|
||||
|
||||
Input.prototype.fromRaw = function fromRaw(data) {
|
||||
var p = bcoin.reader(data);
|
||||
|
||||
this.prevout = Outpoint.fromRaw(p);
|
||||
this.script = bcoin.script.fromRaw(p.readVarBytes());
|
||||
this.sequence = p.readU32();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Input.fromRaw = function fromRaw(data, enc) {
|
||||
return new Input(Input.parseRaw(data, enc));
|
||||
if (typeof data === 'string')
|
||||
data = new Buffer(data, enc);
|
||||
return new Input().fromRaw(data);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -372,19 +447,16 @@ Input.fromRaw = function fromRaw(data, enc) {
|
||||
* @returns {Buffer|String}
|
||||
*/
|
||||
|
||||
Input.prototype.toExtended = function toExtended(enc) {
|
||||
var p = new BufferWriter();
|
||||
var data;
|
||||
Input.prototype.toExtended = function toExtended(writer) {
|
||||
var p = bcoin.writer(writer);
|
||||
|
||||
bcoin.protocol.framer.input(this, p);
|
||||
bcoin.protocol.framer.witness(this.witness, p);
|
||||
this.toRaw(p);
|
||||
this.witness.toRaw(p);
|
||||
|
||||
data = p.render();
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
if (enc === 'hex')
|
||||
data = data.toString('hex');
|
||||
|
||||
return data;
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -394,15 +466,12 @@ Input.prototype.toExtended = function toExtended(enc) {
|
||||
* @returns {NakedInput} - A "naked" input object.
|
||||
*/
|
||||
|
||||
Input.parseExtended = function parseExtended(data, enc) {
|
||||
Input.prototype.fromExtended = function fromExtended(data) {
|
||||
var input, p;
|
||||
|
||||
if (enc === 'hex')
|
||||
data = new Buffer(data, 'hex');
|
||||
|
||||
p = new BufferReader(data);
|
||||
input = bcoin.protocol.parser.parseInput(p);
|
||||
input.witness = bcoin.protocol.parser.parseWitness(p);
|
||||
p = bcoin.reader(data);
|
||||
this.fromRaw(p);
|
||||
this.witness = bcoin.witness.fromRaw(p);
|
||||
|
||||
return input;
|
||||
};
|
||||
@ -416,7 +485,9 @@ Input.parseExtended = function parseExtended(data, enc) {
|
||||
*/
|
||||
|
||||
Input.fromExtended = function fromExtended(data, enc) {
|
||||
return new Input(Input.parseExtended(data, enc));
|
||||
if (typeof data === 'string')
|
||||
data = new Buffer(data, enc);
|
||||
return new Input().fromExtended(data);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -437,4 +508,6 @@ Input.isInput = function isInput(obj) {
|
||||
* Expose
|
||||
*/
|
||||
|
||||
module.exports = Input;
|
||||
exports = Input;
|
||||
exports.Outpoint = Outpoint;
|
||||
module.exports = exports;
|
||||
|
||||
@ -149,7 +149,7 @@ KeyRing.prototype.getProgram = function getProgram() {
|
||||
hash = utils.ripesha(this.getPublicKey());
|
||||
program = bcoin.script.createWitnessProgram(0, hash);
|
||||
} else if (this.type === 'multisig') {
|
||||
hash = utils.sha256(this.getScript().encode());
|
||||
hash = utils.sha256(this.getScript().toRaw());
|
||||
program = bcoin.script.createWitnessProgram(0, hash);
|
||||
} else {
|
||||
assert(false, 'Unknown address type.');
|
||||
@ -172,7 +172,7 @@ KeyRing.prototype.getProgramHash = function getProgramHash(enc) {
|
||||
return;
|
||||
|
||||
if (!this._programHash)
|
||||
this._programHash = utils.ripesha(this.getProgram().encode());
|
||||
this._programHash = utils.ripesha(this.getProgram().toRaw());
|
||||
|
||||
return enc === 'hex'
|
||||
? this._programHash.toString('hex')
|
||||
@ -222,7 +222,7 @@ KeyRing.prototype.getScriptHash160 = function getScriptHash256(enc) {
|
||||
return;
|
||||
|
||||
if (!this._scriptHash160)
|
||||
this._scriptHash160 = utils.ripesha(this.getScript().encode());
|
||||
this._scriptHash160 = utils.ripesha(this.getScript().toRaw());
|
||||
|
||||
return enc === 'hex'
|
||||
? this._scriptHash160.toString('hex')
|
||||
@ -240,7 +240,7 @@ KeyRing.prototype.getScriptHash256 = function getScriptHash256(enc) {
|
||||
return;
|
||||
|
||||
if (!this._scriptHash256)
|
||||
this._scriptHash256 = utils.sha256(this.getScript().encode());
|
||||
this._scriptHash256 = utils.sha256(this.getScript().toRaw());
|
||||
|
||||
return enc === 'hex'
|
||||
? this._scriptHash256.toString('hex')
|
||||
|
||||
@ -55,12 +55,25 @@ function MemBlock(data) {
|
||||
bcoin.abstractblock.call(this, data);
|
||||
|
||||
this.memory = true;
|
||||
this.coinbaseHeight = data.coinbaseHeight;
|
||||
this.raw = data.raw;
|
||||
this.coinbaseHeight = null;
|
||||
this.raw = null;
|
||||
|
||||
if (data)
|
||||
this.fromOptions(data);
|
||||
}
|
||||
|
||||
utils.inherits(MemBlock, bcoin.abstractblock);
|
||||
|
||||
MemBlock.prototype.fromOptions = function fromOptions(data) {
|
||||
this.coinbaseHeight = data.coinbaseHeight;
|
||||
this.raw = data.raw;
|
||||
return this;
|
||||
};
|
||||
|
||||
MemBlock.fromOptions = function fromOptions(data) {
|
||||
return new MemBlock().fromOptions(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the full block size.
|
||||
* @returns {Number}
|
||||
@ -92,6 +105,46 @@ MemBlock.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
|
||||
return this.coinbaseHeight;
|
||||
};
|
||||
|
||||
MemBlock.prototype.fromRaw = function fromRaw(data) {
|
||||
var p = bcoin.reader(data);
|
||||
var height = -1;
|
||||
var inCount, input;
|
||||
|
||||
this.version = p.readU32(); // Technically signed
|
||||
this.prevBlock = p.readHash('hex');
|
||||
this.merkleRoot = p.readHash('hex');
|
||||
this.ts = p.readU32();
|
||||
this.bits = p.readU32();
|
||||
this.nonce = p.readU32();
|
||||
this.totalTX = p.readVarint();
|
||||
|
||||
if (this.version > 1 && this.totalTX > 0) {
|
||||
p.readU32(); // Technically signed
|
||||
inCount = p.readVarint();
|
||||
|
||||
if (inCount === 0) {
|
||||
if (p.readU8() !== 0)
|
||||
inCount = p.readVarint();
|
||||
}
|
||||
|
||||
if (inCount > 0)
|
||||
input = bcoin.input.fromRaw(p);
|
||||
}
|
||||
|
||||
if (input)
|
||||
height = bcoin.script.getCoinbaseHeight(input.script.raw);
|
||||
|
||||
this.coinbaseHeight = height;
|
||||
this.txs = [];
|
||||
this.raw = p.data;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
MemBlock.fromRaw = function fromRaw(data) {
|
||||
return new MemBlock().fromRaw(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse the serialized block data and create an actual {@link Block}.
|
||||
* @returns {Block}
|
||||
@ -99,9 +152,9 @@ MemBlock.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
|
||||
*/
|
||||
|
||||
MemBlock.prototype.toBlock = function toBlock() {
|
||||
var data = bcoin.protocol.parser.parseBlock(this.raw);
|
||||
var block = bcoin.block.fromRaw(this.raw);
|
||||
this.raw = null;
|
||||
return new bcoin.block(data);
|
||||
return block;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -1515,7 +1515,7 @@ Mempool.prototype.getConfidence = function getConfidence(hash, callback) {
|
||||
if (hash instanceof bcoin.tx)
|
||||
return callback(null, hash, hash.hash('hex'));
|
||||
|
||||
return this.getTX(hash, function(err, tx) {
|
||||
return self.getTX(hash, function(err, tx) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
return callback(null, tx, hash);
|
||||
@ -1942,7 +1942,8 @@ MempoolEntry.fromTX = function fromTX(tx, height) {
|
||||
MempoolEntry.prototype.toRaw = function toRaw(writer) {
|
||||
var p = new BufferWriter(writer);
|
||||
|
||||
bcoin.protocol.framer.renderTX(this.tx, true, p);
|
||||
this.tx.toRaw(p);
|
||||
|
||||
p.writeU32(this.height);
|
||||
p.writeU32(this.size);
|
||||
p.writeDouble(this.priority);
|
||||
|
||||
@ -44,6 +44,24 @@ function MerkleBlock(data) {
|
||||
|
||||
bcoin.abstractblock.call(this, data);
|
||||
|
||||
this.hashes = null;
|
||||
this.flags = null;
|
||||
|
||||
// List of matched TXs
|
||||
this.map = {};
|
||||
this.matches = [];
|
||||
this._validPartial = null;
|
||||
|
||||
// TXs that will be pushed on
|
||||
this.txs = [];
|
||||
|
||||
if (data)
|
||||
this.fromOptions(data);
|
||||
}
|
||||
|
||||
utils.inherits(MerkleBlock, bcoin.abstractblock);
|
||||
|
||||
MerkleBlock.prototype.fromOptions = function fromOptions(data) {
|
||||
assert(Array.isArray(data.hashes));
|
||||
assert(Buffer.isBuffer(data.flags));
|
||||
|
||||
@ -57,17 +75,21 @@ function MerkleBlock(data) {
|
||||
|
||||
// TXs that will be pushed on
|
||||
this.txs = [];
|
||||
}
|
||||
|
||||
utils.inherits(MerkleBlock, bcoin.abstractblock);
|
||||
return this;
|
||||
};
|
||||
|
||||
MerkleBlock.fromOptions = function fromOptions(data) {
|
||||
return new MerkleBlock().fromOptions(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize the merkleblock.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
MerkleBlock.prototype.render = function render() {
|
||||
return this.getRaw();
|
||||
MerkleBlock.prototype.render = function render(writer) {
|
||||
return this.toRaw(writer);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -76,22 +98,9 @@ MerkleBlock.prototype.render = function render() {
|
||||
*/
|
||||
|
||||
MerkleBlock.prototype.getSize = function getSize() {
|
||||
if (this._size == null)
|
||||
this.getRaw();
|
||||
return this._size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the raw merkleblock serialization.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
MerkleBlock.prototype.getRaw = function getRaw() {
|
||||
if (!this._raw) {
|
||||
this._raw = bcoin.protocol.framer.merkleBlock(this);
|
||||
this._size = this._raw.length;
|
||||
}
|
||||
return this._raw;
|
||||
var writer = new bcoin.writer();
|
||||
this.toRaw(writer);
|
||||
return writer.written;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -325,13 +334,29 @@ MerkleBlock.prototype.inspect = function inspect() {
|
||||
* @returns {Buffer|String}
|
||||
*/
|
||||
|
||||
MerkleBlock.prototype.toRaw = function toRaw(enc) {
|
||||
var data = this.render();
|
||||
MerkleBlock.prototype.toRaw = function toRaw(writer) {
|
||||
var p = bcoin.writer(writer);
|
||||
var i;
|
||||
|
||||
if (enc === 'hex')
|
||||
data = data.toString('hex');
|
||||
p.writeU32(this.version);
|
||||
p.writeHash(this.prevBlock);
|
||||
p.writeHash(this.merkleRoot);
|
||||
p.writeU32(this.ts);
|
||||
p.writeU32(this.bits);
|
||||
p.writeU32(this.nonce);
|
||||
p.writeU32(this.totalTX);
|
||||
|
||||
return data;
|
||||
p.writeVarint(this.hashes.length);
|
||||
|
||||
for (i = 0; i < this.hashes.length; i++)
|
||||
p.writeHash(this.hashes[i]);
|
||||
|
||||
p.writeVarBytes(this.flags);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -341,11 +366,28 @@ MerkleBlock.prototype.toRaw = function toRaw(enc) {
|
||||
* @returns {NakedBlock} A "naked" headers object.
|
||||
*/
|
||||
|
||||
MerkleBlock.parseRaw = function parseRaw(data, enc) {
|
||||
if (enc === 'hex')
|
||||
data = new Buffer(data, 'hex');
|
||||
MerkleBlock.prototype.fromRaw = function fromRaw(data) {
|
||||
var p = bcoin.reader(data);
|
||||
var i, hashCount;
|
||||
|
||||
return bcoin.protocol.parser.parseMerkleBlock(data);
|
||||
this.version = p.readU32();
|
||||
this.prevBlock = p.readHash('hex');
|
||||
this.merkleRoot = p.readHash('hex');
|
||||
this.ts = p.readU32();
|
||||
this.bits = p.readU32();
|
||||
this.nonce = p.readU32();
|
||||
this.totalTX = p.readU32();
|
||||
|
||||
hashCount = p.readVarint();
|
||||
|
||||
this.hashes = [];
|
||||
|
||||
for (i = 0; i < hashCount; i++)
|
||||
this.hashes.push(p.readHash('hex'));
|
||||
|
||||
this.flags = p.readVarBytes();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -356,7 +398,9 @@ MerkleBlock.parseRaw = function parseRaw(data, enc) {
|
||||
*/
|
||||
|
||||
MerkleBlock.fromRaw = function fromRaw(data, enc) {
|
||||
return new MerkleBlock(MerkleBlock.parseRaw(data, enc));
|
||||
if (typeof data === 'string')
|
||||
data = new Buffer(data, enc);
|
||||
return new MerkleBlock().fromRaw(data);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -441,22 +485,20 @@ MerkleBlock.fromBlock = function fromBlock(block, filter) {
|
||||
for (p = 0; p < bits.length; p++)
|
||||
flags[p / 8 | 0] |= bits[p] << (p % 8);
|
||||
|
||||
block = new MerkleBlock({
|
||||
version: block.version,
|
||||
prevBlock: block.prevBlock,
|
||||
merkleRoot: block.merkleRoot,
|
||||
ts: block.ts,
|
||||
bits: block.bits,
|
||||
nonce: block.nonce,
|
||||
totalTX: totalTX,
|
||||
height: block.height,
|
||||
hashes: hashes,
|
||||
flags: flags
|
||||
});
|
||||
var merkle = new MerkleBlock();
|
||||
merkle.version = block.version;
|
||||
merkle.prevBlock = block.prevBlock;
|
||||
merkle.merkleRoot = block.merkleRoot;
|
||||
merkle.ts = block.ts;
|
||||
merkle.bits = block.bits;
|
||||
merkle.nonce = block.nonce;
|
||||
merkle.totalTX = totalTX;
|
||||
merkle.height = block.height;
|
||||
merkle.hashes = hashes;
|
||||
merkle.flags = flags;
|
||||
merkle.txs = txs;
|
||||
|
||||
block.txs = txs;
|
||||
|
||||
return block;
|
||||
return merkle;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -122,7 +122,7 @@ Miner.prototype._init = function _init() {
|
||||
this.on('block', function(block) {
|
||||
// Emit the block hex as a failsafe (in case we can't send it)
|
||||
bcoin.debug('Found block: %d (%s).', block.height, block.rhash);
|
||||
bcoin.debug('Raw: %s', block.toRaw('hex'));
|
||||
bcoin.debug('Raw: %s', block.toRaw().toString('hex'));
|
||||
});
|
||||
|
||||
this.on('status', function(stat) {
|
||||
|
||||
@ -196,12 +196,12 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
|
||||
if (prev.isScripthash()) {
|
||||
if (addr.program && utils.equal(prev.get(1), addr.programHash)) {
|
||||
// Witness program nested in regular P2SH.
|
||||
redeemScript = addr.program.encode();
|
||||
redeemScript = addr.program.toRaw();
|
||||
vector = input.witness;
|
||||
if (addr.program.isWitnessScripthash()) {
|
||||
// P2WSH nested within pay-to-scripthash
|
||||
// (it had to be this complicated, didn't it?)
|
||||
witnessScript = addr.script.encode();
|
||||
witnessScript = addr.script.toRaw();
|
||||
prev = addr.script;
|
||||
} else if (addr.program.isWitnessPubkeyhash()) {
|
||||
// P2WPKH nested within pay-to-scripthash.
|
||||
@ -211,7 +211,7 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
|
||||
}
|
||||
} else if (addr.script && utils.equal(prev.get(1), addr.scriptHash160)) {
|
||||
// Regular P2SH.
|
||||
redeemScript = addr.script.encode();
|
||||
redeemScript = addr.script.toRaw();
|
||||
vector = input.script;
|
||||
prev = addr.script;
|
||||
} else {
|
||||
@ -226,7 +226,7 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
|
||||
if (!addr.script || !utils.equal(prev.get(1), addr.scriptHash256))
|
||||
return false;
|
||||
|
||||
witnessScript = addr.script.encode();
|
||||
witnessScript = addr.script.toRaw();
|
||||
prev = addr.script;
|
||||
} else if (prev.isWitnessPubkeyhash()) {
|
||||
// Bare P2WPKH.
|
||||
@ -1228,7 +1228,7 @@ MTX.prototype.sortMembers = function sortMembers() {
|
||||
var res = a.value - b.value;
|
||||
if (res !== 0)
|
||||
return res;
|
||||
return utils.cmp(a.encode(), b.encode());
|
||||
return utils.cmp(a.script.toRaw(), b.script.toRaw());
|
||||
});
|
||||
|
||||
if (this.changeIndex !== -1) {
|
||||
@ -1273,46 +1273,32 @@ MTX.prototype.setLocktime = function setLocktime(locktime) {
|
||||
this.locktime = locktime;
|
||||
};
|
||||
|
||||
/**
|
||||
* @see TX.parseJSON
|
||||
*/
|
||||
|
||||
MTX.parseJSON = bcoin.tx.parseJSON;
|
||||
|
||||
/**
|
||||
* @see TX.fromJSON
|
||||
*/
|
||||
|
||||
MTX.fromJSON = function fromJSON(json) {
|
||||
return new MTX(MTX.parseJSON(json));
|
||||
return new MTX().fromJSON(JSON);
|
||||
};
|
||||
|
||||
/**
|
||||
* @see TX.parseRaw
|
||||
*/
|
||||
|
||||
MTX.parseRaw = bcoin.tx.parseRaw;
|
||||
|
||||
/**
|
||||
* @see TX.fromRaw
|
||||
*/
|
||||
|
||||
MTX.fromRaw = function fromRaw(data, enc) {
|
||||
return new MTX(MTX.parseRaw(data, enc));
|
||||
if (typeof data === 'string')
|
||||
data = new Buffer(data, enc);
|
||||
return new MTX().fromRaw(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* @see TX.parseExtended
|
||||
*/
|
||||
|
||||
MTX.parseExtended = bcoin.tx.parseExtended;
|
||||
|
||||
/**
|
||||
* @see TX.fromExtended
|
||||
*/
|
||||
|
||||
MTX.fromExtended = function fromExtended(data, enc) {
|
||||
return new MTX(MTX.parseExtended(data, enc));
|
||||
if (typeof data === 'string')
|
||||
data = new Buffer(data, enc);
|
||||
return new MTX().fromExtended(data);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -12,7 +12,6 @@ var utils = require('./utils');
|
||||
var constants = bcoin.protocol.constants;
|
||||
var assert = utils.assert;
|
||||
var BufferWriter = require('./writer');
|
||||
var Framer = bcoin.protocol.framer;
|
||||
|
||||
/**
|
||||
* Represents a transaction output.
|
||||
@ -28,11 +27,20 @@ var Framer = bcoin.protocol.framer;
|
||||
*/
|
||||
|
||||
function Output(options, mutable) {
|
||||
var value;
|
||||
|
||||
if (!(this instanceof Output))
|
||||
return new Output(options, mutable);
|
||||
|
||||
this.mutable = false;
|
||||
this.value = 0;
|
||||
this.script = null;
|
||||
|
||||
if (options)
|
||||
this.fromOptions(options, mutable);
|
||||
}
|
||||
|
||||
Output.prototype.fromOptions = function fromOptions(options, mutable) {
|
||||
var value;
|
||||
|
||||
assert(options, 'Output data is required.');
|
||||
|
||||
value = options.value;
|
||||
@ -46,7 +54,13 @@ function Output(options, mutable) {
|
||||
|
||||
assert(typeof this.value === 'number');
|
||||
assert(!this.mutable || this.value >= 0);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Output.fromOptions = function fromOptions(options) {
|
||||
return new Output().fromOptions(options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the script type.
|
||||
@ -147,7 +161,7 @@ Output.prototype.inspect = function inspect() {
|
||||
Output.prototype.toJSON = function toJSON() {
|
||||
return {
|
||||
value: utils.btc(this.value),
|
||||
script: this.script.toRaw('hex')
|
||||
script: this.script.toRaw().toString('hex')
|
||||
};
|
||||
};
|
||||
|
||||
@ -167,7 +181,7 @@ Output.prototype.getDustThreshold = function getDustThreshold(rate) {
|
||||
if (this.script.isUnspendable())
|
||||
return 0;
|
||||
|
||||
size = Framer.output(this, new BufferWriter()).written;
|
||||
size = this.toRaw(new BufferWriter()).written;
|
||||
size += 148;
|
||||
|
||||
return 3 * bcoin.tx.getMinFee(size, rate);
|
||||
@ -190,11 +204,11 @@ Output.prototype.isDust = function isDust(rate) {
|
||||
* for passing to the Output constructor).
|
||||
*/
|
||||
|
||||
Output.parseJSON = function parseJSON(json) {
|
||||
return {
|
||||
Output.prototype.fromJSON = function fromJSON(json) {
|
||||
return Output.fromOptions({
|
||||
value: utils.satoshi(json.value),
|
||||
script: bcoin.script.parseRaw(json.script, 'hex')
|
||||
};
|
||||
script: bcoin.script.fromRaw(json.script, 'hex')
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -204,7 +218,7 @@ Output.parseJSON = function parseJSON(json) {
|
||||
*/
|
||||
|
||||
Output.fromJSON = function fromJSON(json) {
|
||||
return new Output(Output.parseJSON(json));
|
||||
return new Output().fromJSON(json);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -213,13 +227,16 @@ Output.fromJSON = function fromJSON(json) {
|
||||
* @returns {Buffer|String}
|
||||
*/
|
||||
|
||||
Output.prototype.toRaw = function toRaw(enc) {
|
||||
var data = Framer.output(this);
|
||||
Output.prototype.toRaw = function toRaw(writer) {
|
||||
var p = bcoin.writer(writer);
|
||||
|
||||
if (enc === 'hex')
|
||||
data = data.toString('hex');
|
||||
p.write64(this.value);
|
||||
p.writeVarBytes(this.script.toRaw());
|
||||
|
||||
return data;
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -229,13 +246,13 @@ Output.prototype.toRaw = function toRaw(enc) {
|
||||
* @returns {NakedOutput} A "naked" output object.
|
||||
*/
|
||||
|
||||
Output.parseRaw = function parseRaw(data, enc) {
|
||||
if (enc === 'hex')
|
||||
data = new Buffer(data, 'hex');
|
||||
Output.prototype.fromRaw = function fromRaw(data) {
|
||||
var p = bcoin.reader(data);
|
||||
|
||||
data = bcoin.protocol.parser.parseOutput(data);
|
||||
this.value = p.read64N();
|
||||
this.script = bcoin.script.fromRaw(p.readVarBytes());
|
||||
|
||||
return data;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -246,7 +263,10 @@ Output.parseRaw = function parseRaw(data, enc) {
|
||||
*/
|
||||
|
||||
Output.fromRaw = function fromRaw(data, enc) {
|
||||
return new Output(Output.parseRaw(data, enc));
|
||||
if (typeof data === 'string')
|
||||
data = new Buffer(data, enc);
|
||||
|
||||
return new Output().fromRaw(data);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -719,11 +719,11 @@ Peer.prototype._onPacket = function onPacket(packet) {
|
||||
case 'filterclear':
|
||||
return this._handleFilterClear(payload);
|
||||
case 'block':
|
||||
payload = new bcoin.memblock(payload);
|
||||
// payload = new bcoin.memblock(payload);
|
||||
this.fire(cmd, payload);
|
||||
break;
|
||||
case 'merkleblock':
|
||||
payload = new bcoin.merkleblock(payload);
|
||||
// payload = new bcoin.merkleblock(payload);
|
||||
payload.verifyPartial();
|
||||
this.lastBlock = payload;
|
||||
this.waiting = payload.matches.length;
|
||||
@ -731,7 +731,7 @@ Peer.prototype._onPacket = function onPacket(packet) {
|
||||
this._flushMerkle();
|
||||
break;
|
||||
case 'tx':
|
||||
payload = new bcoin.tx(payload);
|
||||
// payload = new bcoin.tx(payload);
|
||||
if (this.lastBlock) {
|
||||
if (this.lastBlock.hasTX(payload)) {
|
||||
this.lastBlock.addTX(payload);
|
||||
|
||||
@ -299,15 +299,8 @@ Framer.prototype.getBlocks = function getBlocks(data) {
|
||||
* @returns {Buffer} tx packet.
|
||||
*/
|
||||
|
||||
Framer.prototype.tx = function tx(tx) {
|
||||
var checksum;
|
||||
|
||||
// Save some time by using the
|
||||
// cached hash as our checksum.
|
||||
if (tx.hash)
|
||||
checksum = tx.hash();
|
||||
|
||||
return this.packet('tx', Framer.renderTX(tx, false), checksum);
|
||||
Framer.prototype.tx = function _tx(tx) {
|
||||
return this.packet('tx', Framer.tx(tx), tx.hash());
|
||||
};
|
||||
|
||||
/**
|
||||
@ -321,18 +314,16 @@ Framer.prototype.witnessTX = function witnessTX(tx) {
|
||||
|
||||
// Save some time by using the
|
||||
// cached hash as our checksum.
|
||||
if (tx.witnessHash) {
|
||||
if (tx.hasWitness()) {
|
||||
// We can't use the coinbase
|
||||
// hash since it is all zeroes.
|
||||
if (!tx.isCoinbase())
|
||||
checksum = tx.witnessHash();
|
||||
} else {
|
||||
checksum = tx.hash();
|
||||
}
|
||||
if (tx.hasWitness()) {
|
||||
// We can't use the coinbase
|
||||
// hash since it is all zeroes.
|
||||
if (!tx.isCoinbase())
|
||||
checksum = tx.witnessHash();
|
||||
} else {
|
||||
checksum = tx.hash();
|
||||
}
|
||||
|
||||
return this.packet('tx', Framer.renderTX(tx, true), checksum);
|
||||
return this.packet('tx', Framer.witnessTX(tx), checksum);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -660,38 +651,6 @@ Framer._getBlocks = function _getBlocks(data, writer, headers) {
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize a coin.
|
||||
* @param {NakedCoin|Coin} coin
|
||||
* @param {Boolean} extended - Whether to include the hash and index.
|
||||
* @param {BufferWriter?} writer - A buffer writer to continue writing from.
|
||||
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
|
||||
*/
|
||||
|
||||
Framer.coin = function _coin(coin, extended, writer) {
|
||||
var p = new BufferWriter(writer);
|
||||
var height = coin.height;
|
||||
|
||||
if (height === -1)
|
||||
height = 0x7fffffff;
|
||||
|
||||
p.writeU32(coin.version);
|
||||
p.writeU32(height);
|
||||
p.write64(coin.value);
|
||||
Framer.script(coin.script, p);
|
||||
p.writeU8(coin.coinbase ? 1 : 0);
|
||||
|
||||
if (extended) {
|
||||
p.writeHash(coin.hash);
|
||||
p.writeU32(coin.index);
|
||||
}
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize transaction without witness.
|
||||
* @param {NakedTX|TX} tx
|
||||
@ -700,87 +659,7 @@ Framer.coin = function _coin(coin, extended, writer) {
|
||||
*/
|
||||
|
||||
Framer.tx = function _tx(tx, writer) {
|
||||
var p = new BufferWriter(writer);
|
||||
var i;
|
||||
|
||||
p.write32(tx.version);
|
||||
|
||||
p.writeVarint(tx.inputs.length);
|
||||
for (i = 0; i < tx.inputs.length; i++)
|
||||
Framer.input(tx.inputs[i], p);
|
||||
|
||||
p.writeVarint(tx.outputs.length);
|
||||
for (i = 0; i < tx.outputs.length; i++)
|
||||
Framer.output(tx.outputs[i], p);
|
||||
|
||||
p.writeU32(tx.locktime);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
p._witnessSize = 0;
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize an outpoint.
|
||||
* @param {Hash} hash
|
||||
* @param {Number} index
|
||||
* @param {BufferWriter?} writer - A buffer writer to continue writing from.
|
||||
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
|
||||
*/
|
||||
|
||||
Framer.outpoint = function outpoint(hash, index, writer) {
|
||||
var p = new BufferWriter(writer);
|
||||
|
||||
p.writeHash(hash);
|
||||
p.writeU32(index);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize an input.
|
||||
* @param {NakedInput|Input} input
|
||||
* @param {BufferWriter?} writer - A buffer writer to continue writing from.
|
||||
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
|
||||
*/
|
||||
|
||||
Framer.input = function _input(input, writer) {
|
||||
var p = new BufferWriter(writer);
|
||||
|
||||
p.writeHash(input.prevout.hash);
|
||||
p.writeU32(input.prevout.index);
|
||||
Framer.script(input.script, p);
|
||||
p.writeU32(input.sequence);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize an output.
|
||||
* @param {NakedOutput|Output} output
|
||||
* @param {BufferWriter?} writer - A buffer writer to continue writing from.
|
||||
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
|
||||
*/
|
||||
|
||||
Framer.output = function _output(output, writer) {
|
||||
var p = new BufferWriter(writer);
|
||||
|
||||
p.write64(output.value);
|
||||
Framer.script(output.script, p);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
return p;
|
||||
return tx.renderNormal(writer);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -792,85 +671,7 @@ Framer.output = function _output(output, writer) {
|
||||
*/
|
||||
|
||||
Framer.witnessTX = function _witnessTX(tx, writer) {
|
||||
var p = new BufferWriter(writer);
|
||||
var witnessSize = 0;
|
||||
var i, start;
|
||||
|
||||
p.write32(tx.version);
|
||||
p.writeU8(0);
|
||||
p.writeU8(tx.flag || 1);
|
||||
|
||||
p.writeVarint(tx.inputs.length);
|
||||
|
||||
for (i = 0; i < tx.inputs.length; i++)
|
||||
Framer.input(tx.inputs[i], p);
|
||||
|
||||
p.writeVarint(tx.outputs.length);
|
||||
|
||||
for (i = 0; i < tx.outputs.length; i++)
|
||||
Framer.output(tx.outputs[i], p);
|
||||
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
start = p.written;
|
||||
Framer.witness(tx.inputs[i].witness, p);
|
||||
witnessSize += p.written - start;
|
||||
}
|
||||
|
||||
p.writeU32(tx.locktime);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
p._witnessSize = witnessSize + 2;
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize a script. Note that scripts require
|
||||
* extra magic since they're so goddamn bizarre.
|
||||
* Normally in an "encoded" script we don't
|
||||
* include the varint size because scripthashes
|
||||
* don't include them. This is why
|
||||
* script.encode/decode is separate from the
|
||||
* framer and parser.
|
||||
* @param {NakedScript|Script} script
|
||||
* @param {BufferWriter?} writer - A buffer writer to continue writing from.
|
||||
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
|
||||
*/
|
||||
|
||||
Framer.script = function _script(script, writer) {
|
||||
var p = new BufferWriter(writer);
|
||||
var data = script.raw || script;
|
||||
|
||||
p.writeVarBytes(data);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize a witness.
|
||||
* @param {NakedWitness|Witness} witness
|
||||
* @param {BufferWriter?} writer - A buffer writer to continue writing from.
|
||||
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
|
||||
*/
|
||||
|
||||
Framer.witness = function _witness(witness, writer) {
|
||||
var p = new BufferWriter(writer);
|
||||
var i;
|
||||
|
||||
p.writeVarint(witness.items.length);
|
||||
|
||||
for (i = 0; i < witness.items.length; i++)
|
||||
p.writeVarBytes(witness.items[i]);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
return p;
|
||||
return tx.renderWitness(writer);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -881,7 +682,7 @@ Framer.witness = function _witness(witness, writer) {
|
||||
*/
|
||||
|
||||
Framer.block = function _block(block, writer) {
|
||||
return Framer._block(block, false, writer);
|
||||
return block.renderNormal(block);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -893,152 +694,7 @@ Framer.block = function _block(block, writer) {
|
||||
*/
|
||||
|
||||
Framer.witnessBlock = function _witnessBlock(block, writer) {
|
||||
return Framer._block(block, true, writer);
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize a transaction lazily (use existing raw data if present).
|
||||
* @param {NakedTX|TX} tx
|
||||
* @param {Boolean} useWitness - Whether to include witness data.
|
||||
* @param {BufferWriter?} writer - A buffer writer to continue writing from.
|
||||
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
|
||||
*/
|
||||
|
||||
Framer.renderTX = function renderTX(tx, useWitness, writer) {
|
||||
var p = new BufferWriter(writer);
|
||||
var witnessSize;
|
||||
|
||||
// Cache the serialization if we can.
|
||||
if (tx.render && !tx.mutable && !tx._raw)
|
||||
tx.render();
|
||||
|
||||
// Try the cached raw data first.
|
||||
if (tx._raw) {
|
||||
if (useWitness) {
|
||||
// If we're serializing the witness,
|
||||
// we can use whatever data getRaw()
|
||||
// gave us.
|
||||
p.writeBytes(tx._raw);
|
||||
witnessSize = tx._witnessSize;
|
||||
} else {
|
||||
// We have to use the standard format
|
||||
// here. Try to grab it from cache.
|
||||
if (bcoin.protocol.parser.isWitnessTX(tx._raw)) {
|
||||
Framer.tx(tx, p);
|
||||
witnessSize = p._witnessSize;
|
||||
} else {
|
||||
p.writeBytes(tx._raw);
|
||||
witnessSize = tx._witnessSize;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (useWitness) {
|
||||
if (bcoin.tx.prototype.hasWitness.call(tx)) {
|
||||
Framer.witnessTX(tx, p);
|
||||
} else {
|
||||
// Only use the witness serialization if
|
||||
// we have a witness. This clause isn't
|
||||
// necessary above since we already
|
||||
// determined this in getRaw().
|
||||
Framer.tx(tx, p);
|
||||
}
|
||||
} else {
|
||||
// Any other case, we use
|
||||
// the standard serialization.
|
||||
Framer.tx(tx, p);
|
||||
}
|
||||
witnessSize = p._witnessSize;
|
||||
}
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
p._witnessSize = witnessSize;
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize a transaction to BCoin "extended format".
|
||||
* This is the serialization format BCoin uses internally
|
||||
* to store transactions in the database. The extended
|
||||
* serialization includes the height, block hash, index,
|
||||
* timestamp, pending-since time, and optionally a vector
|
||||
* for the serialized coins.
|
||||
* @param {NakedTX|TX} tx
|
||||
* @param {Boolean?} saveCoins - Whether to serialize the coins.
|
||||
* @param {String?} enc - One of `"hex"` or `null`.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
Framer.extendedTX = function extendedTX(tx, saveCoins, writer) {
|
||||
var height = tx.height;
|
||||
var index = tx.index;
|
||||
var changeIndex = tx.changeIndex != null ? tx.changeIndex : -1;
|
||||
var p = new BufferWriter(writer);
|
||||
var i, input;
|
||||
|
||||
if (height === -1)
|
||||
height = 0x7fffffff;
|
||||
|
||||
if (index === -1)
|
||||
index = 0x7fffffff;
|
||||
|
||||
if (changeIndex === -1)
|
||||
changeIndex = 0x7fffffff;
|
||||
|
||||
Framer.renderTX(tx, true, p);
|
||||
p.writeU32(height);
|
||||
p.writeHash(tx.block || constants.ZERO_HASH);
|
||||
p.writeU32(index);
|
||||
p.writeU32(tx.ts);
|
||||
p.writeU32(tx.ps);
|
||||
// p.writeU32(changeIndex);
|
||||
|
||||
if (saveCoins) {
|
||||
p.writeVarint(tx.inputs.length);
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
|
||||
if (!input.coin) {
|
||||
p.writeVarint(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
p.writeVarBytes(Framer.coin(input.coin, false));
|
||||
}
|
||||
}
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
Framer._block = function _block(block, useWitness, writer) {
|
||||
var p = new BufferWriter(writer);
|
||||
var witnessSize = 0;
|
||||
var i;
|
||||
|
||||
p.write32(block.version);
|
||||
p.writeHash(block.prevBlock);
|
||||
p.writeHash(block.merkleRoot);
|
||||
p.writeU32(block.ts);
|
||||
p.writeU32(block.bits);
|
||||
p.writeU32(block.nonce);
|
||||
p.writeVarint(block.txs.length);
|
||||
|
||||
for (i = 0; i < block.txs.length; i++) {
|
||||
Framer.renderTX(block.txs[i], useWitness, p);
|
||||
witnessSize += p._witnessSize;
|
||||
}
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
p._witnessSize = witnessSize;
|
||||
|
||||
return p;
|
||||
return block.renderWitness(writer);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1049,28 +705,7 @@ Framer._block = function _block(block, useWitness, writer) {
|
||||
*/
|
||||
|
||||
Framer.merkleBlock = function _merkleBlock(block, writer) {
|
||||
var p = new BufferWriter(writer);
|
||||
var i;
|
||||
|
||||
p.writeU32(block.version);
|
||||
p.writeHash(block.prevBlock);
|
||||
p.writeHash(block.merkleRoot);
|
||||
p.writeU32(block.ts);
|
||||
p.writeU32(block.bits);
|
||||
p.writeU32(block.nonce);
|
||||
p.writeU32(block.totalTX);
|
||||
|
||||
p.writeVarint(block.hashes.length);
|
||||
|
||||
for (i = 0; i < block.hashes.length; i++)
|
||||
p.writeHash(block.hashes[i]);
|
||||
|
||||
p.writeVarBytes(block.flags);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
return p;
|
||||
return block.toRaw(writer);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1082,43 +717,12 @@ Framer.merkleBlock = function _merkleBlock(block, writer) {
|
||||
|
||||
Framer.headers = function _headers(headers, writer) {
|
||||
var p = new BufferWriter(writer);
|
||||
var i, header;
|
||||
var i;
|
||||
|
||||
p.writeVarint(headers.length);
|
||||
|
||||
for (i = 0; i < headers.length; i++) {
|
||||
header = headers[i];
|
||||
p.write32(header.version);
|
||||
p.writeHash(header.prevBlock);
|
||||
p.writeHash(header.merkleRoot);
|
||||
p.writeU32(header.ts);
|
||||
p.writeU32(header.bits);
|
||||
p.writeU32(header.nonce);
|
||||
p.writeVarint(header.totalTX);
|
||||
}
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize a block header without any transaction count field.
|
||||
* @param {NakedBlock|Block|MerkleBlock|Headers|ChainEntry} block
|
||||
* @param {BufferWriter?} writer - A buffer writer to continue writing from.
|
||||
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
|
||||
*/
|
||||
|
||||
Framer.blockHeaders = function blockHeaders(block, writer) {
|
||||
var p = new BufferWriter(writer);
|
||||
|
||||
p.write32(block.version);
|
||||
p.writeHash(block.prevBlock);
|
||||
p.writeHash(block.merkleRoot);
|
||||
p.writeU32(block.ts);
|
||||
p.writeU32(block.bits);
|
||||
p.writeU32(block.nonce);
|
||||
for (i = 0; i < headers.length; i++)
|
||||
headers[i].toRaw(p);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
@ -1149,6 +753,7 @@ Framer.reject = function reject(details, writer) {
|
||||
p.writeVarString(details.message || '', 'ascii');
|
||||
p.writeU8(ccode);
|
||||
p.writeVarString(details.reason || '', 'ascii');
|
||||
|
||||
if (details.data)
|
||||
p.writeHash(details.data);
|
||||
|
||||
@ -1368,7 +973,8 @@ Framer.UTXOs = function UTXOs(data, writer) {
|
||||
|
||||
p.writeU32(coin.version);
|
||||
p.writeU32(height);
|
||||
Framer.output(coin, p);
|
||||
p.write64(coin.value);
|
||||
p.writeVarBytes(coin.script.toRaw());
|
||||
}
|
||||
|
||||
if (!writer)
|
||||
@ -1388,7 +994,7 @@ Framer.submitOrder = function submitOrder(order, writer) {
|
||||
var p = new BufferWriter(writer);
|
||||
|
||||
p.writeHash(order.hash);
|
||||
Framer.renderTX(order.tx, true, p);
|
||||
order.tx.toRaw(p);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
@ -1494,130 +1100,6 @@ Framer.feeFilter = function feeFilter(data, writer) {
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate total block size and
|
||||
* witness size without serializing.
|
||||
* @param {NakedBlock|Block} block
|
||||
* @returns {Object} In the form of `{size: Number, witnessSize: Number}`.
|
||||
*/
|
||||
|
||||
Framer.block.sizes = function blockSizes(block) {
|
||||
var writer = new BufferWriter();
|
||||
Framer.witnessBlock(block, writer);
|
||||
return {
|
||||
size: writer.written,
|
||||
witnessSize: writer._witnessSize
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate total transaction size and
|
||||
* witness size without serializing.
|
||||
* @param {NakedBlock|Block} block
|
||||
* @returns {Object} In the form of `{size: Number, witnessSize: Number}`.
|
||||
*/
|
||||
|
||||
Framer.tx.sizes = function txSizes(tx) {
|
||||
var writer = new BufferWriter();
|
||||
Framer.renderTX(tx, true, writer);
|
||||
return {
|
||||
size: writer.written,
|
||||
witnessSize: writer._witnessSize
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate block size with witness (if present).
|
||||
* @param {NakedBlock|Block} block
|
||||
* @returns {Number} Size.
|
||||
*/
|
||||
|
||||
Framer.block.witnessSize = function blockWitnessSize(block) {
|
||||
return Framer.block.sizes(block).size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate transaction size with witness (if present).
|
||||
* @param {NakedTX|TX} tx
|
||||
* @returns {Number} Size.
|
||||
*/
|
||||
|
||||
Framer.tx.witnessSize = function txWitnessSize(tx) {
|
||||
return Framer.tx.sizes(tx).size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate transaction size without witness.
|
||||
* @param {NakedBlock|Block} block
|
||||
* @returns {Number} Size.
|
||||
*/
|
||||
|
||||
Framer.block.size = function blockSize(block) {
|
||||
var writer = new BufferWriter();
|
||||
Framer.block(block, writer);
|
||||
return writer.written;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate transaction size without witness.
|
||||
* @param {NakedTX|TX} tx
|
||||
* @returns {Number} Size.
|
||||
*/
|
||||
|
||||
Framer.tx.size = function txSize(tx) {
|
||||
var writer = new BufferWriter();
|
||||
Framer.renderTX(tx, false, writer);
|
||||
return writer.written;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate block virtual size.
|
||||
* @param {NakedBlock|Block} block
|
||||
* @returns {Number} Virtual size.
|
||||
*/
|
||||
|
||||
Framer.block.virtualSize = function blockVirtualSize(block) {
|
||||
var scale = constants.WITNESS_SCALE_FACTOR;
|
||||
return (Framer.block.cost(block) + scale - 1) / scale | 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate transaction virtual size.
|
||||
* @param {NakedTX|TX} tx
|
||||
* @returns {Number} Virtual size.
|
||||
*/
|
||||
|
||||
Framer.tx.virtualSize = function txVirtualSize(tx) {
|
||||
var scale = constants.WITNESS_SCALE_FACTOR;
|
||||
return (Framer.tx.cost(tx) + scale - 1) / scale | 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate block cost.
|
||||
* @param {NakedBlock|Block} block
|
||||
* @returns {Number} cost
|
||||
*/
|
||||
|
||||
Framer.block.cost = function blockCost(block) {
|
||||
var sizes = Framer.block.sizes(block);
|
||||
var base = sizes.size - sizes.witnessSize;
|
||||
var scale = constants.WITNESS_SCALE_FACTOR;
|
||||
return base * (scale - 1) + sizes.size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate transaction cost.
|
||||
* @param {NakedTX|TX} tx
|
||||
* @returns {Number} cost
|
||||
*/
|
||||
|
||||
Framer.tx.cost = function txCost(tx) {
|
||||
var sizes = Framer.tx.sizes(tx);
|
||||
var base = sizes.size - sizes.witnessSize;
|
||||
var scale = constants.WITNESS_SCALE_FACTOR;
|
||||
return base * (scale - 1) + sizes.size;
|
||||
};
|
||||
|
||||
/*
|
||||
* Expose
|
||||
*/
|
||||
|
||||
@ -384,12 +384,8 @@ Parser.parseGetUTXOs = function parseGetUTXOs(p) {
|
||||
prevout = [];
|
||||
count = p.readVarint();
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
prevout.push({
|
||||
hash: p.readHash('hex'),
|
||||
index: p.readU32()
|
||||
});
|
||||
}
|
||||
for (i = 0; i < count; i++)
|
||||
prevout.push(bcoin.outpoint.fromRaw(p));
|
||||
|
||||
return {
|
||||
mempool: mempool,
|
||||
@ -428,7 +424,7 @@ Parser.parseUTXOs = function parseUTXOs(p) {
|
||||
if (height === 0x7fffffff)
|
||||
height = -1;
|
||||
|
||||
coin = Parser.parseOutput(p);
|
||||
coin = bcoin.output.fromRaw(p);
|
||||
coin.version = version;
|
||||
coin.height = height;
|
||||
coins.push(coin);
|
||||
@ -642,39 +638,7 @@ Parser.parseInv = function parseInv(p) {
|
||||
*/
|
||||
|
||||
Parser.parseMerkleBlock = function parseMerkleBlock(p) {
|
||||
var version, prevBlock, merkleRoot, ts, bits, nonce, totalTX;
|
||||
var i, hashCount, hashes, flags;
|
||||
|
||||
p = new BufferReader(p);
|
||||
|
||||
version = p.readU32();
|
||||
prevBlock = p.readHash('hex');
|
||||
merkleRoot = p.readHash('hex');
|
||||
ts = p.readU32();
|
||||
bits = p.readU32();
|
||||
nonce = p.readU32();
|
||||
totalTX = p.readU32();
|
||||
|
||||
hashCount = p.readVarint();
|
||||
|
||||
hashes = [];
|
||||
|
||||
for (i = 0; i < hashCount; i++)
|
||||
hashes.push(p.readHash('hex'));
|
||||
|
||||
flags = p.readVarBytes();
|
||||
|
||||
return {
|
||||
version: version,
|
||||
prevBlock: prevBlock,
|
||||
merkleRoot: merkleRoot,
|
||||
ts: ts,
|
||||
bits: bits,
|
||||
nonce: nonce,
|
||||
totalTX: totalTX,
|
||||
hashes: hashes,
|
||||
flags: flags
|
||||
};
|
||||
return bcoin.merkleblock.fromRaw(p);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -691,91 +655,12 @@ Parser.parseHeaders = function parseHeaders(p) {
|
||||
|
||||
count = p.readVarint();
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
headers.push({
|
||||
version: p.readU32(), // Technically signed
|
||||
prevBlock: p.readHash('hex'),
|
||||
merkleRoot: p.readHash('hex'),
|
||||
ts: p.readU32(),
|
||||
bits: p.readU32(),
|
||||
nonce: p.readU32(),
|
||||
totalTX: p.readVarint()
|
||||
});
|
||||
}
|
||||
for (i = 0; i < count; i++)
|
||||
headers.push(bcoin.headers.fromRaw(p));
|
||||
|
||||
return headers;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse headers packet.
|
||||
* @param {Buffer|BufferReader} p
|
||||
* @returns {NakedBlock}
|
||||
*/
|
||||
|
||||
Parser.parseBlockHeaders = function parseBlockHeaders(p) {
|
||||
p = new BufferReader(p);
|
||||
|
||||
return {
|
||||
version: p.readU32(), // Technically signed
|
||||
prevBlock: p.readHash('hex'),
|
||||
merkleRoot: p.readHash('hex'),
|
||||
ts: p.readU32(),
|
||||
bits: p.readU32(),
|
||||
nonce: p.readU32()
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a transaction in "extended" serialization format.
|
||||
* @param {Buffer|BufferReader} p
|
||||
* @param {Boolean?} saveCoins - If true, the function will
|
||||
* attempt to parse the coins.
|
||||
* @param {String?} enc - One of `"hex"` or `null`.
|
||||
* @returns {NakedTX} - A "naked" transaction object.
|
||||
*/
|
||||
|
||||
Parser.parseExtendedTX = function parseExtendedTX(p, saveCoins) {
|
||||
var i, tx, coinCount, coin;
|
||||
|
||||
p = new BufferReader(p);
|
||||
|
||||
tx = Parser.parseTX(p);
|
||||
|
||||
tx.height = p.readU32();
|
||||
tx.block = p.readHash('hex');
|
||||
tx.index = p.readU32();
|
||||
tx.ts = p.readU32();
|
||||
tx.ps = p.readU32();
|
||||
// tx.changeIndex = p.readU32();
|
||||
|
||||
if (tx.block === constants.NULL_HASH)
|
||||
tx.block = null;
|
||||
|
||||
if (tx.height === 0x7fffffff)
|
||||
tx.height = -1;
|
||||
|
||||
if (tx.index === 0x7fffffff)
|
||||
tx.index = -1;
|
||||
|
||||
if (tx.changeIndex === 0x7fffffff)
|
||||
tx.changeIndex = -1;
|
||||
|
||||
if (saveCoins) {
|
||||
coinCount = p.readVarint();
|
||||
for (i = 0; i < coinCount; i++) {
|
||||
coin = p.readVarBytes();
|
||||
if (coin.length === 0)
|
||||
continue;
|
||||
coin = Parser.parseCoin(coin, false);
|
||||
coin.hash = tx.inputs[i].prevout.hash;
|
||||
coin.index = tx.inputs[i].prevout.index;
|
||||
tx.inputs[i].coin = coin;
|
||||
}
|
||||
}
|
||||
|
||||
return tx;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse block packet.
|
||||
* @param {Buffer|BufferReader} p
|
||||
@ -783,46 +668,7 @@ Parser.parseExtendedTX = function parseExtendedTX(p, saveCoins) {
|
||||
*/
|
||||
|
||||
Parser.parseBlock = function parseBlock(p) {
|
||||
var txs = [];
|
||||
var version, prevBlock, merkleRoot, ts, bits, nonce;
|
||||
var i, totalTX, tx;
|
||||
var raw, size, witnessSize;
|
||||
|
||||
p = new BufferReader(p);
|
||||
|
||||
p.start();
|
||||
|
||||
version = p.readU32(); // Technically signed
|
||||
prevBlock = p.readHash('hex');
|
||||
merkleRoot = p.readHash('hex');
|
||||
ts = p.readU32();
|
||||
bits = p.readU32();
|
||||
nonce = p.readU32();
|
||||
totalTX = p.readVarint();
|
||||
|
||||
witnessSize = 0;
|
||||
|
||||
for (i = 0; i < totalTX; i++) {
|
||||
tx = Parser.parseTX(p);
|
||||
witnessSize += tx._witnessSize;
|
||||
txs.push(tx);
|
||||
}
|
||||
|
||||
raw = p.endData();
|
||||
size = raw.length;
|
||||
|
||||
return {
|
||||
version: version,
|
||||
prevBlock: prevBlock,
|
||||
merkleRoot: merkleRoot,
|
||||
ts: ts,
|
||||
bits: bits,
|
||||
nonce: nonce,
|
||||
txs: txs,
|
||||
_raw: raw,
|
||||
_size: size,
|
||||
_witnessSize: witnessSize
|
||||
};
|
||||
return bcoin.block.fromRaw(p);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -832,135 +678,7 @@ Parser.parseBlock = function parseBlock(p) {
|
||||
*/
|
||||
|
||||
Parser.parseMemBlock = function parseMemBlock(p) {
|
||||
var version, prevBlock, merkleRoot;
|
||||
var ts, bits, nonce, totalTX, height;
|
||||
var inCount, input;
|
||||
|
||||
p = new BufferReader(p);
|
||||
|
||||
version = p.readU32(); // Technically signed
|
||||
prevBlock = p.readHash('hex');
|
||||
merkleRoot = p.readHash('hex');
|
||||
ts = p.readU32();
|
||||
bits = p.readU32();
|
||||
nonce = p.readU32();
|
||||
|
||||
totalTX = p.readVarint();
|
||||
|
||||
if (version > 1 && totalTX > 0) {
|
||||
p.readU32(); // Technically signed
|
||||
inCount = p.readVarint();
|
||||
|
||||
if (inCount === 0) {
|
||||
if (p.readU8() !== 0)
|
||||
inCount = p.readVarint();
|
||||
}
|
||||
|
||||
if (inCount > 0)
|
||||
input = Parser.parseInput(p);
|
||||
}
|
||||
|
||||
if (input)
|
||||
height = bcoin.script.getCoinbaseHeight(input.script.raw);
|
||||
else
|
||||
height = -1;
|
||||
|
||||
return {
|
||||
version: version,
|
||||
prevBlock: prevBlock,
|
||||
merkleRoot: merkleRoot,
|
||||
ts: ts,
|
||||
bits: bits,
|
||||
nonce: nonce,
|
||||
totalTX: totalTX,
|
||||
coinbaseHeight: height,
|
||||
txs: [],
|
||||
raw: p.data
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse serialized input.
|
||||
* @param {Buffer|BufferReader} p
|
||||
* @returns {NakedInput}
|
||||
*/
|
||||
|
||||
Parser.parseInput = function parseInput(p) {
|
||||
var hash, index, script, sequence;
|
||||
|
||||
p = new BufferReader(p);
|
||||
|
||||
hash = p.readHash('hex');
|
||||
index = p.readU32();
|
||||
script = Parser.parseScript(p);
|
||||
sequence = p.readU32();
|
||||
|
||||
return {
|
||||
prevout: {
|
||||
hash: hash,
|
||||
index: index
|
||||
},
|
||||
coin: null,
|
||||
script: script,
|
||||
sequence: sequence
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse serialized output.
|
||||
* @param {Buffer|BufferReader} p
|
||||
* @returns {NakedOutput}
|
||||
*/
|
||||
|
||||
Parser.parseOutput = function parseOutput(p) {
|
||||
var value, script;
|
||||
|
||||
p = new BufferReader(p);
|
||||
|
||||
value = p.read64N();
|
||||
script = Parser.parseScript(p);
|
||||
|
||||
return {
|
||||
value: value,
|
||||
script: script
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse serialized coin.
|
||||
* @param {Buffer|BufferReader} p
|
||||
* @param {Boolean} extended - Whether to parse the hash and index.
|
||||
* @returns {NakedCoin}
|
||||
*/
|
||||
|
||||
Parser.parseCoin = function parseCoin(p, extended) {
|
||||
var version, height, value, script, hash, index, coinbase;
|
||||
|
||||
p = new BufferReader(p);
|
||||
|
||||
version = p.readU32();
|
||||
height = p.readU32();
|
||||
value = p.read64N();
|
||||
script = Parser.parseScript(p);
|
||||
coinbase = p.readU8() === 1;
|
||||
|
||||
if (extended) {
|
||||
hash = p.readHash('hex');
|
||||
index = p.readU32();
|
||||
}
|
||||
|
||||
if (height === 0x7fffffff)
|
||||
height = -1;
|
||||
|
||||
return {
|
||||
version: version,
|
||||
height: height,
|
||||
value: value,
|
||||
script: script,
|
||||
coinbase: coinbase,
|
||||
hash: hash,
|
||||
index: index
|
||||
};
|
||||
return bcoin.memblock.fromRaw(p);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -971,180 +689,7 @@ Parser.parseCoin = function parseCoin(p, extended) {
|
||||
*/
|
||||
|
||||
Parser.parseTX = function parseTX(p) {
|
||||
var inCount, inputs, input;
|
||||
var outCount, outputs;
|
||||
var version, locktime, i;
|
||||
var raw, size, witnessSize;
|
||||
|
||||
if (Parser.isWitnessTX(p))
|
||||
return Parser.parseWitnessTX(p);
|
||||
|
||||
p = new BufferReader(p);
|
||||
|
||||
p.start();
|
||||
|
||||
version = p.readU32(); // Technically signed
|
||||
|
||||
inCount = p.readVarint();
|
||||
inputs = [];
|
||||
|
||||
for (i = 0; i < inCount; i++) {
|
||||
input = Parser.parseInput(p);
|
||||
input.witness = { items: [] };
|
||||
inputs.push(input);
|
||||
}
|
||||
|
||||
outCount = p.readVarint();
|
||||
outputs = [];
|
||||
|
||||
for (i = 0; i < outCount; i++)
|
||||
outputs.push(Parser.parseOutput(p));
|
||||
|
||||
locktime = p.readU32();
|
||||
|
||||
raw = p.endData();
|
||||
size = raw.length;
|
||||
witnessSize = 0;
|
||||
|
||||
return {
|
||||
version: version,
|
||||
flag: 1,
|
||||
inputs: inputs,
|
||||
outputs: outputs,
|
||||
locktime: locktime,
|
||||
_raw: raw,
|
||||
_size: size,
|
||||
_witnessSize: witnessSize
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether data is a witness transaction.
|
||||
* @param {Buffer|BufferReader} p
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
Parser.isWitnessTX = function isWitnessTX(p) {
|
||||
if (Buffer.isBuffer(p)) {
|
||||
if (p.length < 12)
|
||||
return false;
|
||||
|
||||
return p[4] === 0 && p[5] !== 0;
|
||||
}
|
||||
|
||||
if (p.left() < 12)
|
||||
return false;
|
||||
|
||||
return p.data[p.offset + 4] === 0 && p.data[p.offset + 5] !== 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse tx packet in witness serialization.
|
||||
* @param {Buffer|BufferReader} p
|
||||
* @returns {NakedTX}
|
||||
*/
|
||||
|
||||
Parser.parseWitnessTX = function parseWitnessTX(p) {
|
||||
var inCount, inputs, witness;
|
||||
var outCount, outputs;
|
||||
var marker, flag;
|
||||
var version, locktime, i;
|
||||
var raw, size, witnessSize, hasWitness;
|
||||
|
||||
p = new BufferReader(p);
|
||||
|
||||
p.start();
|
||||
|
||||
version = p.readU32(); // Technically signed
|
||||
marker = p.readU8();
|
||||
flag = p.readU8();
|
||||
|
||||
if (marker !== 0)
|
||||
throw new Error('Invalid witness tx (marker != 0)');
|
||||
|
||||
if (flag === 0)
|
||||
throw new Error('Invalid witness tx (flag == 0)');
|
||||
|
||||
inCount = p.readVarint();
|
||||
inputs = [];
|
||||
|
||||
for (i = 0; i < inCount; i++)
|
||||
inputs.push(Parser.parseInput(p));
|
||||
|
||||
outCount = p.readVarint();
|
||||
outputs = [];
|
||||
|
||||
for (i = 0; i < outCount; i++)
|
||||
outputs.push(Parser.parseOutput(p));
|
||||
|
||||
p.start();
|
||||
|
||||
for (i = 0; i < inCount; i++) {
|
||||
witness = Parser.parseWitness(p);
|
||||
inputs[i].witness = witness;
|
||||
if (witness.items.length > 0)
|
||||
hasWitness = true;
|
||||
}
|
||||
|
||||
if (!hasWitness)
|
||||
throw new Error('Witness tx has an empty witness.');
|
||||
|
||||
witnessSize = p.end() + 2;
|
||||
|
||||
locktime = p.readU32();
|
||||
|
||||
raw = p.endData();
|
||||
size = raw.length;
|
||||
|
||||
return {
|
||||
version: version,
|
||||
flag: flag,
|
||||
inputs: inputs,
|
||||
outputs: outputs,
|
||||
locktime: locktime,
|
||||
_raw: raw,
|
||||
_size: size,
|
||||
_witnessSize: witnessSize
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse serialized script (with varint length).
|
||||
* @param {Buffer|BufferReader} p
|
||||
* @returns {NakedScript}
|
||||
*/
|
||||
|
||||
Parser.parseScript = function parseScript(p) {
|
||||
var data;
|
||||
|
||||
p = new BufferReader(p);
|
||||
data = p.readVarBytes();
|
||||
|
||||
return {
|
||||
raw: data
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse serialized witness.
|
||||
* @param {Buffer|BufferReader} p
|
||||
* @returns {NakedWitness}
|
||||
*/
|
||||
|
||||
Parser.parseWitness = function parseWitness(p) {
|
||||
var items = [];
|
||||
var chunkCount, i;
|
||||
|
||||
p = new BufferReader(p);
|
||||
|
||||
chunkCount = p.readVarint();
|
||||
|
||||
for (i = 0; i < chunkCount; i++)
|
||||
items.push(p.readVarBytes());
|
||||
|
||||
return {
|
||||
items: items
|
||||
};
|
||||
return bcoin.tx.fromRaw(p);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -32,12 +32,20 @@ var ScriptError = bcoin.errors.ScriptError;
|
||||
*/
|
||||
|
||||
function Witness(items) {
|
||||
if (items instanceof Witness)
|
||||
return items;
|
||||
|
||||
if (!(this instanceof Witness))
|
||||
return new Witness(items);
|
||||
|
||||
if (!items)
|
||||
items = [];
|
||||
this.items = [];
|
||||
this.redeem = null;
|
||||
|
||||
if (items)
|
||||
this.fromOptions(items);
|
||||
}
|
||||
|
||||
Witness.prototype.fromOptions = function fromOptions(items) {
|
||||
if (items.items)
|
||||
items = items.items;
|
||||
|
||||
@ -46,7 +54,13 @@ function Witness(items) {
|
||||
this.redeem = null;
|
||||
|
||||
assert(Array.isArray(this.items));
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Witness.fromOptions = function fromOptions(options) {
|
||||
return new Witness().fromOptions(options);
|
||||
};
|
||||
|
||||
Witness.prototype.toArray = function toArray() {
|
||||
return this.items.slice();
|
||||
@ -247,11 +261,19 @@ Witness.prototype.indexOf = function indexOf(data) {
|
||||
* @returns {Buffer|String} Serialized script.
|
||||
*/
|
||||
|
||||
Witness.prototype.toRaw = function toRaw(enc) {
|
||||
var data = bcoin.protocol.framer.witness(this);
|
||||
if (enc === 'hex')
|
||||
data = data.toString('hex');
|
||||
return data;
|
||||
Witness.prototype.toRaw = function toRaw(writer) {
|
||||
var p = bcoin.writer(writer);
|
||||
var i;
|
||||
|
||||
p.writeVarint(this.items.length);
|
||||
|
||||
for (i = 0; i < this.items.length; i++)
|
||||
p.writeVarBytes(this.items[i]);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -417,18 +439,15 @@ Witness.encodeItem = function encodeItem(data) {
|
||||
return data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a witness from a serialized buffer.
|
||||
* @param {Buffer|String} data - Serialized witness.
|
||||
* @param {String?} enc - Either `"hex"` or `null`.
|
||||
* @returns {Object} Naked witness object.
|
||||
*/
|
||||
Witness.prototype.fromRaw = function fromRaw(data) {
|
||||
var p = bcoin.reader(data);
|
||||
var chunkCount = p.readVarint();
|
||||
var i;
|
||||
|
||||
Witness.parseRaw = function parseRaw(data, enc) {
|
||||
if (enc === 'hex')
|
||||
data = new Buffer(data, 'hex');
|
||||
for (i = 0; i < chunkCount; i++)
|
||||
this.items.push(p.readVarBytes());
|
||||
|
||||
return bcoin.protocol.parser.parseWitness(data);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -439,7 +458,9 @@ Witness.parseRaw = function parseRaw(data, enc) {
|
||||
*/
|
||||
|
||||
Witness.fromRaw = function fromRaw(data, enc) {
|
||||
return new Witness(Witness.parseRaw(data, enc));
|
||||
if (typeof data === 'string')
|
||||
data = new Buffer(data, enc);
|
||||
return new Witness().fromRaw(data);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1012,28 +1033,52 @@ function Script(raw) {
|
||||
if (!(this instanceof Script))
|
||||
return new Script(raw);
|
||||
|
||||
if (!raw)
|
||||
raw = STACK_FALSE;
|
||||
|
||||
if (raw.raw)
|
||||
raw = raw.raw;
|
||||
|
||||
this.raw = null;
|
||||
this.code = null;
|
||||
this.raw = STACK_FALSE;
|
||||
this.code = [];
|
||||
this.redeem = null;
|
||||
|
||||
if (Array.isArray(raw)) {
|
||||
raw = Script.parseArray(raw);
|
||||
this.raw = Script.encode(raw);
|
||||
this.code = raw;
|
||||
if (raw)
|
||||
this.fromOptions(raw);
|
||||
}
|
||||
|
||||
Script.prototype.fromOptions = function fromOptions(options) {
|
||||
var code, raw;
|
||||
|
||||
if (Buffer.isBuffer(options)) {
|
||||
raw = options;
|
||||
} else if (Array.isArray(options)) {
|
||||
code = options;
|
||||
} else {
|
||||
this.raw = raw;
|
||||
this.code = Script.decode(raw);
|
||||
code = options.code;
|
||||
raw = options.raw;
|
||||
}
|
||||
|
||||
if (code)
|
||||
code = Script.parseArray(code);
|
||||
|
||||
this.raw = raw;
|
||||
this.code = code;
|
||||
this.redeem = null;
|
||||
|
||||
if (!this.raw) {
|
||||
assert(this.code);
|
||||
this.raw = Script.encode(this.code);
|
||||
} else if (!this.code) {
|
||||
assert(this.raw);
|
||||
this.code = Script.decode(this.raw);
|
||||
}
|
||||
|
||||
assert(Buffer.isBuffer(this.raw));
|
||||
assert(Array.isArray(this.code));
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Script.fromOptions = function fromOptions(raw) {
|
||||
if (raw instanceof Script)
|
||||
return raw;
|
||||
return new Script().fromOptions(raw);
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert the script to an array of
|
||||
@ -1101,17 +1146,6 @@ Script.prototype.toASM = function toASM(decode) {
|
||||
return Script.formatASM(this.code, decode);
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode the script to a Buffer. Note that this
|
||||
* will _not_ contain the varint size before it.
|
||||
* This allows it to be hashed for scripthashes.
|
||||
* @returns {Buffer} Serialized script.
|
||||
*/
|
||||
|
||||
Script.prototype.encode = function encode() {
|
||||
return this.raw;
|
||||
};
|
||||
|
||||
/**
|
||||
* Re-encode the script internally. Useful if you
|
||||
* changed something manually in the `code` array.
|
||||
@ -1127,11 +1161,12 @@ Script.prototype.compile = function compile() {
|
||||
* @returns {Buffer|String} Serialized script.
|
||||
*/
|
||||
|
||||
Script.prototype.toRaw = function toRaw(enc) {
|
||||
var data = this.encode();
|
||||
if (enc === 'hex')
|
||||
data = data.toString('hex');
|
||||
return data;
|
||||
Script.prototype.toRaw = function toRaw(writer) {
|
||||
if (writer) {
|
||||
writer.writeVarBytes(this.raw);
|
||||
return writer;
|
||||
}
|
||||
return this.raw;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -3636,7 +3671,7 @@ Script.prototype.isPushOnly = function isPushOnly() {
|
||||
if (op.data)
|
||||
continue;
|
||||
|
||||
if (op.value == -1)
|
||||
if (op.value === -1)
|
||||
return false;
|
||||
|
||||
if (op.value > opcodes.OP_16)
|
||||
@ -4112,25 +4147,6 @@ Script.sign = function sign(msg, key, type) {
|
||||
return p.render();
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a serialized script, returning the "naked"
|
||||
* representation of a Script object (the same
|
||||
* properties, but it is not instantiated -- suitable
|
||||
* as an options object for Script).
|
||||
* @param {Buffer|String} data - Serialized script.
|
||||
* @param {String?} enc - Either `"hex"` or `null`.
|
||||
* @returns {Object} Naked script object.
|
||||
*/
|
||||
|
||||
Script.parseRaw = function parseRaw(data, enc) {
|
||||
if (enc === 'hex')
|
||||
data = new Buffer(data, 'hex');
|
||||
|
||||
return {
|
||||
raw: data
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a script from a serialized buffer.
|
||||
* @param {Buffer|String} data - Serialized script.
|
||||
@ -4138,8 +4154,20 @@ Script.parseRaw = function parseRaw(data, enc) {
|
||||
* @returns {Script}
|
||||
*/
|
||||
|
||||
Script.prototype.fromRaw = function fromRaw(data) {
|
||||
if (data instanceof bcoin.reader)
|
||||
data = data.readVarBytes();
|
||||
|
||||
this.raw = data;
|
||||
this.code = Script.decode(data);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Script.fromRaw = function fromRaw(data, enc) {
|
||||
return new Script(Script.parseRaw(data, enc));
|
||||
if (typeof data === 'string')
|
||||
data = new Buffer(data, enc);
|
||||
return new Script().fromRaw(data);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -4344,8 +4372,8 @@ function Opcode(value, data) {
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
Opcode.prototype.toRaw = function toRaw() {
|
||||
return Script.encode([this]);
|
||||
Opcode.prototype.toRaw = function toRaw(writer) {
|
||||
return Script.encode([this], writer);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
499
lib/bcoin/tx.js
499
lib/bcoin/tx.js
@ -49,11 +49,41 @@ var BufferWriter = require('./writer');
|
||||
*/
|
||||
|
||||
function TX(data) {
|
||||
var i;
|
||||
|
||||
if (!(this instanceof TX))
|
||||
return new TX(data);
|
||||
|
||||
this.version = 1;
|
||||
this.flag = 1;
|
||||
this.inputs = [];
|
||||
this.outputs = [];
|
||||
this.locktime = 0;
|
||||
this.ts = 0;
|
||||
this.block = null;
|
||||
this.index = -1;
|
||||
this.ps = utils.now();
|
||||
this.height = -1;
|
||||
this.mutable = false;
|
||||
|
||||
this._hash = null;
|
||||
this._whash = null;
|
||||
|
||||
this._raw = null;
|
||||
this._size = null;
|
||||
this._witnessSize = null;
|
||||
|
||||
this._outputValue = null;
|
||||
this._inputValue = null;
|
||||
this._hashPrevouts = null;
|
||||
this._hashSequence = null;
|
||||
this._hashOutputs = null;
|
||||
|
||||
if (data)
|
||||
this.fromOptions(data);
|
||||
}
|
||||
|
||||
TX.prototype.fromOptions = function fromOptions(data) {
|
||||
var i;
|
||||
|
||||
assert(data, 'TX data is required.');
|
||||
assert(typeof data.version === 'number');
|
||||
assert(typeof data.flag === 'number');
|
||||
@ -91,7 +121,13 @@ function TX(data) {
|
||||
|
||||
for (i = 0; i < data.outputs.length; i++)
|
||||
this.outputs.push(new bcoin.output(data.outputs[i]));
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
TX.fromOptions = function fromOptions(data) {
|
||||
return new TX().fromOptions(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clone the transaction.
|
||||
@ -218,8 +254,14 @@ TX.prototype.witnessHash = function witnessHash(enc) {
|
||||
* @returns {Buffer} Serialized transaction.
|
||||
*/
|
||||
|
||||
TX.prototype.render = function render() {
|
||||
return this.getRaw();
|
||||
TX.prototype.render = function render(writer) {
|
||||
var raw = this.getRaw();
|
||||
if (writer) {
|
||||
writer.writeBytes(raw);
|
||||
writer._witnessSize = raw._witnessSize;
|
||||
return writer;
|
||||
}
|
||||
return raw;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -229,11 +271,17 @@ TX.prototype.render = function render() {
|
||||
* @returns {Buffer} Serialized transaction.
|
||||
*/
|
||||
|
||||
TX.prototype.renderNormal = function renderNormal() {
|
||||
TX.prototype.renderNormal = function renderNormal(writer) {
|
||||
var raw = this.getRaw();
|
||||
if (!bcoin.protocol.parser.isWitnessTX(raw))
|
||||
if (!TX.isWitness(raw)) {
|
||||
if (writer) {
|
||||
writer.writeBytes(raw);
|
||||
writer._witnessSize = raw._witnessSize;
|
||||
return writer;
|
||||
}
|
||||
return raw;
|
||||
return bcoin.protocol.framer.tx(this);
|
||||
}
|
||||
return this.frameNormal(writer);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -243,11 +291,17 @@ TX.prototype.renderNormal = function renderNormal() {
|
||||
* @returns {Buffer} Serialized transaction.
|
||||
*/
|
||||
|
||||
TX.prototype.renderWitness = function renderWitness() {
|
||||
TX.prototype.renderWitness = function renderWitness(writer) {
|
||||
var raw = this.getRaw();
|
||||
if (bcoin.protocol.parser.isWitnessTX(raw))
|
||||
if (TX.isWitness(raw)) {
|
||||
if (writer) {
|
||||
writer.writeBytes(raw);
|
||||
writer._witnessSize = raw._witnessSize;
|
||||
return writer;
|
||||
}
|
||||
return raw;
|
||||
return bcoin.protocol.framer.witnessTX(this);
|
||||
}
|
||||
return this.frameWitness(writer);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -268,9 +322,9 @@ TX.prototype.getRaw = function getRaw() {
|
||||
}
|
||||
|
||||
if (this.hasWitness())
|
||||
raw = bcoin.protocol.framer.witnessTX(this);
|
||||
raw = this.frameWitness();
|
||||
else
|
||||
raw = bcoin.protocol.framer.tx(this);
|
||||
raw = this.frameNormal();
|
||||
|
||||
if (!this.mutable) {
|
||||
this._raw = raw;
|
||||
@ -287,8 +341,16 @@ TX.prototype.getRaw = function getRaw() {
|
||||
*/
|
||||
|
||||
TX.prototype.getSizes = function getSizes() {
|
||||
if (this.mutable)
|
||||
return bcoin.protocol.framer.tx.sizes(this);
|
||||
var writer;
|
||||
|
||||
if (this.mutable) {
|
||||
writer = new BufferWriter();
|
||||
this.toRaw(writer);
|
||||
return {
|
||||
size: writer.written,
|
||||
witnessSize: writer._witnessSize
|
||||
};
|
||||
}
|
||||
|
||||
this.getRaw();
|
||||
|
||||
@ -401,6 +463,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
|
||||
// Clone the transaction.
|
||||
copy = {
|
||||
version: this.version,
|
||||
flag: 1,
|
||||
inputs: [],
|
||||
outputs: [],
|
||||
locktime: this.locktime
|
||||
@ -410,7 +473,6 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
|
||||
copy.inputs.push({
|
||||
prevout: this.inputs[i].prevout,
|
||||
script: this.inputs[i].script,
|
||||
witness: this.inputs[i].witness,
|
||||
sequence: this.inputs[i].sequence
|
||||
});
|
||||
}
|
||||
@ -472,7 +534,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
|
||||
}
|
||||
|
||||
// Render the copy and append the hashtype.
|
||||
bcoin.protocol.framer.tx(copy, p);
|
||||
TX(copy).toRaw(p);
|
||||
p.writeU32(type);
|
||||
|
||||
return utils.dsha256(p.render());
|
||||
@ -480,7 +542,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
|
||||
|
||||
TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, type) {
|
||||
var p = new BufferWriter();
|
||||
var i, prevout, hashPrevouts, hashSequence, hashOutputs;
|
||||
var i, hashPrevouts, hashSequence, hashOutputs;
|
||||
|
||||
if (typeof index !== 'number')
|
||||
index = this.inputs.indexOf(index);
|
||||
@ -496,11 +558,8 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, type) {
|
||||
hashPrevouts = this._hashPrevouts;
|
||||
} else {
|
||||
hashPrevouts = new BufferWriter();
|
||||
for (i = 0; i < this.inputs.length; i++) {
|
||||
prevout = this.inputs[i].prevout;
|
||||
hashPrevouts.writeHash(prevout.hash);
|
||||
hashPrevouts.writeU32(prevout.index);
|
||||
}
|
||||
for (i = 0; i < this.inputs.length; i++)
|
||||
this.inputs[i].prevout.toRaw(hashPrevouts);
|
||||
hashPrevouts = utils.dsha256(hashPrevouts.render());
|
||||
if (!this.mutable)
|
||||
this._hashPrevouts = hashPrevouts;
|
||||
@ -533,13 +592,13 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, type) {
|
||||
} else {
|
||||
hashOutputs = new BufferWriter();
|
||||
for (i = 0; i < this.outputs.length; i++)
|
||||
bcoin.protocol.framer.output(this.outputs[i], hashOutputs);
|
||||
this.outputs[i].toRaw(hashOutputs);
|
||||
hashOutputs = utils.dsha256(hashOutputs.render());
|
||||
if (!this.mutable)
|
||||
this._hashOutputs = hashOutputs;
|
||||
}
|
||||
} else if ((type & 0x1f) === constants.hashType.SINGLE && index < this.outputs.length) {
|
||||
hashOutputs = bcoin.protocol.framer.output(this.outputs[index]);
|
||||
hashOutputs = this.outputs[index].toRaw();
|
||||
hashOutputs = utils.dsha256(hashOutputs);
|
||||
} else {
|
||||
hashOutputs = utils.copy(constants.ZERO_HASH);
|
||||
@ -550,7 +609,7 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, type) {
|
||||
p.writeBytes(hashSequence);
|
||||
p.writeHash(this.inputs[index].prevout.hash);
|
||||
p.writeU32(this.inputs[index].prevout.index);
|
||||
p.writeVarBytes(prev.encode());
|
||||
p.writeVarBytes(prev.toRaw());
|
||||
p.write64(this.inputs[index].coin.value);
|
||||
p.writeU32(this.inputs[index].sequence);
|
||||
p.writeBytes(hashOutputs);
|
||||
@ -1640,7 +1699,7 @@ TX.prototype.getPrevout = function getPrevout() {
|
||||
|
||||
TX.prototype.isWatched = function isWatched(filter) {
|
||||
var found = false;
|
||||
var i, input, output, hash, index, outpoint;
|
||||
var i, input, output, outpoint;
|
||||
|
||||
if (!filter)
|
||||
return false;
|
||||
@ -1656,12 +1715,12 @@ TX.prototype.isWatched = function isWatched(filter) {
|
||||
// Test the output script
|
||||
if (output.script.test(filter)) {
|
||||
if (filter.update === constants.filterFlags.ALL) {
|
||||
outpoint = bcoin.protocol.framer.outpoint(this.hash(), i);
|
||||
filter.add(outpoint);
|
||||
outpoint = bcoin.outpoint.fromTX(this, i);
|
||||
filter.add(outpoint.toRaw());
|
||||
} else if (filter.update === constants.filterFlags.PUBKEY_ONLY) {
|
||||
if (output.script.isPubkey(true) || output.script.isMultisig()) {
|
||||
outpoint = bcoin.protocol.framer.outpoint(this.hash(), i);
|
||||
filter.add(outpoint);
|
||||
outpoint = bcoin.outpoint.fromTX(this, i);
|
||||
filter.add(outpoint.toRaw());
|
||||
}
|
||||
}
|
||||
found = true;
|
||||
@ -1675,9 +1734,7 @@ TX.prototype.isWatched = function isWatched(filter) {
|
||||
// 4. Test data elements in input scripts
|
||||
for (i = 0; i < this.inputs.length; i++) {
|
||||
input = this.inputs[i];
|
||||
hash = input.prevout.hash;
|
||||
index = input.prevout.index;
|
||||
outpoint = bcoin.protocol.framer.outpoint(hash, index);
|
||||
outpoint = input.prevout.toRaw();
|
||||
|
||||
// Test the COutPoint structure
|
||||
if (filter.test(outpoint))
|
||||
@ -1835,25 +1892,31 @@ TX.prototype.toJSON = function toJSON() {
|
||||
* for passing to the TX constructor).
|
||||
*/
|
||||
|
||||
TX.parseJSON = function fromJSON(json) {
|
||||
TX.prototype.fromJSON = function fromJSON(json) {
|
||||
assert.equal(json.type, 'tx');
|
||||
return {
|
||||
block: json.block ? utils.revHex(json.block) : null,
|
||||
height: json.height,
|
||||
ts: json.ts,
|
||||
ps: json.ps,
|
||||
index: json.index,
|
||||
changeIndex: json.changeIndex || -1,
|
||||
version: json.version,
|
||||
flag: json.flag,
|
||||
inputs: json.inputs.map(function(input) {
|
||||
return bcoin.input.parseJSON(input);
|
||||
}),
|
||||
outputs: json.outputs.map(function(output) {
|
||||
return bcoin.output.parseJSON(output);
|
||||
}),
|
||||
locktime: json.locktime
|
||||
};
|
||||
|
||||
this.block = json.block ? utils.revHex(json.block) : null;
|
||||
this.height = json.height;
|
||||
this.ts = json.ts;
|
||||
this.ps = json.ps;
|
||||
this.index = json.index;
|
||||
this.changeIndex = json.changeIndex || -1;
|
||||
|
||||
this.version = json.version;
|
||||
|
||||
this.flag = json.flag;
|
||||
|
||||
this.inputs = json.inputs.map(function(input) {
|
||||
return bcoin.input.fromJSON(input);
|
||||
}),
|
||||
|
||||
this.outputs = json.outputs.map(function(output) {
|
||||
return bcoin.output.fromJSON(output);
|
||||
}),
|
||||
|
||||
this.locktime = json.locktime;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1864,8 +1927,7 @@ TX.parseJSON = function fromJSON(json) {
|
||||
*/
|
||||
|
||||
TX.fromJSON = function fromJSON(json) {
|
||||
assert.equal(json.type, 'tx');
|
||||
return new TX(TX.parseJSON(json));
|
||||
return new TX().fromJSON(json);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1875,27 +1937,8 @@ TX.fromJSON = function fromJSON(json) {
|
||||
* @returns {Buffer|String}
|
||||
*/
|
||||
|
||||
TX.prototype.toRaw = function toRaw(enc) {
|
||||
var data = this.render();
|
||||
|
||||
if (enc === 'hex')
|
||||
data = data.toString('hex');
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a serialized transaction.
|
||||
* @param {Buffer} data
|
||||
* @param {String?} enc - Encoding, can be `'hex'` or null.
|
||||
* @returns {NakedTX} A "naked" transaction object.
|
||||
*/
|
||||
|
||||
TX.parseRaw = function parseRaw(data, enc) {
|
||||
if (enc === 'hex')
|
||||
data = new Buffer(data, 'hex');
|
||||
|
||||
return bcoin.protocol.parser.parseTX(data);
|
||||
TX.prototype.toRaw = function toRaw(writer) {
|
||||
return this.render(writer);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1906,7 +1949,207 @@ TX.parseRaw = function parseRaw(data, enc) {
|
||||
*/
|
||||
|
||||
TX.fromRaw = function fromRaw(data, enc) {
|
||||
return new bcoin.tx(TX.parseRaw(data, enc));
|
||||
if (typeof data === 'string')
|
||||
data = new Buffer(data, enc);
|
||||
return new TX().fromRaw(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse tx packet (will automatically switch to witness
|
||||
* parsing if a witness transaction is detected).
|
||||
* @param {Buffer|BufferReader} p
|
||||
* @returns {NakedTX}
|
||||
*/
|
||||
|
||||
TX.prototype.fromRaw = function fromRaw(data) {
|
||||
var p, i, inCount, outCount, input;
|
||||
|
||||
if (TX.isWitness(data))
|
||||
return this.fromWitness(data);
|
||||
|
||||
p = bcoin.reader(data);
|
||||
p.start();
|
||||
|
||||
this.version = p.readU32(); // Technically signed
|
||||
|
||||
inCount = p.readVarint();
|
||||
|
||||
this.inputs = [];
|
||||
|
||||
for (i = 0; i < inCount; i++) {
|
||||
input = bcoin.input.fromRaw(p);
|
||||
input.witness = new bcoin.witness();
|
||||
this.inputs.push(input);
|
||||
}
|
||||
|
||||
outCount = p.readVarint();
|
||||
|
||||
this.outputs = [];
|
||||
|
||||
for (i = 0; i < outCount; i++)
|
||||
this.outputs.push(bcoin.output.fromRaw(p));
|
||||
|
||||
this.locktime = p.readU32();
|
||||
|
||||
this._raw = p.endData();
|
||||
this._size = this._raw.length;
|
||||
this._witnessSize = 0;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse tx packet in witness serialization.
|
||||
* @param {Buffer|BufferReader} p
|
||||
* @returns {NakedTX}
|
||||
*/
|
||||
|
||||
TX.prototype.fromWitness = function fromWitness(data) {
|
||||
var p = bcoin.reader(data);
|
||||
var i, marker, inCount, outCount, witness, hasWitness;
|
||||
|
||||
p.start();
|
||||
|
||||
this.version = p.readU32(); // Technically signed
|
||||
marker = p.readU8();
|
||||
this.flag = p.readU8();
|
||||
|
||||
if (marker !== 0)
|
||||
throw new Error('Invalid witness tx (marker != 0)');
|
||||
|
||||
if (this.flag === 0)
|
||||
throw new Error('Invalid witness tx (flag == 0)');
|
||||
|
||||
inCount = p.readVarint();
|
||||
|
||||
this.inputs = [];
|
||||
|
||||
for (i = 0; i < inCount; i++)
|
||||
this.inputs.push(bcoin.input.fromRaw(p));
|
||||
|
||||
outCount = p.readVarint();
|
||||
|
||||
this.outputs = [];
|
||||
|
||||
for (i = 0; i < outCount; i++)
|
||||
this.outputs.push(bcoin.output.fromRaw(p));
|
||||
|
||||
p.start();
|
||||
|
||||
for (i = 0; i < inCount; i++) {
|
||||
witness = bcoin.witness.fromRaw(p);
|
||||
this.inputs[i].witness = witness;
|
||||
if (witness.items.length > 0)
|
||||
hasWitness = true;
|
||||
}
|
||||
|
||||
if (!hasWitness)
|
||||
throw new Error('Witness tx has an empty witness.');
|
||||
|
||||
this._witnessSize = p.end() + 2;
|
||||
|
||||
this.locktime = p.readU32();
|
||||
|
||||
this._raw = p.endData();
|
||||
this._size = this._raw.length;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether data is a witness transaction.
|
||||
* @param {Buffer|BufferReader} p
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
TX.isWitness = function isWitness(p) {
|
||||
if (Buffer.isBuffer(p)) {
|
||||
if (p.length < 12)
|
||||
return false;
|
||||
|
||||
return p[4] === 0 && p[5] !== 0;
|
||||
}
|
||||
|
||||
if (p.left() < 12)
|
||||
return false;
|
||||
|
||||
return p.data[p.offset + 4] === 0 && p.data[p.offset + 5] !== 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize transaction without witness.
|
||||
* @param {NakedTX|TX} tx
|
||||
* @param {BufferWriter?} writer - A buffer writer to continue writing from.
|
||||
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
|
||||
*/
|
||||
|
||||
TX.prototype.frameNormal = function frameNormal(writer) {
|
||||
var p = bcoin.writer(writer);
|
||||
var i;
|
||||
|
||||
p.write32(this.version);
|
||||
|
||||
p.writeVarint(this.inputs.length);
|
||||
|
||||
for (i = 0; i < this.inputs.length; i++)
|
||||
this.inputs[i].toRaw(p);
|
||||
|
||||
p.writeVarint(this.outputs.length);
|
||||
|
||||
for (i = 0; i < this.outputs.length; i++)
|
||||
this.outputs[i].toRaw(p);
|
||||
|
||||
p.writeU32(this.locktime);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
p._witnessSize = 0;
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize transaction with witness. Calculates the witness
|
||||
* size as it is framing (exposed on return value as `_witnessSize`).
|
||||
* @param {NakedTX|TX} tx
|
||||
* @param {BufferWriter?} writer - A buffer writer to continue writing from.
|
||||
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
|
||||
*/
|
||||
|
||||
TX.prototype.frameWitness = function frameWitness(writer) {
|
||||
var p = bcoin.writer(writer);
|
||||
var witnessSize = 0;
|
||||
var i, start;
|
||||
|
||||
p.write32(this.version);
|
||||
p.writeU8(0);
|
||||
p.writeU8(this.flag || 1);
|
||||
|
||||
p.writeVarint(this.inputs.length);
|
||||
|
||||
for (i = 0; i < this.inputs.length; i++)
|
||||
this.inputs[i].toRaw(p);
|
||||
|
||||
p.writeVarint(this.outputs.length);
|
||||
|
||||
for (i = 0; i < this.outputs.length; i++)
|
||||
this.outputs[i].toRaw(p);
|
||||
|
||||
for (i = 0; i < this.inputs.length; i++) {
|
||||
start = p.written;
|
||||
this.inputs[i].witness.toRaw(p);
|
||||
witnessSize += p.written - start;
|
||||
}
|
||||
|
||||
p.writeU32(this.locktime);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
p._witnessSize = witnessSize + 2;
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1921,21 +2164,49 @@ TX.fromRaw = function fromRaw(data, enc) {
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
TX.prototype.toExtended = function toExtended(saveCoins, enc) {
|
||||
var data, tmp;
|
||||
TX.prototype.toExtended = function toExtended(saveCoins, writer) {
|
||||
var height = this.height;
|
||||
var index = this.index;
|
||||
var changeIndex = this.changeIndex != null ? this.changeIndex : -1;
|
||||
var p = bcoin.writer(writer);
|
||||
var i, input;
|
||||
|
||||
if (typeof saveCoins === 'string') {
|
||||
tmp = saveCoins;
|
||||
saveCoins = enc;
|
||||
enc = tmp;
|
||||
if (height === -1)
|
||||
height = 0x7fffffff;
|
||||
|
||||
if (index === -1)
|
||||
index = 0x7fffffff;
|
||||
|
||||
if (changeIndex === -1)
|
||||
changeIndex = 0x7fffffff;
|
||||
|
||||
this.toRaw(p);
|
||||
|
||||
p.writeU32(height);
|
||||
p.writeHash(this.block || constants.ZERO_HASH);
|
||||
p.writeU32(index);
|
||||
p.writeU32(this.ts);
|
||||
p.writeU32(this.ps);
|
||||
// p.writeU32(changeIndex);
|
||||
|
||||
if (saveCoins) {
|
||||
p.writeVarint(this.inputs.length);
|
||||
for (i = 0; i < this.inputs.length; i++) {
|
||||
input = this.inputs[i];
|
||||
|
||||
if (!input.coin) {
|
||||
p.writeVarint(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
p.writeVarBytes(input.coin.toRaw());
|
||||
}
|
||||
}
|
||||
|
||||
data = bcoin.protocol.framer.extendedTX(this, saveCoins);
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
|
||||
if (enc === 'hex')
|
||||
data = data.toString('hex');
|
||||
|
||||
return data;
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1947,19 +2218,45 @@ TX.prototype.toExtended = function toExtended(saveCoins, enc) {
|
||||
* @returns {NakedTX} - A "naked" transaction object.
|
||||
*/
|
||||
|
||||
TX.parseExtended = function parseExtended(data, saveCoins, enc) {
|
||||
var tmp;
|
||||
TX.prototype.fromExtended = function fromExtended(data, saveCoins) {
|
||||
var p = bcoin.reader(data);
|
||||
var i, coinCount, coin;
|
||||
|
||||
if (typeof saveCoins === 'string') {
|
||||
tmp = saveCoins;
|
||||
saveCoins = enc;
|
||||
enc = tmp;
|
||||
this.fromRaw(p);
|
||||
|
||||
this.height = p.readU32();
|
||||
this.block = p.readHash('hex');
|
||||
this.index = p.readU32();
|
||||
this.ts = p.readU32();
|
||||
this.ps = p.readU32();
|
||||
// this.changeIndex = p.readU32();
|
||||
|
||||
if (this.block === constants.NULL_HASH)
|
||||
this.block = null;
|
||||
|
||||
if (this.height === 0x7fffffff)
|
||||
this.height = -1;
|
||||
|
||||
if (this.index === 0x7fffffff)
|
||||
this.index = -1;
|
||||
|
||||
if (this.changeIndex === 0x7fffffff)
|
||||
this.changeIndex = -1;
|
||||
|
||||
if (saveCoins) {
|
||||
coinCount = p.readVarint();
|
||||
for (i = 0; i < coinCount; i++) {
|
||||
coin = p.readVarBytes();
|
||||
if (coin.length === 0)
|
||||
continue;
|
||||
coin = bcoin.coin.fromRaw(coin);
|
||||
coin.hash = this.inputs[i].prevout.hash;
|
||||
coin.index = this.inputs[i].prevout.index;
|
||||
this.inputs[i].coin = coin;
|
||||
}
|
||||
}
|
||||
|
||||
if (enc === 'hex')
|
||||
data = new Buffer(data, 'hex');
|
||||
|
||||
return bcoin.protocol.parser.parseExtendedTX(data, saveCoins);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1973,7 +2270,13 @@ TX.parseExtended = function parseExtended(data, saveCoins, enc) {
|
||||
*/
|
||||
|
||||
TX.fromExtended = function fromExtended(data, saveCoins, enc) {
|
||||
return new TX(TX.parseExtended(data, saveCoins, enc));
|
||||
if (typeof saveCoins === 'string') {
|
||||
enc = saveCoins;
|
||||
saveCoins = false;
|
||||
}
|
||||
if (typeof data === 'string')
|
||||
data = new Buffer(data, enc);
|
||||
return new TX().fromExtended(data, saveCoins);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -817,13 +817,13 @@ Framer.item = function _item(item, p) {
|
||||
} else {
|
||||
if (item instanceof bcoin.block) {
|
||||
p.writeU8(40);
|
||||
bcoin.protocol.framer.witnessBlock(item, p);
|
||||
item.render(p);
|
||||
} else if (item instanceof bcoin.tx) {
|
||||
p.writeU8(41);
|
||||
bcoin.protocol.framer.extendedTX(item, true, p);
|
||||
item.toExtended(true, p);
|
||||
} else if (item instanceof bcoin.coin) {
|
||||
p.writeU8(42);
|
||||
bcoin.protocol.framer.coin(item, true, p);
|
||||
item.toExtended(p);
|
||||
} else if (item instanceof bcoin.chainentry) {
|
||||
p.writeU8(43);
|
||||
item.toRaw(p);
|
||||
|
||||
@ -32,7 +32,7 @@ describe('Block', function() {
|
||||
],
|
||||
flags: new Buffer([245, 122, 0])
|
||||
});
|
||||
var raw = mblock.toRaw('hex');
|
||||
var raw = mblock.toRaw().toString('hex');
|
||||
var block;
|
||||
|
||||
var raw2 = '02000000d1831d4411bdfda89d9d8c842b541beafd1437fc560dbe5c0'
|
||||
|
||||
@ -29,7 +29,7 @@ function parseTX(file) {
|
||||
|
||||
function parseExtended(file) {
|
||||
file = fs.readFileSync(__dirname + '/' + file, 'utf8').trim();
|
||||
return bcoin.tx.fromExtended(file, 'hex', true);
|
||||
return bcoin.tx.fromExtended(file, true, 'hex');
|
||||
}
|
||||
|
||||
function clearCache(tx, nocache) {
|
||||
@ -152,7 +152,7 @@ describe('TX', function() {
|
||||
assert(coolest.verify(constants.flags.VERIFY_NONE));
|
||||
});
|
||||
|
||||
it('should parse witness tx properly', function() {
|
||||
it('should parse witness tx properly' + suffix, function() {
|
||||
clearCache(wtx, nocache);
|
||||
assert.equal(wtx.inputs.length, 5);
|
||||
assert.equal(wtx.outputs.length, 1980);
|
||||
@ -503,14 +503,14 @@ describe('TX', function() {
|
||||
assert(tx.outputs[0].value.bitLength() === 56);
|
||||
var raw = tx.toRaw()
|
||||
assert.throws(function() {
|
||||
tx.fromRaw(raw);
|
||||
bcoin.tx.fromRaw(raw);
|
||||
});
|
||||
delete tx._raw;
|
||||
tx.outputs[0].value = new bn('00ffffffffffffff', 'hex').ineg();
|
||||
assert(tx.outputs[0].value.bitLength() === 56);
|
||||
var raw = tx.toRaw()
|
||||
assert.throws(function() {
|
||||
tx.fromRaw(raw);
|
||||
bcoin.tx.fromRaw(raw);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user