refactor.

This commit is contained in:
Christopher Jeffrey 2016-04-04 02:53:55 -07:00
parent c874b9f2af
commit 79aa613662
7 changed files with 134 additions and 291 deletions

View File

@ -83,6 +83,7 @@ bcoin.debug = function debug() {
bcoin.utils = utils;
bcoin.utils.debug = bcoin.debug;
bcoin.utils.ensurePrefix = bcoin.ensurePrefix;
bcoin.bn = require('bn.js');
bcoin.locker = require('./bcoin/locker');
bcoin.reader = require('./bcoin/reader');
bcoin.writer = require('./bcoin/writer');

View File

@ -51,15 +51,11 @@ function Coin(tx, index) {
if (Buffer.isBuffer(this.hash))
this.hash = utils.toHex(this.hash);
// Object.freeze(this);
assert(typeof this.version === 'number');
assert(utils.isFinite(this.height));
assert(bn.isBN(this.value));
assert(this.script instanceof bcoin.script);
assert(typeof this.coinbase === 'boolean');
// assert(typeof this.hash === 'string');
// assert(utils.isFinite(this.index));
}
utils.inherits(Coin, bcoin.output);
@ -89,25 +85,17 @@ Coin.prototype.getAge = function getAge(height) {
return age;
};
Coin.prototype.__defineGetter__('confirmations', function() {
return this.getConfirmations();
});
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),
script: this.script,
coinbase: this.coinbase,
hash: this.hash ? utils.revHex(this.hash) : null,
index: this.index,
age: this.age,
age: this.getAge(),
address: this.getAddress()
};
};

View File

@ -19,8 +19,6 @@ function Input(options, tx) {
if (!(this instanceof Input))
return new Input(options);
assert(typeof options.script !== 'string');
this.prevout = options.prevout;
this.script = bcoin.script(options.script);
this.sequence = options.sequence == null ? 0xffffffff : options.sequence;
@ -67,24 +65,24 @@ Input.prototype.getType = function getType() {
};
Input.prototype.getRedeem = function getRedeem() {
var type, redeem;
var redeem = this.script;
var type;
if (this.isCoinbase())
return;
type = this.getType();
if (type === 'witnessscripthash')
return this.witness.getRedeem();
if (type === 'scripthash') {
redeem = this.script.getRedeem();
redeem = redeem.getRedeem();
if (!redeem)
return;
if (redeem.isWitnessScripthash())
return this.witness.getRedeem();
return redeem;
}
if (redeem.isWitnessScripthash())
redeem = this.witness.getRedeem();
return redeem;
};
Input.prototype.getSubtype = function getSubtype() {
@ -125,10 +123,6 @@ Input.prototype.getAddress = function getAddress() {
return address;
};
Input.prototype.isRBF = function isRBF() {
return this.sequence === 0xffffffff - 1;
};
Input.prototype.isFinal = function isFinal() {
return this.sequence === 0xffffffff;
};
@ -155,14 +149,7 @@ Input.prototype.test = function test(addressMap) {
return false;
};
Input.prototype.getID = function getID() {
var data = this.script.encode();
var hash = utils.toHex(utils.ripesha(data));
return '[' + this.type + ':' + hash.slice(0, 7) + ']';
};
Input.prototype.inspect = function inspect() {
var redeem = this.getRedeem();
var coin;
if (this.coin) {
@ -174,9 +161,9 @@ Input.prototype.inspect = function inspect() {
height: -1,
value: '0.0',
script: '',
coinbase: false,
hash: this.prevout.hash,
index: this.prevout.index,
spent: false,
age: 0,
address: null
};
@ -187,9 +174,9 @@ Input.prototype.inspect = function inspect() {
subtype: this.getSubtype(),
address: this.getAddress(),
value: utils.btc(coin.value),
script: bcoin.script.format(this.script),
witness: bcoin.script.format(this.witness),
redeem: redeem ? bcoin.script.format(redeem) : null,
script: this.script,
witness: this.witness,
redeem: this.getRedeem(),
sequence: this.sequence,
coin: coin
};
@ -225,7 +212,6 @@ Input.fromJSON = function fromJSON(json) {
return new Input(Input._fromJSON(json));
};
// NOTE: We cannot encode the witness here.
Input.prototype.toRaw = function toRaw(enc) {
var data = bcoin.protocol.framer.input(this);

View File

@ -187,7 +187,7 @@ MerkleBlock.isMerkleBlock = function isMerkleBlock(obj) {
&& typeof obj._verifyPartial === 'function';
};
MerkleBlock.prototype.fromBlock = function fromBlock(block, bloom) {
MerkleBlock.fromBlock = function fromBlock(block, bloom) {
var matches = [];
var txs = [];
var leaves = [];
@ -232,7 +232,7 @@ MerkleBlock.prototype.fromBlock = function fromBlock(block, bloom) {
var parent = 0;
var p;
for (p = pos << height; p < (pos + 1) << height && p < totalTX; p++)
for (p = (pos << height); p < ((pos + 1) << height) && p < totalTX; p++)
parent |= matches[p];
bits.push(parent);

View File

@ -19,8 +19,6 @@ function Output(options, tx) {
if (!(this instanceof Output))
return new Output(options);
assert(typeof options.script !== 'string');
value = options.value;
if (typeof value === 'number') {
@ -32,10 +30,8 @@ function Output(options, tx) {
this.script = bcoin.script(options.script);
this._mutable = !tx || (tx instanceof bcoin.mtx);
// For safety: do not allow usage of
// Numbers, do not allow negative values.
assert(typeof value !== 'number');
assert(!this.value.isNeg());
assert(!this._mutable || !this.value.isNeg());
}
Output.prototype.__defineGetter__('type', function() {
@ -92,17 +88,11 @@ Output.prototype.test = function test(addressMap) {
return false;
};
Output.prototype.getID = function getID() {
var data = this.script.encode();
var hash = utils.toHex(utils.ripesha(data));
return '[' + this.type + ':' + hash.slice(0, 7) + ']';
};
Output.prototype.inspect = function inspect() {
return {
type: this.getType(),
value: utils.btc(this.value),
script: bcoin.script.format(this.script),
script: this.script,
address: this.getAddress()
};
};

View File

@ -15,6 +15,10 @@ var STACK_TRUE = new Buffer([1]);
var STACK_FALSE = new Buffer([]);
var STACK_NEGATE = new Buffer([0xff]);
/**
* Witness
*/
function Witness(items) {
if (items instanceof Witness)
return items;
@ -45,36 +49,36 @@ Witness.prototype.toStack = function toStack() {
return new Stack(this.items.slice());
};
Witness.prototype.getInputType = function getInputType(prev) {
return Script.getInputType(this.items, prev, true);
Witness.prototype.getInputType = function getInputType() {
return Script.getInputType(this.items, true);
};
Witness.prototype.getInputAddress = function getInputAddress(prev) {
return Script.getInputAddress(this.items, prev, true);
Witness.prototype.getInputAddress = function getInputAddress() {
return Script.getInputAddress(this.items, true);
};
Witness.prototype.getInputHash = function getInputHash(prev) {
return Script.getInputHash(this.items, prev, true);
Witness.prototype.getInputHash = function getInputHash() {
return Script.getInputHash(this.items, true);
};
Witness.prototype.isPubkeyInput = function isPubkeyInput(key) {
return Script.isPubkeyInput(this.items, key);
Witness.prototype.isPubkeyInput = function isPubkeyInput() {
return Script.isPubkeyInput(this.items);
};
Witness.prototype.isPubkeyhashInput = function isPubkeyhashInput(hash) {
return Script.isPubkeyhashInput(this.items, hash);
Witness.prototype.isPubkeyhashInput = function isPubkeyhashInput() {
return Script.isPubkeyhashInput(this.items);
};
Witness.prototype.isMultisigInput = function isMultisigInput(keys) {
return Script.isMultisigInput(this.items, keys, true);
Witness.prototype.isMultisigInput = function isMultisigInput() {
return Script.isMultisigInput(this.items, true);
};
Witness.prototype.isScripthashInput = function isScripthashInput(redeem) {
return Script.isScripthashInput(this.items, redeem, true);
Witness.prototype.isScripthashInput = function isScripthashInput() {
return Script.isScripthashInput(this.items, true);
};
Witness.prototype.isUnknownInput = function isUnknownInput(prev) {
return Script.isUnknownInput(this.items, prev, true);
Witness.prototype.isUnknownInput = function isUnknownInput() {
return Script.isUnknownInput(this.items, true);
};
Witness.prototype.getRedeem = function getRedeem() {
@ -162,6 +166,10 @@ Witness.isWitness = function isWitness(obj) {
&& typeof obj.toStack === 'function';
};
/**
* Stack
*/
function Stack(items) {
this.items = items || [];
this.alt = [];
@ -550,14 +558,11 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
var code = this.code.slice();
var ip = 0;
var lastSep = -1;
var op, val;
var if_, else_, endif;
var op, val, if_, else_, endif;
var n, n1, n2, n3;
var res;
var key, sig, type, subscript, hash;
var res, key, sig, type, subscript, hash;
var keys, i, j, m;
var succ;
var locktime;
var succ, locktime;
if (flags == null)
flags = constants.flags.STANDARD_VERIFY_FLAGS;
@ -770,7 +775,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
return false;
}
if (typeof n === 'boolean')
n = new bn(n ? 1 : 0, 'le');
n = new bn(n ? 1 : 0);
stack.push(Script.array(n));
break;
}
@ -805,7 +810,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
throw new ScriptError('Stack too small.', op, ip);
n2 = Script.num(stack.pop(), flags);
n1 = Script.num(stack.pop(), flags);
n = new bn(0, 'le');
n = new bn(0);
switch (op) {
case opcodes.OP_ADD:
n = n1.add(n2);
@ -850,7 +855,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
return false;
}
if (typeof n === 'boolean')
n = new bn(n ? 1 : 0, 'le');
n = new bn(n ? 1 : 0);
res = Script.bool(n);
if (op === opcodes.OP_NUMEQUALVERIFY) {
if (!res)
@ -1473,14 +1478,11 @@ Script.prototype.getSize = function getSize() {
return this.encode().length;
};
Script.prototype.getInputAddress = function getInputAddress(prev) {
return Script.getInputAddress(this.code, prev, false);
Script.prototype.getInputAddress = function getInputAddress() {
return Script.getInputAddress(this.code, false);
};
Script.getInputAddress = function getInputAddress(code, prev, isWitness) {
if (prev)
return prev.getAddress();
Script.getInputAddress = function getInputAddress(code, isWitness) {
if (Script.isPubkeyInput(code))
return;
@ -1494,10 +1496,10 @@ Script.getInputAddress = function getInputAddress(code, prev, isWitness) {
return bcoin.address.compileData(code[1], 'pubkeyhash');
}
if (Script.isMultisigInput(code, null, isWitness))
if (Script.isMultisigInput(code, isWitness))
return;
if (Script.isScripthashInput(code, null, isWitness)) {
if (Script.isScripthashInput(code, isWitness)) {
if (isWitness) {
return bcoin.address.compileData(
code[code.length - 1],
@ -1536,27 +1538,24 @@ Script.prototype.getAddress = function getAddress() {
return bcoin.address.compileHash(this.code[1], 'scripthash');
};
Script.prototype.getInputHash = function getInputHash(prev) {
return Script.getInputHash(this.code, prev, false);
Script.prototype.getInputHash = function getInputHash() {
return Script.getInputHash(this.code, false);
};
Script.getInputHash = function getInputHash(prev, isWitness) {
if (prev)
return prev.getHash();
Script.getInputHash = function getInputHash(isWitness) {
if (Script.isPubkeyInput(code))
return;
if (Script.isPubkeyhashInput(code))
return utils.ripesha(code[1]);
return utils.toHex(utils.ripesha(code[1]));
if (Script.isMultisigInput(code, null, isWitness))
if (Script.isMultisigInput(code, isWitness))
return;
if (Script.isScripthashInput(code, null, isWitness)) {
if (Script.isScripthashInput(code, isWitness)) {
return isWitness
? utils.sha256(code[code.length - 1])
: utils.ripesha(code[code.length - 1]);
? utils.toHex(utils.sha256(code[code.length - 1]))
: utils.toHex(utils.ripesha(code[code.length - 1]));
}
};
@ -1567,67 +1566,39 @@ Script.prototype.getHash = function getHash() {
program = this.getWitnessProgram();
if (!program.type || program.type === 'unknown')
return;
return program.data;
return utils.toHex(program.data);
}
if (this.isPubkey())
return utils.ripesha(this.code[0]);
return utils.toHex(utils.ripesha(this.code[0]));
if (this.isPubkeyhash())
return this.code[2];
return utils.toHex(this.code[2]);
if (this.isMultisig())
return utils.ripesha(this.encode());
return utils.toHex(utils.ripesha(this.encode()));
if (this.isScripthash())
return this.code[1];
return utils.toHex(this.code[1]);
};
Script.prototype.isPubkey = function isPubkey(key) {
var res;
if (this.code.length !== 2)
return false;
res = Script.isKey(this.code[0]) && this.code[1] === opcodes.OP_CHECKSIG;
if (!res)
return false;
if (key) {
if (!utils.isEqual(this.code[0], key))
return false;
}
return true;
Script.prototype.isPubkey = function isPubkey() {
return this.code.length === 2
&& Script.isKey(this.code[0])
&& this.code[1] === opcodes.OP_CHECKSIG;
};
Script.prototype.isPubkeyhash = function isPubkeyhash(hash) {
var res;
if (this.code.length !== 5)
return false;
res = this.code[0] === opcodes.OP_DUP
Script.prototype.isPubkeyhash = function isPubkeyhash() {
return this.code.length === 5
&& this.code[0] === opcodes.OP_DUP
&& this.code[1] === opcodes.OP_HASH160
&& Script.isHash(this.code[2])
&& this.code[3] === opcodes.OP_EQUALVERIFY
&& this.code[4] === opcodes.OP_CHECKSIG;
if (!res)
return false;
if (hash) {
if (!utils.isEqual(this.code[2], hash))
return false;
}
return true;
};
Script.prototype.isMultisig = function isMultisig(keys) {
var m, n, i, j;
var total = 0;
Script.prototype.isMultisig = function isMultisig() {
var m, n, i;
if (this.code.length < 4)
return false;
@ -1656,71 +1627,29 @@ Script.prototype.isMultisig = function isMultisig(keys) {
return false;
}
if (keys) {
for (i = 1; i < n + 1; i++) {
for (j = 0; j < keys.length; j++) {
if (utils.isEqual(this.code[i], keys[j])) {
total++;
break;
}
}
}
if (total !== n)
return false;
}
return true;
};
Script.prototype.isScripthash = function isScripthash(hash) {
var res;
Script.prototype.isScripthash = function isScripthash() {
// Bitcoind requires strict
// minimaldata encoding for scripthash.
if (this.raw) {
if (hash) {
if (!Script.isHash(this.code[1]))
return false;
if (!utils.isEqual(this.code[1], hash))
return false;
}
return this.raw.length === 23
&& this.raw[0] === opcodes.OP_HASH160
&& this.raw[1] === 0x14
&& this.raw[22] === opcodes.OP_EQUAL;
}
if (this.code.length !== 3)
return false;
res = this.code[0] === opcodes.OP_HASH160
return this.code.length === 3
&& this.code[0] === opcodes.OP_HASH160
&& Script.isHash(this.code[1])
&& this.code[2] === opcodes.OP_EQUAL;
if (!res)
return false;
if (hash) {
if (!utils.isEqual(this.code[1], hash))
return false;
}
return true;
};
Script.prototype.isNulldata = function isNulldata() {
var res;
if (this.code.length !== 2)
return false;
res = this.code[0] === opcodes.OP_RETURN && Script.isData(this.code[1]);
if (!res)
return false;
return true;
return this.code.length === 2
&& this.code[0] === opcodes.OP_RETURN
&& Script.isData(this.code[1]);
};
Script.prototype.isCommitment = function isCommitment() {
@ -1795,11 +1724,11 @@ Script.prototype.isWitnessScripthash = function isWitnessScripthash() {
return this.code[0] === opcodes.OP_0 && this.code[1].length === 32;
};
Script.prototype.getInputType = function getInputType(prev) {
return Script.getInputType(this.code, prev);
Script.prototype.getInputType = function getInputType() {
return Script.getInputType(this.code);
};
Script.getInputType = function getInputType(code, prev, isWitness) {
Script.getInputType = function getInputType(code, isWitness) {
var type;
if (prev)
@ -1807,8 +1736,8 @@ Script.getInputType = function getInputType(code, prev, isWitness) {
type = (Script.isPubkeyInput(code) && 'pubkey')
|| (Script.isPubkeyhashInput(code) && 'pubkeyhash')
|| (Script.isMultisigInput(code, null, isWitness) && 'multisig')
|| (Script.isScripthashInput(code, null, isWitness) && 'scripthash')
|| (Script.isMultisigInput(code, isWitness) && 'multisig')
|| (Script.isScripthashInput(code, isWitness) && 'scripthash')
|| 'unknown';
if (isWitness) {
@ -1822,12 +1751,12 @@ Script.getInputType = function getInputType(code, prev, isWitness) {
return type;
};
Script.prototype.isUnknownInput = function isUnknownInput(prev) {
return Script.isUnknownInput(this.code, prev, false);
Script.prototype.isUnknownInput = function isUnknownInput() {
return Script.isUnknownInput(this.code, false);
};
Script.isUnknownInput = function isUnknownInput(code, prev, isWitness) {
return Script.getInputType(code, prev, isWitness) === 'unknown';
Script.isUnknownInput = function isUnknownInput(code, isWitness) {
return Script.getInputType(code, isWitness) === 'unknown';
};
Script.createOutputScript = function(options) {
@ -1903,56 +1832,34 @@ Script.createOutputScript = function(options) {
return script;
};
Script.prototype.isPubkeyInput = function isPubkeyInput(key) {
return Script.isPubkeyInput(this.code, key);
Script.prototype.isPubkeyInput = function isPubkeyInput() {
return Script.isPubkeyInput(this.code);
};
Script.isPubkeyInput = function isPubkeyInput(code, key) {
if (code.length !== 1)
return false;
if (!Script.isSignature(code[0]))
return false;
assert(!key);
return true;
Script.isPubkeyInput = function isPubkeyInput(code) {
return code.length === 1 && Script.isSignature(code[0]);
};
Script.prototype.isPubkeyhashInput = function isPubkeyhashInput(key) {
return Script.isPubkeyhashInput(this.code, key);
Script.prototype.isPubkeyhashInput = function isPubkeyhashInput() {
return Script.isPubkeyhashInput(this.code);
};
Script.isPubkeyhashInput = function isPubkeyhashInput(code, key) {
if (code.length !== 2)
return false;
if (!Script.isSignature(code[0]))
return false;
if (!Script.isKey(code[1]))
return false;
if (key) {
if (!utils.isEqual(code[1], key))
return false;
}
return true;
Script.isPubkeyhashInput = function isPubkeyhashInput(code) {
return code.length === 2
&& Script.isSignature(code[0])
&& Script.isKey(code[1]);
};
Script.prototype.isMultisigInput = function isMultisigInput(keys) {
return Script.isMultisigInput(this.code, keys);
Script.prototype.isMultisigInput = function isMultisigInput() {
return Script.isMultisigInput(this.code);
};
Script.isMultisigInput = function isMultisigInput(code, keys, isWitness) {
Script.isMultisigInput = function isMultisigInput(code, isWitness) {
var i;
// We need to rule out scripthash because
// it may look like multisig. This is
// strange because it's technically a
// recursive call.
if (Script.isScripthashInput(code, null, isWitness))
// We need to rule out scripthash
// because it may look like multisig.
if (Script.isScripthashInput(code, isWitness))
return false;
if (code.length < 3)
@ -1971,16 +1878,14 @@ Script.isMultisigInput = function isMultisigInput(code, keys, isWitness) {
return false;
}
assert(!keys);
return true;
};
Script.prototype.isScripthashInput = function isScripthashInput(redeem) {
return Script.isScripthashInput(this.code, redeem);
Script.prototype.isScripthashInput = function isScripthashInput() {
return Script.isScripthashInput(this.code);
};
Script.isScripthashInput = function isScripthashInput(code, redeem, isWitness) {
Script.isScripthashInput = function isScripthashInput(code, isWitness) {
var raw;
// Grab the raw redeem script.
@ -2001,11 +1906,6 @@ Script.isScripthashInput = function isScripthashInput(code, redeem, isWitness) {
if (!Buffer.isBuffer(raw))
return false;
// Check data against last array in case
// a raw redeem script was passed in.
if (redeem)
return utils.isEqual(redeem.encode(), raw);
// Testing for scripthash inputs requires
// some evil magic to work. We do it by
// ruling things _out_. This test will not
@ -2045,7 +1945,7 @@ Script.prototype.getCoinbaseData = function getCoinbaseData() {
if (Buffer.isBuffer(this.code[1]))
coinbase.extraNonce = new bn(this.code[1], 'le');
else
coinbase.extraNonce = new bn(0, 'le');
coinbase.extraNonce = new bn(0);
flags = this.code.slice(2).filter(function(chunk) {
return Buffer.isBuffer(chunk) && chunk.length !== 0;

View File

@ -1106,24 +1106,17 @@ TX.prototype.getConfirmations = function getConfirmations(height) {
return height - this.height + 1;
};
TX.prototype.getValue = function getValue() {
return this.getOutputValue();
};
TX.prototype.getPrevout = function getPrevout() {
var prevout = {};
TX.prototype.hasType = function hasType(type) {
var i;
if (this.isCoinbase())
return [];
for (i = 0; i < this.inputs.length; i++) {
if (this.inputs[i].getType() === type)
return true;
}
this.inputs.forEach(function(input) {
prevout[input.prevout.hash] = true;
});
for (i = 0; i < this.outputs.length; i++) {
if (this.outputs[i].getType() === type)
return true;
}
return false;
return Object.keys(prevout);
};
// See "Filter matching algorithm":
@ -1135,11 +1128,17 @@ TX.prototype.isWatched = function isWatched(bloom) {
return false;
function testScript(code) {
return code.some(function(chunk) {
var i, chunk;
for (i = 0; i < code.length; i++) {
chunk = code[i];
if (!Buffer.isBuffer(chunk) || chunk.length === 0)
return false;
return bloom.test(chunk);
});
continue;
if (bloom.test(chunk))
return true;
}
return false;
}
// 1. Test the tx hash
@ -1204,35 +1203,14 @@ TX.prototype.__defineGetter__('rwhash', function() {
return utils.revHex(this.witnessHash('hex'));
});
TX.prototype.__defineGetter__('fee', function() {
return this.getFee();
TX.prototype.__defineGetter__('txid', function() {
return this.rhash;
});
TX.prototype.__defineGetter__('value', function() {
return this.getValue();
TX.prototype.__defineGetter__('wtxid', function() {
return this.rwhash;
});
TX.prototype.__defineGetter__('confirmations', function() {
return this.getConfirmations();
});
TX.prototype.__defineGetter__('priority', function() {
return this.getPriority();
});
TX.prototype.getPrevout = function getPrevout() {
var prevout = {};
if (this.isCoinbase())
return [];
this.inputs.forEach(function(input) {
prevout[input.prevout.hash] = true;
});
return Object.keys(prevout);
};
TX.prototype.inspect = function inspect() {
return {
type: this.type,
@ -1241,7 +1219,7 @@ TX.prototype.inspect = function inspect() {
size: this.getSize(),
virtualSize: this.getVirtualSize(),
height: this.height,
value: utils.btc(this.getValue()),
value: utils.btc(this.getOutputValue()),
fee: utils.btc(this.getFee()),
minFee: utils.btc(this.getMinFee()),
confirmations: this.getConfirmations(),