Added deserialization, made some modifications

This commit is contained in:
vub 2013-10-07 08:21:00 -04:00
parent 41f0027883
commit 9922864da4
8 changed files with 122 additions and 76 deletions

View file

@ -11,6 +11,14 @@ system in place.
Prototype software, use at your own peril. Prototype software, use at your own peril.
# How to use
* Run `npm run-script compile` to compile to a browser-friendly minified
file. Once in the browser, the global Bitcoin object will contain everything
you need.
* To use in NodeJS, install this package as you would any other and
put in `var Bitcoin = require('bitcoinjs-lib')`.
# License # License
This library is free and open-source software released under the MIT This library is free and open-source software released under the MIT

3
bitcoinjs-min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -20,7 +20,9 @@
"devDependencies" : { "devDependencies" : {
"mocha": "1.8.1", "mocha": "1.8.1",
"istanbul": "0.1.30" "istanbul": "0.1.30",
"uglify-js": "*",
"node-browserify": "https://github.com/substack/node-browserify/tarball/master"
}, },
"testling": { "testling": {
@ -30,6 +32,7 @@
}, },
"scripts": { "scripts": {
"test": "istanbul test ./node_modules/.bin/_mocha -- --reporter list test/*.js" "test": "istanbul test ./node_modules/.bin/_mocha -- --reporter list test/*.js",
"compile": "browserify src/index.js -s Bitcoin | uglifyjs > bitcoinjs-min.js"
} }
} }

View file

@ -13,12 +13,14 @@ var p2sh_types = {
}; };
var Address = function (bytes) { var Address = function (bytes) {
if (typeof bytes === 'string') { if (typeof bytes === 'string') {
bytes = Address.decodeString(bytes); this.hash = base58.decode(bytes);
} this.version = this.hash.version;
this.hash = bytes; }
else {
this.version = 0x00; this.hash = bytes;
this.version = 0x00;
}
}; };
/** /**
@ -30,45 +32,24 @@ Address.prototype.toString = function () {
// Get a copy of the hash // Get a copy of the hash
var hash = this.hash.slice(0); var hash = this.hash.slice(0);
// Version return base58.checkEncode(hash,this.version);
hash.unshift(this.version);
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {asBytes: true}), {asBytes: true});
var bytes = hash.concat(checksum.slice(0,4));
return base58.encode(bytes);
}; };
Address.prototype.getHashBase64 = function () { Address.prototype.getHashBase64 = function () {
return conv.bytesToBase64(this.hash); return conv.bytesToBase64(this.hash);
}; };
Address.getVersion = function(string) {
return base58.decode(string)[0];
}
// TODO(shtylman) isValid? // TODO(shtylman) isValid?
Address.validate = function(string, type) { Address.validate = function(string) {
try { try {
var bytes = base58.decode(string); base58.checkDecode(string);
} catch (e) { } catch (e) {
return false; return false;
} }
var hash = bytes.slice(0, 21);
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {asBytes: true}), {asBytes: true});
if (checksum[0] != bytes[21] ||
checksum[1] != bytes[22] ||
checksum[2] != bytes[23] ||
checksum[3] != bytes[24]) {
return false;
}
var version = hash[0];
if (type && version !== address_types[type] && version !== p2sh_types[type]) {
return false;
}
return true; return true;
}; };
@ -76,26 +57,7 @@ Address.validate = function(string, type) {
* Parse a Bitcoin address contained in a string. * Parse a Bitcoin address contained in a string.
*/ */
Address.decodeString = function (string) { Address.decodeString = function (string) {
var bytes = base58.decode(string); return base58.checkDecode(string);
var hash = bytes.slice(0, 21);
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {asBytes: true}), {asBytes: true});
if (checksum[0] != bytes[21] ||
checksum[1] != bytes[22] ||
checksum[2] != bytes[23] ||
checksum[3] != bytes[24]) {
throw new Error('Address Checksum validation failed: ' + string);
}
var version = hash.shift();
// TODO(shtylman) allow for specific version decoding same as validate above
if (version != 0) {
throw new Error('Address version not supported: ' + string);
}
return hash;
}; };
module.exports = Address; module.exports = Address;

View file

@ -48,8 +48,8 @@ module.exports.decode = function (input) {
var leading_zero = 0; var leading_zero = 0;
var seen_other = false; var seen_other = false;
for (var i=0; i<length ; ++i) { for (var i=0; i<length ; ++i) {
var char = input[i]; var chr = input[i];
var p = positions[char]; var p = positions[chr];
// if we encounter an invalid character, decoding fails // if we encounter an invalid character, decoding fails
if (p === undefined) { if (p === undefined) {
@ -58,7 +58,7 @@ module.exports.decode = function (input) {
num = num.multiply(base).add(BigInteger.valueOf(p)); num = num.multiply(base).add(BigInteger.valueOf(p));
if (char == '1' && !seen_other) { if (chr == '1' && !seen_other) {
++leading_zero; ++leading_zero;
} }
else { else {
@ -76,3 +76,26 @@ module.exports.decode = function (input) {
return bytes; return bytes;
} }
module.exports.checkEncode = function(x,vbyte,format) {
vbyte = vbyte || 0;
var front = [vbyte].concat(x);
var checksum = Crypto.SHA256(Crypto.SHA256(front, {asBytes: true}), {asBytes: true})
.slice(0,4);
return module.exports.encode(front.concat(checksum));
}
module.exports.checkDecode = function(x) {
var bytes = module.exports.decode(x),
front = bytes.slice(0,bytes.length-4),
back = bytes.slice(bytes.length-4);
var checksum = Crypto.SHA256(Crypto.SHA256(front,{asBytes: true}), {asBytes: true})
.slice(0,4);
if (""+checksum != ""+back) {
throw new Error("Checksum failed");
}
var o = front.slice(1);
o.version = front[0];
return o;
}

View file

@ -30,6 +30,7 @@ module.exports = {
Script: require('./script'), Script: require('./script'),
Opcode: require('./opcode'), Opcode: require('./opcode'),
Transaction: require('./transaction').Transaction, Transaction: require('./transaction').Transaction,
Util: require('./util'),
TransactionIn: require('./transaction').TransactionIn, TransactionIn: require('./transaction').TransactionIn,
TransactionOut: require('./transaction').TransactionOut, TransactionOut: require('./transaction').TransactionOut,
ECPointFp: require('./jsbn/ec').ECPointFp, ECPointFp: require('./jsbn/ec').ECPointFp,

View file

@ -412,6 +412,55 @@ Transaction.prototype.calcImpact = function (wallet) {
}; };
} }
}; };
Transaction.deserialize = function(buffer) {
var pos = 0;
var readAsInt = function(bytes) {
if (bytes == 0) return 0;
pos++;
return buffer[pos-1] + readAsInt(bytes-1) * 256;
}
var readVarInt = function() {
pos++;
if (buffer[pos-1] < 253) {
return buffer[pos-1];
}
return readAsInt(buffer[pos-1] - 251);
}
var readBytes = function(bytes) {
pos += bytes;
return buffer.slice(pos - bytes, pos);
}
var readVarString = function() {
var size = readVarInt();
return readBytes(size);
}
var obj = {
ins: [],
outs: []
}
obj.version = readAsInt(4);
var ins = readVarInt();
for (var i = 0; i < ins; i++) {
obj.ins.push({
outpoint: {
hash: Bitcoin.Util.bytesToBase64(readBytes(32)),
index: readAsInt(4)
},
script: new Script(readVarString()),
sequence: readAsInt(4)
});
}
var outs = readVarInt();
for (var i = 0; i < outs; i++) {
obj.outs.push({
value: readBytes(8),
script: new Script(readVarString())
});
}
obj.locktime = readAsInt(4);
return new Transaction(obj);
}
var TransactionIn = function (data) var TransactionIn = function (data)
{ {

View file

@ -22,7 +22,13 @@ module.exports = {
} }
return array; return array;
}, },
/**
* Create a byte array representing a number with the given length
*/
numToBytes: function(num,bytes) {
if (bytes == 0 || (bytes === null && num === 0)) return [];
else return [num % 256].concat(bw.numToBytes(Math.floor(num / 256),bytes-1));
},
/** /**
* Turn an integer into a "var_int". * Turn an integer into a "var_int".
* *
@ -30,21 +36,12 @@ module.exports = {
* *
* Returns a byte array. * Returns a byte array.
*/ */
numToVarInt: function (i) numToVarInt: function(num) {
{ var m = module.exports;
if (i < 0xfd) { if (num < 253) return [num];
// unsigned char else if (num < 65536) return [253].concat(m.numToBytes(num,2));
return [i]; else if (num < 4294967296) return [254].concat(m.numToBytes(num,4));
} else if (i <= 1<<16) { else return [253].concat(m.numToBytes(num,8));
// unsigned short (LE)
return [0xfd, i >>> 8, i & 255];
} else if (i <= 1<<32) {
// unsigned int (LE)
return [0xfe].concat(Crypto.util.wordsToBytes([i]));
} else {
// unsigned long long (LE)
return [0xff].concat(Crypto.util.wordsToBytes([i >>> 32, i]));
}
}, },
/** /**