Merge branch 'master' of https://github.com/gasteve/node-libcoin
Conflicts: util/util.js
This commit is contained in:
commit
467f0779f7
|
@ -35,7 +35,7 @@ function ClassSpec(b) {
|
|||
dumpPrivKey: '',
|
||||
encryptWallet: '',
|
||||
getAccount: '',
|
||||
getAccountAddress: '',
|
||||
getAccountAddress: 'str',
|
||||
getAddedNodeInfo: '',
|
||||
getAddressesByAccount: '',
|
||||
getBalance: 'str int',
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
|
||||
function signOne(hash, addrStr, keys)
|
||||
{
|
||||
var keyObj = keys[addrStr];
|
||||
var rawPrivKey = new Buffer(keyObj.priv, 'hex');
|
||||
var key = new KeyModule.Key();
|
||||
key.private = rawPrivKey;
|
||||
var signature = key.signSync(hash);
|
||||
|
||||
return signature;
|
||||
}
|
||||
|
||||
function signTxIn(nIn, tx, txInputs, network, keys, scripts)
|
||||
{
|
||||
// locate TX input needing a signature
|
||||
var txin = tx.ins[nIn];
|
||||
var scriptSig = txin.getScript();
|
||||
|
||||
// locate TX output, within txInputs
|
||||
var txoutHash = txin.getOutpointHash();
|
||||
if (!(txoutHash in txInputs))
|
||||
throw new Error("signTxIn missing input hash");
|
||||
var txFrom = txInputs[txoutHash];
|
||||
var txoutIndex = txin.getOutpointIndex();
|
||||
if (txFrom.outs.length >= txoutIndex)
|
||||
throw new Error("signTxIn missing input index");
|
||||
var txout = txFrom.outs[txoutIndex];
|
||||
var scriptPubKey = txout.getScript();
|
||||
|
||||
// detect type of transaction, and extract useful elements
|
||||
var txType = scriptPubKey.classify();
|
||||
if (txType == TX_UNKNOWN)
|
||||
throw new Error("unknown TX type");
|
||||
var scriptData = scriptPubKey.capture();
|
||||
|
||||
// if P2SH, lookup the script
|
||||
var subscriptRaw = undefined;
|
||||
var subscript = undefined;
|
||||
var subType = undefined;
|
||||
var subData = undefined;
|
||||
if (txType == TX_SCRIPTHASH) {
|
||||
var addr = new Address(network.addressScript, scriptData[0]);
|
||||
var addrStr = addr.toString();
|
||||
if (!(addrStr in scripts))
|
||||
throw new Error("unknown script hash address");
|
||||
|
||||
subscriptRaw = new Buffer(scripts[addrStr], 'hex');
|
||||
subscript = new Script(subscriptRaw);
|
||||
subType = subscript.classify();
|
||||
if (subType == TX_UNKNOWN)
|
||||
throw new Error("unknown subscript TX type");
|
||||
subData = subscript.capture();
|
||||
}
|
||||
|
||||
var hash = tx.hashForSignature(scriptPubKey, i, 0);
|
||||
|
||||
switch (txType) {
|
||||
case TX_PUBKEY:
|
||||
// already signed
|
||||
if (scriptSig.chunks.length > 0)
|
||||
return;
|
||||
|
||||
var pubkeyhash = util.sha256ripe160(scriptData[0]);
|
||||
var addr = new Address(network.addressPubkey, pubkeyhash);
|
||||
var addrStr = addr.toString();
|
||||
if (!(addrStr in keys))
|
||||
throw new Error("unknown pubkey");
|
||||
|
||||
var signature = signOne(hash, addrStr, keys);
|
||||
scriptSig.writeBytes(signature);
|
||||
break;
|
||||
|
||||
case TX_PUBKEYHASH:
|
||||
// already signed
|
||||
if (scriptSig.chunks.length > 0)
|
||||
return;
|
||||
|
||||
var addr = new Address(network.addressPubkey, scriptData[0]);
|
||||
var addrStr = addr.toString();
|
||||
if (!(addrStr in keys))
|
||||
throw new Error("unknown pubkey hash address");
|
||||
|
||||
var signature = signOne(hash, addrStr, keys);
|
||||
scriptSig.writeBytes(signature);
|
||||
scriptSig.writeBytes(key.public);
|
||||
break;
|
||||
|
||||
case TX_SCRIPTHASH:
|
||||
// already signed
|
||||
if (scriptSig.chunks.length > 0)
|
||||
return;
|
||||
|
||||
var addr = new Address(network.addressPubkey, subData[0]);
|
||||
var addrStr = addr.toString();
|
||||
if (!(addrStr in keys))
|
||||
throw new Error("unknown script(pubkey hash) address");
|
||||
|
||||
var signature = signOne(hash, addrStr, keys);
|
||||
scriptSig.writeBytes(signature);
|
||||
scriptSig.writeBytes(key.public);
|
||||
break;
|
||||
|
||||
case TX_MULTISIG:
|
||||
while (scriptSig.chunks.length < scriptData.length) {
|
||||
scriptSig.writeBytes(util.EMPTY_BUFFER);
|
||||
}
|
||||
for (var i = 0; i < scriptData.length; i++) {
|
||||
// skip already signed
|
||||
if (scriptSig.chunks[i].length > 0)
|
||||
continue;
|
||||
|
||||
var pubkeyhash = util.sha256ripe160(scriptSig.chunks[i]);
|
||||
var addr = new Address(network.addressPubkey, pubkeyhash);
|
||||
var addrStr = addr.toString();
|
||||
if (!(addrStr in keys))
|
||||
continue;
|
||||
|
||||
var signature = signOne(hash, addrStr, keys);
|
||||
scriptSig.chunks[i] = signature;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (txtype == TX_SCRIPTHASH)
|
||||
scriptSig.writeBytes(subscriptRaw);
|
||||
}
|
||||
|
||||
exports.Transaction = function Transaction(tx, txInputs, network, keys, scripts)
|
||||
{
|
||||
for (var i = 0; i < tx.ins.length; i++)
|
||||
signTxIn(i, tx, txInputs, network, keys, scripts);
|
||||
};
|
||||
|
|
@ -45,7 +45,7 @@ function spec(b) {
|
|||
return Buffer.concat([this.o, slen, this.s, qbuf]);
|
||||
};
|
||||
|
||||
TransactionIn.prototype.getOutpointHash = function getOutpointIndex() {
|
||||
TransactionIn.prototype.getOutpointHash = function getOutpointHash() {
|
||||
if ("undefined" !== typeof this.o.outHashCache) {
|
||||
return this.o.outHashCache;
|
||||
}
|
||||
|
@ -181,6 +181,19 @@ function spec(b) {
|
|||
return this.hash;
|
||||
};
|
||||
|
||||
// convert encoded list of inputs to easy-to-use JS list-of-lists
|
||||
Transaction.prototype.inputs = function inputs() {
|
||||
var res = [];
|
||||
for (var i = 0; i < this.ins.length; i++) {
|
||||
var txin = this.ins[i];
|
||||
var outHash = txin.getOutpointHash();
|
||||
var outIndex = txin.getOutpointIndex();
|
||||
res.push([outHash, outIndex]);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and cache transaction inputs.
|
||||
*
|
||||
|
|
|
@ -31,6 +31,12 @@ function ClassSpec(b) {
|
|||
return obj;
|
||||
};
|
||||
|
||||
WalletKey.prototype.fromObj = function(obj) {
|
||||
this.created = obj.created;
|
||||
this.privKey = new KeyModule.Key();
|
||||
this.privKey.private = new Buffer(obj.priv, 'hex');
|
||||
};
|
||||
|
||||
return WalletKey;
|
||||
};
|
||||
module.defineClass(ClassSpec);
|
||||
|
|
21
package.json
21
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "libcoin",
|
||||
"description": "Bitcoin Library",
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.4",
|
||||
"author": {
|
||||
"name": "Stephen Pair",
|
||||
"email": "stephen@bitpay.com"
|
||||
|
@ -10,7 +10,6 @@
|
|||
{"name": "Stefan Thomas", "email": "moon@justmoon.net"},
|
||||
{"name": "Jeff Garzik", "email": "jgarzik@bitpay.com"}
|
||||
],
|
||||
"main": "./index",
|
||||
"keywords": [
|
||||
"bitcoin",
|
||||
"btc",
|
||||
|
@ -25,15 +24,15 @@
|
|||
},
|
||||
"scripts": {},
|
||||
"dependencies": {
|
||||
"classtool": ">=1.0.0",
|
||||
"base58-native": ">=0.1.1",
|
||||
"bindings": ">=1.1.0",
|
||||
"bufferput": ">=0.1.1",
|
||||
"bignum": "0.6.1",
|
||||
"binary": "0.3.0",
|
||||
"step": "0.0.4",
|
||||
"buffers": ">=0.1.1",
|
||||
"buffertools": "1.1.1"
|
||||
"classtool": "=1.0.0",
|
||||
"base58-native": "=0.1.1",
|
||||
"bindings": "=1.1.0",
|
||||
"bufferput": "=0.1.1",
|
||||
"bignum": "=0.6.1",
|
||||
"binary": "=0.3.0",
|
||||
"step": "=0.0.4",
|
||||
"buffers": "=0.1.1",
|
||||
"buffertools": "=1.1.1"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"license": "MIT"
|
||||
|
|
|
@ -5,6 +5,7 @@ var Address = require('../Address').class();
|
|||
var PrivateKey = require('../PrivateKey').class();
|
||||
var networks = require('../networks');
|
||||
var KeyModule = require('../Key');
|
||||
var coinUtil = require('../util/util');
|
||||
|
||||
suite('basic');
|
||||
|
||||
|
@ -110,8 +111,22 @@ function is_invalid(datum)
|
|||
assert.equal(valid, false);
|
||||
}
|
||||
|
||||
function test_value(datum)
|
||||
{
|
||||
if (datum.length != 2)
|
||||
throw new Error("Bad test");
|
||||
|
||||
var decimal = datum[0];
|
||||
var intStr = datum[1];
|
||||
|
||||
var bn = coinUtil.parseValue(decimal);
|
||||
assert.notEqual(bn, undefined);
|
||||
assert.equal(bn.toString(), intStr);
|
||||
}
|
||||
|
||||
var dataValid = JSON.parse(fs.readFileSync('test/base58_keys_valid.json'));
|
||||
var dataInvalid = JSON.parse(fs.readFileSync('test/base58_keys_invalid.json'));
|
||||
var dataValues = JSON.parse(fs.readFileSync('test/values.json'));
|
||||
|
||||
test('valid', function() {
|
||||
dataValid.forEach(function(datum) { is_valid(datum); });
|
||||
|
@ -121,3 +136,7 @@ test('invalid', function() {
|
|||
dataInvalid.forEach(function(datum) { is_invalid(datum); });
|
||||
});
|
||||
|
||||
test('values', function() {
|
||||
dataValues.forEach(function(datum) { test_value(datum); });
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
[
|
||||
[ "0", "0" ],
|
||||
[ "1.0", "100000000" ],
|
||||
[ "0.1", "10000000" ],
|
||||
[ ".1", "10000000" ],
|
||||
[ "0.0005", "50000" ]
|
||||
]
|
52
util/util.js
52
util/util.js
|
@ -108,6 +108,49 @@ var formatValue = exports.formatValue = function (valueBuffer) {
|
|||
return integerPart+"."+decimalPart;
|
||||
};
|
||||
|
||||
var reFullVal = /^\s*(\d+)\.(\d+)/;
|
||||
var reFracVal = /^\s*\.(\d+)/;
|
||||
var reWholeVal = /^\s*(\d+)/;
|
||||
|
||||
function padFrac(frac)
|
||||
{
|
||||
while (frac.length < 8)
|
||||
frac = frac + '0';
|
||||
return frac;
|
||||
}
|
||||
|
||||
function parseFullValue(res)
|
||||
{
|
||||
return bignum(res[1]).mul('100000000').add(padFrac(res[2]));
|
||||
}
|
||||
|
||||
function parseFracValue(res)
|
||||
{
|
||||
return bignum(padFrac(res[1]));
|
||||
}
|
||||
|
||||
function parseWholeValue(res)
|
||||
{
|
||||
return bignum(res[1]).mul('100000000');
|
||||
}
|
||||
|
||||
exports.parseValue = function parseValue(valueStr)
|
||||
{
|
||||
var res = valueStr.match(reFullVal);
|
||||
if (res)
|
||||
return parseFullValue(res);
|
||||
|
||||
res = valueStr.match(reFracVal);
|
||||
if (res)
|
||||
return parseFracValue(res);
|
||||
|
||||
res = valueStr.match(reWholeVal);
|
||||
if (res)
|
||||
return parseWholeValue(res);
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
// Utility that synchronizes function calls based on a key
|
||||
var createSynchrotron = exports.createSynchrotron = function (fn) {
|
||||
var table = {};
|
||||
|
@ -280,15 +323,6 @@ var varStrBuf = exports.varStrBuf = function varStrBuf(s) {
|
|||
return Buffer.concat(varIntBuf(s.length), s);
|
||||
};
|
||||
|
||||
var buf64 = exports.buf64 = function buf64(n) {
|
||||
var lo = n & 0xffffffff;
|
||||
var hi = (n >>> 32);
|
||||
var buf = new Buffer(4 + 4);
|
||||
buf.writeUInt32LE(lo, 0);
|
||||
buf.writeUInt32LE(hi, 4);
|
||||
return buf;
|
||||
};
|
||||
|
||||
// Initializations
|
||||
exports.NULL_HASH = new Buffer(32).fill(0);
|
||||
exports.EMPTY_BUFFER = new Buffer(0);
|
||||
|
|
Loading…
Reference in New Issue