segwit. misc.

This commit is contained in:
Christopher Jeffrey 2016-02-26 17:08:06 -08:00
parent 5a8e2b80f3
commit 8467f339c1
15 changed files with 271 additions and 330 deletions

View File

@ -24,7 +24,9 @@ function Block(data) {
bcoin.abstractblock.call(this, data); bcoin.abstractblock.call(this, data);
this.type = 'block'; this.type = 'block';
this.witness = data.witness || false;
this._witness = data._witness || false;
this._cost = data._cost || 0;
this.txs = data.txs || []; this.txs = data.txs || [];
@ -36,49 +38,45 @@ function Block(data) {
return bcoin.tx(data, self, i); return bcoin.tx(data, self, i);
}); });
if (this.witness) {
this._wsize = this._raw.length;
this._wraw = this._raw;
this._raw = null;
this._size = 0;
}
if (!this._raw)
this._raw = this.render();
if (!this._size)
this._size = this._raw.length;
this._cost = data._cost || 0;
} }
utils.inherits(Block, bcoin.abstractblock); utils.inherits(Block, bcoin.abstractblock);
Block.prototype.render = function render() { Block.prototype.render = function render() {
if (!this._raw) { if (this._raw) {
this._raw = bcoin.protocol.framer.block(this); if (!this._witness)
this._size = this._raw.length; return this._raw;
return bcoin.protocol.framer.block(this);
} }
this._raw = bcoin.protocol.framer.block(this);
this._size = this._raw.length;
this._witness = false;
return this._raw; return this._raw;
}; };
Block.prototype.renderWitness = function renderWitness() { Block.prototype.renderWitness = function renderWitness() {
if (!this._wraw) { if (this._raw) {
this._wraw = bcoin.protocol.framer.witnessBlock(this); if (this._witness)
this._wsize = this._wraw.length; return this._raw;
return bcoin.protocol.framer.witnessBlock(this);
} }
return this._wraw;
this._raw = bcoin.protocol.framer.witnessBlock(this);
this._size = this._raw.length;
this._witness = true;
return this._raw;
}; };
Block.prototype.getBlockSize = function getBlockSize() { Block.prototype.getSize = function getSize() {
return this.render().length; return this.render().length;
}; };
Block.prototype.getBlockCost = function getBlockCost() { Block.prototype.getCost = function getCost() {
if (!this._cost) if (!this._cost)
this._cost = this.renderWitness()._cost; this._cost = this._renderWitness()._cost;
return this._cost; return this._cost;
}; };
@ -125,9 +123,6 @@ Block.prototype.getWitnessRoot = function getWitnessRoot() {
Block.prototype.__defineGetter__('witnessRoot', function() { Block.prototype.__defineGetter__('witnessRoot', function() {
var coinbase, i, commitment, witnessRoot; var coinbase, i, commitment, witnessRoot;
if (!block.witness)
return;
if (this._witnessRoot) if (this._witnessRoot)
return this._witnessRoot; return this._witnessRoot;

View File

@ -117,6 +117,20 @@ Coin.prototype.__defineGetter__('age', function() {
return this.getAge(); return this.getAge();
}); });
Coin.prototype.inspect = function inspect() {
return {
type: this.getType(),
version: this.version,
height: this.height,
value: utils.btc(this.value),
script: bcoin.script.format(this.script),
hash: utils.revHex(this.hash),
index: this.index,
address: this.getAddress(),
spent: this.spent
};
};
Coin.prototype.toJSON = function toJSON() { Coin.prototype.toJSON = function toJSON() {
return { return {
version: this.version, version: this.version,

View File

@ -69,6 +69,39 @@ Input.prototype.getType = function getType() {
return type; return type;
}; };
Input.prototype.getRedeem = function getRedeem() {
var type;
if (this.isCoinbase())
return;
type = this.getType();
if (type === 'witnessscripthash')
return bcoin.script.getRedeem(this.witness);
if (type === 'scripthash') {
redeem = bcoin.script.getRedeem(this.script);
if (script.isWitnessScripthash(redeem))
return bcoin.script.getRedeem(this.witness);
return redeem;
}
};
Input.prototype.getSubtype = function getSubtype() {
var redeem;
if (this.isCoinbase())
return;
redeem = this.getRedeem();
if (!redeem)
return;
return bcoin.script.getOutputType(redeem);
};
Input.prototype.getAddress = function getAddress() { Input.prototype.getAddress = function getAddress() {
var address; var address;
@ -190,29 +223,34 @@ Input.prototype.getData = function getData() {
}; };
Input.prototype.inspect = function inspect() { Input.prototype.inspect = function inspect() {
var data = this.getData(); var redeem = this.getRedeem();
var output = this.output var output;
? this.output.inspect()
: { type: 'unknown', value: '0.0' };
output.hash = utils.revHex(this.prevout.hash); if (this.output) {
output.index = this.prevout.index; output = this.output.inspect();
} else {
output = {
type: 'unknown',
version: 1,
height: -1,
value: '0.0',
script: '',
hash: utils.toHex(constants.zeroHash),
index: 0,
spent: false,
address: null
};
}
return { return {
type: this.getType(), type: this.getType(),
subtype: data.subtype, subtype: this.getSubtype(),
address: this.getAddress(), address: this.getAddress(),
keys: data.keys.map(utils.toHex),
hashes: data.hashes.map(utils.toHex),
addresses: data.addresses,
scriptAddress: data.scriptAddress,
signatures: data.signatures.map(utils.toHex),
text: data.text,
locktime: data.locktime,
value: utils.btc(output.value), value: utils.btc(output.value),
script: bcoin.script.format(data.script), script: bcoin.script.format(this.script),
redeem: data.redeem ? bcoin.script.format(data.redeem) : null, witness: bcoin.script.format(this.witness),
sequence: data.sequence, redeem: redeem ? bcoin.script.format(redeem) : null,
sequence: this.sequence,
output: output output: output
}; };
}; };

View File

@ -34,12 +34,6 @@ function MerkleBlock(data) {
// TXs that will be pushed on // TXs that will be pushed on
this.txs = []; this.txs = [];
if (!this._raw)
this._raw = this.render();
if (!this._size)
this._size = this._raw.length;
} }
utils.inherits(MerkleBlock, bcoin.abstractblock); utils.inherits(MerkleBlock, bcoin.abstractblock);

View File

@ -34,9 +34,11 @@ function MTX(options) {
this.index = -1; this.index = -1;
this._hash = null; this._hash = null;
this._whash = null;
this._raw = null; this._raw = null;
this._size = 0; this._size = 0;
this._offset = 0; this._offset = 0;
this._cost = 0;
this.height = -1; this.height = -1;
@ -98,6 +100,10 @@ MTX.prototype.getSize = function getSize() {
return this.render().length; return this.render().length;
}; };
MTX.prototype.getCost = function getCost() {
return this.renderWitness()._cost;
};
MTX.prototype.addInput = function addInput(options, index) { MTX.prototype.addInput = function addInput(options, index) {
var input, i; var input, i;
@ -1097,6 +1103,7 @@ MTX.prototype.toJSON = function toJSON() {
return { return {
type: 'mtx', type: 'mtx',
hash: utils.revHex(this.hash('hex')), hash: utils.revHex(this.hash('hex')),
witnessHash: utils.revHex(this.witnessHash('hex')),
height: this.height, height: this.height,
block: this.block ? utils.revHex(this.block) : null, block: this.block ? utils.revHex(this.block) : null,
ts: this.ts, ts: this.ts,

View File

@ -124,23 +124,11 @@ Output.prototype.getData = function getData() {
}; };
Output.prototype.inspect = function inspect() { Output.prototype.inspect = function inspect() {
var data = this.getData();
return { return {
type: this.getType(), type: this.getType(),
address: this.getAddress(), value: utils.btc(this.value),
keys: data.keys.map(utils.toHex), script: bcoin.script.format(this.script),
hashes: data.hashes.map(utils.toHex), address: this.getAddress()
addresses: data.addresses,
scriptAddress: data.scriptAddress,
m: data.m,
n: data.n,
text: data.text,
locktime: data.locktime,
hash: this.hash ? utils.revHex(this.hash) : undefined,
index: this.index,
height: data.height,
value: utils.btc(data.value),
script: bcoin.script.format(data.script)
}; };
}; };

View File

@ -211,6 +211,7 @@ exports.block = {
exports.tx = { exports.tx = {
version: 1, version: 1,
maxSize: 100000, maxSize: 100000,
maxCost: 400000,
minFee: 10000, minFee: 10000,
bareMultisig: true, bareMultisig: true,
freeThreshold: exports.coin.muln(144).divn(250), freeThreshold: exports.coin.muln(144).divn(250),

View File

@ -422,7 +422,7 @@ segnet.halvingInterval = 210000;
segnet.genesis = { segnet.genesis = {
version: 1, version: 1,
hash: utils.revHex( hash: utils.revHex(
'ead13e4b1d0164b21128523156f729373d7a11bc9b6a1ee2e6e883ab9d9a728c' '0d5b9c518ddf053fcac71730830df4526a9949c08f34acf6a1d30464d22f02aa'
), ),
prevBlock: utils.toHex( prevBlock: utils.toHex(
[ 0, 0, 0, 0, 0, 0, 0, 0, [ 0, 0, 0, 0, 0, 0, 0, 0,
@ -432,7 +432,7 @@ segnet.genesis = {
merkleRoot: utils.revHex( merkleRoot: utils.revHex(
'4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b' '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'
), ),
ts: 1452368293, ts: 1452831101,
bits: 0x1d00ffff, bits: 0x1d00ffff,
nonce: 0 nonce: 0
}; };
@ -457,4 +457,4 @@ segnet.block = {
segnet.segwitHeight = 0; segnet.segwitHeight = 0;
segnet.genesisBlock = '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4aa5619156ffff001d000000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'; segnet.genesisBlock = '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a7d719856ffff001d000000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000';

View File

@ -357,7 +357,6 @@ Parser.parseBlock = function parseBlock(p) {
} }
return { return {
witness: witness,
version: utils.read32(p, 0), version: utils.read32(p, 0),
prevBlock: p.slice(4, 36), prevBlock: p.slice(4, 36),
merkleRoot: p.slice(36, 68), merkleRoot: p.slice(36, 68),
@ -366,6 +365,7 @@ Parser.parseBlock = function parseBlock(p) {
nonce: utils.readU32(p, 76), nonce: utils.readU32(p, 76),
totalTX: totalTX, totalTX: totalTX,
txs: txs, txs: txs,
_witness: witness,
_raw: p, _raw: p,
_size: p.length, _size: p.length,
_cost: cost _cost: cost
@ -587,11 +587,11 @@ Parser.parseTX = function parseTX(p) {
off += 4; off += 4;
return { return {
witness: false,
version: version, version: version,
inputs: txIn, inputs: txIn,
outputs: txOut, outputs: txOut,
locktime: locktime, locktime: locktime,
_witness: false,
_cost: off * 4, _cost: off * 4,
_raw: p.length !== off ? p.slice(0, off) : p, _raw: p.length !== off ? p.slice(0, off) : p,
_size: off _size: off
@ -700,13 +700,13 @@ Parser.parseWitnessTX = function parseWitnessTX(p) {
cost += 4 * 4; cost += 4 * 4;
return { return {
witness: true,
version: version, version: version,
marker: marker, marker: marker,
flag: flag, flag: flag,
inputs: txIn, inputs: txIn,
outputs: txOut, outputs: txOut,
locktime: locktime, locktime: locktime,
_witness: true,
_raw: off !== p.length ? p.slice(0, off) : p, _raw: off !== p.length ? p.slice(0, off) : p,
_size: off, _size: off,
_cost: cost _cost: cost

View File

@ -288,7 +288,7 @@ script.normalize = function normalize(s) {
}; };
script.verify = function verify(input, witness, output, tx, i, flags) { script.verify = function verify(input, witness, output, tx, i, flags) {
var copy, res, redeem; var copy, res, raw, redeem, hadWitness;
var stack = []; var stack = [];
if (flags == null) if (flags == null)
@ -313,10 +313,20 @@ script.verify = function verify(input, witness, output, tx, i, flags) {
if (!res || stack.length === 0 || !script.bool(stack.pop())) if (!res || stack.length === 0 || !script.bool(stack.pop()))
return false; return false;
if ((flags & constants.flags.VERIFY_WITNESS) && script.isWitnessProgram(output)) { if ((flags & constants.flags.VERIFY_WITNESS)
if (!script.verifyProgram(input, witness, output, tx, i, flags)) && script.isWitnessProgram(output)) {
hadWitness = true;
// Input script must be empty.
if (input.length !== 0)
return false; return false;
// TODO: FIX STACK HERE
// Verify the program in the output script
if (!script.verifyProgram(witness, output, tx, i, flags))
return false;
// Force a cleanstack
stack.length = 0;
} }
// If the script is P2SH, execute the real output script // If the script is P2SH, execute the real output script
@ -333,12 +343,12 @@ script.verify = function verify(input, witness, output, tx, i, flags) {
return false; return false;
// Grab the real redeem script // Grab the real redeem script
redeem = stack.pop(); raw = stack.pop();
if (!Buffer.isBuffer(redeem)) if (!Buffer.isBuffer(raw))
return false; return false;
redeem = script.decode(redeem); redeem = script.decode(raw);
// Execute the redeem script // Execute the redeem script
res = script.execute(redeem, stack, tx, i, flags); res = script.execute(redeem, stack, tx, i, flags);
@ -347,9 +357,20 @@ script.verify = function verify(input, witness, output, tx, i, flags) {
if (!res || stack.length === 0 || !script.bool(stack.pop())) if (!res || stack.length === 0 || !script.bool(stack.pop()))
return false; return false;
if ((flags & constants.flags.VERIFY_WITNESS) && script.isWitnessProgram(redeem)) { if ((flags & constants.flags.VERIFY_WITNESS)
if (!script.verifyProgram(input, witness, redeem, tx, i, flags)) && script.isWitnessProgram(redeem)) {
hadWitness = true;
// Input script must be exactly one push of the redeem script.
if (!(input.length === 1 && utils.isEqual(input[0], raw)))
return false; return false;
// Verify the program in the redeem script
if (!script.verifyProgram(witness, redeem, tx, i, flags))
return false;
// Force a cleanstack
stack.length = 0;
} }
} }
@ -361,14 +382,21 @@ script.verify = function verify(input, witness, output, tx, i, flags) {
return false; return false;
} }
// If we had a witness but no witness program, fail.
if (flags & constants.flags.VERIFY_WITNESS) {
assert((flags & constants.flags.VERIFY_P2SH) !== 0);
if (!hadWitness && witness.length > 0)
return false;
}
return true; return true;
}; };
script.verifyProgram = function verifyProgram(input, witness, output, tx, i, flags) { script.verifyProgram = function verifyProgram(witness, output, tx, i, flags) {
var program, witnessScript, script, stack, j; var program, witnessScript, script, stack, j;
if (!(flags & constants.flags.VERIFY_WITNESS) || !script.isWitnessProgram(output)) assert((flags & constants.flags.VERIFY_WITNESS) !== 0);
return true; assert(script.isWitnessProgram(output));
program = script.getWitnessProgram(output); program = script.getWitnessProgram(output);
@ -395,9 +423,6 @@ script.verifyProgram = function verifyProgram(input, witness, output, tx, i, fla
stack = witness.slice(); stack = witness.slice();
if (program.type === 'witnesspubkeyhash') { if (program.type === 'witnesspubkeyhash') {
if (input.length !== 0)
return false;
if (stack.length !== 2) if (stack.length !== 2)
return false; return false;
@ -440,6 +465,10 @@ script.verifyProgram = function verifyProgram(input, witness, output, tx, i, fla
if (!res || stack.length === 0 || !script.bool(stack.pop())) if (!res || stack.length === 0 || !script.bool(stack.pop()))
return false; return false;
// Witnesses always require cleanstack
if (stack.length !== 0)
return false;
return true; return true;
}; };
@ -1750,92 +1779,25 @@ script.getUnknownData = function getUnknownData(s) {
}; };
}; };
script.getInputKeys = function getInputKeys(s, prev) { script.getInputAddress = function getInputAddress(s, prev, isWitness) {
if (prev) {
if (script.isScripthash(prev))
return script.getOutputKeys(script.getRedeem(s));
return script.getOutputKeys(prev);
}
if (script.isScripthashInput(s))
return script.getOutputKeys(script.getRedeem(s));
if (script.isPubkeyhashInput(s))
return [s[1]];
return [];
};
script.getOutputKeys = function getOutputKeys(s) {
if (script.isPubkey(s))
return [s[0]];
if (script.isMultisig(s))
return s.slice(1, -2);
return [];
};
script.getInputKeyHashes = function getInputKeyHashes(s, prev) {
if (prev) {
if (script.isScripthash(prev))
return script.getOutputKeyHashes(script.getRedeem(s));
return script.getOuputKeyHashes(prev);
}
if (script.isScripthashInput(s))
return script.getOutputKeyHashes(script.getRedeem(s));
if (script.isPubkeyhashInput(s))
return [bcoin.address.hash160(s[1])];
return [];
};
script.getOuputKeyHashes = function getOuputKeyHashes(s) {
if (script.isPubkey(s))
return [bcoin.address.hash160(s[0])];
if (script.isPubkeyhash(s))
return [s[2]];
if (script.isMultisig(s)) {
return s.slice(1, -2).map(function(key) {
return bcoin.address.hash160(key);
});
}
return [];
};
script.getInputScripthash = function getInputScripthash(s, prev) {
if (prev)
return script.getOutputScripthash(prev);
if (script.isScripthashInput(s))
return bcoin.address.hash160(s[s.length - 1]);
};
script.getOutputScripthash = function getOutputScripthash(s) {
if (script.isScripthash(s))
return s[1];
};
script.getInputAddress = function getInputAddress(s, prev) {
if (prev) if (prev)
return script.getOutputAddress(prev); return script.getOutputAddress(prev);
if (script.isPubkeyInput(s)) if (script.isPubkeyInput(s))
return; return;
if (script.isPubkeyhashInput(s)) if (script.isPubkeyhashInput(s)) {
return bcoin.address.compileData(s[1], 'pubkeyhash'); return bcoin.address.compileData(s[1],
isWitness ? 'witnesspubkeyhash' : 'pubkeyhash');
}
if (script.isMultisigInput(s)) if (script.isMultisigInput(s))
return; return;
if (script.isScripthashInput(s)) if (script.isScripthashInput(s)) {
return bcoin.address.compileData(s[s.length - 1], 'scripthash'); return bcoin.address.compileData(s[s.length - 1],
isWitness ? 'witnessscripthash' : 'scripthash');
}
}; };
script.getOutputAddress = function getOutputAddress(s) { script.getOutputAddress = function getOutputAddress(s) {
@ -1843,7 +1805,7 @@ script.getOutputAddress = function getOutputAddress(s) {
if (script.isWitnessProgram(s)) { if (script.isWitnessProgram(s)) {
program = script.getWitnessProgram(s); program = script.getWitnessProgram(s);
if (!program.type || program.type === 'witnessunknown') if (!program.type || program.type === 'unknown')
return; return;
return bcoin.address.compileHash(program.data, program.type); return bcoin.address.compileHash(program.data, program.type);
} }
@ -1865,43 +1827,6 @@ script.getOutputAddress = function getOutputAddress(s) {
return bcoin.address.compileHash(s[1], 'scripthash'); return bcoin.address.compileHash(s[1], 'scripthash');
}; };
script.getInputMN = function getInputMN(s, prev) {
if (prev) {
if (script.isScripthash(prev))
return script.getOutputMN(script.getRedeem(s));
return script.getOuputMN(prev);
}
if (script.isScripthashInput(s))
return script.getOutputMN(script.getRedeem(s));
return { m: 1, n: 1 };
};
script.getOuputMN = function getOuputMN(s) {
if (script.isMultisig(s))
return { m: s[0], n: s[s.length - 2] };
return { m: 1, n: 1 };
};
script.recoverKey = function recoverKey(sig, msg) {
var key;
try {
key = bcoin.ecdsa.recoverPubKey(msg, sig.slice(0, -1), 0);
} catch (e) {
return;
}
return new Buffer(bcoin.ecdsa.keyPair({ pub: key }).getPublic(true, 'array'));
};
script.guessKey = function guessKey(sig, prev, tx, i) {
var msg = tx.signatureHash(i, prev, sig[sig.length - 1]);
return script.recoverKey(sig, msg);
};
script.isPubkey = function isPubkey(s, key) { script.isPubkey = function isPubkey(s, key) {
var res; var res;
@ -2085,7 +2010,7 @@ script.getWitnessProgram = function getWitnessProgram(s) {
if (version > 0) { if (version > 0) {
// No interpretation of script (anyone can spend) // No interpretation of script (anyone can spend)
type = 'witnessunknown'; type = 'unknown';
} else if (version === 0 && data.length === 20) { } else if (version === 0 && data.length === 20) {
type = 'witnesspubkeyhash'; type = 'witnesspubkeyhash';
} else if (version === 0 && data.length === 32) { } else if (version === 0 && data.length === 32) {
@ -2146,28 +2071,14 @@ script.getInputType = function getInputType(s, prev, isWitness) {
return type; return type;
}; };
script.isPubkeyInput = function isPubkeyInput(s, key, tx, index) { script.isPubkeyInput = function isPubkeyInput(s, key) {
if (s.length !== 1) if (s.length !== 1)
return false; return false;
if (!script.isSignature(s[0])) if (!script.isSignature(s[0]))
return false; return false;
// Execute the script against our key's assert(!key);
// checksig script to see if this is our input.
// This will only work if the script verifies.
if (key) {
assert(tx);
assert(index != null);
if (!script.verify(s, [key, 'checksig'], tx, index))
return false;
}
// if (key) {
// var recovered;
// recovered = script.guessKey(s[0], [key, 'checksig'], tx, index);
// return utils.isEqual(key, recovered || []);
// }
return true; return true;
}; };
@ -2190,8 +2101,8 @@ script.isPubkeyhashInput = function isPubkeyhashInput(s, key) {
return true; return true;
}; };
script.isMultisigInput = function isMultisigInput(s, keys, tx, index) { script.isMultisigInput = function isMultisigInput(s, keys) {
var i, prev; var i;
// We need to rule out scripthash because // We need to rule out scripthash because
// it may look like multisig. This is // it may look like multisig. This is
@ -2211,38 +2122,7 @@ script.isMultisigInput = function isMultisigInput(s, keys, tx, index) {
return false; return false;
} }
// Execute the script against our pubkeys' assert(!keys);
// redeem script to see if this is our input.
// This will only work if the script verifies.
if (keys) {
assert(keys.length >= 2);
assert(tx);
assert(index != null);
prev = script.createMultisig(keys, s.length - 1, keys.length);
if (!script.verify(s, prev, tx, index))
return false;
}
// We can also try to recover the keys from the signatures.
// if (keys) {
// var prev, recovered, j, total;
// recovered = [];
// total = 0;
// for (i = 1; i < s.length; i++) {
// prev = script.createMultisig(keys, s.length - 1, keys.length);
// recovered.push(script.guessKey(s[i], prev, tx, index) || []);
// }
// for (i = 0; i < recovered.length; i++) {
// for (j = 0; j < keys.length; j++) {
// if (utils.isEqual(recovered[i], keys[j])) {
// total++;
// break;
// }
// }
// }
// if (total !== s.length - 1)
// return false;
// }
return true; return true;
}; };

View File

@ -30,14 +30,14 @@ function TX(data, block, index) {
this.ts = data.ts || 0; this.ts = data.ts || 0;
this.block = data.block || null; this.block = data.block || null;
this.index = data.index || -1; this.index = data.index || -1;
this._hash = null;
this._hash = null;
this._whash = null;
this._raw = data._raw || null; this._raw = data._raw || null;
this._wraw = data._wraw || null;
this._size = data._size || 0; this._size = data._size || 0;
this._offset = data._offset || 0; this._offset = data._offset || 0;
this._cost = data._cost || 0;
this.witness = data.witness || false; this._witness = data._witness || false;
this.height = data.height != null ? data.height : -1; this.height = data.height != null ? data.height : -1;
@ -62,19 +62,6 @@ function TX(data, block, index) {
this.setBlock(block, index); this.setBlock(block, index);
} }
} }
if (this.witness) {
this._wsize = this._raw.length;
this._wraw = this._raw;
this._raw = null;
this._size = 0;
}
if (!this._raw)
this._raw = this.render();
if (!this._size)
this._size = this._raw.length;
} }
TX.prototype.setBlock = function setBlock(block, index) { TX.prototype.setBlock = function setBlock(block, index) {
@ -103,8 +90,12 @@ TX.prototype.clone = function clone() {
// return output; // return output;
// }); // });
delete tx._witness;
delete tx._raw; delete tx._raw;
delete tx._size; delete tx._size;
delete tx._cost;
delete tx._hash;
delete tx._whash;
return tx; return tx;
}; };
@ -139,23 +130,47 @@ TX.prototype.hasWitness = function hasWitness() {
}; };
TX.prototype.render = function render() { TX.prototype.render = function render() {
if (!this._raw) { if (this._raw) {
this._raw = bcoin.protocol.framer.tx(this); if (!this._witness)
this._size = this._raw.length; return this._raw;
return bcoin.protocol.framer.tx(this);
} }
if (this.hasWitness())
return bcoin.protocol.framer.tx(this);
this._raw = bcoin.protocol.framer.tx(this);
this._size = this._raw.length;
this._witness = false;
return this._raw; return this._raw;
}; };
TX.prototype.renderWitness = function renderWitness() { TX.prototype.renderWitness = function renderWitness() {
if (!this._wraw) { if (this._raw) {
this._wraw = bcoin.protocol.framer.witnessTX(this); if (this._witness)
this._wsize = this._wraw.length; return this._raw;
return bcoin.protocol.framer.witnessTX(this);
} }
return this._wraw;
if (!this.hasWitness())
return bcoin.protocol.framer.witnessTX(this);
this._raw = bcoin.protocol.framer.witnessTX(this);
this._size = this._raw.length;
this._witness = true;
return this._raw;
}; };
TX.prototype.getSize = function getSize() { TX.prototype.getSize = function getSize() {
return this._size || this.render().length; return this.render().length;
};
TX.prototype.getCost = function getCost() {
if (!this._cost)
this._cost = this.renderWitness()._cost;
return this._cost;
}; };
TX.prototype._inputIndex = function _inputIndex(hash, index) { TX.prototype._inputIndex = function _inputIndex(hash, index) {
@ -266,19 +281,17 @@ TX.prototype.normalizedHash = function normalizedHash(enc, force) {
if (this.isCoinbase()) if (this.isCoinbase())
return this.hash(enc); return this.hash(enc);
if (!this._tbsHash || force) { if (!this._nhash || force) {
for (i = 0; i < copy.inputs.length; i++) { for (i = 0; i < copy.inputs.length; i++)
if (!copy.inputs[i].isCoinbase()) copy.inputs[i].script = [];
copy.inputs[i].script = [];
}
copy = bcoin.protocol.framer.tx(copy); copy = bcoin.protocol.framer.tx(copy);
this._tbsHash = utils.dsha256(copy); this._nhash = utils.dsha256(copy);
} }
return enc === 'hex' return enc === 'hex'
? utils.toHex(this._tbsHash) ? utils.toHex(this._nhash)
: this._tbsHash.slice(); : this._nhash.slice();
}; };
TX.prototype.verify = function verify(index, force, flags) { TX.prototype.verify = function verify(index, force, flags) {
@ -363,8 +376,7 @@ TX.prototype.getFunds = function getFunds(side) {
return this.getOutputValue(); return this.getOutputValue();
}; };
TX.prototype.testInputs = function testInputs(addressTable, index, collect) { TX.prototype.testInputs = function testInputs(addressTable, index) {
var inputs = [];
var i, input; var i, input;
if (typeof addressTable === 'string') if (typeof addressTable === 'string')
@ -389,24 +401,14 @@ TX.prototype.testInputs = function testInputs(addressTable, index, collect) {
input = this.inputs[i]; input = this.inputs[i];
if (input.test(addressTable)) { if (input.test(addressTable))
if (!collect) return true;
return true;
inputs.push(input);
}
} }
if (!collect) return false;
return false;
if (inputs.length === 0)
return false;
return inputs;
}; };
TX.prototype.testOutputs = function testOutputs(addressTable, index, collect) { TX.prototype.testOutputs = function testOutputs(addressTable, index) {
var outputs = [];
var i, output; var i, output;
if (typeof addressTable === 'string') if (typeof addressTable === 'string')
@ -431,20 +433,11 @@ TX.prototype.testOutputs = function testOutputs(addressTable, index, collect) {
output = this.outputs[i]; output = this.outputs[i];
if (output.test(addressTable)) { if (output.test(addressTable))
if (!collect) return true;
return true;
outputs.push(output);
}
} }
if (!collect) return false;
return false;
if (outputs.length === 0)
return false;
return outputs;
}; };
TX.prototype.hasPrevout = function hasPrevout() { TX.prototype.hasPrevout = function hasPrevout() {
@ -871,6 +864,7 @@ TX.prototype.toJSON = function toJSON() {
return { return {
type: this.type, type: this.type,
hash: utils.revHex(this.hash('hex')), hash: utils.revHex(this.hash('hex')),
witnessHash: utils.revHex(this.witnessHash('hex')),
height: this.height, height: this.height,
block: this.block ? utils.revHex(this.block) : null, block: this.block ? utils.revHex(this.block) : null,
ts: this.ts, ts: this.ts,

View File

@ -493,18 +493,18 @@ Wallet.prototype.getAddress = function getAddress() {
Wallet.prototype.ownInput = function ownInput(tx, index) { Wallet.prototype.ownInput = function ownInput(tx, index) {
if (tx instanceof bcoin.input) if (tx instanceof bcoin.input)
return tx.test(this.addressMap) ? [tx] : false; return tx.test(this.addressMap);
this.fillPrevout(tx); this.fillPrevout(tx);
return tx.testInputs(this.addressMap, index, true); return tx.testInputs(this.addressMap, index);
}; };
Wallet.prototype.ownOutput = function ownOutput(tx, index) { Wallet.prototype.ownOutput = function ownOutput(tx, index) {
if ((tx instanceof bcoin.output) || (tx instanceof bcoin.coin)) if ((tx instanceof bcoin.output) || (tx instanceof bcoin.coin))
return tx.test(this.addressMap) ? [tx] : false; return tx.test(this.addressMap);
return tx.testOutputs(this.addressMap, index, true); return tx.testOutputs(this.addressMap, index);
}; };
Wallet.prototype.fill = function fill(tx, options) { Wallet.prototype.fill = function fill(tx, options) {

View File

@ -100,7 +100,8 @@ var regtest = createGenesisBlock({
var segnet = createGenesisBlock({ var segnet = createGenesisBlock({
version: 1, version: 1,
ts: 1452368293, // ts: 1452368293,
ts: 1452831101,
bits: 0x1d00ffff, bits: 0x1d00ffff,
nonce: 0 nonce: 0
}); });
@ -109,13 +110,13 @@ utils.print(main);
utils.print(testnet); utils.print(testnet);
utils.print(regtest); utils.print(regtest);
utils.print(segnet); utils.print(segnet);
utils.print('main hash: %s', main.hash); utils.print('main hash: %s', utils.revHex(main.hash));
utils.print('main raw: %s', utils.toHex(main._raw)); utils.print('main raw: %s', utils.toHex(main._raw));
utils.print(''); utils.print('');
utils.print('testnet hash: %s', testnet.hash); utils.print('testnet hash: %s', utils.revHex(testnet.hash));
utils.print('testnet raw: %s', utils.toHex(testnet._raw)); utils.print('testnet raw: %s', utils.toHex(testnet._raw));
utils.print(''); utils.print('');
utils.print('regtest hash: %s', regtest.hash); utils.print('regtest hash: %s', utils.revHex(regtest.hash));
utils.print('regtest raw: %s', utils.toHex(regtest._raw)); utils.print('regtest raw: %s', utils.toHex(regtest._raw));
utils.print('segnet hash: %s', segnet.hash); utils.print('segnet hash: %s', utils.revHex(segnet.hash));
utils.print('segnet raw: %s', utils.toHex(segnet._raw)); utils.print('segnet raw: %s', utils.toHex(segnet._raw));

View File

@ -2,6 +2,7 @@ var assert = require('assert');
var bn = require('bn.js'); var bn = require('bn.js');
var bcoin = require('../'); var bcoin = require('../');
var constants = bcoin.protocol.constants; var constants = bcoin.protocol.constants;
var utils = bcoin.utils;
var dummyInput = { var dummyInput = {
prevout: { prevout: {
@ -52,9 +53,8 @@ describe('Wallet', function() {
}); });
src.addInput(dummyInput); src.addInput(dummyInput);
assert(w.ownOutput(src)); assert(w.ownOutput(src));
assert.equal(w.ownOutput(src).reduce(function(acc, out) { assert(w.ownOutput(src.outputs[0]));
return acc.iadd(out.value); assert(!w.ownOutput(src.outputs[1]));
}, new bn(0)).toString(10), 5460 * 2);
var tx = bcoin.mtx() var tx = bcoin.mtx()
.addInput(src, 0) .addInput(src, 0)
@ -87,9 +87,8 @@ describe('Wallet', function() {
}); });
src.addInput(dummyInput); src.addInput(dummyInput);
assert(w.ownOutput(src)); assert(w.ownOutput(src));
assert.equal(w.ownOutput(src).reduce(function(acc, out) { assert(w.ownOutput(src.outputs[0]));
return acc.iadd(out.value); assert(!w.ownOutput(src.outputs[1]));
}, new bn(0)).toString(10), 5460 * 2);
var tx = bcoin.mtx() var tx = bcoin.mtx()
.addInput(src, 0) .addInput(src, 0)
@ -387,4 +386,32 @@ describe('Wallet', function() {
cb(); cb();
}); });
var coinbase = '010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2c027156266a24aa21a9edb1e139795984903d6629ddedf3763fb9bc582fd68a46b1f8c7c57f9fbcc7fc900101ffffffff02887d102a0100000023210290dd626747729e1cc445cb9a11cfb7e78ea896db9f5c335e6730491d9ee7474dac0000000000000000266a24aa21a9edb1e139795984903d6629ddedf3763fb9bc582fd68a46b1f8c7c57f9fbcc7fc900120000000000000000000000000000000000000000000000000000000000000000000000000';
var chash = 'ba0cb2bf1aa19e4643208f7b38798a3deaa3320968d2cb1e42c5802a7baaba99';
var wpkh = '0100000001fc8f4ccd25b285bcae9f305d2ec3feb79a71384bab0303f810b58089b9c6e084000000006a473044022036548e256acfbc6a77f322d32ae0f11cb20a05a240d72550bda9d8cf169b35e90220303ad1a60d8297a12501dbebc46ec39c7652ac3d75ff394b8d4c3cbdaf3279c7012103f85883e08a3581b636bbafee55f337b6bf4467826a280fda5bf0533368e99b73ffffffff0200ba1dd2050000001976a91443cec67a63867420c0c934ffbbf89f14729304f988acf0cbf01907000000160014e7b8143685eb4eb03810c8ffb7c4a74d5f23161c00000000';
var whash = 'a72943c0131d655ff3d272f202d4f6ad2cf378eba9416c9b8028920d71d8f90a';
var w2hash = 'c532af06b9a81d9171618fb0b30075ddb3a6fca68c9b89536e6e34b0beddcc23';
// https://segnet.smartbit.com.au/tx/c532af06b9a81d9171618fb0b30075ddb3a6fca68c9b89536e6e34b0beddcc23
var w2pkh = new Buffer(bcoin.fs.readFileSync(__dirname + '/wtx.hex', 'ascii').trim(), 'hex');
it('should have a wtxid', function(cb) {
var src = bcoin.mtx({
outputs: [{
value: 5460 * 2,
address: bcoin.address.compileData(new Buffer([]))
}]
});
src.addInput(dummyInput);
console.log(src.toJSON());
var t = bcoin.protocol.parser.parseWitnessTX(new Buffer(coinbase, 'hex'));
utils.print(t);
var t = new bcoin.tx(bcoin.protocol.parser.parseWitnessTX(new Buffer(w2pkh, 'hex')));
utils.print(t);
delete t._raw;
delete t._hash;
delete t._whash;
cb();
});
}); });

2
test/wtx.hex Normal file

File diff suppressed because one or more lines are too long