modules: drop all circular deps.
This commit is contained in:
parent
4c9d9d5160
commit
6f9ad90e07
@ -16,6 +16,7 @@ var constants = require('../protocol/constants');
|
||||
var siphash = require('../crypto/siphash');
|
||||
var AbstractBlock = require('../primitives/abstractblock');
|
||||
var TX = require('../primitives/tx');
|
||||
var Headers = require('../primitives/headers');
|
||||
var Block = require('../primitives/block');
|
||||
|
||||
/**
|
||||
@ -403,6 +404,13 @@ CompactBlock.prototype.destroy = function destroy() {
|
||||
}
|
||||
};
|
||||
|
||||
CompactBlock.prototype.toHeaders = function toHeaders() {
|
||||
var headers = new Headers(this);
|
||||
headers._hash = this._hash;
|
||||
headers._valid = true;
|
||||
return headers;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a BlockTransactionsRequest (bip152): `getblocktxn` packet.
|
||||
* @see https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = AbstractBlock;
|
||||
|
||||
var constants = require('../protocol/constants');
|
||||
var utils = require('../utils/utils');
|
||||
var crypto = require('../crypto/crypto');
|
||||
@ -17,7 +15,6 @@ var VerifyResult = utils.VerifyResult;
|
||||
var BufferWriter = require('../utils/writer');
|
||||
var time = require('../net/timedata');
|
||||
var InvItem = require('./invitem');
|
||||
var Headers = require('./headers');
|
||||
|
||||
/**
|
||||
* The class which all block-like objects inherit from.
|
||||
@ -262,18 +259,6 @@ AbstractBlock.prototype.toInv = function toInv() {
|
||||
return new InvItem(constants.inv.BLOCK, this.hash('hex'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert the block to a headers object.
|
||||
* @returns {Headers}
|
||||
*/
|
||||
|
||||
AbstractBlock.prototype.toHeaders = function toHeaders() {
|
||||
var headers = new Headers(this);
|
||||
headers._hash = this._hash;
|
||||
headers._valid = true;
|
||||
return headers;
|
||||
};
|
||||
|
||||
/*
|
||||
* Expose
|
||||
*/
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = Address;
|
||||
|
||||
var Network = require('../protocol/network');
|
||||
var networks = require('../protocol/networks');
|
||||
var constants = require('../protocol/constants');
|
||||
@ -17,7 +15,7 @@ var crypto = require('../crypto/crypto');
|
||||
var assert = require('assert');
|
||||
var BufferWriter = require('../utils/writer');
|
||||
var BufferReader = require('../utils/reader');
|
||||
var Script = require('../script/script');
|
||||
var scriptTypes = constants.scriptTypes;
|
||||
|
||||
/**
|
||||
* Represents an address.
|
||||
@ -40,7 +38,7 @@ function Address(options) {
|
||||
return new Address(options);
|
||||
|
||||
this.hash = constants.ZERO_HASH160;
|
||||
this.type = Script.types.PUBKEYHASH;
|
||||
this.type = scriptTypes.PUBKEYHASH;
|
||||
this.version = -1;
|
||||
this.network = Network.primary;
|
||||
|
||||
@ -141,15 +139,6 @@ Address.prototype.toBase58 = function toBase58(network) {
|
||||
return utils.toBase58(this.toRaw(network));
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert the address to an output script.
|
||||
* @returns {Script}
|
||||
*/
|
||||
|
||||
Address.prototype.toScript = function toScript() {
|
||||
return Script.fromAddress(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert the Address to a string.
|
||||
* @returns {Base58String}
|
||||
@ -259,42 +248,42 @@ Address.fromBase58 = function fromBase58(address) {
|
||||
Address.prototype.fromScript = function fromScript(script) {
|
||||
if (script.isPubkey()) {
|
||||
this.hash = crypto.hash160(script.get(0));
|
||||
this.type = Script.types.PUBKEYHASH;
|
||||
this.type = scriptTypes.PUBKEYHASH;
|
||||
this.version = -1;
|
||||
return this;
|
||||
}
|
||||
|
||||
if (script.isPubkeyhash()) {
|
||||
this.hash = script.get(2);
|
||||
this.type = Script.types.PUBKEYHASH;
|
||||
this.type = scriptTypes.PUBKEYHASH;
|
||||
this.version = -1;
|
||||
return this;
|
||||
}
|
||||
|
||||
if (script.isScripthash()) {
|
||||
this.hash = script.get(1);
|
||||
this.type = Script.types.SCRIPTHASH;
|
||||
this.type = scriptTypes.SCRIPTHASH;
|
||||
this.version = -1;
|
||||
return this;
|
||||
}
|
||||
|
||||
if (script.isWitnessPubkeyhash()) {
|
||||
this.hash = script.get(1);
|
||||
this.type = Script.types.WITNESSPUBKEYHASH;
|
||||
this.type = scriptTypes.WITNESSPUBKEYHASH;
|
||||
this.version = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
if (script.isWitnessScripthash()) {
|
||||
this.hash = script.get(1);
|
||||
this.type = Script.types.WITNESSSCRIPTHASH;
|
||||
this.type = scriptTypes.WITNESSSCRIPTHASH;
|
||||
this.version = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
if (script.isWitnessMasthash()) {
|
||||
this.hash = script.get(1);
|
||||
this.type = Script.types.WITNESSSCRIPTHASH;
|
||||
this.type = scriptTypes.WITNESSSCRIPTHASH;
|
||||
this.version = 1;
|
||||
return this;
|
||||
}
|
||||
@ -302,7 +291,7 @@ Address.prototype.fromScript = function fromScript(script) {
|
||||
// Put this last: it's the slowest to check.
|
||||
if (script.isMultisig()) {
|
||||
this.hash = script.hash160();
|
||||
this.type = Script.types.SCRIPTHASH;
|
||||
this.type = scriptTypes.SCRIPTHASH;
|
||||
this.version = -1;
|
||||
return this;
|
||||
}
|
||||
@ -319,14 +308,14 @@ Address.prototype.fromWitness = function fromWitness(witness) {
|
||||
// since we can't get the version.
|
||||
if (witness.isPubkeyhashInput()) {
|
||||
this.hash = crypto.hash160(witness.get(1));
|
||||
this.type = Script.types.WITNESSPUBKEYHASH;
|
||||
this.type = scriptTypes.WITNESSPUBKEYHASH;
|
||||
this.version = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
if (witness.isScripthashInput()) {
|
||||
this.hash = crypto.sha256(witness.get(witness.length - 1));
|
||||
this.type = Script.types.WITNESSSCRIPTHASH;
|
||||
this.type = scriptTypes.WITNESSSCRIPTHASH;
|
||||
this.version = 0;
|
||||
return this;
|
||||
}
|
||||
@ -341,14 +330,14 @@ Address.prototype.fromWitness = function fromWitness(witness) {
|
||||
Address.prototype.fromInputScript = function fromInputScript(script) {
|
||||
if (script.isPubkeyhashInput()) {
|
||||
this.hash = crypto.hash160(script.get(1));
|
||||
this.type = Script.types.PUBKEYHASH;
|
||||
this.type = scriptTypes.PUBKEYHASH;
|
||||
this.version = -1;
|
||||
return this;
|
||||
}
|
||||
|
||||
if (script.isScripthashInput()) {
|
||||
this.hash = crypto.hash160(script.get(script.length - 1));
|
||||
this.type = Script.types.SCRIPTHASH;
|
||||
this.type = scriptTypes.SCRIPTHASH;
|
||||
this.version = -1;
|
||||
return this;
|
||||
}
|
||||
@ -406,10 +395,10 @@ Address.prototype.fromHash = function fromHash(hash, type, version, network) {
|
||||
hash = new Buffer(hash, 'hex');
|
||||
|
||||
if (typeof type === 'string')
|
||||
type = Script.types[type.toUpperCase()];
|
||||
type = scriptTypes[type.toUpperCase()];
|
||||
|
||||
if (type == null)
|
||||
type = Script.types.PUBKEYHASH;
|
||||
type = scriptTypes.PUBKEYHASH;
|
||||
|
||||
if (version == null)
|
||||
version = -1;
|
||||
@ -428,11 +417,11 @@ Address.prototype.fromHash = function fromHash(hash, type, version, network) {
|
||||
} else {
|
||||
assert(Address.isWitness(type), 'Wrong version (non-witness).');
|
||||
assert(version >= 0 && version <= 16, 'Bad program version.');
|
||||
if (version === 0 && type === Script.types.WITNESSPUBKEYHASH)
|
||||
if (version === 0 && type === scriptTypes.WITNESSPUBKEYHASH)
|
||||
assert(hash.length === 20, 'Hash is the wrong size.');
|
||||
else if (version === 0 && type === Script.types.WITNESSSCRIPTHASH)
|
||||
else if (version === 0 && type === scriptTypes.WITNESSSCRIPTHASH)
|
||||
assert(hash.length === 32, 'Hash is the wrong size.');
|
||||
else if (version === 1 && type === Script.types.WITNESSSCRIPTHASH)
|
||||
else if (version === 1 && type === scriptTypes.WITNESSSCRIPTHASH)
|
||||
assert(hash.length === 32, 'Hash is the wrong size.');
|
||||
}
|
||||
|
||||
@ -469,9 +458,9 @@ Address.fromHash = function fromHash(hash, type, version, network) {
|
||||
|
||||
Address.prototype.fromData = function fromData(data, type, version, network) {
|
||||
if (typeof type === 'string')
|
||||
type = Script.types[type.toUpperCase()];
|
||||
type = scriptTypes[type.toUpperCase()];
|
||||
|
||||
if (type === Script.types.WITNESSSCRIPTHASH) {
|
||||
if (type === scriptTypes.WITNESSSCRIPTHASH) {
|
||||
if (version === 0) {
|
||||
assert(Buffer.isBuffer(data));
|
||||
data = crypto.sha256(data);
|
||||
@ -481,7 +470,7 @@ Address.prototype.fromData = function fromData(data, type, version, network) {
|
||||
} else {
|
||||
throw new Error('Cannot create from version=' + version);
|
||||
}
|
||||
} else if (type === Script.types.WITNESSPUBKEYHASH) {
|
||||
} else if (type === scriptTypes.WITNESSPUBKEYHASH) {
|
||||
if (version !== 0)
|
||||
throw new Error('Cannot create from version=' + version);
|
||||
assert(Buffer.isBuffer(data));
|
||||
@ -530,7 +519,7 @@ Address.validate = function validate(address, type) {
|
||||
}
|
||||
|
||||
if (typeof type === 'string')
|
||||
type = Script.types[type.toUpperCase()];
|
||||
type = scriptTypes[type.toUpperCase()];
|
||||
|
||||
if (type && address.type !== type)
|
||||
return false;
|
||||
@ -580,13 +569,13 @@ Address.getHash = function getHash(data, enc) {
|
||||
Address.getPrefix = function getPrefix(type, network) {
|
||||
var prefixes = network.addressPrefix;
|
||||
switch (type) {
|
||||
case Script.types.PUBKEYHASH:
|
||||
case scriptTypes.PUBKEYHASH:
|
||||
return prefixes.pubkeyhash;
|
||||
case Script.types.SCRIPTHASH:
|
||||
case scriptTypes.SCRIPTHASH:
|
||||
return prefixes.scripthash;
|
||||
case Script.types.WITNESSPUBKEYHASH:
|
||||
case scriptTypes.WITNESSPUBKEYHASH:
|
||||
return prefixes.witnesspubkeyhash;
|
||||
case Script.types.WITNESSSCRIPTHASH:
|
||||
case scriptTypes.WITNESSSCRIPTHASH:
|
||||
return prefixes.witnessscripthash;
|
||||
default:
|
||||
return -1;
|
||||
@ -604,13 +593,13 @@ Address.getType = function getType(prefix, network) {
|
||||
var prefixes = network.addressPrefix;
|
||||
switch (prefix) {
|
||||
case prefixes.pubkeyhash:
|
||||
return Script.types.PUBKEYHASH;
|
||||
return scriptTypes.PUBKEYHASH;
|
||||
case prefixes.scripthash:
|
||||
return Script.types.SCRIPTHASH;
|
||||
return scriptTypes.SCRIPTHASH;
|
||||
case prefixes.witnesspubkeyhash:
|
||||
return Script.types.WITNESSPUBKEYHASH;
|
||||
return scriptTypes.WITNESSPUBKEYHASH;
|
||||
case prefixes.witnessscripthash:
|
||||
return Script.types.WITNESSSCRIPTHASH;
|
||||
return scriptTypes.WITNESSSCRIPTHASH;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
@ -624,9 +613,9 @@ Address.getType = function getType(prefix, network) {
|
||||
|
||||
Address.isWitness = function isWitness(type) {
|
||||
switch (type) {
|
||||
case Script.types.WITNESSPUBKEYHASH:
|
||||
case scriptTypes.WITNESSPUBKEYHASH:
|
||||
return true;
|
||||
case Script.types.WITNESSSCRIPTHASH:
|
||||
case scriptTypes.WITNESSSCRIPTHASH:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = Block;
|
||||
|
||||
var utils = require('../utils/utils');
|
||||
var crypto = require('../crypto/crypto');
|
||||
var assert = require('assert');
|
||||
@ -19,6 +17,7 @@ var BufferWriter = require('../utils/writer');
|
||||
var BufferReader = require('../utils/reader');
|
||||
var TX = require('./tx');
|
||||
var MerkleBlock = require('./merkleblock');
|
||||
var Headers = require('./headers');
|
||||
var Network = require('../protocol/network');
|
||||
|
||||
/**
|
||||
@ -790,6 +789,18 @@ Block.prototype.frameWitness = function frameWitness(writer) {
|
||||
return this.frame(true, writer);
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert the block to a headers object.
|
||||
* @returns {Headers}
|
||||
*/
|
||||
|
||||
Block.prototype.toHeaders = function toHeaders() {
|
||||
var headers = new Headers(this);
|
||||
headers._hash = this._hash;
|
||||
headers._valid = true;
|
||||
return headers;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether an object is a Block.
|
||||
* @param {Object} obj
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = Coin;
|
||||
|
||||
var utils = require('../utils/utils');
|
||||
var constants = require('../protocol/constants');
|
||||
var Network = require('../protocol/network');
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = Headers;
|
||||
|
||||
var utils = require('../utils/utils');
|
||||
var AbstractBlock = require('./abstractblock');
|
||||
var BufferWriter = require('../utils/writer');
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = Input;
|
||||
|
||||
var utils = require('../utils/utils');
|
||||
var assert = require('assert');
|
||||
var constants = require('../protocol/constants');
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = InvItem;
|
||||
|
||||
var constants = require('../protocol/constants');
|
||||
var BufferWriter = require('../utils/writer');
|
||||
var BufferReader = require('../utils/reader');
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = KeyRing;
|
||||
|
||||
var constants = require('../protocol/constants');
|
||||
var utils = require('../utils/utils');
|
||||
var crypto = require('../crypto/crypto');
|
||||
|
||||
@ -7,12 +7,11 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = MemBlock;
|
||||
|
||||
var utils = require('../utils/utils');
|
||||
var AbstractBlock = require('./abstractblock');
|
||||
var Block = require('./block');
|
||||
var Script = require('../script/script');
|
||||
var Headers = require('./headers');
|
||||
var BufferReader = require('../utils/reader');
|
||||
|
||||
/**
|
||||
@ -194,6 +193,18 @@ MemBlock.prototype.toBlock = function toBlock() {
|
||||
return block;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert the block to a headers object.
|
||||
* @returns {Headers}
|
||||
*/
|
||||
|
||||
MemBlock.prototype.toHeaders = function toHeaders() {
|
||||
var headers = new Headers(this);
|
||||
headers._hash = this._hash;
|
||||
headers._valid = true;
|
||||
return headers;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether an object is a MemBlock.
|
||||
* @param {Object} obj
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = MerkleBlock;
|
||||
|
||||
var utils = require('../utils/utils');
|
||||
var crypto = require('../crypto/crypto');
|
||||
var assert = require('assert');
|
||||
@ -18,6 +16,7 @@ var AbstractBlock = require('./abstractblock');
|
||||
var VerifyResult = utils.VerifyResult;
|
||||
var BufferWriter = require('../utils/writer');
|
||||
var BufferReader = require('../utils/reader');
|
||||
var Headers = require('./headers');
|
||||
var TX = require('./tx');
|
||||
|
||||
/**
|
||||
@ -639,6 +638,18 @@ MerkleBlock.isMerkleBlock = function isMerkleBlock(obj) {
|
||||
&& typeof obj.verifyPartial === 'function';
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert the block to a headers object.
|
||||
* @returns {Headers}
|
||||
*/
|
||||
|
||||
MerkleBlock.prototype.toHeaders = function toHeaders() {
|
||||
var headers = new Headers(this);
|
||||
headers._hash = this._hash;
|
||||
headers._valid = true;
|
||||
return headers;
|
||||
};
|
||||
|
||||
/*
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = MTX;
|
||||
|
||||
var utils = require('../utils/utils');
|
||||
var assert = require('assert');
|
||||
var constants = require('../protocol/constants');
|
||||
|
||||
@ -6,8 +6,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = NetworkAddress;
|
||||
|
||||
var constants = require('../protocol/constants');
|
||||
var Network = require('../protocol/network');
|
||||
var time = require('../net/timedata');
|
||||
|
||||
@ -6,8 +6,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = Outpoint;
|
||||
|
||||
var utils = require('../utils/utils');
|
||||
var assert = require('assert');
|
||||
var constants = require('../protocol/constants');
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = Output;
|
||||
|
||||
var utils = require('../utils/utils');
|
||||
var constants = require('../protocol/constants');
|
||||
var Network = require('../protocol/network');
|
||||
@ -16,7 +14,6 @@ var Script = require('../script/script');
|
||||
var BufferWriter = require('../utils/writer');
|
||||
var BufferReader = require('../utils/reader');
|
||||
var assert = require('assert');
|
||||
var TX = require('./tx');
|
||||
|
||||
/**
|
||||
* Represents a transaction output.
|
||||
@ -156,7 +153,7 @@ Output.prototype.toJSON = function toJSON(network) {
|
||||
|
||||
Output.prototype.getDustThreshold = function getDustThreshold(rate) {
|
||||
var scale = constants.WITNESS_SCALE_FACTOR;
|
||||
var size;
|
||||
var size, fee;
|
||||
|
||||
if (rate == null)
|
||||
rate = constants.tx.MIN_RELAY;
|
||||
@ -173,7 +170,12 @@ Output.prototype.getDustThreshold = function getDustThreshold(rate) {
|
||||
size += 32 + 4 + 1 + 107 + 4;
|
||||
}
|
||||
|
||||
return 3 * TX.getMinFee(size, rate);
|
||||
fee = Math.floor(rate * size / 1000);
|
||||
|
||||
if (fee === 0 && rate > 0)
|
||||
fee = rate;
|
||||
|
||||
return 3 * fee;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = TX;
|
||||
|
||||
var utils = require('../utils/utils');
|
||||
var crypto = require('../crypto/crypto');
|
||||
var assert = require('assert');
|
||||
@ -1466,10 +1464,7 @@ TX.prototype.hasStandardInputs = function hasStandardInputs() {
|
||||
if (stack.length === 0)
|
||||
return false;
|
||||
|
||||
redeem = stack.getRedeem();
|
||||
|
||||
if (!redeem)
|
||||
return false;
|
||||
redeem = Script.fromRaw(stack.top(-1));
|
||||
|
||||
if (redeem.getSigops(true) > maxSigops)
|
||||
return false;
|
||||
|
||||
468
lib/script/encoding.js
Normal file
468
lib/script/encoding.js
Normal file
@ -0,0 +1,468 @@
|
||||
/*!
|
||||
* encoding.js - script-related encoding for bcoin
|
||||
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
|
||||
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
|
||||
* https://github.com/bcoin-org/bcoin
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var BN = require('bn.js');
|
||||
var constants = require('../protocol/constants');
|
||||
var utils = require('../utils/utils');
|
||||
var assert = require('assert');
|
||||
var opcodes = constants.opcodes;
|
||||
var STACK_FALSE = new Buffer(0);
|
||||
var ScriptError = require('../utils/errors').ScriptError;
|
||||
|
||||
/**
|
||||
* Test whether the data element is a ripemd160 hash.
|
||||
* @param {Buffer?} hash
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
exports.isHash = function isHash(hash) {
|
||||
return Buffer.isBuffer(hash) && hash.length === 20;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether the data element is a public key. Note that
|
||||
* this does not verify the format of the key, only the length.
|
||||
* @param {Buffer?} key
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
exports.isKey = function isKey(key) {
|
||||
return Buffer.isBuffer(key) && key.length >= 33 && key.length <= 65;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether the data element is a signature. Note that
|
||||
* this does not verify the format of the signature, only the length.
|
||||
* @param {Buffer?} sig
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
exports.isSignature = function isSignature(sig) {
|
||||
return Buffer.isBuffer(sig) && sig.length >= 9 && sig.length <= 73;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether the data element is a null dummy (a zero-length array).
|
||||
* @param {Buffer?} data
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
exports.isDummy = function isDummy(data) {
|
||||
return Buffer.isBuffer(data) && data.length === 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether the data element is a compressed key.
|
||||
* @param {Buffer} key
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
exports.isCompressedEncoding = function isCompressedEncoding(key) {
|
||||
assert(Buffer.isBuffer(key));
|
||||
|
||||
if (key.length !== 33)
|
||||
return false;
|
||||
|
||||
if (key[0] !== 0x02 && key[0] !== 0x03)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether the data element is a valid key.
|
||||
* @param {Buffer} key
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
exports.isKeyEncoding = function isKeyEncoding(key) {
|
||||
assert(Buffer.isBuffer(key));
|
||||
|
||||
if (key.length < 33)
|
||||
return false;
|
||||
|
||||
if (key[0] === 0x04) {
|
||||
if (key.length !== 65)
|
||||
return false;
|
||||
} else if (key[0] === 0x02 || key[0] === 0x03) {
|
||||
if (key.length !== 33)
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test a signature to see if it abides by BIP66.
|
||||
* @see https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki
|
||||
* @param {Buffer} sig
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
exports.isSignatureEncoding = function isSignatureEncoding(sig) {
|
||||
var lenR, lenS;
|
||||
|
||||
assert(Buffer.isBuffer(sig));
|
||||
|
||||
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash]
|
||||
// * total-length: 1-byte length descriptor of everything that follows,
|
||||
// excluding the sighash byte.
|
||||
// * R-length: 1-byte length descriptor of the R value that follows.
|
||||
// * R: arbitrary-length big-endian encoded R value. It must use the shortest
|
||||
// possible encoding for a positive integers (which means no null bytes at
|
||||
// the start, except a single one when the next byte has its highest bit set).
|
||||
// * S-length: 1-byte length descriptor of the S value that follows.
|
||||
// * S: arbitrary-length big-endian encoded S value. The same rules apply.
|
||||
// * sighash: 1-byte value indicating what data is hashed (not part of the DER
|
||||
// signature)
|
||||
|
||||
// Minimum and maximum size constraints.
|
||||
if (sig.length < 9)
|
||||
return false;
|
||||
|
||||
if (sig.length > 73)
|
||||
return false;
|
||||
|
||||
// A signature is of type 0x30 (compound).
|
||||
if (sig[0] !== 0x30)
|
||||
return false;
|
||||
|
||||
// Make sure the length covers the entire signature.
|
||||
if (sig[1] !== sig.length - 3)
|
||||
return false;
|
||||
|
||||
// Extract the length of the R element.
|
||||
lenR = sig[3];
|
||||
|
||||
// Make sure the length of the S element is still inside the signature.
|
||||
if (5 + lenR >= sig.length)
|
||||
return false;
|
||||
|
||||
// Extract the length of the S element.
|
||||
lenS = sig[5 + lenR];
|
||||
|
||||
// Verify that the length of the signature matches the sum of the length
|
||||
// of the elements.
|
||||
if (lenR + lenS + 7 !== sig.length)
|
||||
return false;
|
||||
|
||||
// Check whether the R element is an integer.
|
||||
if (sig[2] !== 0x02)
|
||||
return false;
|
||||
|
||||
// Zero-length integers are not allowed for R.
|
||||
if (lenR === 0)
|
||||
return false;
|
||||
|
||||
// Negative numbers are not allowed for R.
|
||||
if (sig[4] & 0x80)
|
||||
return false;
|
||||
|
||||
// Null bytes at the start of R are not allowed, unless R would
|
||||
// otherwise be interpreted as a negative number.
|
||||
if (lenR > 1 && (sig[4] === 0x00) && !(sig[5] & 0x80))
|
||||
return false;
|
||||
|
||||
// Check whether the S element is an integer.
|
||||
if (sig[lenR + 4] !== 0x02)
|
||||
return false;
|
||||
|
||||
// Zero-length integers are not allowed for S.
|
||||
if (lenS === 0)
|
||||
return false;
|
||||
|
||||
// Negative numbers are not allowed for S.
|
||||
if (sig[lenR + 6] & 0x80)
|
||||
return false;
|
||||
|
||||
// Null bytes at the start of S are not allowed, unless S would otherwise be
|
||||
// interpreted as a negative number.
|
||||
if (lenS > 1 && (sig[lenR + 6] === 0x00) && !(sig[lenR + 7] & 0x80))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Format script code into a human readable-string.
|
||||
* @param {Array} code
|
||||
* @returns {String} Human-readable string.
|
||||
*/
|
||||
|
||||
exports.formatStack = function formatStack(items) {
|
||||
var out = [];
|
||||
var i;
|
||||
|
||||
for (i = 0; i < items.length; i++)
|
||||
out.push(items[i].toString('hex'));
|
||||
|
||||
return out.join(' ');
|
||||
};
|
||||
|
||||
/**
|
||||
* Format script code into a human readable-string.
|
||||
* @param {Array} code
|
||||
* @returns {String} Human-readable string.
|
||||
*/
|
||||
|
||||
exports.formatCode = function formatCode(code) {
|
||||
var out = [];
|
||||
var i, op, data, value, size;
|
||||
|
||||
for (i = 0; i < code.length; i++) {
|
||||
op = code[i];
|
||||
data = op.data;
|
||||
value = op.value;
|
||||
|
||||
if (data) {
|
||||
size = data.length.toString(16);
|
||||
|
||||
while (size.length % 2 !== 0)
|
||||
size = '0' + size;
|
||||
|
||||
if (!constants.opcodesByVal[value]) {
|
||||
value = value.toString(16);
|
||||
if (value.length < 2)
|
||||
value = '0' + value;
|
||||
value = '0x' + value + ' 0x' + data.toString('hex');
|
||||
out.push(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
value = constants.opcodesByVal[value];
|
||||
value = value + ' 0x' + size + ' 0x' + data.toString('hex');
|
||||
out.push(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(typeof value === 'number');
|
||||
|
||||
if (constants.opcodesByVal[value]) {
|
||||
value = constants.opcodesByVal[value];
|
||||
out.push(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value === -1) {
|
||||
out.push('OP_INVALIDOPCODE');
|
||||
break;
|
||||
}
|
||||
|
||||
value = value.toString(16);
|
||||
|
||||
if (value.length < 2)
|
||||
value = '0' + value;
|
||||
|
||||
value = '0x' + value;
|
||||
out.push(value);
|
||||
}
|
||||
|
||||
return out.join(' ');
|
||||
};
|
||||
|
||||
/**
|
||||
* Format script code into bitcoind asm format.
|
||||
* @param {Array} code
|
||||
* @param {Boolean?} decode - Attempt to decode hash types.
|
||||
* @returns {String} Human-readable string.
|
||||
*/
|
||||
|
||||
exports.formatItem = function formatItem(data, decode) {
|
||||
var symbol, type;
|
||||
|
||||
if (data.length <= 4) {
|
||||
data = exports.num(data, constants.flags.VERIFY_NONE);
|
||||
return data.toString(10);
|
||||
}
|
||||
|
||||
if (decode) {
|
||||
symbol = '';
|
||||
if (exports.isSignatureEncoding(data)) {
|
||||
type = data[data.length - 1];
|
||||
symbol = constants.hashTypeByVal[type & 0x1f] || '';
|
||||
if (symbol) {
|
||||
if (type & constants.hashType.ANYONECANPAY)
|
||||
symbol += '|ANYONECANPAY';
|
||||
symbol = '[' + symbol + ']';
|
||||
}
|
||||
data = data.slice(0, -1);
|
||||
}
|
||||
return data.toString('hex') + symbol;
|
||||
}
|
||||
|
||||
return data.toString('hex');
|
||||
};
|
||||
|
||||
/**
|
||||
* Format script code into bitcoind asm format.
|
||||
* @param {Array} code
|
||||
* @param {Boolean?} decode - Attempt to decode hash types.
|
||||
* @returns {String} Human-readable string.
|
||||
*/
|
||||
|
||||
exports.formatASM = function formatASM(code, decode) {
|
||||
var out = [];
|
||||
var i, op, data, value;
|
||||
|
||||
if (code.length > 0 && code[0].value === opcodes.OP_RETURN)
|
||||
decode = false;
|
||||
|
||||
for (i = 0; i < code.length; i++) {
|
||||
op = code[i];
|
||||
data = op.data;
|
||||
value = op.value;
|
||||
|
||||
if (value === -1) {
|
||||
out.push('[error]');
|
||||
break;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
data = exports.formatItem(data, decode);
|
||||
out.push(data);
|
||||
continue;
|
||||
}
|
||||
|
||||
value = constants.opcodesByVal[value] || 'OP_UNKNOWN';
|
||||
|
||||
out.push(value);
|
||||
}
|
||||
|
||||
return out.join(' ');
|
||||
};
|
||||
|
||||
/**
|
||||
* Format script code into bitcoind asm format.
|
||||
* @param {Array} code
|
||||
* @param {Boolean?} decode - Attempt to decode hash types.
|
||||
* @returns {String} Human-readable string.
|
||||
*/
|
||||
|
||||
exports.formatStackASM = function formatStackASM(items, decode) {
|
||||
var out = [];
|
||||
var i, item, data;
|
||||
|
||||
for (i = 0; i < items.length; i++) {
|
||||
item = items[i];
|
||||
data = exports.formatItem(item, decode);
|
||||
out.push(data);
|
||||
}
|
||||
|
||||
return out.join(' ');
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a CScriptNum.
|
||||
* @param {Buffer} value
|
||||
* @param {Number?} flags - Script standard flags.
|
||||
* @param {Number?} size - Max size in bytes.
|
||||
* @returns {BN}
|
||||
* @throws {ScriptError}
|
||||
*/
|
||||
|
||||
exports.num = function num(value, flags, size) {
|
||||
var result;
|
||||
|
||||
assert(Buffer.isBuffer(value));
|
||||
|
||||
if (flags == null)
|
||||
flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
||||
|
||||
if (size == null)
|
||||
size = 4;
|
||||
|
||||
if (value.length > size)
|
||||
throw new ScriptError('UNKNOWN_ERROR', 'Script number overflow.');
|
||||
|
||||
if ((flags & constants.flags.VERIFY_MINIMALDATA) && value.length > 0) {
|
||||
// If the low bits on the last byte are unset,
|
||||
// fail if the value's second to last byte does
|
||||
// not have the high bit set. A number can't
|
||||
// justify having the last byte's low bits unset
|
||||
// unless they ran out of space for the sign bit
|
||||
// in the second to last bit. We also fail on [0]
|
||||
// to avoid negative zero (also avoids positive
|
||||
// zero).
|
||||
if (!(value[value.length - 1] & 0x7f)) {
|
||||
if (value.length === 1 || !(value[value.length - 2] & 0x80)) {
|
||||
throw new ScriptError(
|
||||
'UNKNOWN_ERROR',
|
||||
'Non-minimally encoded Script number.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value.length === 0)
|
||||
return new BN(0);
|
||||
|
||||
result = new BN(value, 'le');
|
||||
|
||||
// If the input vector's most significant byte is
|
||||
// 0x80, remove it from the result's msb and return
|
||||
// a negative.
|
||||
// Equivalent to:
|
||||
// -(result & ~(0x80 << (8 * (value.length - 1))))
|
||||
if (value[value.length - 1] & 0x80)
|
||||
result.setn((value.length * 8) - 1, 0).ineg();
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a script array. Will convert Numbers and big
|
||||
* numbers to a little-endian buffer while taking into
|
||||
* account negative zero, minimaldata, etc.
|
||||
* @example
|
||||
* assert.deepEqual(Script.array(0), new Buffer(0));
|
||||
* assert.deepEqual(Script.array(0xffee), new Buffer('eeff00', 'hex'));
|
||||
* assert.deepEqual(Script.array(new BN(0xffee)), new Buffer('eeff00', 'hex'));
|
||||
* assert.deepEqual(Script.array(new BN(0x1e).ineg()), new Buffer('9e', 'hex'));
|
||||
* @param {Number|BN} value
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
exports.array = function(value) {
|
||||
var neg, result;
|
||||
|
||||
if (utils.isNumber(value))
|
||||
value = new BN(value);
|
||||
|
||||
assert(BN.isBN(value));
|
||||
|
||||
if (value.cmpn(0) === 0)
|
||||
return STACK_FALSE;
|
||||
|
||||
// If the most significant byte is >= 0x80
|
||||
// and the value is positive, push a new
|
||||
// zero-byte to make the significant
|
||||
// byte < 0x80 again.
|
||||
|
||||
// If the most significant byte is >= 0x80
|
||||
// and the value is negative, push a new
|
||||
// 0x80 byte that will be popped off when
|
||||
// converting to an integral.
|
||||
|
||||
// If the most significant byte is < 0x80
|
||||
// and the value is negative, add 0x80 to
|
||||
// it, since it will be subtracted and
|
||||
// interpreted as a negative when
|
||||
// converting to an integral.
|
||||
|
||||
neg = value.cmpn(0) < 0;
|
||||
result = value.toArray('le');
|
||||
|
||||
if (result[result.length - 1] & 0x80)
|
||||
result.push(neg ? 0x80 : 0);
|
||||
else if (neg)
|
||||
result[result.length - 1] |= 0x80;
|
||||
|
||||
return new Buffer(result);
|
||||
};
|
||||
@ -7,12 +7,11 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = Opcode;
|
||||
|
||||
var BN = require('bn.js');
|
||||
var constants = require('../protocol/constants');
|
||||
var utils = require('../utils/utils');
|
||||
var Script = require('./script');
|
||||
var encoding = require('./encoding');
|
||||
var BufferWriter = require('../utils/writer');
|
||||
var assert = require('assert');
|
||||
var opcodes = constants.opcodes;
|
||||
|
||||
@ -40,8 +39,36 @@ function Opcode(value, data) {
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
Opcode.prototype.toRaw = function toRaw(writer) {
|
||||
return Script.encode([this], writer);
|
||||
Opcode.prototype.toRaw = function toRaw() {
|
||||
var p = new BufferWriter();
|
||||
|
||||
if (this.value === -1)
|
||||
throw new Error('Cannot reserialize a parse error.');
|
||||
|
||||
if (this.data) {
|
||||
if (this.value <= 0x4b) {
|
||||
p.writeU8(this.data.length);
|
||||
p.writeBytes(this.data);
|
||||
} else if (this.value === opcodes.OP_PUSHDATA1) {
|
||||
p.writeU8(opcodes.OP_PUSHDATA1);
|
||||
p.writeU8(this.data.length);
|
||||
p.writeBytes(this.data);
|
||||
} else if (this.value === opcodes.OP_PUSHDATA2) {
|
||||
p.writeU8(opcodes.OP_PUSHDATA2);
|
||||
p.writeU16(this.data.length);
|
||||
p.writeBytes(this.data);
|
||||
} else if (this.value === opcodes.OP_PUSHDATA4) {
|
||||
p.writeU8(opcodes.OP_PUSHDATA4);
|
||||
p.writeU32(this.data.length);
|
||||
p.writeBytes(this.data);
|
||||
} else {
|
||||
throw new Error('Unknown pushdata opcode.');
|
||||
}
|
||||
} else {
|
||||
p.writeU8(this.value);
|
||||
}
|
||||
|
||||
return p.render();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -107,7 +134,7 @@ Opcode.fromPush = function fromPush(data) {
|
||||
*/
|
||||
|
||||
Opcode.fromNumber = function fromNumber(num) {
|
||||
return Opcode.fromData(Script.array(num));
|
||||
return Opcode.fromData(encoding.array(num));
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = Program;
|
||||
|
||||
var constants = require('../protocol/constants');
|
||||
var utils = require('../utils/utils');
|
||||
var assert = require('assert');
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = Script;
|
||||
|
||||
var BN = require('bn.js');
|
||||
var constants = require('../protocol/constants');
|
||||
var utils = require('../utils/utils');
|
||||
@ -26,6 +24,7 @@ var Program = require('./program');
|
||||
var Opcode = require('./opcode');
|
||||
var Stack = require('./stack');
|
||||
var SigCache = require('./sigcache');
|
||||
var encoding = require('./encoding');
|
||||
var ec = require('../crypto/ec');
|
||||
var Address = require('../primitives/address');
|
||||
|
||||
@ -1332,51 +1331,7 @@ Script.bool = function bool(value) {
|
||||
*/
|
||||
|
||||
Script.num = function num(value, flags, size) {
|
||||
var result;
|
||||
|
||||
assert(Buffer.isBuffer(value));
|
||||
|
||||
if (flags == null)
|
||||
flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
||||
|
||||
if (size == null)
|
||||
size = 4;
|
||||
|
||||
if (value.length > size)
|
||||
throw new ScriptError('UNKNOWN_ERROR', 'Script number overflow.');
|
||||
|
||||
if ((flags & constants.flags.VERIFY_MINIMALDATA) && value.length > 0) {
|
||||
// If the low bits on the last byte are unset,
|
||||
// fail if the value's second to last byte does
|
||||
// not have the high bit set. A number can't
|
||||
// justify having the last byte's low bits unset
|
||||
// unless they ran out of space for the sign bit
|
||||
// in the second to last bit. We also fail on [0]
|
||||
// to avoid negative zero (also avoids positive
|
||||
// zero).
|
||||
if (!(value[value.length - 1] & 0x7f)) {
|
||||
if (value.length === 1 || !(value[value.length - 2] & 0x80)) {
|
||||
throw new ScriptError(
|
||||
'UNKNOWN_ERROR',
|
||||
'Non-minimally encoded Script number.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value.length === 0)
|
||||
return new BN(0);
|
||||
|
||||
result = new BN(value, 'le');
|
||||
|
||||
// If the input vector's most significant byte is
|
||||
// 0x80, remove it from the result's msb and return
|
||||
// a negative.
|
||||
// Equivalent to:
|
||||
// -(result & ~(0x80 << (8 * (value.length - 1))))
|
||||
if (value[value.length - 1] & 0x80)
|
||||
result.setn((value.length * 8) - 1, 0).ineg();
|
||||
|
||||
return result;
|
||||
return encoding.num(value, flags, size);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1393,41 +1348,7 @@ Script.num = function num(value, flags, size) {
|
||||
*/
|
||||
|
||||
Script.array = function(value) {
|
||||
var neg, result;
|
||||
|
||||
if (utils.isNumber(value))
|
||||
value = new BN(value);
|
||||
|
||||
assert(BN.isBN(value));
|
||||
|
||||
if (value.cmpn(0) === 0)
|
||||
return STACK_FALSE;
|
||||
|
||||
// If the most significant byte is >= 0x80
|
||||
// and the value is positive, push a new
|
||||
// zero-byte to make the significant
|
||||
// byte < 0x80 again.
|
||||
|
||||
// If the most significant byte is >= 0x80
|
||||
// and the value is negative, push a new
|
||||
// 0x80 byte that will be popped off when
|
||||
// converting to an integral.
|
||||
|
||||
// If the most significant byte is < 0x80
|
||||
// and the value is negative, add 0x80 to
|
||||
// it, since it will be subtracted and
|
||||
// interpreted as a negative when
|
||||
// converting to an integral.
|
||||
|
||||
neg = value.cmpn(0) < 0;
|
||||
result = value.toArray('le');
|
||||
|
||||
if (result[result.length - 1] & 0x80)
|
||||
result.push(neg ? 0x80 : 0);
|
||||
else if (neg)
|
||||
result[result.length - 1] |= 0x80;
|
||||
|
||||
return new Buffer(result);
|
||||
return encoding.array(value);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2690,7 +2611,7 @@ Script.prototype.set = function set(i, data) {
|
||||
*/
|
||||
|
||||
Script.isHash = function isHash(hash) {
|
||||
return Buffer.isBuffer(hash) && hash.length === 20;
|
||||
return encoding.isHash(hash);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2701,7 +2622,7 @@ Script.isHash = function isHash(hash) {
|
||||
*/
|
||||
|
||||
Script.isKey = function isKey(key) {
|
||||
return Buffer.isBuffer(key) && key.length >= 33 && key.length <= 65;
|
||||
return encoding.isKey(key);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2712,7 +2633,7 @@ Script.isKey = function isKey(key) {
|
||||
*/
|
||||
|
||||
Script.isSignature = function isSignature(sig) {
|
||||
return Buffer.isBuffer(sig) && sig.length >= 9 && sig.length <= 73;
|
||||
return encoding.isSignature(sig);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2722,7 +2643,7 @@ Script.isSignature = function isSignature(sig) {
|
||||
*/
|
||||
|
||||
Script.isDummy = function isDummy(data) {
|
||||
return Buffer.isBuffer(data) && data.length === 0;
|
||||
return encoding.isDummy(data);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2761,15 +2682,7 @@ Script.validateKey = function validateKey(key, flags, version) {
|
||||
*/
|
||||
|
||||
Script.isCompressedEncoding = function isCompressedEncoding(key) {
|
||||
assert(Buffer.isBuffer(key));
|
||||
|
||||
if (key.length !== 33)
|
||||
return false;
|
||||
|
||||
if (key[0] !== 0x02 && key[0] !== 0x03)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return encoding.isCompressedEncoding(key);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2779,22 +2692,7 @@ Script.isCompressedEncoding = function isCompressedEncoding(key) {
|
||||
*/
|
||||
|
||||
Script.isKeyEncoding = function isKeyEncoding(key) {
|
||||
assert(Buffer.isBuffer(key));
|
||||
|
||||
if (key.length < 33)
|
||||
return false;
|
||||
|
||||
if (key[0] === 0x04) {
|
||||
if (key.length !== 65)
|
||||
return false;
|
||||
} else if (key[0] === 0x02 || key[0] === 0x03) {
|
||||
if (key.length !== 33)
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return encoding.isKeyEncoding(key);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2847,87 +2745,7 @@ Script.validateSignature = function validateSignature(sig, flags) {
|
||||
*/
|
||||
|
||||
Script.isSignatureEncoding = function isSignatureEncoding(sig) {
|
||||
var lenR, lenS;
|
||||
|
||||
assert(Buffer.isBuffer(sig));
|
||||
|
||||
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash]
|
||||
// * total-length: 1-byte length descriptor of everything that follows,
|
||||
// excluding the sighash byte.
|
||||
// * R-length: 1-byte length descriptor of the R value that follows.
|
||||
// * R: arbitrary-length big-endian encoded R value. It must use the shortest
|
||||
// possible encoding for a positive integers (which means no null bytes at
|
||||
// the start, except a single one when the next byte has its highest bit set).
|
||||
// * S-length: 1-byte length descriptor of the S value that follows.
|
||||
// * S: arbitrary-length big-endian encoded S value. The same rules apply.
|
||||
// * sighash: 1-byte value indicating what data is hashed (not part of the DER
|
||||
// signature)
|
||||
|
||||
// Minimum and maximum size constraints.
|
||||
if (sig.length < 9)
|
||||
return false;
|
||||
|
||||
if (sig.length > 73)
|
||||
return false;
|
||||
|
||||
// A signature is of type 0x30 (compound).
|
||||
if (sig[0] !== 0x30)
|
||||
return false;
|
||||
|
||||
// Make sure the length covers the entire signature.
|
||||
if (sig[1] !== sig.length - 3)
|
||||
return false;
|
||||
|
||||
// Extract the length of the R element.
|
||||
lenR = sig[3];
|
||||
|
||||
// Make sure the length of the S element is still inside the signature.
|
||||
if (5 + lenR >= sig.length)
|
||||
return false;
|
||||
|
||||
// Extract the length of the S element.
|
||||
lenS = sig[5 + lenR];
|
||||
|
||||
// Verify that the length of the signature matches the sum of the length
|
||||
// of the elements.
|
||||
if (lenR + lenS + 7 !== sig.length)
|
||||
return false;
|
||||
|
||||
// Check whether the R element is an integer.
|
||||
if (sig[2] !== 0x02)
|
||||
return false;
|
||||
|
||||
// Zero-length integers are not allowed for R.
|
||||
if (lenR === 0)
|
||||
return false;
|
||||
|
||||
// Negative numbers are not allowed for R.
|
||||
if (sig[4] & 0x80)
|
||||
return false;
|
||||
|
||||
// Null bytes at the start of R are not allowed, unless R would
|
||||
// otherwise be interpreted as a negative number.
|
||||
if (lenR > 1 && (sig[4] === 0x00) && !(sig[5] & 0x80))
|
||||
return false;
|
||||
|
||||
// Check whether the S element is an integer.
|
||||
if (sig[lenR + 4] !== 0x02)
|
||||
return false;
|
||||
|
||||
// Zero-length integers are not allowed for S.
|
||||
if (lenS === 0)
|
||||
return false;
|
||||
|
||||
// Negative numbers are not allowed for S.
|
||||
if (sig[lenR + 6] & 0x80)
|
||||
return false;
|
||||
|
||||
// Null bytes at the start of S are not allowed, unless S would otherwise be
|
||||
// interpreted as a negative number.
|
||||
if (lenS > 1 && (sig[lenR + 6] === 0x00) && !(sig[lenR + 7] & 0x80))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return encoding.isSignatureEncoding(sig);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2972,58 +2790,7 @@ Script.isLowDER = function isLowDER(sig) {
|
||||
*/
|
||||
|
||||
Script.format = function format(code) {
|
||||
var out = [];
|
||||
var i, op, data, value, size;
|
||||
|
||||
for (i = 0; i < code.length; i++) {
|
||||
op = code[i];
|
||||
data = op.data;
|
||||
value = op.value;
|
||||
|
||||
if (data) {
|
||||
size = data.length.toString(16);
|
||||
|
||||
while (size.length % 2 !== 0)
|
||||
size = '0' + size;
|
||||
|
||||
if (!constants.opcodesByVal[value]) {
|
||||
value = value.toString(16);
|
||||
if (value.length < 2)
|
||||
value = '0' + value;
|
||||
value = '0x' + value + ' 0x' + data.toString('hex');
|
||||
out.push(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
value = constants.opcodesByVal[value];
|
||||
value = value + ' 0x' + size + ' 0x' + data.toString('hex');
|
||||
out.push(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(typeof value === 'number');
|
||||
|
||||
if (constants.opcodesByVal[value]) {
|
||||
value = constants.opcodesByVal[value];
|
||||
out.push(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value === -1) {
|
||||
out.push('OP_INVALIDOPCODE');
|
||||
break;
|
||||
}
|
||||
|
||||
value = value.toString(16);
|
||||
|
||||
if (value.length < 2)
|
||||
value = '0' + value;
|
||||
|
||||
value = '0x' + value;
|
||||
out.push(value);
|
||||
}
|
||||
|
||||
return out.join(' ');
|
||||
return encoding.formatCode(code);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -3034,52 +2801,7 @@ Script.format = function format(code) {
|
||||
*/
|
||||
|
||||
Script.formatASM = function formatASM(code, decode) {
|
||||
var out = [];
|
||||
var i, op, type, symbol, data, value;
|
||||
|
||||
for (i = 0; i < code.length; i++) {
|
||||
op = code[i];
|
||||
data = op.data;
|
||||
value = op.value;
|
||||
|
||||
if (value === -1) {
|
||||
out.push('[error]');
|
||||
break;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
if (data.length <= 4) {
|
||||
data = Script.num(data, constants.flags.VERIFY_NONE);
|
||||
out.push(data.toString(10));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (decode && code[0] !== opcodes.OP_RETURN) {
|
||||
symbol = '';
|
||||
if (Script.isSignatureEncoding(data)) {
|
||||
type = data[data.length - 1];
|
||||
symbol = constants.hashTypeByVal[type & 0x1f] || '';
|
||||
if (symbol) {
|
||||
if (type & constants.hashType.ANYONECANPAY)
|
||||
symbol += '|ANYONECANPAY';
|
||||
symbol = '[' + symbol + ']';
|
||||
}
|
||||
data = data.slice(0, -1);
|
||||
}
|
||||
out.push(data.toString('hex') + symbol);
|
||||
continue;
|
||||
}
|
||||
|
||||
out.push(data.toString('hex'));
|
||||
continue;
|
||||
}
|
||||
|
||||
value = constants.opcodesByVal[value] || 'OP_UNKNOWN';
|
||||
|
||||
out.push(value);
|
||||
}
|
||||
|
||||
return out.join(' ');
|
||||
return encoding.formatASM(code, decode);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -7,10 +7,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = Stack;
|
||||
|
||||
var Script = require('./script');
|
||||
var Witness = require('./witness');
|
||||
var encoding = require('./encoding');
|
||||
|
||||
/**
|
||||
* Represents the stack of a Script during execution.
|
||||
@ -51,7 +48,7 @@ Stack.prototype.inspect = function inspect() {
|
||||
*/
|
||||
|
||||
Stack.prototype.toString = function toString() {
|
||||
return Witness.format(this.items);
|
||||
return encoding.formatStack(this.items);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -61,19 +58,7 @@ Stack.prototype.toString = function toString() {
|
||||
*/
|
||||
|
||||
Stack.prototype.toASM = function toASM(decode) {
|
||||
return Script.formatASM(this.items, decode);
|
||||
};
|
||||
|
||||
/**
|
||||
* Pop the redeem script off the stack and deserialize it.
|
||||
* @returns {Script|null} The redeem script.
|
||||
*/
|
||||
|
||||
Stack.prototype.getRedeem = function getRedeem() {
|
||||
var redeem = this.items[this.items.length - 1];
|
||||
if (!redeem)
|
||||
return;
|
||||
return new Script(redeem);
|
||||
return encoding.formatStackASM(this.items, decode);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = Witness;
|
||||
|
||||
var BN = require('bn.js');
|
||||
var constants = require('../protocol/constants');
|
||||
var utils = require('../utils/utils');
|
||||
@ -18,6 +16,7 @@ var STACK_FALSE = new Buffer(0);
|
||||
var STACK_NEGATE = new Buffer([0x81]);
|
||||
var scriptTypes = constants.scriptTypes;
|
||||
var Script = require('./script');
|
||||
var encoding = require('./encoding');
|
||||
var Opcode = require('./opcode');
|
||||
var BufferWriter = require('../utils/writer');
|
||||
var BufferReader = require('../utils/reader');
|
||||
@ -131,7 +130,7 @@ Witness.prototype.inspect = function inspect() {
|
||||
*/
|
||||
|
||||
Witness.prototype.toString = function toString() {
|
||||
return Witness.format(this.items);
|
||||
return encoding.formatStack(this.items);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -141,7 +140,7 @@ Witness.prototype.toString = function toString() {
|
||||
*/
|
||||
|
||||
Witness.prototype.toASM = function toASM(decode) {
|
||||
return Script.formatASM(Script.parseArray(this.items), decode);
|
||||
return encoding.formatStackASM(this.items, decode);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -211,8 +210,8 @@ Witness.prototype.isPubkeyInput = function isPubkeyInput() {
|
||||
|
||||
Witness.prototype.isPubkeyhashInput = function isPubkeyhashInput() {
|
||||
return this.items.length === 2
|
||||
&& Script.isSignatureEncoding(this.items[0])
|
||||
&& Script.isKeyEncoding(this.items[1]);
|
||||
&& encoding.isSignatureEncoding(this.items[0])
|
||||
&& encoding.isKeyEncoding(this.items[1]);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -446,7 +445,7 @@ Witness.prototype.getNumber = function getNumber(i) {
|
||||
var item = this.items[i];
|
||||
if (!item || item.length > 5)
|
||||
return;
|
||||
return Script.num(item, constants.flags.VERIFY_NONE, 5);
|
||||
return encoding.num(item, constants.flags.VERIFY_NONE, 5);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -505,7 +504,7 @@ Witness.encodeItem = function encodeItem(data) {
|
||||
}
|
||||
|
||||
if (BN.isBN(data))
|
||||
return Script.array(data);
|
||||
return encoding.array(data);
|
||||
|
||||
if (typeof data === 'string')
|
||||
return new Buffer(data, 'utf8');
|
||||
@ -583,22 +582,6 @@ Witness.fromString = function fromString(items) {
|
||||
return new Witness().fromString(items);
|
||||
};
|
||||
|
||||
/**
|
||||
* Format script code into a human readable-string.
|
||||
* @param {Array} code
|
||||
* @returns {String} Human-readable string.
|
||||
*/
|
||||
|
||||
Witness.format = function format(items) {
|
||||
var out = [];
|
||||
var i;
|
||||
|
||||
for (i = 0; i < items.length; i++)
|
||||
out.push(items[i].toString('hex'));
|
||||
|
||||
return out.join(' ');
|
||||
};
|
||||
|
||||
/**
|
||||
* Test an object to see if it is a Witness.
|
||||
* @param {Object} obj
|
||||
|
||||
Loading…
Reference in New Issue
Block a user