diff --git a/src/script.js b/src/script.js index 019178c..636f5dd 100644 --- a/src/script.js +++ b/src/script.js @@ -104,72 +104,74 @@ Script.prototype.parse = function() { * templates and return a string naming the detected type. * * Currently supported are: - * Pubkeyhash + * Pubkeyhash (address) * Paying to a Bitcoin address which is the hash of a pubkey. * OP_DUP OP_HASH160 [pubKeyHash] OP_EQUALVERIFY OP_CHECKSIG - * Example: * - * Pubkey: + * Pubkey * Paying to a public key directly. * [pubKey] OP_CHECKSIG - * Example: txid 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098 * * Scripthash (P2SH) * Paying to an address which is the hash of a script * OP_HASH160 [Scripthash] OP_EQUAL - * Example: * * Multisig * Paying to multiple pubkeys and require a number of the signatures * m [pubkey] [pubkey] [pubkey] n OP_CHECKMULTISIG - * Example: * - * Strange: + * Nulldata + * Provably prune-able outputs + * OP_RETURN [data] + * + * Nonstandard: * Any other script (no template matched). + * + * https://github.com/bitcoin/bitcoin/blob/19e5b9d2dfcac4efadba636745485d9660fb1abe/src/script.cpp#L75 */ -// Below is the current standard set of out types -/* const char* GetTxnOutputType(txnouttype t) -{ - switch (t) - { - case TX_NONSTANDARD: return "nonstandard"; - case TX_PUBKEY: return "pubkey"; - case TX_PUBKEYHASH: return "pubkeyhash"; - case TX_SCRIPTHASH: return "scripthash"; - case TX_MULTISIG: return "multisig"; - case TX_NULL_DATA: return "nulldata"; - } - return NULL; -}*/ - -// https://github.com/bitcoin/bitcoin/blob/19e5b9d2dfcac4efadba636745485d9660fb1abe/src/script.cpp#L75 - -// supporting tx_null_data https://github.com/bitcoin/bitcoin/pull/3128 -// https://helloblock.io/mainnet/transactions/ebc9fa1196a59e192352d76c0f6e73167046b9d37b8302b6bb6968dfd279b767 Script.prototype.getOutType = function() { - if (this.chunks.length == 5 && + if (isPubkeyhash.call(this)) { + return 'pubkeyhash' + } else if (isPubkey.call(this)) { + return 'pubkey' + } else if (isScripthash.call(this)) { + return 'scripthash' + } else if (isMultisig.call(this)) { + return 'multisig' + } else if (isNulldata.call(this)) { + return 'nulldata' + } else { + return 'nonstandard' + } +} + +function isPubkeyhash() { + return this.chunks.length == 5 && this.chunks[0] == Opcode.map.OP_DUP && this.chunks[1] == Opcode.map.OP_HASH160 && Array.isArray(this.chunks[2]) && this.chunks[2].length === 20 && this.chunks[3] == Opcode.map.OP_EQUALVERIFY && - this.chunks[4] == Opcode.map.OP_CHECKSIG) { - // Transfer to Bitcoin address - return 'pubkeyhash'; - } else if (this.chunks.length === 2 && + this.chunks[4] == Opcode.map.OP_CHECKSIG +} + +function isPubkey() { + return this.chunks.length === 2 && Array.isArray(this.chunks[0]) && - this.chunks[1] === Opcode.map.OP_CHECKSIG) { - // [pubkey] OP_CHECKSIG - return 'pubkey'; - } else if (this.chunks[this.chunks.length - 1] == Opcode.map.OP_EQUAL && + this.chunks[1] === Opcode.map.OP_CHECKSIG +} + +function isScripthash() { + return this.chunks[this.chunks.length - 1] == Opcode.map.OP_EQUAL && this.chunks[0] == Opcode.map.OP_HASH160 && Array.isArray(this.chunks[1]) && this.chunks[1].length === 20 && - this.chunks.length == 3) { - // Transfer to M-OF-N - return 'scripthash'; - } else if (this.chunks.length > 3 && + this.chunks.length == 3 +} + +function isMultisig() { + return this.chunks.length > 3 && // m is a smallint isSmallIntOp(this.chunks[0]) && // n is a smallint @@ -181,32 +183,28 @@ Script.prototype.getOutType = function() { // n is the size of chunk length minus 3 (m, n, OP_CHECKMULTISIG) this.chunks.length - 3 === this.chunks[this.chunks.length - 2] - Opcode.map.OP_RESERVED && // last chunk is OP_CHECKMULTISIG - this.chunks[this.chunks.length - 1] == Opcode.map.OP_CHECKMULTISIG) { - return 'multisig' - } else if (this.chunks[0] === Opcode.map.OP_RETURN) { - return 'nulldata' - } else { - return 'nonstandard'; - } + this.chunks[this.chunks.length - 1] == Opcode.map.OP_CHECKMULTISIG +} + +function isNulldata() { + return this.chunks[0] === Opcode.map.OP_RETURN } function isSmallIntOp(opcode) { return ((opcode == Opcode.map.OP_0) || - ((opcode >= Opcode.map.OP_1) && (opcode <= Opcode.map.OP_16))); -}; + ((opcode >= Opcode.map.OP_1) && (opcode <= Opcode.map.OP_16))) +} /** * Returns the address corresponding to this output in hash160 form. * Assumes strange scripts are P2SH */ Script.prototype.toScriptHash = function() { - var outType = this.getOutType() - - if (outType == 'pubkeyhash') { + if(isPubkeyhash.call(this)) { return this.chunks[2] } - if (outType == 'scripthash') { + if(isScripthash.call(this)) { return crypto.hash160(this.buffer) } @@ -215,13 +213,11 @@ Script.prototype.toScriptHash = function() { //TODO: support testnet Script.prototype.getToAddress = function() { - var outType = this.getOutType() - - if (outType == 'pubkeyhash') { + if(isPubkeyhash.call(this)) { return new Address(this.chunks[2]) } - if (outType == 'scripthash') { + if(isScripthash.call(this)) { return new Address(this.chunks[1], 5) } @@ -255,7 +251,7 @@ Script.prototype.getFromAddress = function(){ * Multisig: * Paying to M-of-N public keys. * - * Strange: + * Nonstandard: * Any other script (no template matched). */ Script.prototype.getInType = function() { @@ -263,20 +259,20 @@ Script.prototype.getInType = function() { Array.isArray(this.chunks[0])) { // Direct IP to IP transactions only have the signature in their scriptSig. // TODO: We could also check that the length of the data is correct. - return 'pubkey'; + return 'pubkey' } else if (this.chunks.length == 2 && Array.isArray(this.chunks[0]) && Array.isArray(this.chunks[1])) { - return 'pubkeyhash'; + return 'pubkeyhash' } else if (this.chunks[0] == Opcode.map.OP_0 && this.chunks.slice(1).reduce(function(t, chunk, i) { - return t && Array.isArray(chunk) && (chunk[0] == 48 || i == this.chunks.length - 1); + return t && Array.isArray(chunk) && (chunk[0] == 48 || i == this.chunks.length - 1) }, true)) { - return 'multisig'; + return 'multisig' } else { - return 'nonstandard'; + return 'nonstandard' } -}; +} /** * Returns the affected public key for this input.