diff --git a/Script.js b/Script.js index 62b485b32..a7d247127 100644 --- a/Script.js +++ b/Script.js @@ -170,32 +170,71 @@ function spec(b) { Script.prototype.writeOp = function (opcode) { - var buf = Put(); - buf.put(this.buffer); - buf.word8(opcode); - this.buffer = buf.buffer(); + var buf = Buffer(this.buffer.length + 1); + this.buffer.copy(buf); + buf.writeUInt8(opcode, this.buffer.length); + + this.buffer = buf; this.chunks.push(opcode); }; + Script.prototype.writeN = function (n) + { + if (n < 0 || n > 16) + throw new Error("writeN: out of range value " + n); + + if (n == 0) + this.writeOp(OP_0); + else + this.writeOp(OP_1 + n - 1); + }; + + function prefixSize(data_length) + { + if (data_length < OP_PUSHDATA1) { + return 1; + } else if (data_length <= 0xff) { + return 1 + 1; + } else if (data_length <= 0xffff) { + return 1 + 2; + } else { + return 1 + 4; + } + }; + + function encodeLen(data_length) { + var buf = undefined; + if (data_length < OP_PUSHDATA1) { + buf = new Buffer(1); + buf.writeUInt8(data_length, 0); + } + + else if (data_length <= 0xff) { + buf = new Buffer(1 + 1); + buf.writeUInt8(OP_PUSHDATA1, 0); + buf.writeUInt8(data_length, 1); + } + + else if (data_length <= 0xffff) { + buf = new Buffer(1 + 2); + buf.writeUInt8(OP_PUSHDATA2, 0); + buf.writeUInt16LE(data_length, 1); + } + + else { + buf = new Buffer(1 + 4); + buf.writeUInt8(OP_PUSHDATA4, 0); + buf.writeUInt32LE(data_length, 1); + } + + return buf; + }; + Script.prototype.writeBytes = function (data) { - var buf = Put(); - buf.put(this.buffer); - if (data.length < OP_PUSHDATA1) { - buf.word8(data.length); - } else if (data.length <= 0xff) { - buf.word8(OP_PUSHDATA1); - buf.word8(data.length); - } else if (data.length <= 0xffff) { - buf.word8(OP_PUSHDATA2); - buf.word16le(data.length); - } else { - buf.word8(OP_PUSHDATA4); - buf.word32le(data.length); - } - buf.put(data); - this.buffer = buf.buffer(); + var newSize = this.buffer.length + prefixSize(data.length) + data.length; + this.buffer = Buffer.concat([this.buffer, encodeLen(data.length), data]); this.chunks.push(data); }; @@ -256,6 +295,25 @@ function spec(b) { return script; }; + Script.createMultisig = function(n_required, keys) { + var script = new Script(); + script.writeN(n_required); + keys.forEach(function(key) { + script.writeBytes(key); + }); + script.writeN(keys.length); + script.writeOp(OP_CHECKMULTISIG); + return script; + }; + + Script.createP2SH = function(scriptHash) { + var script = new Script(); + script.writeOp(OP_HASH160); + script.writeBytes(scriptHash); + script.writeOp(OP_EQUAL); + return script; + }; + Script.fromTestData = function (testData) { testData = testData.map(function (chunk) { if ("string" === typeof chunk) { diff --git a/Wallet.js b/Wallet.js index 5178c577a..ac5a290d0 100644 --- a/Wallet.js +++ b/Wallet.js @@ -1,9 +1,12 @@ require('classtool'); +var hex = function(hex) {return new Buffer(hex, 'hex');}; function ClassSpec(b) { var fs = require('fs'); var EncFile = require('./util/EncFile'); + var Address = require('./Address').class(); var networks = require('./networks'); + var util = b.util || require('./util/util'); var ENC_METHOD = 'aes-256-cbc'; var skeleton = { @@ -14,6 +17,7 @@ function ClassSpec(b) { best_hash: null, best_height: -1, keys: [], + scripts: {}, }; function Wallet(cfg) { @@ -72,6 +76,60 @@ function ClassSpec(b) { this.dirty = true; }; + Wallet.prototype.findKeyHash = function(pubKeyHash) { + var pkhStr = pubKeyHash.toString(); + + for (var i = 0; i < this.datastore.keys.length; i++) { + var obj = this.datastore.keys[i]; + var addrStr = obj.addr; + var addr = new Address(addrStr); + if (addr.payload().toString() == pkhStr) + return obj; + } + + return undefined; + }; + + Wallet.prototype.expandKey = function(key) { + var addr = new Address(key); + var isAddr = true; + + try { + addr.validate(); + var b = addr.payload(); + var obj = this.findKeyHash(b); + key = obj.pub; + } catch(e) { + // do nothing + } + + var re = /^[a-fA-F0-9]+$/; + if (!key.match(re)) + throw new Error("Unknown key type"); + return hex(key); + }; + + Wallet.prototype.expandKeys = function(keys) { + var res = []; + var us = this; + keys.forEach(function(key) { + var expKey = us.expandKey(key); + res.push(expKey); + }); + return res; + }; + + Wallet.prototype.addScript = function(script) { + var buf = script.getBuffer(); + var hash = util.sha256ripe160(buf); + var addr = new Address(this.network.addressScript, hash); + var addrStr = addr.as('base58'); + this.datastore.scripts[addrStr] = buf.toString('hex'); + this.dirty = true; + + return addrStr; + }; + return Wallet; }; module.defineClass(ClassSpec);