script work.

This commit is contained in:
Christopher Jeffrey 2016-06-14 18:13:51 -07:00
parent 27b18c0fd2
commit 3a18052f87
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
3 changed files with 269 additions and 143 deletions

View File

@ -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);
};
/**

View File

@ -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;
}
}

View File

@ -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}
*/