script work.
This commit is contained in:
parent
27b18c0fd2
commit
3a18052f87
@ -373,7 +373,7 @@ function MinerBlock(options) {
|
||||
index: 0xffffffff
|
||||
},
|
||||
coin: null,
|
||||
script: new bcoin.script([
|
||||
script: bcoin.script.fromArray([
|
||||
// Height (required in v2+ blocks)
|
||||
bcoin.script.array(this.height),
|
||||
// extraNonce - incremented when
|
||||
@ -442,9 +442,10 @@ utils.inherits(MinerBlock, EventEmitter);
|
||||
*/
|
||||
|
||||
MinerBlock.prototype.updateCommitment = function updateCommitment() {
|
||||
var output = this.coinbase.outputs[1];
|
||||
var hash = this.block.getCommitmentHash();
|
||||
var commit = bcoin.script.createCommitment(hash, this.coinbaseFlags);
|
||||
this.coinbase.outputs[1].script = commit;
|
||||
output.script = commit;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -453,9 +454,10 @@ MinerBlock.prototype.updateCommitment = function updateCommitment() {
|
||||
|
||||
MinerBlock.prototype.updateCoinbase = function updateCoinbase() {
|
||||
var input = this.coinbase.inputs[0];
|
||||
input.script.code[1] = bcoin.opcode.fromNumber(this.extraNonce);
|
||||
var output = this.coinbase.outputs[0];
|
||||
input.script.set(1, this.extraNonce);
|
||||
input.script.compile();
|
||||
this.coinbase.outputs[0].value = this.block.getReward(this.network);
|
||||
output.value = this.block.getReward(this.network);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
160
lib/bcoin/mtx.js
160
lib/bcoin/mtx.js
@ -161,8 +161,7 @@ MTX.prototype.addInput = function addInput(options, index) {
|
||||
*/
|
||||
|
||||
MTX.prototype.scriptInput = function scriptInput(index, addr) {
|
||||
var input, prev, n, i, redeemScript, witnessScript, vector, dummy;
|
||||
var inputScript, witnessItems;
|
||||
var input, prev, n, i, vector, redeemScript, witnessScript;
|
||||
|
||||
if (typeof index !== 'number')
|
||||
index = this.inputs.indexOf(index);
|
||||
@ -174,13 +173,10 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
|
||||
// We should have previous outputs by now.
|
||||
assert(input.coin, 'Coins are not available for scripting.');
|
||||
|
||||
inputScript = input.script.toArray();
|
||||
witnessItems = input.witness.toArray();
|
||||
|
||||
// Optimization: Don't bother with any below
|
||||
// calculation if the output is already templated.
|
||||
// Just say this is "our" output.
|
||||
if (inputScript.length || witnessItems.length)
|
||||
if (input.script.length !== 0 || input.witness.length !== 0)
|
||||
return true;
|
||||
|
||||
// Optimization: test output against the
|
||||
@ -197,11 +193,10 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
|
||||
// with segwit: figuring out where the redeem script and witness
|
||||
// redeem scripts go.
|
||||
if (prev.isScripthash()) {
|
||||
if (addr.program && utils.equal(prev.code[1].data, addr.programHash)) {
|
||||
if (addr.program && utils.equal(prev.get(1), addr.programHash)) {
|
||||
// Witness program nested in regular P2SH.
|
||||
redeemScript = addr.program.encode();
|
||||
vector = witnessItems;
|
||||
dummy = new Buffer([]);
|
||||
vector = input.witness;
|
||||
if (addr.program.isWitnessScripthash()) {
|
||||
// P2WSH nested within pay-to-scripthash
|
||||
// (it had to be this complicated, didn't it?)
|
||||
@ -213,117 +208,114 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
|
||||
} else {
|
||||
assert(false, 'Unknown program.');
|
||||
}
|
||||
} else if (addr.script && utils.equal(prev.code[1].data, addr.scriptHash160)) {
|
||||
} else if (addr.script && utils.equal(prev.get(1), addr.scriptHash160)) {
|
||||
// Regular P2SH.
|
||||
redeemScript = addr.script.encode();
|
||||
vector = inputScript;
|
||||
vector = input.script;
|
||||
prev = addr.script;
|
||||
dummy = opcodes.OP_0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (prev.isWitnessProgram()) {
|
||||
// Witness program.
|
||||
vector = witnessItems;
|
||||
dummy = new Buffer([]);
|
||||
vector = input.witness;
|
||||
|
||||
if (prev.isWitnessScripthash()) {
|
||||
// Bare P2WSH.
|
||||
if (!addr.script || !utils.equal(prev.code[1].data, addr.scriptHash256))
|
||||
if (!addr.script || !utils.equal(prev.get(1), addr.scriptHash256))
|
||||
return false;
|
||||
|
||||
witnessScript = addr.script.encode();
|
||||
prev = addr.script;
|
||||
} else if (prev.isWitnessPubkeyhash()) {
|
||||
// Bare P2WPKH.
|
||||
if (!utils.equal(prev.code[1].data, addr.keyHash))
|
||||
if (!utils.equal(prev.get(1), addr.keyHash))
|
||||
return false;
|
||||
|
||||
prev = Script.createPubkeyhash(prev.code[1].data);
|
||||
prev = Script.createPubkeyhash(prev.get(1));
|
||||
} else {
|
||||
// Bare... who knows?
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Wow, a normal output! Praise be to Jengus and Gord.
|
||||
vector = inputScript;
|
||||
dummy = opcodes.OP_0;
|
||||
vector = input.script;
|
||||
}
|
||||
|
||||
if (prev.isPubkey()) {
|
||||
// P2PK
|
||||
if (!utils.equal(prev.code[0].data, addr.publicKey))
|
||||
if (!utils.equal(prev.get(1), addr.publicKey))
|
||||
return false;
|
||||
|
||||
// Already has a script template (at least)
|
||||
if (vector.length)
|
||||
if (vector.length !== 0)
|
||||
return true;
|
||||
|
||||
vector[0] = dummy;
|
||||
vector.set(0, opcodes.OP_0);
|
||||
} else if (prev.isPubkeyhash()) {
|
||||
// P2PKH
|
||||
if (!utils.equal(prev.code[2].data, addr.keyHash))
|
||||
if (!utils.equal(prev.get(2), addr.keyHash))
|
||||
return false;
|
||||
|
||||
// Already has a script template (at least)
|
||||
if (vector.length)
|
||||
if (vector.length !== 0)
|
||||
return true;
|
||||
|
||||
vector[0] = dummy;
|
||||
vector[1] = addr.publicKey;
|
||||
vector.set(0, opcodes.OP_0);
|
||||
vector.set(1, addr.publicKey);
|
||||
} else if (prev.isMultisig()) {
|
||||
// Multisig
|
||||
if (prev.indexOf(addr.publicKey) === -1)
|
||||
return false;
|
||||
|
||||
// Already has a script template (at least)
|
||||
if (vector.length)
|
||||
if (vector.length !== 0)
|
||||
return true;
|
||||
|
||||
// Technically we should create m signature slots,
|
||||
// but we create n signature slots so we can order
|
||||
// the signatures properly.
|
||||
vector[0] = dummy;
|
||||
vector.set(0, opcodes.OP_0);
|
||||
|
||||
// Grab `n` value (number of keys).
|
||||
n = prev.getSmall(-2);
|
||||
n = prev.getSmall(prev.length - 2);
|
||||
|
||||
// Fill script with `n` signature slots.
|
||||
for (i = 0; i < n; i++)
|
||||
vector[i + 1] = dummy;
|
||||
vector.set(i + 1, opcodes.OP_0);
|
||||
} else {
|
||||
if (prev.indexOf(addr.publicKey) === -1)
|
||||
return false;
|
||||
|
||||
// Already has a script template (at least)
|
||||
if (vector.length)
|
||||
if (vector.length !== 0)
|
||||
return true;
|
||||
|
||||
// Likely a non-standard scripthash multisig
|
||||
// input. Determine n value by counting keys.
|
||||
// Also, only allow nonstandard types for
|
||||
// scripthash.
|
||||
vector[0] = dummy;
|
||||
vector.set(0, opcodes.OP_0);
|
||||
|
||||
// Fill script with `n` signature slots.
|
||||
for (i = 0; i < prev.code.length; i++) {
|
||||
if (Script.isKey(prev.code[i].data))
|
||||
vector[i + 1] = dummy;
|
||||
for (i = 0; i < prev.length; i++) {
|
||||
if (Script.isKey(prev.get(i)))
|
||||
vector.set(i + 1, opcodes.OP_0);
|
||||
}
|
||||
}
|
||||
|
||||
// P2SH requires the redeem
|
||||
// script after signatures.
|
||||
if (redeemScript)
|
||||
inputScript.push(redeemScript);
|
||||
input.script.push(redeemScript);
|
||||
|
||||
// P2WSH requires the witness
|
||||
// script after signatures.
|
||||
if (witnessScript)
|
||||
witnessItems.push(witnessScript);
|
||||
input.witness.push(witnessScript);
|
||||
|
||||
input.script = bcoin.script.fromArray(inputScript);
|
||||
input.witness = bcoin.witness.fromArray(witnessItems);
|
||||
input.script.compile();
|
||||
input.witness.compile();
|
||||
|
||||
return true;
|
||||
};
|
||||
@ -372,7 +364,7 @@ MTX.prototype.createSignature = function createSignature(index, prev, key, type,
|
||||
|
||||
MTX.prototype.signInput = function signInput(index, addr, key, type) {
|
||||
var input, prev, signature, keyIndex, signatures, i;
|
||||
var len, m, n, keys, vector, dummy, version, inputScript, witnessItems;
|
||||
var len, m, n, keys, vector, version;
|
||||
|
||||
if (typeof index !== 'number')
|
||||
index = this.inputs.indexOf(index);
|
||||
@ -384,15 +376,11 @@ MTX.prototype.signInput = function signInput(index, addr, key, type) {
|
||||
// We should have previous outputs by now.
|
||||
assert(input.coin, 'Coins are not available for signing.');
|
||||
|
||||
inputScript = input.script.toArray();
|
||||
witnessItems = input.witness.toArray();
|
||||
|
||||
// Get the previous output's script
|
||||
prev = input.coin.script;
|
||||
|
||||
vector = inputScript;
|
||||
vector = input.script;
|
||||
len = vector.length;
|
||||
dummy = opcodes.OP_0;
|
||||
version = 0;
|
||||
|
||||
// We need to grab the redeem script when
|
||||
@ -410,15 +398,13 @@ MTX.prototype.signInput = function signInput(index, addr, key, type) {
|
||||
// pushes onto the stack).
|
||||
if (prev.isWitnessScripthash()) {
|
||||
prev = input.witness.getRedeem();
|
||||
vector = witnessItems;
|
||||
vector = input.witness;
|
||||
len = vector.length - 1;
|
||||
dummy = new Buffer([]);
|
||||
version = 1;
|
||||
} else if (prev.isWitnessPubkeyhash()) {
|
||||
prev = Script.createPubkeyhash(prev.code[1].data);
|
||||
vector = witnessItems;
|
||||
prev = Script.createPubkeyhash(prev.get(1));
|
||||
vector = input.witness;
|
||||
len = vector.length;
|
||||
dummy = new Buffer([]);
|
||||
version = 1;
|
||||
}
|
||||
|
||||
@ -428,17 +414,15 @@ MTX.prototype.signInput = function signInput(index, addr, key, type) {
|
||||
// P2PK
|
||||
if (prev.isPubkey()) {
|
||||
// Already signed.
|
||||
if (Script.isSignature(vector[0]))
|
||||
if (Script.isSignature(vector.get(0)))
|
||||
return true;
|
||||
|
||||
// Make sure the pubkey is ours.
|
||||
if (!utils.equal(addr.publicKey, prev.code[0].data))
|
||||
if (!utils.equal(addr.publicKey, prev.get(0)))
|
||||
return false;
|
||||
|
||||
vector[0] = signature;
|
||||
|
||||
input.script = bcoin.script.fromArray(inputScript);
|
||||
input.witness = bcoin.witness.fromArray(witnessItems);
|
||||
vector.set(0, signature);
|
||||
vector.compile();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -446,17 +430,15 @@ MTX.prototype.signInput = function signInput(index, addr, key, type) {
|
||||
// P2PKH
|
||||
if (prev.isPubkeyhash()) {
|
||||
// Already signed.
|
||||
if (Script.isSignature(vector[0]))
|
||||
if (Script.isSignature(vector.get(0)))
|
||||
return true;
|
||||
|
||||
// Make sure the pubkey hash is ours.
|
||||
if (!utils.equal(addr.keyHash, prev.code[2].data))
|
||||
if (!utils.equal(addr.keyHash, prev.get(2)))
|
||||
return false;
|
||||
|
||||
vector[0] = signature;
|
||||
|
||||
input.script = bcoin.script.fromArray(inputScript);
|
||||
input.witness = bcoin.witness.fromArray(witnessItems);
|
||||
vector.set(0, signature);
|
||||
vector.compile();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -465,13 +447,16 @@ MTX.prototype.signInput = function signInput(index, addr, key, type) {
|
||||
if (prev.isMultisig()) {
|
||||
// Grab the redeem script's keys to figure
|
||||
// out where our key should go.
|
||||
keys = prev.toArray().slice(1, -2);
|
||||
keys = [];
|
||||
|
||||
for (i = 1; i < prev.length - 2; i++)
|
||||
keys.push(prev.get(i));
|
||||
|
||||
// Grab `m` value (number of sigs required).
|
||||
m = prev.getSmall(0);
|
||||
|
||||
// Grab `n` value (number of keys).
|
||||
n = prev.getSmall(-2);
|
||||
n = prev.getSmall(prev.length - 2);
|
||||
} else {
|
||||
// Only allow non-standard signing for
|
||||
// scripthash.
|
||||
@ -480,9 +465,9 @@ MTX.prototype.signInput = function signInput(index, addr, key, type) {
|
||||
|
||||
keys = [];
|
||||
|
||||
for (i = 0; i < prev.code.length; i++) {
|
||||
if (Script.isKey(prev.code[i].data))
|
||||
keys.push(prev.code[i].data);
|
||||
for (i = 0; i < prev.length; i++) {
|
||||
if (Script.isKey(prev.get(i)))
|
||||
keys.push(prev.get(i));
|
||||
}
|
||||
|
||||
// We don't know what m is, so
|
||||
@ -498,7 +483,7 @@ MTX.prototype.signInput = function signInput(index, addr, key, type) {
|
||||
// Count the number of current signatures.
|
||||
signatures = 0;
|
||||
for (i = 1; i < len; i++) {
|
||||
if (Script.isSignature(vector[i]))
|
||||
if (Script.isSignature(vector.get(i)))
|
||||
signatures++;
|
||||
}
|
||||
|
||||
@ -511,7 +496,7 @@ MTX.prototype.signInput = function signInput(index, addr, key, type) {
|
||||
// or by `m`. Add some signature slots for
|
||||
// us to use.
|
||||
while (len - 1 < n) {
|
||||
vector.splice(len, 0, dummy);
|
||||
vector.insert(len, opcodes.OP_0);
|
||||
len++;
|
||||
}
|
||||
|
||||
@ -534,8 +519,8 @@ MTX.prototype.signInput = function signInput(index, addr, key, type) {
|
||||
// and increment the total number of
|
||||
// signatures.
|
||||
if (keyIndex < len && signatures < m) {
|
||||
if (Script.isZero(vector[keyIndex])) {
|
||||
vector[keyIndex] = signature;
|
||||
if (vector.getSmall(keyIndex) === 0) {
|
||||
vector.set(keyIndex, signature);
|
||||
signatures++;
|
||||
}
|
||||
}
|
||||
@ -544,8 +529,8 @@ MTX.prototype.signInput = function signInput(index, addr, key, type) {
|
||||
if (signatures >= m) {
|
||||
// Remove empty slots left over.
|
||||
for (i = len - 1; i >= 1; i--) {
|
||||
if (Script.isZero(vector[i])) {
|
||||
vector.splice(i, 1);
|
||||
if (vector.getSmall(i) === 0) {
|
||||
vector.remove(i);
|
||||
len--;
|
||||
}
|
||||
}
|
||||
@ -555,7 +540,7 @@ MTX.prototype.signInput = function signInput(index, addr, key, type) {
|
||||
// with implementations that potentially handle
|
||||
// signature slots differently.
|
||||
while (signatures > m) {
|
||||
vector.splice(len - 1, 1);
|
||||
vector.remove(len - 1);
|
||||
signatures--;
|
||||
len--;
|
||||
}
|
||||
@ -565,8 +550,7 @@ MTX.prototype.signInput = function signInput(index, addr, key, type) {
|
||||
assert(len - 1 === m);
|
||||
}
|
||||
|
||||
input.script = bcoin.script.fromArray(inputScript);
|
||||
input.witness = bcoin.witness.fromArray(witnessItems);
|
||||
vector.compile();
|
||||
|
||||
return signatures === m;
|
||||
};
|
||||
@ -591,7 +575,7 @@ MTX.prototype.isSigned = function isSigned() {
|
||||
prev = input.coin.script;
|
||||
|
||||
// Script length, needed for multisig
|
||||
vector = input.script.toArray();
|
||||
vector = input.script;
|
||||
len = vector.length;
|
||||
|
||||
// We need to grab the redeem script when
|
||||
@ -606,19 +590,19 @@ MTX.prototype.isSigned = function isSigned() {
|
||||
// and potentially alter the length.
|
||||
if (prev.isWitnessScripthash()) {
|
||||
prev = input.witness.getRedeem();
|
||||
vector = input.witness.toArray();
|
||||
vector = input.witness;
|
||||
len = vector.length - 1;
|
||||
} else if (prev.isWitnessPubkeyhash()) {
|
||||
prev = Script.createPubkeyhash(prev.code[1].data);
|
||||
vector = input.witness.toArray();
|
||||
prev = Script.createPubkeyhash(prev.get(1));
|
||||
vector = input.witness;
|
||||
len = vector.length;
|
||||
}
|
||||
|
||||
if (prev.isPubkey()) {
|
||||
if (!Script.isSignature(vector[0]))
|
||||
if (!Script.isSignature(vector.get(0)))
|
||||
return false;
|
||||
} else if (prev.isPubkeyhash()) {
|
||||
if (!Script.isSignature(vector[0]))
|
||||
if (!Script.isSignature(vector.get(0)))
|
||||
return false;
|
||||
} else if (prev.isMultisig()) {
|
||||
// Grab `m` value (number of required sigs).
|
||||
@ -626,7 +610,7 @@ MTX.prototype.isSigned = function isSigned() {
|
||||
|
||||
// Ensure all members are signatures.
|
||||
for (j = 1; j < len; j++) {
|
||||
if (!Script.isSignature(vector[j]))
|
||||
if (!Script.isSignature(vector.get(j)))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -839,7 +823,7 @@ MTX.prototype.maxSize = function maxSize(options, force) {
|
||||
// here since it will be ignored by
|
||||
// the isMultisig clause.
|
||||
// OP_PUSHDATA2 [redeem]
|
||||
redeem = getRedeem(input.script, prev.code[1].data);
|
||||
redeem = getRedeem(input.script, prev.get(1));
|
||||
if (redeem) {
|
||||
prev = redeem;
|
||||
sz = prev.getSize();
|
||||
@ -870,7 +854,7 @@ MTX.prototype.maxSize = function maxSize(options, force) {
|
||||
hadWitness = true;
|
||||
|
||||
if (prev.isWitnessScripthash()) {
|
||||
redeem = getRedeem(input.witness, prev.code[1].data);
|
||||
redeem = getRedeem(input.witness, prev.get(1));
|
||||
if (redeem) {
|
||||
prev = redeem;
|
||||
sz = prev.getSize();
|
||||
@ -878,7 +862,7 @@ MTX.prototype.maxSize = function maxSize(options, force) {
|
||||
size += sz;
|
||||
}
|
||||
} else if (prev.isWitnessPubkeyhash()) {
|
||||
prev = Script.createPubkeyhash(prev.code[1].data);
|
||||
prev = Script.createPubkeyhash(prev.get(1));
|
||||
}
|
||||
}
|
||||
|
||||
@ -930,8 +914,8 @@ MTX.prototype.maxSize = function maxSize(options, force) {
|
||||
size += 1;
|
||||
} else {
|
||||
// OP_PUSHDATA0 [signature]
|
||||
for (j = 0; j < prev.code.length; j++) {
|
||||
if (Script.isKey(prev.code[j].data))
|
||||
for (j = 0; j < prev.length; j++) {
|
||||
if (Script.isKey(prev.get(j)))
|
||||
size += 1 + 73;
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,6 +28,7 @@ var ScriptError = bcoin.errors.ScriptError;
|
||||
* stack items or raw witness buffer.
|
||||
* @property {Buffer[]} items
|
||||
* @property {Script?} redeem
|
||||
* @property {Number} length
|
||||
*/
|
||||
|
||||
function Witness(items) {
|
||||
@ -253,35 +254,98 @@ Witness.prototype.toRaw = function toRaw(enc) {
|
||||
return data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unshift an item onto the witness vector.
|
||||
* @param {Number|String|Buffer|BN} data
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
Witness.prototype.unshift = function unshift(data) {
|
||||
return this.items.unshift(Witness.encodeItem(data));
|
||||
};
|
||||
|
||||
/**
|
||||
* Push an item onto the witness vector.
|
||||
* @param {Number|String|Buffer|BN} data
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
Witness.prototype.push = function push(data) {
|
||||
return this.items.push(Witness.encodeItem(data));
|
||||
};
|
||||
|
||||
/**
|
||||
* Shift an item off the witness vector.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
Witness.prototype.shift = function shift() {
|
||||
return this.items.shift();
|
||||
};
|
||||
|
||||
/**
|
||||
* Shift an item off the witness vector.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
Witness.prototype.pop = function push(data) {
|
||||
return this.items.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove an item from the witness vector.
|
||||
* @param {Number} index
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
Witness.prototype.remove = function remove(i) {
|
||||
return this.items.splice(i, 1)[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Insert an item into the witness vector.
|
||||
* @param {Number} index
|
||||
* @param {Number|String|Buffer|BN} data
|
||||
*/
|
||||
|
||||
Witness.prototype.insert = function insert(i, data) {
|
||||
assert(i <= this.items.length, 'Index out of bounds.');
|
||||
this.items.splice(i, 0, Witness.encodeItem(data))[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an item from the witness vector.
|
||||
* @param {Number} index
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
Witness.prototype.get = function get(i) {
|
||||
return this.items[i];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a small int (0-16) from the witness vector.
|
||||
* @param {Number} index
|
||||
* @returns {Number} `-1` on non-existent.
|
||||
*/
|
||||
|
||||
Witness.prototype.getSmall = function getSmall(i) {
|
||||
var item = this.items[i];
|
||||
if (!item || item.length > 1)
|
||||
return -1;
|
||||
if (item.length === 0)
|
||||
return 0;
|
||||
if (!(item[0] >= 1 && item[1] <= 16))
|
||||
return -1;
|
||||
return item[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a number from the witness vector.
|
||||
* @param {Number} index
|
||||
* @returns {BN}
|
||||
*/
|
||||
|
||||
Witness.prototype.getNumber = function getNumber(i) {
|
||||
var item = this.items[i];
|
||||
if (!item || item.length > 5)
|
||||
@ -289,6 +353,12 @@ Witness.prototype.getNumber = function getNumber(i) {
|
||||
return Script.num(item, constants.flags.VERIFY_NONE, 5);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a string from the witness vector.
|
||||
* @param {Number} index
|
||||
* @returns {String}
|
||||
*/
|
||||
|
||||
Witness.prototype.getString = function getString(i) {
|
||||
var item = this.items[i];
|
||||
if (!item)
|
||||
@ -296,35 +366,54 @@ Witness.prototype.getString = function getString(i) {
|
||||
return item.toString('utf8');
|
||||
};
|
||||
|
||||
/**
|
||||
* Set an item in the witness vector.
|
||||
* @param {Number} index
|
||||
* @param {Number|String|Buffer|BN} data
|
||||
*/
|
||||
|
||||
Witness.prototype.set = function set(i, data) {
|
||||
assert(i <= this.items.length, 'Index out of bounds.');
|
||||
this.items[i] = Witness.encodeItem(data);
|
||||
};
|
||||
|
||||
Witness.prototype.__defineGetter__('length', function() {
|
||||
return this.code.length;
|
||||
return this.items.length;
|
||||
});
|
||||
|
||||
Witness.prototype.__defineSetter__('length', function(len) {
|
||||
return this.code.length = len;
|
||||
return this.items.length = len;
|
||||
});
|
||||
|
||||
/**
|
||||
* Encode a witness item.
|
||||
* @param {Number|String|Buffer|BN} data
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
Witness.encodeItem = function encodeItem(data) {
|
||||
if (data instanceof Opcode)
|
||||
data = data.data || data.value;
|
||||
|
||||
if (typeof data === 'number') {
|
||||
if (data === opcodes.OP_1NEGATE)
|
||||
data = -1;
|
||||
else if (data === opcodes.OP_0)
|
||||
data = 0;
|
||||
else if (data >= opcodes.OP_1 && data <= opcodes.OP_16)
|
||||
data -= 0x50;
|
||||
else
|
||||
throw new Error('Non-push opcode in witness.');
|
||||
return Script.array(data);
|
||||
return STACK_NEGATE;
|
||||
|
||||
if (data === opcodes.OP_0)
|
||||
return STACK_FALSE;
|
||||
|
||||
if (data >= opcodes.OP_1 && data <= opcodes.OP_16)
|
||||
return new Buffer([data - 0x50]);
|
||||
|
||||
throw new Error('Non-push opcode in witness.');
|
||||
}
|
||||
|
||||
if (bn.isBN(data))
|
||||
return Script.array(data);
|
||||
|
||||
if (typeof data === 'string')
|
||||
return new Buffer(data, 'utf8');
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
@ -913,6 +1002,7 @@ Stack.isStack = function isStack(obj) {
|
||||
* @property {Array} code - Script code.
|
||||
* @property {Buffer?} raw - Serialized script.
|
||||
* @property {Script?} redeem - Redeem script.
|
||||
* @property {Number} length
|
||||
*/
|
||||
|
||||
function Script(raw) {
|
||||
@ -2204,7 +2294,7 @@ Script.isCode = function isCode(raw) {
|
||||
|
||||
Script.createPubkey = function createPubkey(key) {
|
||||
assert(key.length >= 33);
|
||||
return new Script([key, opcodes.OP_CHECKSIG]);
|
||||
return Script.fromArray([key, opcodes.OP_CHECKSIG]);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2215,7 +2305,7 @@ Script.createPubkey = function createPubkey(key) {
|
||||
|
||||
Script.createPubkeyhash = function createPubkeyhash(hash) {
|
||||
assert(hash.length === 20);
|
||||
return new Script([
|
||||
return Script.fromArray([
|
||||
opcodes.OP_DUP,
|
||||
opcodes.OP_HASH160,
|
||||
hash,
|
||||
@ -2250,7 +2340,7 @@ Script.createMultisig = function createMultisig(keys, m, n) {
|
||||
code.push(n + 0x50);
|
||||
code.push(opcodes.OP_CHECKMULTISIG);
|
||||
|
||||
return new Script(code);
|
||||
return Script.fromArray(code);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2261,7 +2351,7 @@ Script.createMultisig = function createMultisig(keys, m, n) {
|
||||
|
||||
Script.createScripthash = function createScripthash(hash) {
|
||||
assert(hash.length === 20);
|
||||
return new Script([
|
||||
return Script.fromArray([
|
||||
opcodes.OP_HASH160,
|
||||
hash,
|
||||
opcodes.OP_EQUAL
|
||||
@ -2277,7 +2367,7 @@ Script.createScripthash = function createScripthash(hash) {
|
||||
Script.createNulldata = function createNulldata(flags) {
|
||||
assert(Buffer.isBuffer(flags));
|
||||
assert(flags.length <= constants.script.MAX_OP_RETURN, 'Nulldata too large.');
|
||||
return new Script([
|
||||
return Script.fromArray([
|
||||
opcodes.OP_RETURN,
|
||||
flags
|
||||
]);
|
||||
@ -2293,13 +2383,13 @@ Script.createNulldata = function createNulldata(flags) {
|
||||
Script.createWitnessProgram = function createWitnessProgram(version, data) {
|
||||
assert(typeof version === 'number' && version >= 0 && version <= 16);
|
||||
assert(data.length >= 2 && data.length <= 32);
|
||||
return new Script([version === 0 ? 0 : version + 0x50, data]);
|
||||
return Script.fromArray([version === 0 ? 0 : version + 0x50, data]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a witness block commitment.
|
||||
* @param {Buffer} hash
|
||||
* @params {String|Buffer} flags
|
||||
* @param {String|Buffer} flags
|
||||
* @returns {Script}
|
||||
*/
|
||||
|
||||
@ -2316,7 +2406,7 @@ Script.createCommitment = function createCommitment(hash, flags) {
|
||||
p.writeU32BE(0xaa21a9ed);
|
||||
p.writeHash(hash);
|
||||
|
||||
return new Script([
|
||||
return Script.fromArray([
|
||||
opcodes.OP_RETURN,
|
||||
p.render(),
|
||||
flags
|
||||
@ -2390,8 +2480,8 @@ Script.prototype.isStandard = function isStandard() {
|
||||
var m, n;
|
||||
|
||||
if (type === 'multisig') {
|
||||
m = this.getSmall(0);
|
||||
n = this.getSmall(-2);
|
||||
m = Script.getSmall(this.raw[0]);
|
||||
n = Script.getSmall(this.raw[this.raw.length - 2]);
|
||||
|
||||
if (n < 1 || n > 3)
|
||||
return false;
|
||||
@ -2947,7 +3037,7 @@ Script.getCoinbaseHeight = function getCoinbaseHeight(raw) {
|
||||
|
||||
height = Script.getSmall(raw[0]);
|
||||
|
||||
if (height != null)
|
||||
if (height !== -1)
|
||||
return height;
|
||||
|
||||
if (raw[0] <= 0x06 && raw.length >= 1 + raw[0])
|
||||
@ -3013,14 +3103,31 @@ Script.prototype.test = function test(filter) {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unshift an item onto the `code` array.
|
||||
* @param {Number|String|BN|Buffer} data
|
||||
* @returns {Number} Length.
|
||||
*/
|
||||
|
||||
Script.prototype.unshift = function unshift(data) {
|
||||
return this.code.unshift(Opcode.from(data));
|
||||
};
|
||||
|
||||
/**
|
||||
* Push an item onto the `code` array.
|
||||
* @param {Number|String|BN|Buffer} data
|
||||
* @returns {Number} Length.
|
||||
*/
|
||||
|
||||
Script.prototype.push = function push(data) {
|
||||
return this.code.push(Opcode.from(data));
|
||||
};
|
||||
|
||||
/**
|
||||
* Shift an item off of the `code` array.
|
||||
* @returns {Buffer|Number}
|
||||
*/
|
||||
|
||||
Script.prototype.shift = function shift() {
|
||||
var op = this.code.shift();
|
||||
if (!op)
|
||||
@ -3028,6 +3135,11 @@ Script.prototype.shift = function shift() {
|
||||
return op.data || op.value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pop an item off of the `code` array.
|
||||
* @returns {Buffer|Number}
|
||||
*/
|
||||
|
||||
Script.prototype.pop = function push(data) {
|
||||
var op = this.code.pop();
|
||||
if (!op)
|
||||
@ -3035,6 +3147,12 @@ Script.prototype.pop = function push(data) {
|
||||
return op.data || op.value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove an item from the `code` array.
|
||||
* @param {Number} index
|
||||
* @returns {Buffer|Number}
|
||||
*/
|
||||
|
||||
Script.prototype.remove = function remove(i) {
|
||||
var op = this.code.splice(i, 1)[0];
|
||||
if (!op)
|
||||
@ -3042,11 +3160,23 @@ Script.prototype.remove = function remove(i) {
|
||||
return op.data || op.value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Insert an item into the `code` array.
|
||||
* @param {Number} index
|
||||
* @param {Number|String|BN|Buffer} data
|
||||
*/
|
||||
|
||||
Script.prototype.insert = function insert(i, data) {
|
||||
assert(i <= this.code.length, 'Index out of bounds.');
|
||||
this.code.splice(i, 0, Opcode.from(data))[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an item from the `code` array.
|
||||
* @param {Number} index
|
||||
* @returns {Buffer|Number}
|
||||
*/
|
||||
|
||||
Script.prototype.get = function get(i) {
|
||||
var op = this.code[i];
|
||||
if (!op)
|
||||
@ -3054,13 +3184,44 @@ Script.prototype.get = function get(i) {
|
||||
return op.data || op.value;
|
||||
};
|
||||
|
||||
Script.prototype.getNumber = function getNumber(i) {
|
||||
/**
|
||||
* Get a small integer from an opcode (OP_0-OP_16).
|
||||
* @param {Number} index
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
Script.prototype.getSmall = function getSmall(i) {
|
||||
var op = this.code[i];
|
||||
if (!op)
|
||||
return -1;
|
||||
return Script.getSmall(op.value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a number from the `code` array (5-byte limit).
|
||||
* @params {Number} index
|
||||
* @returns {BN}
|
||||
*/
|
||||
|
||||
Script.prototype.getNumber = function getNumber(i) {
|
||||
var small = this.getSmall(i);
|
||||
var op = this.code[i];
|
||||
|
||||
if (small !== -1)
|
||||
return new bn(small);
|
||||
|
||||
if (!op || !op.data || op.data.length > 5)
|
||||
return;
|
||||
|
||||
return Script.num(op.data, constants.flags.VERIFY_NONE, 5);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a string from the `code` array (utf8).
|
||||
* @params {Number} index
|
||||
* @returns {String}
|
||||
*/
|
||||
|
||||
Script.prototype.getString = function getString(i) {
|
||||
var op = this.code[i];
|
||||
if (!op || !op.data)
|
||||
@ -3068,6 +3229,12 @@ Script.prototype.getString = function getString(i) {
|
||||
return op.data.toString('utf8');
|
||||
};
|
||||
|
||||
/**
|
||||
* Set an item in the `code` array.
|
||||
* @param {Number} index
|
||||
* @param {Buffer|Number|String|BN} data
|
||||
*/
|
||||
|
||||
Script.prototype.set = function set(i, data) {
|
||||
assert(i <= this.code.length, 'Index out of bounds.');
|
||||
this.code[i] = Opcode.from(data);
|
||||
@ -3123,20 +3290,6 @@ Script.isDummy = function isDummy(data) {
|
||||
return Buffer.isBuffer(data) && data.length === 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether the data element is a null dummy or an OP_0.
|
||||
* @private
|
||||
* @param {Buffer?} data
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
Script.isZero = function isZero(op) {
|
||||
if (op === opcodes.OP_0)
|
||||
return true;
|
||||
|
||||
return Script.isDummy(op);
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether the data element is a valid key if VERIFY_STRICTENC is enabled.
|
||||
* @param {Buffer} key
|
||||
@ -3698,19 +3851,6 @@ Script.fromString = function fromString(code) {
|
||||
return new Script(p.render());
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a small integer from an opcode (OP_0-OP_16).
|
||||
* @param {Number} index
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
Script.prototype.getSmall = function getSmall(i) {
|
||||
if (i < 0)
|
||||
i = this.code.length + i;
|
||||
|
||||
return Script.getSmall(this.code[i].value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a small integer from an opcode (OP_0-OP_16).
|
||||
* @param {Number} index
|
||||
@ -3719,7 +3859,7 @@ Script.prototype.getSmall = function getSmall(i) {
|
||||
|
||||
Script.getSmall = function getSmall(op) {
|
||||
if (typeof op !== 'number')
|
||||
return null;
|
||||
return -1;
|
||||
|
||||
if (op === opcodes.OP_0)
|
||||
return 0;
|
||||
@ -4339,7 +4479,7 @@ Opcode.fromString = function fromString(data, enc) {
|
||||
|
||||
/**
|
||||
* Instantiate a pushdata opcode from anything.
|
||||
* @params {String|Buffer|Number|BN|Opcode} data
|
||||
* @param {String|Buffer|Number|BN|Opcode} data
|
||||
* @returns {Opcode}
|
||||
*/
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user