segwit. misc.
This commit is contained in:
parent
5a8e2b80f3
commit
8467f339c1
@ -24,7 +24,9 @@ function Block(data) {
|
||||
bcoin.abstractblock.call(this, data);
|
||||
|
||||
this.type = 'block';
|
||||
this.witness = data.witness || false;
|
||||
|
||||
this._witness = data._witness || false;
|
||||
this._cost = data._cost || 0;
|
||||
|
||||
this.txs = data.txs || [];
|
||||
|
||||
@ -36,49 +38,45 @@ function Block(data) {
|
||||
|
||||
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);
|
||||
|
||||
Block.prototype.render = function render() {
|
||||
if (!this._raw) {
|
||||
this._raw = bcoin.protocol.framer.block(this);
|
||||
this._size = this._raw.length;
|
||||
if (this._raw) {
|
||||
if (!this._witness)
|
||||
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;
|
||||
};
|
||||
|
||||
Block.prototype.renderWitness = function renderWitness() {
|
||||
if (!this._wraw) {
|
||||
this._wraw = bcoin.protocol.framer.witnessBlock(this);
|
||||
this._wsize = this._wraw.length;
|
||||
if (this._raw) {
|
||||
if (this._witness)
|
||||
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;
|
||||
};
|
||||
|
||||
Block.prototype.getBlockCost = function getBlockCost() {
|
||||
Block.prototype.getCost = function getCost() {
|
||||
if (!this._cost)
|
||||
this._cost = this.renderWitness()._cost;
|
||||
|
||||
this._cost = this._renderWitness()._cost;
|
||||
return this._cost;
|
||||
};
|
||||
|
||||
@ -125,9 +123,6 @@ Block.prototype.getWitnessRoot = function getWitnessRoot() {
|
||||
Block.prototype.__defineGetter__('witnessRoot', function() {
|
||||
var coinbase, i, commitment, witnessRoot;
|
||||
|
||||
if (!block.witness)
|
||||
return;
|
||||
|
||||
if (this._witnessRoot)
|
||||
return this._witnessRoot;
|
||||
|
||||
|
||||
@ -117,6 +117,20 @@ Coin.prototype.__defineGetter__('age', function() {
|
||||
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() {
|
||||
return {
|
||||
version: this.version,
|
||||
|
||||
@ -69,6 +69,39 @@ Input.prototype.getType = function getType() {
|
||||
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() {
|
||||
var address;
|
||||
|
||||
@ -190,29 +223,34 @@ Input.prototype.getData = function getData() {
|
||||
};
|
||||
|
||||
Input.prototype.inspect = function inspect() {
|
||||
var data = this.getData();
|
||||
var output = this.output
|
||||
? this.output.inspect()
|
||||
: { type: 'unknown', value: '0.0' };
|
||||
var redeem = this.getRedeem();
|
||||
var output;
|
||||
|
||||
output.hash = utils.revHex(this.prevout.hash);
|
||||
output.index = this.prevout.index;
|
||||
if (this.output) {
|
||||
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 {
|
||||
type: this.getType(),
|
||||
subtype: data.subtype,
|
||||
subtype: this.getSubtype(),
|
||||
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),
|
||||
script: bcoin.script.format(data.script),
|
||||
redeem: data.redeem ? bcoin.script.format(data.redeem) : null,
|
||||
sequence: data.sequence,
|
||||
script: bcoin.script.format(this.script),
|
||||
witness: bcoin.script.format(this.witness),
|
||||
redeem: redeem ? bcoin.script.format(redeem) : null,
|
||||
sequence: this.sequence,
|
||||
output: output
|
||||
};
|
||||
};
|
||||
|
||||
@ -34,12 +34,6 @@ function MerkleBlock(data) {
|
||||
|
||||
// TXs that will be pushed on
|
||||
this.txs = [];
|
||||
|
||||
if (!this._raw)
|
||||
this._raw = this.render();
|
||||
|
||||
if (!this._size)
|
||||
this._size = this._raw.length;
|
||||
}
|
||||
|
||||
utils.inherits(MerkleBlock, bcoin.abstractblock);
|
||||
|
||||
@ -34,9 +34,11 @@ function MTX(options) {
|
||||
this.index = -1;
|
||||
|
||||
this._hash = null;
|
||||
this._whash = null;
|
||||
this._raw = null;
|
||||
this._size = 0;
|
||||
this._offset = 0;
|
||||
this._cost = 0;
|
||||
|
||||
this.height = -1;
|
||||
|
||||
@ -98,6 +100,10 @@ MTX.prototype.getSize = function getSize() {
|
||||
return this.render().length;
|
||||
};
|
||||
|
||||
MTX.prototype.getCost = function getCost() {
|
||||
return this.renderWitness()._cost;
|
||||
};
|
||||
|
||||
MTX.prototype.addInput = function addInput(options, index) {
|
||||
var input, i;
|
||||
|
||||
@ -1097,6 +1103,7 @@ MTX.prototype.toJSON = function toJSON() {
|
||||
return {
|
||||
type: 'mtx',
|
||||
hash: utils.revHex(this.hash('hex')),
|
||||
witnessHash: utils.revHex(this.witnessHash('hex')),
|
||||
height: this.height,
|
||||
block: this.block ? utils.revHex(this.block) : null,
|
||||
ts: this.ts,
|
||||
|
||||
@ -124,23 +124,11 @@ Output.prototype.getData = function getData() {
|
||||
};
|
||||
|
||||
Output.prototype.inspect = function inspect() {
|
||||
var data = this.getData();
|
||||
return {
|
||||
type: this.getType(),
|
||||
address: this.getAddress(),
|
||||
keys: data.keys.map(utils.toHex),
|
||||
hashes: data.hashes.map(utils.toHex),
|
||||
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)
|
||||
value: utils.btc(this.value),
|
||||
script: bcoin.script.format(this.script),
|
||||
address: this.getAddress()
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -211,6 +211,7 @@ exports.block = {
|
||||
exports.tx = {
|
||||
version: 1,
|
||||
maxSize: 100000,
|
||||
maxCost: 400000,
|
||||
minFee: 10000,
|
||||
bareMultisig: true,
|
||||
freeThreshold: exports.coin.muln(144).divn(250),
|
||||
|
||||
@ -422,7 +422,7 @@ segnet.halvingInterval = 210000;
|
||||
segnet.genesis = {
|
||||
version: 1,
|
||||
hash: utils.revHex(
|
||||
'ead13e4b1d0164b21128523156f729373d7a11bc9b6a1ee2e6e883ab9d9a728c'
|
||||
'0d5b9c518ddf053fcac71730830df4526a9949c08f34acf6a1d30464d22f02aa'
|
||||
),
|
||||
prevBlock: utils.toHex(
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@ -432,7 +432,7 @@ segnet.genesis = {
|
||||
merkleRoot: utils.revHex(
|
||||
'4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'
|
||||
),
|
||||
ts: 1452368293,
|
||||
ts: 1452831101,
|
||||
bits: 0x1d00ffff,
|
||||
nonce: 0
|
||||
};
|
||||
@ -457,4 +457,4 @@ segnet.block = {
|
||||
|
||||
segnet.segwitHeight = 0;
|
||||
|
||||
segnet.genesisBlock = '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4aa5619156ffff001d000000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000';
|
||||
segnet.genesisBlock = '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a7d719856ffff001d000000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000';
|
||||
|
||||
@ -357,7 +357,6 @@ Parser.parseBlock = function parseBlock(p) {
|
||||
}
|
||||
|
||||
return {
|
||||
witness: witness,
|
||||
version: utils.read32(p, 0),
|
||||
prevBlock: p.slice(4, 36),
|
||||
merkleRoot: p.slice(36, 68),
|
||||
@ -366,6 +365,7 @@ Parser.parseBlock = function parseBlock(p) {
|
||||
nonce: utils.readU32(p, 76),
|
||||
totalTX: totalTX,
|
||||
txs: txs,
|
||||
_witness: witness,
|
||||
_raw: p,
|
||||
_size: p.length,
|
||||
_cost: cost
|
||||
@ -587,11 +587,11 @@ Parser.parseTX = function parseTX(p) {
|
||||
off += 4;
|
||||
|
||||
return {
|
||||
witness: false,
|
||||
version: version,
|
||||
inputs: txIn,
|
||||
outputs: txOut,
|
||||
locktime: locktime,
|
||||
_witness: false,
|
||||
_cost: off * 4,
|
||||
_raw: p.length !== off ? p.slice(0, off) : p,
|
||||
_size: off
|
||||
@ -700,13 +700,13 @@ Parser.parseWitnessTX = function parseWitnessTX(p) {
|
||||
cost += 4 * 4;
|
||||
|
||||
return {
|
||||
witness: true,
|
||||
version: version,
|
||||
marker: marker,
|
||||
flag: flag,
|
||||
inputs: txIn,
|
||||
outputs: txOut,
|
||||
locktime: locktime,
|
||||
_witness: true,
|
||||
_raw: off !== p.length ? p.slice(0, off) : p,
|
||||
_size: off,
|
||||
_cost: cost
|
||||
|
||||
@ -288,7 +288,7 @@ script.normalize = function normalize(s) {
|
||||
};
|
||||
|
||||
script.verify = function verify(input, witness, output, tx, i, flags) {
|
||||
var copy, res, redeem;
|
||||
var copy, res, raw, redeem, hadWitness;
|
||||
var stack = [];
|
||||
|
||||
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()))
|
||||
return false;
|
||||
|
||||
if ((flags & constants.flags.VERIFY_WITNESS) && script.isWitnessProgram(output)) {
|
||||
if (!script.verifyProgram(input, witness, output, tx, i, flags))
|
||||
if ((flags & constants.flags.VERIFY_WITNESS)
|
||||
&& script.isWitnessProgram(output)) {
|
||||
hadWitness = true;
|
||||
|
||||
// Input script must be empty.
|
||||
if (input.length !== 0)
|
||||
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
|
||||
@ -333,12 +343,12 @@ script.verify = function verify(input, witness, output, tx, i, flags) {
|
||||
return false;
|
||||
|
||||
// Grab the real redeem script
|
||||
redeem = stack.pop();
|
||||
raw = stack.pop();
|
||||
|
||||
if (!Buffer.isBuffer(redeem))
|
||||
if (!Buffer.isBuffer(raw))
|
||||
return false;
|
||||
|
||||
redeem = script.decode(redeem);
|
||||
redeem = script.decode(raw);
|
||||
|
||||
// Execute the redeem script
|
||||
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()))
|
||||
return false;
|
||||
|
||||
if ((flags & constants.flags.VERIFY_WITNESS) && script.isWitnessProgram(redeem)) {
|
||||
if (!script.verifyProgram(input, witness, redeem, tx, i, flags))
|
||||
if ((flags & constants.flags.VERIFY_WITNESS)
|
||||
&& 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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
if (!(flags & constants.flags.VERIFY_WITNESS) || !script.isWitnessProgram(output))
|
||||
return true;
|
||||
assert((flags & constants.flags.VERIFY_WITNESS) !== 0);
|
||||
assert(script.isWitnessProgram(output));
|
||||
|
||||
program = script.getWitnessProgram(output);
|
||||
|
||||
@ -395,9 +423,6 @@ script.verifyProgram = function verifyProgram(input, witness, output, tx, i, fla
|
||||
stack = witness.slice();
|
||||
|
||||
if (program.type === 'witnesspubkeyhash') {
|
||||
if (input.length !== 0)
|
||||
return false;
|
||||
|
||||
if (stack.length !== 2)
|
||||
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()))
|
||||
return false;
|
||||
|
||||
// Witnesses always require cleanstack
|
||||
if (stack.length !== 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
@ -1750,92 +1779,25 @@ script.getUnknownData = function getUnknownData(s) {
|
||||
};
|
||||
};
|
||||
|
||||
script.getInputKeys = function getInputKeys(s, prev) {
|
||||
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) {
|
||||
script.getInputAddress = function getInputAddress(s, prev, isWitness) {
|
||||
if (prev)
|
||||
return script.getOutputAddress(prev);
|
||||
|
||||
if (script.isPubkeyInput(s))
|
||||
return;
|
||||
|
||||
if (script.isPubkeyhashInput(s))
|
||||
return bcoin.address.compileData(s[1], 'pubkeyhash');
|
||||
if (script.isPubkeyhashInput(s)) {
|
||||
return bcoin.address.compileData(s[1],
|
||||
isWitness ? 'witnesspubkeyhash' : 'pubkeyhash');
|
||||
}
|
||||
|
||||
if (script.isMultisigInput(s))
|
||||
return;
|
||||
|
||||
if (script.isScripthashInput(s))
|
||||
return bcoin.address.compileData(s[s.length - 1], 'scripthash');
|
||||
if (script.isScripthashInput(s)) {
|
||||
return bcoin.address.compileData(s[s.length - 1],
|
||||
isWitness ? 'witnessscripthash' : 'scripthash');
|
||||
}
|
||||
};
|
||||
|
||||
script.getOutputAddress = function getOutputAddress(s) {
|
||||
@ -1843,7 +1805,7 @@ script.getOutputAddress = function getOutputAddress(s) {
|
||||
|
||||
if (script.isWitnessProgram(s)) {
|
||||
program = script.getWitnessProgram(s);
|
||||
if (!program.type || program.type === 'witnessunknown')
|
||||
if (!program.type || program.type === 'unknown')
|
||||
return;
|
||||
return bcoin.address.compileHash(program.data, program.type);
|
||||
}
|
||||
@ -1865,43 +1827,6 @@ script.getOutputAddress = function getOutputAddress(s) {
|
||||
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) {
|
||||
var res;
|
||||
|
||||
@ -2085,7 +2010,7 @@ script.getWitnessProgram = function getWitnessProgram(s) {
|
||||
|
||||
if (version > 0) {
|
||||
// No interpretation of script (anyone can spend)
|
||||
type = 'witnessunknown';
|
||||
type = 'unknown';
|
||||
} else if (version === 0 && data.length === 20) {
|
||||
type = 'witnesspubkeyhash';
|
||||
} else if (version === 0 && data.length === 32) {
|
||||
@ -2146,28 +2071,14 @@ script.getInputType = function getInputType(s, prev, isWitness) {
|
||||
return type;
|
||||
};
|
||||
|
||||
script.isPubkeyInput = function isPubkeyInput(s, key, tx, index) {
|
||||
script.isPubkeyInput = function isPubkeyInput(s, key) {
|
||||
if (s.length !== 1)
|
||||
return false;
|
||||
|
||||
if (!script.isSignature(s[0]))
|
||||
return false;
|
||||
|
||||
// Execute the script against our key's
|
||||
// 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 || []);
|
||||
// }
|
||||
assert(!key);
|
||||
|
||||
return true;
|
||||
};
|
||||
@ -2190,8 +2101,8 @@ script.isPubkeyhashInput = function isPubkeyhashInput(s, key) {
|
||||
return true;
|
||||
};
|
||||
|
||||
script.isMultisigInput = function isMultisigInput(s, keys, tx, index) {
|
||||
var i, prev;
|
||||
script.isMultisigInput = function isMultisigInput(s, keys) {
|
||||
var i;
|
||||
|
||||
// We need to rule out scripthash because
|
||||
// it may look like multisig. This is
|
||||
@ -2211,38 +2122,7 @@ script.isMultisigInput = function isMultisigInput(s, keys, tx, index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Execute the script against our pubkeys'
|
||||
// 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;
|
||||
// }
|
||||
assert(!keys);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
116
lib/bcoin/tx.js
116
lib/bcoin/tx.js
@ -30,14 +30,14 @@ function TX(data, block, index) {
|
||||
this.ts = data.ts || 0;
|
||||
this.block = data.block || null;
|
||||
this.index = data.index || -1;
|
||||
this._hash = null;
|
||||
|
||||
this._hash = null;
|
||||
this._whash = null;
|
||||
this._raw = data._raw || null;
|
||||
this._wraw = data._wraw || null;
|
||||
this._size = data._size || 0;
|
||||
this._offset = data._offset || 0;
|
||||
|
||||
this.witness = data.witness || false;
|
||||
this._cost = data._cost || 0;
|
||||
this._witness = data._witness || false;
|
||||
|
||||
this.height = data.height != null ? data.height : -1;
|
||||
|
||||
@ -62,19 +62,6 @@ function TX(data, 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) {
|
||||
@ -103,8 +90,12 @@ TX.prototype.clone = function clone() {
|
||||
// return output;
|
||||
// });
|
||||
|
||||
delete tx._witness;
|
||||
delete tx._raw;
|
||||
delete tx._size;
|
||||
delete tx._cost;
|
||||
delete tx._hash;
|
||||
delete tx._whash;
|
||||
|
||||
return tx;
|
||||
};
|
||||
@ -139,23 +130,47 @@ TX.prototype.hasWitness = function hasWitness() {
|
||||
};
|
||||
|
||||
TX.prototype.render = function render() {
|
||||
if (!this._raw) {
|
||||
this._raw = bcoin.protocol.framer.tx(this);
|
||||
this._size = this._raw.length;
|
||||
if (this._raw) {
|
||||
if (!this._witness)
|
||||
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;
|
||||
};
|
||||
|
||||
TX.prototype.renderWitness = function renderWitness() {
|
||||
if (!this._wraw) {
|
||||
this._wraw = bcoin.protocol.framer.witnessTX(this);
|
||||
this._wsize = this._wraw.length;
|
||||
if (this._raw) {
|
||||
if (this._witness)
|
||||
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() {
|
||||
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) {
|
||||
@ -266,19 +281,17 @@ TX.prototype.normalizedHash = function normalizedHash(enc, force) {
|
||||
if (this.isCoinbase())
|
||||
return this.hash(enc);
|
||||
|
||||
if (!this._tbsHash || force) {
|
||||
for (i = 0; i < copy.inputs.length; i++) {
|
||||
if (!copy.inputs[i].isCoinbase())
|
||||
copy.inputs[i].script = [];
|
||||
}
|
||||
if (!this._nhash || force) {
|
||||
for (i = 0; i < copy.inputs.length; i++)
|
||||
copy.inputs[i].script = [];
|
||||
|
||||
copy = bcoin.protocol.framer.tx(copy);
|
||||
this._tbsHash = utils.dsha256(copy);
|
||||
this._nhash = utils.dsha256(copy);
|
||||
}
|
||||
|
||||
return enc === 'hex'
|
||||
? utils.toHex(this._tbsHash)
|
||||
: this._tbsHash.slice();
|
||||
? utils.toHex(this._nhash)
|
||||
: this._nhash.slice();
|
||||
};
|
||||
|
||||
TX.prototype.verify = function verify(index, force, flags) {
|
||||
@ -363,8 +376,7 @@ TX.prototype.getFunds = function getFunds(side) {
|
||||
return this.getOutputValue();
|
||||
};
|
||||
|
||||
TX.prototype.testInputs = function testInputs(addressTable, index, collect) {
|
||||
var inputs = [];
|
||||
TX.prototype.testInputs = function testInputs(addressTable, index) {
|
||||
var i, input;
|
||||
|
||||
if (typeof addressTable === 'string')
|
||||
@ -389,24 +401,14 @@ TX.prototype.testInputs = function testInputs(addressTable, index, collect) {
|
||||
|
||||
input = this.inputs[i];
|
||||
|
||||
if (input.test(addressTable)) {
|
||||
if (!collect)
|
||||
return true;
|
||||
inputs.push(input);
|
||||
}
|
||||
if (input.test(addressTable))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!collect)
|
||||
return false;
|
||||
|
||||
if (inputs.length === 0)
|
||||
return false;
|
||||
|
||||
return inputs;
|
||||
return false;
|
||||
};
|
||||
|
||||
TX.prototype.testOutputs = function testOutputs(addressTable, index, collect) {
|
||||
var outputs = [];
|
||||
TX.prototype.testOutputs = function testOutputs(addressTable, index) {
|
||||
var i, output;
|
||||
|
||||
if (typeof addressTable === 'string')
|
||||
@ -431,20 +433,11 @@ TX.prototype.testOutputs = function testOutputs(addressTable, index, collect) {
|
||||
|
||||
output = this.outputs[i];
|
||||
|
||||
if (output.test(addressTable)) {
|
||||
if (!collect)
|
||||
return true;
|
||||
outputs.push(output);
|
||||
}
|
||||
if (output.test(addressTable))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!collect)
|
||||
return false;
|
||||
|
||||
if (outputs.length === 0)
|
||||
return false;
|
||||
|
||||
return outputs;
|
||||
return false;
|
||||
};
|
||||
|
||||
TX.prototype.hasPrevout = function hasPrevout() {
|
||||
@ -871,6 +864,7 @@ TX.prototype.toJSON = function toJSON() {
|
||||
return {
|
||||
type: this.type,
|
||||
hash: utils.revHex(this.hash('hex')),
|
||||
witnessHash: utils.revHex(this.witnessHash('hex')),
|
||||
height: this.height,
|
||||
block: this.block ? utils.revHex(this.block) : null,
|
||||
ts: this.ts,
|
||||
|
||||
@ -493,18 +493,18 @@ Wallet.prototype.getAddress = function getAddress() {
|
||||
|
||||
Wallet.prototype.ownInput = function ownInput(tx, index) {
|
||||
if (tx instanceof bcoin.input)
|
||||
return tx.test(this.addressMap) ? [tx] : false;
|
||||
return tx.test(this.addressMap);
|
||||
|
||||
this.fillPrevout(tx);
|
||||
|
||||
return tx.testInputs(this.addressMap, index, true);
|
||||
return tx.testInputs(this.addressMap, index);
|
||||
};
|
||||
|
||||
Wallet.prototype.ownOutput = function ownOutput(tx, index) {
|
||||
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) {
|
||||
|
||||
@ -100,7 +100,8 @@ var regtest = createGenesisBlock({
|
||||
|
||||
var segnet = createGenesisBlock({
|
||||
version: 1,
|
||||
ts: 1452368293,
|
||||
// ts: 1452368293,
|
||||
ts: 1452831101,
|
||||
bits: 0x1d00ffff,
|
||||
nonce: 0
|
||||
});
|
||||
@ -109,13 +110,13 @@ utils.print(main);
|
||||
utils.print(testnet);
|
||||
utils.print(regtest);
|
||||
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('');
|
||||
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('');
|
||||
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('segnet hash: %s', segnet.hash);
|
||||
utils.print('segnet hash: %s', utils.revHex(segnet.hash));
|
||||
utils.print('segnet raw: %s', utils.toHex(segnet._raw));
|
||||
|
||||
@ -2,6 +2,7 @@ var assert = require('assert');
|
||||
var bn = require('bn.js');
|
||||
var bcoin = require('../');
|
||||
var constants = bcoin.protocol.constants;
|
||||
var utils = bcoin.utils;
|
||||
|
||||
var dummyInput = {
|
||||
prevout: {
|
||||
@ -52,9 +53,8 @@ describe('Wallet', function() {
|
||||
});
|
||||
src.addInput(dummyInput);
|
||||
assert(w.ownOutput(src));
|
||||
assert.equal(w.ownOutput(src).reduce(function(acc, out) {
|
||||
return acc.iadd(out.value);
|
||||
}, new bn(0)).toString(10), 5460 * 2);
|
||||
assert(w.ownOutput(src.outputs[0]));
|
||||
assert(!w.ownOutput(src.outputs[1]));
|
||||
|
||||
var tx = bcoin.mtx()
|
||||
.addInput(src, 0)
|
||||
@ -87,9 +87,8 @@ describe('Wallet', function() {
|
||||
});
|
||||
src.addInput(dummyInput);
|
||||
assert(w.ownOutput(src));
|
||||
assert.equal(w.ownOutput(src).reduce(function(acc, out) {
|
||||
return acc.iadd(out.value);
|
||||
}, new bn(0)).toString(10), 5460 * 2);
|
||||
assert(w.ownOutput(src.outputs[0]));
|
||||
assert(!w.ownOutput(src.outputs[1]));
|
||||
|
||||
var tx = bcoin.mtx()
|
||||
.addInput(src, 0)
|
||||
@ -387,4 +386,32 @@ describe('Wallet', function() {
|
||||
|
||||
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
2
test/wtx.hex
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user