Added sign with keys method to transaction and did lots of small cleanups
This commit is contained in:
parent
917822541c
commit
f53a4e3ffa
5 changed files with 109 additions and 94 deletions
6
bitcoinjs-min.js
vendored
6
bitcoinjs-min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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…
Add table
Reference in a new issue