From 3e608c2cc658316cdf79bf7ef978dbb99ffc537a Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Thu, 17 Dec 2015 14:48:59 -0800 Subject: [PATCH] script and standard transaction types. prefixes. --- lib/bcoin/pool.js | 4 +-- lib/bcoin/protocol/network.js | 8 +++-- lib/bcoin/script.js | 31 +++++++++++++++- lib/bcoin/tx.js | 67 ++++++++++++++++++++++------------- lib/bcoin/wallet.js | 20 +++++------ test/wallet-test.js | 6 ++-- 6 files changed, 94 insertions(+), 42 deletions(-) diff --git a/lib/bcoin/pool.js b/lib/bcoin/pool.js index bc4a4a03..2f67f49b 100644 --- a/lib/bcoin/pool.js +++ b/lib/bcoin/pool.js @@ -545,7 +545,7 @@ Pool.prototype.removeWallet = function removeWallet(w) { }; Pool.prototype.watchWallet = function watchWallet(w) { - if (w.type === 'script') { + if (w.type === 'scripthash') { // For the redeem script hash in outputs: this.watch(w.getFullHash()); // For the redeem script in inputs: @@ -558,7 +558,7 @@ Pool.prototype.watchWallet = function watchWallet(w) { }; Pool.prototype.unwatchWallet = function unwatchWallet(w) { - if (w.type === 'script') { + if (w.type === 'scripthash') { // For the redeem script hash in p2sh outputs: this.unwatch(w.getFullHash()); // For the redeem script in p2sh inputs: diff --git a/lib/bcoin/protocol/network.js b/lib/bcoin/protocol/network.js index 3d3e5dee..07028c68 100644 --- a/lib/bcoin/protocol/network.js +++ b/lib/bcoin/protocol/network.js @@ -20,7 +20,9 @@ var main = network.main = {}; main.prefixes = { pubkey: 0, - script: 5, + pubkeyhash: 0, + multisig: 0, + scripthash: 5, privkey: 128, xpubkey: 0x0488b21e, xprivkey: 0x0488ade4 @@ -107,7 +109,9 @@ testnet.type = 'testnet'; testnet.prefixes = { pubkey: 111, - script: 196, + pubkeyhash: 111, + multisig: 111, + scripthash: 196, privkey: 239, xpubkey: 0x043587cf, xprivkey: 0x04358394 diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index 732356be..cda6da43 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -783,7 +783,27 @@ script.multisig = function(keys, m, n) { ); }; +script.standard = function standard(s) { + return (script.isPubkey(s) && 'pubkey') + || (script.isPubkeyhash(s) && 'pubkeyhash') + || (script.isMultisig(s) && 'multisig') + || (script.isScripthash(s) && 'scripthash') + || (script.isNullData(s) && 'colored') + || 'nonstandard'; +}; + +script.lockTime = function lockTime(s) { + return s.length > 3 + && Array.isArray(s[0]) + && s[1] === 'checklocktimeverify' + && s[2] === 'drop' + && new bn(s[0]); +}; + script.isPubkeyhash = function isPubkeyhash(s, hash) { + if (script.lockTime(s)) + s = s.slice(3); + if (s.length !== 5) return false; @@ -801,7 +821,10 @@ script.isPubkeyhash = function isPubkeyhash(s, hash) { return s[2]; }; -script.isSimplePubkeyhash = function isSimplePubkeyhash(s, hash) { +script.isPubkey = function isPubkey(s, hash) { + if (script.lockTime(s)) + s = s.slice(3); + if (s.length !== 2) return false; @@ -816,6 +839,9 @@ script.isSimplePubkeyhash = function isSimplePubkeyhash(s, hash) { }; script.isMultisig = function isMultisig(s, key) { + if (script.lockTime(s)) + s = s.slice(3); + if (s.length < 4) return false; @@ -863,6 +889,9 @@ script.isPubkeyhashInput = function isPubkeyhashInput(s) { }; script.isScripthash = function isScripthash(s, hash) { + if (script.lockTime(s)) + s = s.slice(3); + if (s.length !== 3) return false; diff --git a/lib/bcoin/tx.js b/lib/bcoin/tx.js index 49bb3e27..3cf3a48f 100644 --- a/lib/bcoin/tx.js +++ b/lib/bcoin/tx.js @@ -156,8 +156,15 @@ TX.prototype.scriptInput = function(input, pub) { if (input.script.length) return; - // P2PKH and simple tx - if (bcoin.script.isPubkeyhash(s) || bcoin.script.isSimplePubkeyhash(s)) { + // P2PK + if (bcoin.script.isPubkey(s)) { + input.script = [ [] ]; + this._recalculateFee(); + return; + } + + // P2PKH + if (bcoin.script.isPubkeyhash(s)) { input.script = [ [], pub ]; this._recalculateFee(); return; @@ -220,8 +227,14 @@ TX.prototype.signInput = function(input, key, type) { // Add the sighash as a single byte to the signature signature = signature.concat(type); - // P2PKH and simple tx - if (bcoin.script.isPubkeyhash(s) || bcoin.script.isSimplePubkeyhash(s)) { + // P2PK + if (bcoin.script.isPubkey(s)) { + input.script[0] = signature; + return; + } + + // P2PKH + if (bcoin.script.isPubkeyhash(s)) { input.script[0] = signature; return; } @@ -345,7 +358,7 @@ TX.prototype.scriptOutput = function(output, options) { if (keys === options.address) { keys = keys.map(function(address) { - return bcoin.wallet.addr2hash(address, 'pubkey'); + return bcoin.wallet.addr2hash(address, 'pubkeyhash'); }); } @@ -367,13 +380,13 @@ TX.prototype.scriptOutput = function(output, options) { assert(n >= 1 && n <= 3); script = bcoin.script.multisig(keys, m, n); - } else if (bcoin.wallet.validateAddress(options.address, 'script')) { + } else if (bcoin.wallet.validateAddress(options.address, 'scripthash')) { // p2sh transaction // https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki // hash160 [20-byte-redeemscript-hash] equal script = [ 'hash160', - bcoin.wallet.addr2hash(options.address, 'script'), + bcoin.wallet.addr2hash(options.address, 'scripthash'), 'eq' ]; } else if (options.address) { @@ -382,7 +395,7 @@ TX.prototype.scriptOutput = function(output, options) { script = [ 'dup', 'hash160', - bcoin.wallet.addr2hash(options.address, 'pubkey'), + bcoin.wallet.addr2hash(options.address, 'pubkeyhash'), 'eqverify', 'checksig' ]; @@ -543,7 +556,13 @@ TX.prototype.maxSize = function maxSize() { // Get the previous output's subscript var s = input.out.tx.getSubscript(input.out.index); - if (bcoin.script.isPubkeyhash(s) || bcoin.script.isSimplePubkeyhash(s)) { + if (bcoin.script.isPubkey(s)) { + // Signature + len + size += 74; + return; + } + + if (bcoin.script.isPubkeyhash(s)) { // Signature + len size += 74; // Pub key + len @@ -760,7 +779,7 @@ TX.prototype.inputAddrs = function inputAddrs() { }).map(function(input) { var pub = input.script[1]; var hash = utils.ripesha(pub); - return bcoin.wallet.hash2addr(hash, 'pubkey'); + return bcoin.wallet.hash2addr(hash, 'pubkeyhash'); }); }; @@ -790,7 +809,7 @@ TX.getInputKey = function(input) { if (bcoin.script.isScripthash(script)) { var pub = script[script.length - 1]; var hash = utils.ripesha(pub); - var addr = bcoin.wallet.hash2addr(hash, 'script'); + var addr = bcoin.wallet.hash2addr(hash, 'scripthash'); var redeem = bcoin.script.decode(pub); var keys = TX.getOutputKey({ script: redeem }); keys.pub = pub; @@ -814,18 +833,7 @@ TX.getOutputKey = function(output) { var script = output.script; - if (bcoin.script.isPubkeyhash(script)) { - var hash = script[2]; - var addr = bcoin.wallet.hash2addr(hash); - return { - sig: null, - pub: null, - hash: hash, - addr: addr - }; - } - - if (bcoin.script.isSimplePubkeyhash(script)) { + if (bcoin.script.isPubkey(script)) { var pubKey = script[0]; var hash = utils.ripesha(pubKey); var addr = bcoin.wallet.hash2addr(hash); @@ -837,6 +845,17 @@ TX.getOutputKey = function(output) { }; } + if (bcoin.script.isPubkeyhash(script)) { + var hash = script[2]; + var addr = bcoin.wallet.hash2addr(hash); + return { + sig: null, + pub: null, + hash: hash, + addr: addr + }; + } + var pubKeys = bcoin.script.isMultisig(script); if (pubKeys) { var keys = pubKeys.map(function(pubKey) { @@ -859,7 +878,7 @@ TX.getOutputKey = function(output) { if (bcoin.script.isScripthash(script, scriptHash)) { var hash = utils.toHex(s[1]); - var addr = bcoin.wallet.hash2addr(hash, 'script'); + var addr = bcoin.wallet.hash2addr(hash, 'scripthash'); return { sig: null, pub: null, diff --git a/lib/bcoin/wallet.js b/lib/bcoin/wallet.js index f253ef76..0d462073 100644 --- a/lib/bcoin/wallet.js +++ b/lib/bcoin/wallet.js @@ -66,7 +66,7 @@ function Wallet(options, passphrase) { this.key = bcoin.ecdsa.genKeyPair(); } - this.type = 'pubkey'; + this.type = 'pubkeyhash'; this.keys = []; this.m = 1; this.n = 1; @@ -123,12 +123,12 @@ Wallet.prototype.multisig = function multisig(options) { options.type = options.type || options.prefix; options.keys = options.keys || options.pubkeys || []; - this.type = options.type || 'pubkey'; + this.type = options.type || 'pubkeyhash'; // this.keys = (options.keys || []).map(utils.toKeyArray); this.keys = []; this.m = options.m || 1; this.n = options.n || 1; - this.nmax = this.type === 'script' + this.nmax = this.type === 'scripthash' ? (this.compressed ? 15 : 7) : 3; @@ -143,7 +143,7 @@ Wallet.prototype.multisig = function multisig(options) { // Use p2sh multisig by default if (!options.type && this.keys.length > 1) - this.type = 'script'; + this.type = 'scripthash'; if (this.m < 1 || this.m > this.n) throw new Error('m ranges between 1 and n'); @@ -236,7 +236,7 @@ Wallet.prototype.getPrivateKey = function getPrivateKey(enc) { Wallet.prototype.getFullPublicKey = function getFullPublicKey(enc) { var pub = this.getOwnPublicKey(); - if (this.type === 'script') { + if (this.type === 'scripthash') { var keys = this.getPublicKeys(); pub = bcoin.script.encode(bcoin.script.multisig(keys, this.m, this.n)); } @@ -308,7 +308,7 @@ Wallet.key2hash = function key2hash(key) { Wallet.hash2addr = function hash2addr(hash, prefix) { hash = utils.toArray(hash, 'hex'); - prefix = network.prefixes[prefix || 'pubkey']; + prefix = network.prefixes[prefix || 'pubkeyhash']; hash = [ prefix ].concat(hash); var addr = hash.concat(utils.checksum(hash)); @@ -317,7 +317,7 @@ Wallet.hash2addr = function hash2addr(hash, prefix) { Wallet.__defineGetter__('prefixes', function() { if (Wallet._prefixes) return Wallet._prefixes; - Wallet._prefixes = ['pubkey', 'script'].reduce(function(out, prefix) { + Wallet._prefixes = ['pubkeyhash', 'scripthash'].reduce(function(out, prefix) { var ch = Wallet.hash2addr(Wallet.key2hash([]), prefix)[0]; out[ch] = prefix; return out; @@ -332,7 +332,7 @@ Wallet.addr2hash = function addr2hash(addr, prefix) { if (!Array.isArray(addr)) addr = utils.fromBase58(addr); - prefix = network.prefixes[prefix || 'pubkey']; + prefix = network.prefixes[prefix || 'pubkeyhash']; if (addr.length !== 25) return []; @@ -365,10 +365,10 @@ Wallet.prototype.ownOutput = function ownOutput(tx, index) { var s = output.script; - if (bcoin.script.isPubkeyhash(s, hash)) + if (bcoin.script.isPubkey(s, hash)) return true; - if (bcoin.script.isSimplePubkeyhash(s, hash)) + if (bcoin.script.isPubkeyhash(s, hash)) return true; if (bcoin.script.isMultisig(s, key)) diff --git a/test/wallet-test.js b/test/wallet-test.js index 44fc889e..04cf40c1 100644 --- a/test/wallet-test.js +++ b/test/wallet-test.js @@ -280,7 +280,7 @@ describe('Wallet', function() { var w1 = bcoin.wallet({ key: key1, multisig: { - type: 'script', + type: 'scripthash', keys: [pub2, pub3], m: 2, n: 3 @@ -289,7 +289,7 @@ describe('Wallet', function() { var w2 = bcoin.wallet({ key: key2, multisig: { - type: 'script', + type: 'scripthash', keys: [pub1, pub3], m: 2, n: 3 @@ -298,7 +298,7 @@ describe('Wallet', function() { var w3 = bcoin.wallet({ key: key3, multisig: { - type: 'script', + type: 'scripthash', keys: [pub1, pub2], m: 2, n: 3