Browse Source

Added sign with keys method to transaction and did lots of small cleanups

hk-custom-address
vub 12 years ago
parent
commit
f53a4e3ffa
  1. 6
      bitcoinjs-min.js
  2. 37
      src/address.js
  3. 75
      src/script.js
  4. 82
      src/transaction.js
  5. 3
      src/util.js

6
bitcoinjs-min.js

File diff suppressed because one or more lines are too long

37
src/address.js

@ -1,6 +1,7 @@
var base58 = require('./base58'); var base58 = require('./base58');
var Crypto = require('./crypto-js/crypto'); var Crypto = require('./crypto-js/crypto');
var conv = require('./convert'); var conv = require('./convert');
var util = require('./util');
var address_types = { var address_types = {
prod: 0, prod: 0,
@ -12,14 +13,18 @@ var p2sh_types = {
testnet: 196 testnet: 196
}; };
var Address = function (bytes) { var Address = function (bytes, version) {
if (typeof bytes === 'string') { if (typeof bytes === 'string') {
this.hash = base58.checkDecode(bytes); this.hash =
this.version = this.hash.version; bytes.length <= 34 ? base58.checkDecode(bytes)
: bytes.length <= 40 ? conv.hexToBytes(bytes)
: util.error('Bad input');
this.version = version || this.hash.version || 0;
} }
else { else {
this.hash = bytes; this.hash = bytes;
this.version = 0x00; this.version = version || 0;
} }
}; };
@ -29,35 +34,31 @@ var Address = function (bytes) {
* Returns the address as a base58-encoded string in the standardized format. * Returns the address as a base58-encoded string in the standardized format.
*/ */
Address.prototype.toString = function () { Address.prototype.toString = function () {
// Get a copy of the hash return base58.checkEncode(this.hash.slice(0),this.version);
var hash = this.hash.slice(0);
return base58.checkEncode(hash,this.version);
}; };
Address.prototype.getHash = function () { Address.prototype.getHash = function () {
return conv.bytesToHex(this.hash); return conv.bytesToHex(this.hash);
}; };
Address.getVersion = function(string) { Address.getVersion = function(string) {
return base58.decode(string)[0]; return base58.decode(string)[0];
} }
// TODO(shtylman) isValid?
Address.validate = function(string) { Address.validate = function(string) {
try { try {
base58.checkDecode(string); base58.checkDecode(string);
} catch (e) { return true;
return false; } catch (e) {
} return false;
return true; }
}; };
/** /**
* Parse a Bitcoin address contained in a string. * Parse a Bitcoin address contained in a string.
*/ */
Address.decodeString = function (string) { Address.decodeString = function (string) {
return base58.checkDecode(string); return base58.checkDecode(string);
}; };
module.exports = Address; module.exports = Address;

75
src/script.js

@ -118,57 +118,42 @@ Script.prototype.parse = function () {
* Any other script (no template matched). * Any other script (no template matched).
*/ */
Script.prototype.getOutType = function () { Script.prototype.getOutType = function () {
if (this.chunks[this.chunks.length-1] == Opcode.map.OP_CHECKMULTISIG && this.chunks[this.chunks.length-2] <= 3) { if (this.chunks[this.chunks.length-1] == Opcode.map.OP_CHECKMULTISIG &&
// Transfer to M-OF-N this.chunks[this.chunks.length-2] <= 3) {
return 'Multisig'; // Transfer to M-OF-N
} else if (this.chunks.length == 5 && return 'Multisig';
this.chunks[0] == Opcode.map.OP_DUP && } else if (this.chunks.length == 5 &&
this.chunks[1] == Opcode.map.OP_HASH160 && this.chunks[0] == Opcode.map.OP_DUP &&
this.chunks[3] == Opcode.map.OP_EQUALVERIFY && this.chunks[1] == Opcode.map.OP_HASH160 &&
this.chunks[4] == Opcode.map.OP_CHECKSIG) { this.chunks[3] == Opcode.map.OP_EQUALVERIFY &&
// Transfer to Bitcoin address this.chunks[4] == Opcode.map.OP_CHECKSIG) {
return 'Address'; // Transfer to Bitcoin address
} else if (this.chunks.length == 2 && return 'Address';
this.chunks[1] == Opcode.map.OP_CHECKSIG) { } else if (this.chunks.length == 2 &&
// Transfer to IP address this.chunks[1] == Opcode.map.OP_CHECKSIG) {
return 'Pubkey'; // Transfer to IP address
} else { return 'Pubkey';
return 'Strange'; } else {
} return 'Strange';
}
} }
/** /**
* Returns the affected address hash for this output. * Returns the address corresponding to this output in hash160 form.
* * Assumes strange scripts are P2SH
* For standard transactions, this will return the hash of the pubKey that
* can spend this output.
*
* In the future, for payToScriptHash outputs, this will return the
* scriptHash. Note that non-standard and standard payToScriptHash transactions
* look the same
*
* This method is useful for indexing transactions.
*/ */
Script.prototype.simpleOutHash = function () Script.prototype.toScriptHash = function () {
{ var outType = this.getOutType();
switch (this.getOutType()) {
case 'Address': return outType == 'Address' ? this.chunks[2]
return this.chunks[2]; : outType == 'Pubkey' ? util.sha256ripe160(this.chunks[0])
case 'Pubkey': : outType == 'Multisig' ? util.sha256ripe160(this.buffer)
return util.sha256ripe160(this.chunks[0]); : util.sha256ripe160(this.buffer)
case 'Multisig':
return util.sha256ripe160(this.buffer);
default:
throw new Error("Encountered non-standard scriptPubKey: " + this.getOutType());
}
}; };
/** Script.prototype.toAddress = function() {
* Old name for Script#simpleOutHash. return new Address(this.toScriptHash());
* }
* @deprecated
*/
Script.prototype.simpleOutPubKeyHash = Script.prototype.simpleOutHash;
/** /**
* Compare the script to known templates of scriptSig. * Compare the script to known templates of scriptSig.

82
src/transaction.js

@ -348,7 +348,7 @@ Transaction.prototype.getDescription = function (wallet) {
* Get the total amount of a transaction's outputs. * Get the total amount of a transaction's outputs.
*/ */
Transaction.prototype.getTotalOutValue = function () { Transaction.prototype.getTotalOutValue = function () {
return this.outs.reduce(function(t,o) { return t + o.value },0); return this.outs.reduce(function(t,o) { return t + o.value },0);
}; };
/** /**
@ -468,6 +468,32 @@ Transaction.prototype.sign = function(index, key, type) {
this.ins[index].script = Script.createInputScript(sig,pub); this.ins[index].script = Script.createInputScript(sig,pub);
} }
// Takes outputs of the form [{ output: 'txhash:index', address: 'address' },...]
Transaction.prototype.signWithKeys = function(keys, outputs, type) {
type = type || SIGHASH_ALL;
var addrdata = keys.map(function(key) {
key = new Bitcoin.Key(key);
return {
key: key,
address: key.getBitcoinAddress().toString()
}
});
var hmap = {};
for (var o in outputs) {
hmap[outputs[o].output] = outputs[o];
}
for (var i = 0; i < this.ins.length; i++) {
var outpoint = this.ins[i].outpoint.hash+':'+this.ins[i].outpoint.index,
histItem = hmap[outpoint];
if (!histItem) continue;
var thisInputAddrdata = addrdata.filter(function(a) {
return a.address == histItem.address;
});
if (thisInputAddrdata.length == 0) continue;
this.sign(i,thisInputAddrdata[0].key);
}
}
/** /**
* Signs a P2SH output at some index with the given key * Signs a P2SH output at some index with the given key
*/ */
@ -483,7 +509,7 @@ Transaction.prototype.p2shsign = function(index, script, key, type) {
Transaction.prototype.multisign = Transaction.prototype.p2shsign; Transaction.prototype.multisign = Transaction.prototype.p2shsign;
Transaction.prototype.validateSig = function(index,script,sig,pub) { Transaction.prototype.validateSig = function(index, script, sig, pub) {
script = new Script(script); script = new Script(script);
var hash = this.hashTransactionForSignature(script,index,1); var hash = this.hashTransactionForSignature(script,index,1);
return ECDSA.verify(hash, conv.coerceToBytes(sig), return ECDSA.verify(hash, conv.coerceToBytes(sig),
@ -491,33 +517,31 @@ Transaction.prototype.validateSig = function(index,script,sig,pub) {
} }
var TransactionIn = function (data) var TransactionIn = function (data) {
{ if (typeof data == "string")
this.outpoint = data.outpoint; this.outpoint = { hash: data.split(':')[0], index: data.split(':')[1] }
if (data.script instanceof Script) { else if (data.outpoint)
this.script = data.script; this.outpoint = data.outpoint
} else { else
if (data.scriptSig) { this.outpoint = { hash: data.hash, index: data.index }
this.script = Script.fromScriptSig(data.scriptSig);
} if (data.scriptSig)
else { this.script = Script.fromScriptSig(data.scriptSig)
this.script = new Script(data.script); else
} this.script = new Script(data.script)
}
this.sequence = data.sequence; this.sequence = data.sequence || 4294967295;
}; };
TransactionIn.prototype.clone = function () TransactionIn.prototype.clone = function () {
{ return new TransactionIn({
var newTxin = new TransactionIn({ outpoint: {
outpoint: { hash: this.outpoint.hash,
hash: this.outpoint.hash, index: this.outpoint.index
index: this.outpoint.index },
}, script: this.script.clone(),
script: this.script.clone(), sequence: this.sequence
sequence: this.sequence });
});
return newTxin;
}; };
var TransactionOut = function (data) { var TransactionOut = function (data) {
@ -526,8 +550,11 @@ var TransactionOut = function (data) {
: util.isArray(data.script) ? new Script(data.script) : util.isArray(data.script) ? new Script(data.script)
: typeof data.script == "string" ? new Script(conv.hexToBytes(data.script)) : typeof data.script == "string" ? new Script(conv.hexToBytes(data.script))
: data.scriptPubKey ? Script.fromScriptSig(data.scriptPubKey) : data.scriptPubKey ? Script.fromScriptSig(data.scriptPubKey)
: data.address ? Script.createOutputScript(data.address)
: new Script(); : new Script();
if (this.script.buffer.length > 0) this.address = this.script.toAddress();
this.value = this.value =
util.isArray(data.value) ? util.bytesToNum(data.value) util.isArray(data.value) ? util.bytesToNum(data.value)
: "string" == typeof data.value ? parseInt(data.value) : "string" == typeof data.value ? parseInt(data.value)
@ -547,4 +574,3 @@ TransactionOut.prototype.clone = function ()
module.exports.Transaction = Transaction; module.exports.Transaction = Transaction;
module.exports.TransactionIn = TransactionIn; module.exports.TransactionIn = TransactionIn;
module.exports.TransactionOut = TransactionOut; module.exports.TransactionOut = TransactionOut;

3
src/util.js

@ -114,5 +114,8 @@ module.exports = {
*/ */
sha256ripe160: function (data) { sha256ripe160: function (data) {
return Crypto.RIPEMD160(Crypto.SHA256(data, {asBytes: true}), {asBytes: true}); return Crypto.RIPEMD160(Crypto.SHA256(data, {asBytes: true}), {asBytes: true});
},
error: function(msg) {
throw new Error(msg);
} }
}; };

Loading…
Cancel
Save