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.
|
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
3
bitcoinjs-min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
29
src/util.js
29
src/util.js
|
@ -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]));
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue