Browse Source

Merge branch 'master' of https://github.com/gasteve/node-libcoin

Conflicts:
	util/util.js
patch-2
Stephen Pair 11 years ago
parent
commit
467f0779f7
  1. 2
      RpcClient.js
  2. 133
      Sign.js
  3. 15
      Transaction.js
  4. 6
      WalletKey.js
  5. 21
      package.json
  6. 19
      test/basic.js
  7. 7
      test/values.json
  8. 52
      util/util.js

2
RpcClient.js

@ -35,7 +35,7 @@ function ClassSpec(b) {
dumpPrivKey: '',
encryptWallet: '',
getAccount: '',
getAccountAddress: '',
getAccountAddress: 'str',
getAddedNodeInfo: '',
getAddressesByAccount: '',
getBalance: 'str int',

133
Sign.js

@ -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);
};

15
Transaction.js

@ -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.
*

6
WalletKey.js

@ -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

@ -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"

19
test/basic.js

@ -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); });
});

7
test/values.json

@ -0,0 +1,7 @@
[
[ "0", "0" ],
[ "1.0", "100000000" ],
[ "0.1", "10000000" ],
[ ".1", "10000000" ],
[ "0.0005", "50000" ]
]

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…
Cancel
Save