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.
# 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
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" : {
"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": {
@ -30,6 +32,7 @@
},
"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) {
if (typeof bytes === 'string') {
bytes = Address.decodeString(bytes);
}
this.hash = bytes;
this.version = 0x00;
if (typeof bytes === 'string') {
this.hash = base58.decode(bytes);
this.version = this.hash.version;
}
else {
this.hash = bytes;
this.version = 0x00;
}
};
/**
@ -30,45 +32,24 @@ Address.prototype.toString = function () {
// Get a copy of the hash
var hash = this.hash.slice(0);
// 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);
return base58.checkEncode(hash,this.version);
};
Address.prototype.getHashBase64 = function () {
return conv.bytesToBase64(this.hash);
};
Address.getVersion = function(string) {
return base58.decode(string)[0];
}
// TODO(shtylman) isValid?
Address.validate = function(string, type) {
Address.validate = function(string) {
try {
var bytes = base58.decode(string);
base58.checkDecode(string);
} 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;
};
@ -76,26 +57,7 @@ Address.validate = function(string, type) {
* Parse a Bitcoin address contained in a string.
*/
Address.decodeString = function (string) {
var bytes = base58.decode(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;
return base58.checkDecode(string);
};
module.exports = Address;

View file

@ -48,8 +48,8 @@ module.exports.decode = function (input) {
var leading_zero = 0;
var seen_other = false;
for (var i=0; i<length ; ++i) {
var char = input[i];
var p = positions[char];
var chr = input[i];
var p = positions[chr];
// if we encounter an invalid character, decoding fails
if (p === undefined) {
@ -58,7 +58,7 @@ module.exports.decode = function (input) {
num = num.multiply(base).add(BigInteger.valueOf(p));
if (char == '1' && !seen_other) {
if (chr == '1' && !seen_other) {
++leading_zero;
}
else {
@ -76,3 +76,26 @@ module.exports.decode = function (input) {
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'),
Opcode: require('./opcode'),
Transaction: require('./transaction').Transaction,
Util: require('./util'),
TransactionIn: require('./transaction').TransactionIn,
TransactionOut: require('./transaction').TransactionOut,
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)
{

View file

@ -22,7 +22,13 @@ module.exports = {
}
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".
*
@ -30,21 +36,12 @@ module.exports = {
*
* Returns a byte array.
*/
numToVarInt: function (i)
{
if (i < 0xfd) {
// unsigned char
return [i];
} else if (i <= 1<<16) {
// 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]));
}
numToVarInt: function(num) {
var m = module.exports;
if (num < 253) return [num];
else if (num < 65536) return [253].concat(m.numToBytes(num,2));
else if (num < 4294967296) return [254].concat(m.numToBytes(num,4));
else return [253].concat(m.numToBytes(num,8));
},
/**