new scripting system.

This commit is contained in:
Christopher Jeffrey 2016-03-14 19:45:11 -07:00
parent bf8475afe1
commit b528965912
13 changed files with 205 additions and 274 deletions

View File

@ -77,7 +77,7 @@ bcoin.ec = require('./bcoin/ec');
bcoin.lru = require('./bcoin/lru');
bcoin.protocol = require('./bcoin/protocol');
bcoin.bloom = require('./bcoin/bloom');
bcoin.script = require('./bcoin/script');
bcoin.script = require('./bcoin/script2');
bcoin.input = require('./bcoin/input');
bcoin.output = require('./bcoin/output');
bcoin.coin = require('./bcoin/coin');

View File

@ -111,13 +111,12 @@ Address.prototype.getScript = function getScript() {
assert(this.keys.length === this.n, 'Not all keys have been added.');
redeem = bcoin.script.createMultisig(this.keys, this.m, this.n);
redeem = bcoin.script.encode(redeem);
if (this.witness) {
if (redeem.length > 10000)
if (redeem.getSize() > 10000)
throw new Error('Redeem script too large (10000 byte limit).');
} else {
if (redeem.length > 520)
if (redeem.getSize() > 520)
throw new Error('Redeem script too large (520 byte limit).');
}
@ -140,12 +139,12 @@ Address.prototype.getProgram = function getProgram() {
0, Address.hash160(this.getPublicKey()));
} else if (this.type === 'multisig') {
program = bcoin.script.createWitnessProgram(
0, Address.sha256(this.getScript()));
0, Address.sha256(this.getScript().encode()));
}
assert(program);
this._program = bcoin.script.encode(program);
this._program = program;
return this._program;
};
@ -157,7 +156,7 @@ Address.prototype.getProgramHash = function getProgramHash() {
if (this._programHash)
return this._programHash;
this._programHash = Address.hash160(this.getProgram());
this._programHash = Address.hash160(this.getProgram().encode());
return this._programHash;
};
@ -186,7 +185,7 @@ Address.prototype.getScriptHash160 = function getScriptHash256() {
if (this._scriptHash160)
return this._scriptHash160;
this._scriptHash160 = Address.hash160(this.getScript());
this._scriptHash160 = Address.hash160(this.getScript().encode());
return this._scriptHash160;
};
@ -198,7 +197,7 @@ Address.prototype.getScriptHash256 = function getScriptHash256() {
if (this._scriptHash256)
return this._scriptHash256;
this._scriptHash256 = Address.sha256(this.getScript());
this._scriptHash256 = Address.sha256(this.getScript().encode());
return this._scriptHash256;
};

View File

@ -215,7 +215,7 @@ Block.prototype._verify = function _verify() {
};
Block.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
var coinbase, s, height;
var coinbase, code, height;
if (this.version < 2)
return -1;
@ -228,10 +228,10 @@ Block.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
if (!coinbase || coinbase.inputs.length === 0)
return -1;
s = coinbase.inputs[0].script;
code = coinbase.inputs[0].script.code;
if (Buffer.isBuffer(s[0]) && s[0].length <= 6)
height = new bn(s[0], 'le').toNumber();
if (Buffer.isBuffer(code[0]) && code[0].length <= 6)
height = new bn(code[0], 'le').toNumber();
else
height = -1;

View File

@ -60,7 +60,7 @@ function Coin(tx, index) {
assert(typeof this.version === 'number');
assert(utils.isFinite(this.height));
assert(this.value instanceof bn);
assert(Array.isArray(this.script));
assert(this.script instanceof bcoin.script);
assert(typeof this.hash === 'string');
assert(utils.isFinite(this.index));
assert(typeof this.spent === 'boolean');
@ -73,7 +73,7 @@ Coin.prototype.__defineGetter__('chain', function() {
});
Coin.prototype.getSize = function getSize() {
return 4 + 4 + 8 + bcoin.script.getSize(this.script) + 32 + 4 + 1;
return 4 + 4 + 8 + this.script.getSize() + 32 + 4 + 1;
};
Coin.prototype.getConfirmations = function getConfirmations(height) {
@ -136,7 +136,7 @@ Coin.prototype.toJSON = function toJSON() {
version: this.version,
height: this.height,
value: utils.btc(this.value),
script: utils.toHex(bcoin.script.encode(this.script)),
script: utils.toHex(this.script.encode()),
hash: utils.revHex(this.hash),
index: this.index,
spent: this.spent
@ -148,7 +148,7 @@ Coin._fromJSON = function _fromJSON(json) {
version: json.version,
height: json.height,
value: utils.satoshi(json.value),
script: bcoin.script.decode(new Buffer(json.script, 'hex')),
script: new bcoin.script(new Buffer(json.script, 'hex')),
hash: utils.revHex(json.hash),
index: json.index,
spent: json.spent

View File

@ -9,6 +9,7 @@ var bcoin = require('../bcoin');
var utils = bcoin.utils;
var assert = utils.assert;
var constants = bcoin.protocol.constants;
var Script = bcoin.script;
/**
* Input
@ -21,7 +22,7 @@ function Input(options, tx) {
assert(typeof options.script !== 'string');
this.prevout = options.prevout;
this.script = options.script || [];
this.script = options.script || new Script([]);
this.sequence = options.sequence == null ? 0xffffffff : options.sequence;
this.witness = options.witness || [];
this._size = options._size || 0;
@ -61,7 +62,7 @@ Input.prototype.getType = function getType() {
type = bcoin.script.getInputType(this.witness, null, true);
if (!type || type === 'unknown')
type = bcoin.script.getInputType(this.script);
type = this.script.getInputType();
if (!this._mutable)
this._type = type;
@ -81,8 +82,10 @@ Input.prototype.getRedeem = function getRedeem() {
return bcoin.script.getRedeem(this.witness);
if (type === 'scripthash') {
redeem = bcoin.script.getRedeem(this.script);
if (bcoin.script.isWitnessScripthash(redeem))
redeem = this.script.getRedeem();
if (!redeem)
return;
if (redeem.isWitnessScripthash())
return bcoin.script.getRedeem(this.witness);
return redeem;
}
@ -99,7 +102,7 @@ Input.prototype.getSubtype = function getSubtype() {
if (!redeem)
return;
return bcoin.script.getOutputType(redeem);
return redeem.getType();
};
Input.prototype.getAddress = function getAddress() {
@ -118,7 +121,7 @@ Input.prototype.getAddress = function getAddress() {
address = bcoin.script.getInputAddress(this.witness, null, true);
if (!address)
address = bcoin.script.getInputAddress(this.script);
address = this.script.getInputAddress();
if (!this._mutable)
this._address = address;
@ -142,13 +145,13 @@ Input.prototype.getLocktime = function getLocktime() {
output = this.output;
redeem = output.script;
if (bcoin.script.isScripthash(redeem))
redeem = bcoin.script.getRedeem(this.script);
if (redeem.isScripthash())
redeem = this.script.getRedeem();
if (redeem[1] !== 'checklocktimeverify')
return;
return bcoin.script.getLocktime(redeem);
return redeem.getLocktime();
};
Input.prototype.isCoinbase = function isCoinbase() {
@ -177,51 +180,12 @@ Input.prototype.test = function test(addressTable) {
return false;
};
Input.prototype.getSigops = function getSigops(scriptHash, accurate) {
var n = bcoin.script.getSigops(this.script, accurate);
if (scriptHash && !this.isCoinbase())
n += bcoin.script.getScripthashSigops(this.script);
return n;
};
Input.prototype.getID = function getID() {
var data = bcoin.script.encode(this.script);
var data = this.script.encode();
var hash = utils.toHex(utils.ripesha(data));
return '[' + this.type + ':' + hash.slice(0, 7) + ']';
};
Input.prototype.getData = function getData() {
var def, data;
assert(this instanceof Input);
def = {
side: 'input',
value: new bn(0),
script: this.script,
sequence: this.sequence
};
def.prev = this.prevout.hash;
def.index = this.prevout.index;
if (this.isCoinbase()) {
data = bcoin.script.getCoinbaseData(this.script);
return utils.merge(def, data, {
type: 'coinbase',
none: true
});
}
if (this.output) {
data = bcoin.script.getInputData(this.script, this.output.script);
data.value = this.output.value;
return utils.merge(def, data);
}
return utils.merge(def, bcoin.script.getInputData(this.script));
};
Input.prototype.inspect = function inspect() {
var redeem = this.getRedeem();
var output;
@ -262,7 +226,7 @@ Input.prototype.toJSON = function toJSON() {
index: this.prevout.index
},
output: this.output ? this.output.toJSON() : null,
script: utils.toHex(bcoin.script.encode(this.script)),
script: utils.toHex(this.script.encode()),
witness: utils.toHex(bcoin.protocol.framer.witness(this.witness)),
sequence: this.sequence
};
@ -275,7 +239,7 @@ Input._fromJSON = function _fromJSON(json) {
index: json.prevout.index
},
output: json.output ? bcoin.coin._fromJSON(json.output) : null,
script: bcoin.script.decode(new Buffer(json.script, 'hex')),
script: new Script(new Buffer(json.script, 'hex')),
witness: bcoin.protocol.parser.parseWitness(new Buffer(json.witness, 'hex')),
sequence: json.sequence
};

View File

@ -10,6 +10,7 @@ var bcoin = require('../bcoin');
var utils = bcoin.utils;
var assert = utils.assert;
var constants = bcoin.protocol.constants;
var Script = bcoin.script;
/**
* MTX
@ -140,7 +141,7 @@ MTX.prototype.addInput = function addInput(options, index) {
input = bcoin.input(options, this);
if (options.script)
input.script = options.script.slice();
input.script = options.script.clone();
if (options.witness)
input.witness = options.witness.slice();
@ -166,7 +167,7 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
// Optimization: Don't bother with any below
// calculation if the output is already templated.
// Just say this is "our" output.
if (input.script.length || input.witness.length)
if (input.script.code.length || input.witness.length)
return true;
// Optimization: test output against the
@ -182,67 +183,67 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
// This is easily the hardest part about building a transaction
// with segwit: figuring out where the redeem script and witness
// redeem scripts go.
if (bcoin.script.isScripthash(prev)) {
if (addr.program && utils.isEqual(prev[1], addr.programHash)) {
if (prev.isScripthash()) {
if (addr.program && utils.isEqual(prev.code[1], addr.programHash)) {
// Witness program nested in regular P2SH.
redeemScript = addr.program;
redeemScript = addr.program.encode();
vector = input.witness;
dummy = new Buffer([]);
assert(addr.program[0] === 0, 'Non-zero version passed to address.');
if (addr.program.length === 34) {
assert(addr.program.code[0] === 0, 'Non-zero version passed to address.');
if (addr.program.code[1].length === 32) {
// P2WSH nested within pay-to-scripthash
// (it had to be this complicated, didn't it?)
witnessScript = addr.script;
prev = bcoin.script.decode(addr.script);
} else if (addr.program.length === 22) {
witnessScript = addr.script.encode();
prev = addr.script;
} else if (addr.program.code[1].length === 20) {
// P2WPKH nested within pay-to-scripthash.
prev = bcoin.script.createPubkeyhash(addr.keyHash);
} else {
assert(false, 'Unknown program data length passed to address.');
}
} else if (addr.script && utils.isEqual(prev[1], addr.scriptHash160)) {
} else if (addr.script && utils.isEqual(prev.code[1], addr.scriptHash160)) {
// Regular P2SH.
redeemScript = addr.script;
prev = bcoin.script.decode(addr.script);
vector = input.script;
redeemScript = addr.script.encode();
vector = input.script.code;
prev = addr.script;
dummy = 0;
} else {
return false;
}
} else if (bcoin.script.isWitnessProgram(prev)) {
} else if (prev.isWitnessProgram()) {
// Witness program.
vector = input.witness;
dummy = new Buffer([]);
if (prev[0] !== 0)
if (prev.code[0] !== 0)
return false;
if (prev[1].length === 32) {
if (prev.code[1].length === 32) {
// Bare P2WSH.
if (!addr.script || !utils.isEqual(prev[1], addr.scriptHash256))
if (!addr.script || !utils.isEqual(prev.code[1], addr.scriptHash256))
return false;
witnessScript = addr.script;
prev = bcoin.script.decode(addr.script);
} else if (prev[1].length === 20) {
witnessScript = addr.script.encode();
prev = addr.script;
} else if (prev.code[1].length === 20) {
// Bare P2WPKH.
if (!utils.isEqual(prev[1], addr.keyHash))
if (!utils.isEqual(prev.code[1], addr.keyHash))
return false;
prev = bcoin.script.createPubkeyhash(prev[1]);
prev = bcoin.script.createPubkeyhash(prev.code[1]);
} else {
// Bare... who knows?
return false;
}
} else {
// Wow, a normal output! Praise be to Jengus and Gord.
vector = input.script;
vector = input.script.code;
dummy = 0;
}
if (bcoin.script.isPubkey(prev)) {
if (prev.isPubkey()) {
// P2PK
if (!utils.isEqual(prev[0], addr.publicKey))
if (!utils.isEqual(prev.code[0], addr.publicKey))
return false;
// Already has a script template (at least)
@ -250,9 +251,9 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
return true;
vector[0] = dummy;
} else if (bcoin.script.isPubkeyhash(prev)) {
} else if (prev.isPubkeyhash()) {
// P2PKH
if (!utils.isEqual(prev[2], addr.keyHash))
if (!utils.isEqual(prev.code[2], addr.keyHash))
return false;
// Already has a script template (at least)
@ -261,9 +262,9 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
vector[0] = dummy;
vector[1] = addr.publicKey;
} else if (bcoin.script.isMultisig(prev)) {
} else if (prev.isMultisig()) {
// Multisig
if (utils.indexOf(prev, addr.publicKey) === -1)
if (utils.indexOf(prev.code, addr.publicKey) === -1)
return false;
// Already has a script template (at least)
@ -276,13 +277,13 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
vector[0] = dummy;
// Grab `n` value (number of keys).
n = prev[prev.length - 2];
n = prev.code[prev.code.length - 2];
// Fill script with `n` signature slots.
for (i = 0; i < n; i++)
vector[i + 1] = dummy;
} else {
if (utils.indexOf(prev, addr.publicKey) === -1)
if (utils.indexOf(prev.code, addr.publicKey) === -1)
return false;
// Already has a script template (at least)
@ -296,8 +297,8 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
vector[0] = dummy;
// Fill script with `n` signature slots.
for (i = 0; i < prev.length; i++) {
if (bcoin.script.isKey(prev[i]))
for (i = 0; i < prev.code.length; i++) {
if (bcoin.script.isKey(prev.code[i]))
vector[i + 1] = dummy;
}
}
@ -305,7 +306,7 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
// P2SH requires the redeem
// script after signatures.
if (redeemScript)
input.script.push(redeemScript);
input.script.code.push(redeemScript);
// P2WSH requires the witness
// script after signatures.
@ -316,7 +317,7 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
};
MTX.prototype.createSignature = function createSignature(index, prev, key, type, version) {
var prev, hash, signature;
var hash, signature;
if (typeof index !== 'number')
index = this.inputs.indexOf(index);
@ -357,15 +358,15 @@ MTX.prototype.signInput = function signInput(index, addr, type) {
// Get the previous output's subscript
prev = input.output.script;
vector = input.script;
vector = input.script.code;
len = vector.length;
dummy = 0;
version = 0;
// We need to grab the redeem script when
// signing p2sh transactions.
if (bcoin.script.isScripthash(prev)) {
prev = bcoin.script.getRedeem(input.script);
if (prev.isScripthash()) {
prev = input.script.getRedeem();
len = vector.length - 1;
}
@ -375,14 +376,14 @@ MTX.prototype.signInput = function signInput(index, addr, type) {
// witnesses are stack items, so the `dummy`
// _has_ to be an empty buffer (what OP_0
// pushes onto the stack).
if (bcoin.script.isWitnessScripthash(prev)) {
if (prev.isWitnessScripthash()) {
prev = bcoin.script.getRedeem(input.witness);
vector = input.witness;
len = vector.length - 1;
dummy = new Buffer([]);
version = 1;
} else if (bcoin.script.isWitnessPubkeyhash(prev)) {
prev = bcoin.script.createPubkeyhash(prev[1]);
} else if (prev.isWitnessPubkeyhash()) {
prev = bcoin.script.createPubkeyhash(prev.code[1]);
vector = input.witness;
len = vector.length;
dummy = new Buffer([]);
@ -393,7 +394,7 @@ MTX.prototype.signInput = function signInput(index, addr, type) {
signature = this.createSignature(index, prev, addr.key, type, version);
// Add signatures.
if (bcoin.script.isPubkey(prev)) {
if (prev.isPubkey()) {
// P2PK
// Already signed.
@ -401,7 +402,7 @@ MTX.prototype.signInput = function signInput(index, addr, type) {
return true;
// Make sure the pubkey is ours.
if (!utils.isEqual(addr.publicKey, prev[0]))
if (!utils.isEqual(addr.publicKey, prev.code[0]))
return false;
vector[0] = signature;
@ -409,7 +410,7 @@ MTX.prototype.signInput = function signInput(index, addr, type) {
return true;
}
if (bcoin.script.isPubkeyhash(prev)) {
if (prev.isPubkeyhash()) {
// P2PKH
// Already signed.
@ -417,7 +418,7 @@ MTX.prototype.signInput = function signInput(index, addr, type) {
return true;
// Make sure the pubkey hash is ours.
if (!utils.isEqual(addr.keyHash, prev[2]))
if (!utils.isEqual(addr.keyHash, prev.code[2]))
return false;
vector[0] = signature;
@ -425,18 +426,18 @@ MTX.prototype.signInput = function signInput(index, addr, type) {
return true;
}
if (bcoin.script.isMultisig(prev)) {
if (prev.isMultisig()) {
// Multisig
// Grab the redeem script's keys to figure
// out where our key should go.
keys = prev.slice(1, -2);
keys = prev.code.slice(1, -2);
// Grab `m` value (number of sigs required).
m = prev[0];
m = prev.code[0];
// Grab `n` value (number of keys).
n = prev[prev.length - 2];
n = prev.code[prev.code.length - 2];
} else {
// Only allow non-standard signing for
// scripthash.
@ -445,9 +446,9 @@ MTX.prototype.signInput = function signInput(index, addr, type) {
keys = [];
for (i = 0; i < prev.length; i++) {
if (bcoin.script.isKey(prev[i]))
keys.push(prev[i]);
for (i = 0; i < prev.code.length; i++) {
if (bcoin.script.isKey(prev.code[i]))
keys.push(prev.code[i]);
}
// We don't know what m is, so
@ -573,7 +574,7 @@ MTX.prototype.addOutput = function addOutput(obj, value) {
this.outputs.push(output);
if (options.script)
output.script = options.script.slice();
output.script = options.script.clone();
this.scriptOutput(this.outputs.length - 1, options);
@ -629,10 +630,7 @@ MTX.prototype.scriptOutput = function scriptOutput(index, options) {
} else if (options.key) {
// P2PK Transaction
// [pubkey] checksig
script = [
utils.ensureBuffer(options.key),
'checksig'
];
script = bcoin.script.createPubkey(utils.ensureBuffer(options.key));
} else if (options.flags) {
// Nulldata Transaction
// return [data]
@ -648,13 +646,13 @@ MTX.prototype.scriptOutput = function scriptOutput(index, options) {
// hash160 [hash] eq
if (options.scriptHash) {
if (options.locktime != null) {
script = [
script = new Script([
bcoin.script.array(options.locktime),
'checklocktimeverify',
'drop'
].concat(script);
].concat(script.code));
}
hash = utils.ripesha(bcoin.script.encode(script));
hash = utils.ripesha(bcoin.script.encode(script.code));
script = bcoin.script.createScripthash(hash);
}
@ -668,7 +666,7 @@ MTX.prototype.maxSize = function maxSize(maxM, maxN) {
// Create copy with 0-script inputs
for (i = 0; i < copy.inputs.length; i++) {
copy.inputs[i].script = [];
copy.inputs[i].script = new Script([]);
copy.inputs[i].witness = [];
}
@ -687,50 +685,48 @@ MTX.prototype.maxSize = function maxSize(maxM, maxN) {
// If we have access to the redeem script,
// we can use it to calculate size much easier.
if (this.inputs[i].script.length && bcoin.script.isScripthash(prev)) {
if (this.inputs[i].script.code.length && prev.isScripthash()) {
// Need to add the redeem script size
// here since it will be ignored by
// the isMultisig clause.
// OP_PUSHDATA2 [redeem]
prev = this.inputs[i].script[this.inputs[i].script.length - 1];
size += utils.sizeIntv(prev.length) + prev.length;
prev = bcoin.script.decode(prev);
prev = this.inputs[i].getRedeem();
size += utils.sizeIntv(prev.getSize()) + prev.getSize();
}
if (bcoin.script.isWitnessProgram(prev)) {
if (prev.isWitnessProgram()) {
witness = true;
// Now calculating vsize. The regular
// redeem script (if there was one)
// is now worth 4 points.
size *= 4;
if (this.inputs[i].witness.length && bcoin.script.isWitnessScripthash(prev)) {
prev = this.inputs[i].witness[this.inputs[i].witness.length - 1];
size += utils.sizeIntv(prev.length) + prev.length;
prev = bcoin.script.decode(prev);
} else if (bcoin.script.isWitnessPubkeyhash(prev)) {
prev = bcoin.script.createPubkeyhash(prev[1]);
if (this.inputs[i].witness.length && prev.isWitnessScripthash()) {
prev = bcoin.script.getRedeem(this.inputs[i].witness);
size += utils.sizeIntv(prev.getSize()) + prev.getSize();
} else if (prev.isWitnessPubkeyhash()) {
prev = bcoin.script.createPubkeyhash(prev.code[1]);
}
}
if (bcoin.script.isPubkey(prev)) {
if (prev.isPubkey()) {
// P2PK
// OP_PUSHDATA0 [signature]
size += 1 + 73;
} else if (bcoin.script.isPubkeyhash(prev)) {
} else if (prev.isPubkeyhash()) {
// P2PKH
// OP_PUSHDATA0 [signature]
size += 1 + 73;
// OP_PUSHDATA0 [key]
size += 1 + 33;
} else if (bcoin.script.isMultisig(prev)) {
} else if (prev.isMultisig()) {
// Bare Multisig
// Get the previous m value:
m = prev[0];
m = prev.code[0];
// OP_0
size += 1;
// OP_PUSHDATA0 [signature] ...
size += (1 + 73) * m;
} else if (bcoin.script.isScripthash(prev)) {
} else if (prev.isScripthash()) {
// P2SH Multisig
// This technically won't work well for other
// kinds of P2SH. It will also over-estimate
@ -760,8 +756,8 @@ MTX.prototype.maxSize = function maxSize(maxM, maxN) {
size += 1;
} else {
// OP_PUSHDATA0 [signature]
for (j = 0; j < prev.length; j++) {
if (bcoin.script.isKey(prev[j]))
for (j = 0; j < prev.code.length; j++) {
if (bcoin.script.isKey(prev.code[j]))
size += 1 + 73;
}
}
@ -986,8 +982,8 @@ MTX.prototype.sortMembers = function sortMembers() {
if (res !== 0)
return res;
a = bcoin.script.encode(a.script);
b = bcoin.script.encode(b.script);
a = a.encode();
b = b.encode();
return utils.cmp(a, b);
});

View File

@ -9,6 +9,7 @@ var bcoin = require('../bcoin');
var utils = bcoin.utils;
var assert = utils.assert;
var constants = bcoin.protocol.constants;
var Script = bcoin.script;
/**
* Output
@ -30,7 +31,7 @@ function Output(options, tx) {
}
this.value = utils.satoshi(value || new bn(0));
this.script = options.script || [];
this.script = options.script || new Script([]);
this._size = options._size || 0;
this._offset = options._offset || 0;
this._mutable = !tx || (tx instanceof bcoin.mtx);
@ -57,7 +58,7 @@ Output.prototype.getType = function getType() {
if (this._type)
return this._type;
type = bcoin.script.getOutputType(this.script);
type = this.script.getType();
if (!this._mutable)
this._type = type;
@ -71,7 +72,7 @@ Output.prototype.getAddress = function getAddress() {
if (this._address)
return this._address;
address = bcoin.script.getOutputAddress(this.script);
address = this.script.getAddress();
if (!this._mutable)
this._address = address;
@ -101,28 +102,12 @@ Output.prototype.test = function test(addressTable) {
return false;
};
Output.prototype.getSigops = function getSigops(accurate) {
return bcoin.script.getSigops(this.script, accurate);
};
Output.prototype.getID = function getID() {
var data = bcoin.script.encode(this.script);
var data = this.script.encode();
var hash = utils.toHex(utils.ripesha(data));
return '[' + this.type + ':' + hash.slice(0, 7) + ']';
};
Output.prototype.getData = function getData() {
var def;
def = {
side: 'output',
value: this.value,
script: this.script
};
return utils.merge(def, bcoin.script.getOutputData(this.script));
};
Output.prototype.inspect = function inspect() {
return {
type: this.getType(),
@ -135,14 +120,14 @@ Output.prototype.inspect = function inspect() {
Output.prototype.toJSON = function toJSON() {
return {
value: utils.btc(this.value),
script: utils.toHex(bcoin.script.encode(this.script))
script: utils.toHex(this.script.encode())
};
};
Output._fromJSON = function _fromJSON(json) {
return {
value: utils.satoshi(json.value),
script: bcoin.script.decode(new Buffer(json.script, 'hex'))
script: new Script(new Buffer(json.script, 'hex'))
};
};

View File

@ -380,18 +380,16 @@ Framer._getBlocks = function _getBlocks(hashes, stop) {
Framer.input = function _input(input) {
var off = 0;
var s, p;
var script, p;
s = bcoin.script.encode(input.script);
p = new Buffer(32 + 4 + utils.sizeIntv(s.length) + s.length + 4);
script = input.script.encode();
p = new Buffer(32 + 4 + utils.sizeIntv(script.length) + script.length + 4);
off += utils.copy(new Buffer(input.prevout.hash, 'hex'), p, off);
off += utils.writeU32(p, input.prevout.index, off);
off += utils.writeIntv(p, s.length, off);
if (!s.copy)
console.log(s);
off += utils.copy(s, p, off);
off += utils.writeIntv(p, script.length, off);
off += utils.copy(script, p, off);
off += utils.writeU32(p, input.sequence, off);
@ -400,23 +398,23 @@ Framer.input = function _input(input) {
Framer.output = function _output(output) {
var off = 0;
var s, p;
var script, p;
s = bcoin.script.encode(output.script);
p = new Buffer(8 + utils.sizeIntv(s.length) + s.length);
script = output.script.encode();
p = new Buffer(8 + utils.sizeIntv(script.length) + script.length);
off += utils.write64(p, output.value, off);
assert(output.value.byteLength() <= 8);
off += utils.writeIntv(p, s.length, off);
off += utils.copy(s, p, off);
off += utils.writeIntv(p, script.length, off);
off += utils.copy(script, p, off);
return p;
};
Framer.utxo =
Framer.coin = function _coin(coin, extended) {
var script = bcoin.script.encode(coin.script);
var script = coin.script.encode();
var intSize = utils.sizeIntv(script.length);
var height = coin.height;
var off = 0;

View File

@ -356,7 +356,7 @@ Parser.parseBlockCompact = function parseBlockCompact(p) {
var height = -1;
var version, prevBlock, merkleRoot, ts, bits, nonce;
var i, totalTX, tx;
var inCount, input, s, raw;
var inCount, input, raw;
p = new BufferReader(p);
p.start();
@ -379,9 +379,8 @@ Parser.parseBlockCompact = function parseBlockCompact(p) {
}
if (input) {
s = input.script;
if (Buffer.isBuffer(s[0]))
height = s[0];
if (Buffer.isBuffer(input.script.code[0]))
height = input.script.code[0];
}
raw = p.data;
@ -411,7 +410,7 @@ Parser.parseInput = function parseInput(p) {
hash = p.readHash();
index = p.readU32();
script = bcoin.script.decode(p.readVarBytes());
script = new bcoin.script(p.readVarBytes());
sequence = p.readU32();
return {
@ -432,7 +431,7 @@ Parser.parseOutput = function parseOutput(p) {
p.start();
value = p.read64();
script = bcoin.script.decode(p.readVarBytes());
script = new bcoin.script(p.readVarBytes());
return {
_size: p.end(),
@ -443,6 +442,7 @@ Parser.parseOutput = function parseOutput(p) {
Parser.parseCoin = function parseCoin(p, extended) {
var version, height, value, script, hash, index, spent;
p = new BufferReader(p);
version = p.readU32();
@ -453,12 +453,12 @@ Parser.parseCoin = function parseCoin(p, extended) {
value = p.read64();
script = bcoin.script.decode(p.readVarBytes());
script = new bcoin.script(p.readVarBytes());
if (extended) {
hash = p.readHash();
index = p.readU32();
spent = p.readU8();
spent = p.readU8() === 1;
} else {
hash = utils.slice(constants.zeroHash);
index = 0xffffffff;
@ -527,7 +527,7 @@ Parser.isWitnessTX = function isWitnessTX(p) {
if (p.left() < 12)
return false;
return p[p.offset + 4] === 0 && p[p.offset + 5] !== 0;
return p.data[p.offset + 4] === 0 && p.data[p.offset + 5] !== 0;
};
Parser.parseWitnessTX = function parseWitnessTX(p) {
@ -822,7 +822,7 @@ BufferReader.prototype.read64BE = function read64BE() {
};
BufferReader.prototype.readBytes = function readBytes(size) {
assert(size > 0)
assert(size >= 0);
assert(this.offset + size <= this.data.length);
var ret = utils.slice(this.data, this.offset, this.offset + size);
this.offset += size;
@ -830,7 +830,7 @@ BufferReader.prototype.readBytes = function readBytes(size) {
};
BufferReader.prototype.readString = function readString(enc, size) {
assert(size > 0)
assert(size >= 0);
assert(this.offset + size <= this.data.length);
var ret = this.data.toString(enc, this.offset, this.offset + size);
this.offset += size;

View File

@ -10,6 +10,7 @@ var bcoin = require('../bcoin');
var utils = bcoin.utils;
var assert = utils.assert;
var constants = bcoin.protocol.constants;
var Script = bcoin.script;
/**
* TX
@ -172,19 +173,6 @@ TX.prototype._inputIndex = function _inputIndex(hash, index) {
return -1;
};
TX.prototype.getSubscript = function getSubscript(index) {
var script;
if (typeof index !== 'number')
index = this.outputs.indexOf(index);
assert(this.outputs[index]);
script = this.outputs[index].script;
return bcoin.script.getSubscript(script);
};
TX.prototype.signatureHash = function signatureHash(index, s, type, version) {
assert(version >= 0 && version <= 1);
if (version === 0)
@ -206,7 +194,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, s, type) {
for (i = 0; i < this.inputs.length; i++) {
copy.inputs.push({
prevout: this.inputs[i].prevout,
script: this.inputs[i].script.slice(),
script: this.inputs[i].script.clone(),
witness: this.inputs[i].witness.slice(),
sequence: this.inputs[i].sequence
});
@ -215,7 +203,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, s, type) {
for (i = 0; i < this.outputs.length; i++) {
copy.outputs.push({
value: this.outputs[i].value,
script: this.outputs[i].script.slice()
script: this.outputs[i].script.clone()
});
}
@ -226,7 +214,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, s, type) {
type = constants.hashType[type];
assert(index >= 0 && index < copy.inputs.length)
assert(Array.isArray(s));
assert(s instanceof bcoin.script);
// Disable this for now. We allow null hash types
// because bitcoind allows empty signatures. On
@ -236,7 +224,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, s, type) {
// Remove all signatures.
for (i = 0; i < copy.inputs.length; i++)
copy.inputs[i].script = [];
copy.inputs[i].script = new Script([]);
// Set our input to previous output's script
copy.inputs[index].script = s;
@ -262,7 +250,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, s, type) {
// Null outputs that are not the at current input index.
for (i = 0; i < copy.outputs.length; i++) {
if (i !== index) {
copy.outputs[i].script = [];
copy.outputs[i].script = new Script([]);
copy.outputs[i].value = new bn('ffffffffffffffff', 'hex');
}
}
@ -302,7 +290,7 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, s, type) {
type = constants.hashType[type];
assert(index >= 0 && index < this.inputs.length)
assert(Array.isArray(s));
assert(s instanceof bcoin.script);
if (!(type & constants.hashType.anyonecanpay)) {
hashPrevouts = new Buffer(36 * this.inputs.length);
@ -353,7 +341,7 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, s, type) {
hashOutputs.fill(0);
}
s = bcoin.script.encode(s);
s = s.encode();
msg = new Buffer(
4 + 32 + 32 + 36
@ -666,23 +654,23 @@ TX.prototype._getSigops = function _getSigops(scriptHash, accurate) {
prev = input.output.script;
total += bcoin.script.getSigops(input.script, accurate);
total += input.script.getSigops(accurate);
if (scriptHash && !this.isCoinbase()) {
if (!bcoin.script.isScripthash(prev))
if (!prev.isScripthash())
return;
if (!bcoin.script.isPushOnly(input.script))
if (!input.script.isPushOnly())
return;
prev = bcoin.script.getRedeem(input.script);
prev = input.script.getRedeem();
total += bcoin.script.getSigops(prev, true);
total += prev.getSigops(true);
}
}, this);
this.outputs.forEach(function(output) {
total += bcoin.script.getSigops(output.script, accurate);
total += output.script.getSigops(accurate);
}, this);
return total;
@ -699,19 +687,19 @@ TX.prototype.getSigops = function getSigops(scriptHash, accurate) {
prev = input.output.script;
if (bcoin.script.isScripthash(prev))
prev = bcoin.script.getRedeem(input.script);
if (prev.isScripthash())
prev = input.script.getRedeem();
if (bcoin.script.isWitnessScripthash(prev)) {
if (prev.isWitnessScripthash()) {
prev = bcoin.script.getRedeem(input.witness);
cost += bcoin.script.getSigops(prev, true);
cost += prev.getSigops(true);
} else {
cost += 0;
}
}, this);
this.outputs.forEach(function(output) {
if (bcoin.script.isWitnessPubkeyhash(output.script))
if (output.script.isWitnessPubkeyhash())
cost += 1;
else
cost += 0;
@ -736,7 +724,7 @@ TX.prototype.isStandard = function isStandard(flags) {
for (i = 0; i < this.inputs.length; i++) {
input = this.inputs[i];
if (bcoin.script.getSize(input.script) > 1650)
if (input.script.getSize() > 1650)
return false;
// Not accurate?
@ -744,16 +732,16 @@ TX.prototype.isStandard = function isStandard(flags) {
continue;
if (flags & constants.flags.VERIFY_SIGPUSHONLY) {
if (!bcoin.script.isPushOnly(input.script))
if (!input.script.isPushOnly())
return false;
}
}
for (i = 0; i < this.outputs.length; i++) {
output = this.outputs[i];
type = bcoin.script.getType(output.script);
type = output.script.getType();
if (!bcoin.script.isStandard(output.script))
if (!output.script.isStandard())
return false;
if (type === 'unknown')
@ -793,7 +781,7 @@ TX.prototype.isStandardInputs = function isStandardInputs(flags) {
if (!input.output)
return false;
args = bcoin.script.getArgs(input.output.script);
args = input.output.script.getArgs();
if (args < 0)
return false;
@ -803,10 +791,10 @@ TX.prototype.isStandardInputs = function isStandardInputs(flags) {
// Bitcoind doesn't do this, but it's possible someone
// could DoS us by sending ridiculous txs to the mempool
// if we don't put this here.
if (!bcoin.script.isPushOnly(input.script))
if (!input.script.isPushOnly())
return false;
res = bcoin.script.execute(input.script, stack, this, i, flags);
res = input.script.execute(stack, this, i, flags);
// TODO: Segwit here.
@ -814,29 +802,27 @@ TX.prototype.isStandardInputs = function isStandardInputs(flags) {
return false;
if ((flags & constants.flags.VERIFY_P2SH)
&& bcoin.script.isScripthash(input.output.script)) {
&& input.output.script.isScripthash()) {
if (stack.length === 0)
return false;
redeem = stack.pop();
redeem = bcoin.script.getRedeem(stack);
if (!Buffer.isBuffer(redeem))
if (!redeem)
return false;
// Not accurate?
if (redeem.length > 520)
if (redeem.getSize() > 520)
return false;
redeem = bcoin.script.decode(redeem);
// Also consider scripthash "unknown"?
if (bcoin.script.getType(redeem) === 'unknown') {
if (bcoin.script.getSigops(redeem, true) > maxSigops)
if (redeem.getType() === 'unknown') {
if (redeem.getSigops(true) > maxSigops)
return false;
continue;
}
targs = bcoin.script.getArgs(redeem);
targs = redeem.getArgs();
if (targs < 0)
return false;
args += targs;
@ -942,11 +928,11 @@ TX.prototype.getValue = function getValue() {
TX.prototype.hasType = function hasType(type) {
for (var i = 0; i < this.inputs.length; i++) {
if (bcoin.script.getInputType(this.inputs[i].script) === type)
if (this.inputs[i].getInputType() === type)
return true;
}
for (var i = 0; i < this.outputs.length; i++) {
if (bcoin.script.getType(this.outputs[i].script) === type)
if (this.outputs[i].getType() === type)
return true;
}
return false;

View File

@ -179,6 +179,6 @@ describe('Protocol', function() {
'de5c0500000017a9141d9ca71efa36d814424ea6ca1437e67287aebe348' +
'700000000', 'hex');
var tx = bcoin.protocol.parser.parseTX(rawTwoTxs);
assert.deepEqual(tx._raw, rawFirstTx);
assert.deepEqual(bcoin.protocol.framer.tx(tx), rawFirstTx);
});
});

View File

@ -1,5 +1,6 @@
var assert = require('assert');
var bcoin = require('../');
var Script = bcoin.script;
describe('Script', function() {
it('should encode/decode script', function() {
@ -34,55 +35,55 @@ describe('Script', function() {
it('should recognize a P2SH output', function () {
var hex = 'a91419a7d869032368fd1f1e26e5e73a4ad0e474960e87'
var encoded = new Buffer(hex, 'hex')
var decoded = bcoin.script.decode(encoded);
assert(bcoin.script.isScripthash(decoded))
var decoded = new bcoin.script(encoded);
assert(decoded.isScripthash())
})
it('should recognize a Null Data output', function () {
var hex = '6a28590c080112220a1b353930632e6f7267282a5f5e294f7665726c6179404f7261636c65103b1a010c'
var encoded = new Buffer(hex, 'hex')
var decoded = bcoin.script.decode(encoded);
assert(bcoin.script.isNulldata(decoded))
var decoded = new Script(encoded);
assert(decoded.isNulldata())
})
it('should handle if statements correctly', function () {
var inputScript = [1, 2];
var prevOutScript = [2, 'equal', 'if', 3, 'else', 4, 'endif', 5];
var inputScript = new Script([1, 2]);
var prevOutScript = new Script([2, 'equal', 'if', 3, 'else', 4, 'endif', 5]);
var stack = [];
bcoin.script.execute(inputScript, stack);
var res = bcoin.script.execute(prevOutScript, stack);
inputScript.execute(stack);
var res = prevOutScript.execute(stack);
assert(res);
assert.deepEqual(stack.slice(), [[1], [3], [5]]);
var inputScript = [1, 2];
var prevOutScript = [9, 'equal', 'if', 3, 'else', 4, 'endif', 5];
var inputScript = new Script([1, 2]);
var prevOutScript = new Script([9, 'equal', 'if', 3, 'else', 4, 'endif', 5]);
var stack = [];
bcoin.script.execute(inputScript, stack);
var res = bcoin.script.execute(prevOutScript, stack);
inputScript.execute(stack);
var res = prevOutScript.execute(stack);
assert(res);
assert.deepEqual(stack.slice(), [[1], [4], [5]]);
var inputScript = [1, 2];
var prevOutScript = [2, 'equal', 'if', 3, 'endif', 5];
var inputScript = new Script([1, 2]);
var prevOutScript = new Script([2, 'equal', 'if', 3, 'endif', 5]);
var stack = [];
bcoin.script.execute(inputScript, stack);
var res = bcoin.script.execute(prevOutScript, stack);
inputScript.execute(stack);
var res = prevOutScript.execute(stack);
assert(res);
assert.deepEqual(stack.slice(), [[1], [3], [5]]);
var inputScript = [1, 2];
var prevOutScript = [9, 'equal', 'if', 3, 'endif', 5];
var inputScript = new Script([1, 2]);
var prevOutScript = new Script([9, 'equal', 'if', 3, 'endif', 5]);
var stack = [];
bcoin.script.execute(inputScript, stack);
var res = bcoin.script.execute(prevOutScript, stack);
inputScript.execute(stack);
var res = prevOutScript.execute(stack);
assert(res);
assert.deepEqual(stack.slice(), [[1], [5]]);
var inputScript = [1, 2];
var prevOutScript = [9, 'equal', 'notif', 3, 'endif', 5];
var inputScript = new Script([1, 2]);
var prevOutScript = new Script([9, 'equal', 'notif', 3, 'endif', 5]);
var stack = [];
bcoin.script.execute(inputScript, stack);
var res = bcoin.script.execute(prevOutScript, stack);
inputScript.execute(stack);
var res = prevOutScript.execute(stack);
assert(res);
assert.deepEqual(stack.slice(), [[1], [3], [5]]);
})

View File

@ -13,12 +13,12 @@ var dummyInput = {
version: 1,
height: 0,
value: constants.maxMoney.clone(),
script: [],
script: new bcoin.script([]),
hash: constants.zeroHash,
index: 0,
spent: false
},
script: [],
script: new bcoin.script([]),
sequence: 0xffffffff
};
@ -167,7 +167,7 @@ describe('Wallet', function() {
// Script inputs but do not sign
w.scriptInputs(fake);
// Fake signature
fake.inputs[0].script[0] = new Buffer([0,0,0,0,0,0,0,0,0]);
fake.inputs[0].script.code[0] = new Buffer([0,0,0,0,0,0,0,0,0]);
// balance: 11000
// Just for debugging
@ -459,6 +459,8 @@ describe('Wallet', function() {
send.addOutput({ address: receive.getAddress(), value: 5460 });
assert(!send.verify(null, true, flags));
w1.fill(send, { m: w1.m, n: w1.n }, function(err) {
if (err)
throw err;
assert(!err);
w1.sign(send);
@ -499,7 +501,7 @@ describe('Wallet', function() {
if (witness)
send.inputs[0].witness[2] = new Buffer([]);
else
send.inputs[0].script[2] = 0;
send.inputs[0].script.code[2] = 0;
assert(!send.verify(null, true, flags));
assert.equal(send.getFee().toNumber(), 10000);