Added deserialization, made some modifications
This commit is contained in:
parent
41f0027883
commit
9922864da4
8 changed files with 122 additions and 76 deletions
|
@ -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
3
bitcoinjs-min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
29
src/util.js
29
src/util.js
|
@ -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));
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue