Compare commits
52 Commits
Author | SHA1 | Date |
---|---|---|
Simon | e97ae1dd2e | |
Simon | c3bbbc3f08 | |
Simon | 4c6a7df8be | |
Simon | 02e607b770 | |
Simon | 76a1efebbf | |
Simon | 75c168836d | |
Simon | 542b3f5893 | |
Ian Munoz | 97f7b5d3e3 | |
str4d | 208069bee8 | |
Karel Bílek | aeaa33f237 | |
Jack Grigg | b84f7ac683 | |
Jack Grigg | 9e0ec8cc89 | |
Jack Grigg | 387541af3d | |
Jack Grigg | ebb8b5683a | |
Jack Grigg | 1a93179609 | |
Jack Grigg | 8f3a99b1be | |
Jack Grigg | d7d6682eab | |
Jack Grigg | 73223235d5 | |
Jack Grigg | 53366f34fe | |
Jack Grigg | 80f5b45034 | |
Jack Grigg | 8740d9e964 | |
Jack Grigg | bc8e5f4121 | |
Gabe Gattis | 764aa6d4e9 | |
Braydon Fuller | 24df178a08 | |
Braydon Fuller | cdb538b94e | |
Braydon Fuller | f6b0b14ac6 | |
Braydon Fuller | c9e056a0a3 | |
Braydon Fuller | 9e82395e71 | |
Braydon Fuller | 7a56719c3c | |
Ruben de Vries | b655659812 | |
Matias Alejo Garcia | d36f72857b | |
Braydon Fuller | 6275689f05 | |
Matias Alejo Garcia | 09893632c2 | |
Braydon Fuller | 514fc8d326 | |
Matias Alejo Garcia | eab662c692 | |
Saran Siriphantnon | 85666e92da | |
Braydon Fuller | 7fb064bde0 | |
Braydon Fuller | b3b18d532f | |
Braydon Fuller | 8c948ef511 | |
Kirill Fomichev | 3579305b5e | |
Braydon Fuller | 4430479cea | |
Gabe Gattis | 9702105ad9 | |
Braydon Fuller | 0c983c9c4a | |
Braydon Fuller | 8bd466373e | |
Kirill Fomichev | af4d9aef34 | |
Braydon Fuller | 6ae9b2f835 | |
Braydon Fuller | 55bb6ad69f | |
Matias Alejo Garcia | 55c7296ab9 | |
Braydon Fuller | c0eec199ed | |
Braydon Fuller | f1d19b438e | |
Braydon Fuller | 6e225ef70e | |
Ed Bosher | c5a107961c |
|
@ -66,8 +66,11 @@ This will generate files named `bitcore-lib.js` and `bitcore-lib.min.js`.
|
||||||
You can also use our pre-generated files, provided for each release along with a PGP signature by one of the project's maintainers. To get them, checkout a release commit (for example, https://github.com/bitpay/bitcore-lib/commit/e33b6e3ba6a1e5830a079e02d949fce69ea33546 for v0.12.6).
|
You can also use our pre-generated files, provided for each release along with a PGP signature by one of the project's maintainers. To get them, checkout a release commit (for example, https://github.com/bitpay/bitcore-lib/commit/e33b6e3ba6a1e5830a079e02d949fce69ea33546 for v0.12.6).
|
||||||
|
|
||||||
To verify signatures, use the following PGP keys:
|
To verify signatures, use the following PGP keys:
|
||||||
- @braydonf: https://pgp.mit.edu/pks/lookup?op=get&search=0x9BBF07CAC07A276D
|
- @braydonf: https://pgp.mit.edu/pks/lookup?op=get&search=0x9BBF07CAC07A276D `D909 EFE6 70B5 F6CC 89A3 607A 9BBF 07CA C07A 276D`
|
||||||
- @pnagurny: https://pgp.mit.edu/pks/lookup?op=get&search=0x0909B33F0AA53013
|
- @gabegattis: https://pgp.mit.edu/pks/lookup?op=get&search=0x441430987182732C `F3EA 8E28 29B4 EC93 88CB B0AA 4414 3098 7182 732C`
|
||||||
|
- @kleetus: https://pgp.mit.edu/pks/lookup?op=get&search=0x33195D27EF6BDB7F `F8B0 891C C459 C197 65C2 5043 3319 5D27 EF6B DB7F`
|
||||||
|
- @matiu: https://pgp.mit.edu/pks/lookup?op=get&search=0x9EDE6DE4DE531FAC `25CE ED88 A1B1 0CD1 12CD 4121 9EDE 6DE4 DE53 1FAC`
|
||||||
|
|
||||||
|
|
||||||
## Development & Tests
|
## Development & Tests
|
||||||
|
|
||||||
|
|
52832
bitcore-lib.js
52832
bitcore-lib.js
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
13
bower.json
13
bower.json
|
@ -1,17 +1,18 @@
|
||||||
{
|
{
|
||||||
"name": "bitcore-lib",
|
"name": "bitcore-lib-zcash",
|
||||||
"main": "./bitcore-lib.min.js",
|
"main": "./bitcore-lib-zcash.min.js",
|
||||||
"version": "0.13.11",
|
"version": "0.13.19",
|
||||||
"homepage": "http://bitcore.io",
|
"homepage": "http://bitcore.io",
|
||||||
"authors": [
|
"authors": [
|
||||||
"BitPay, Inc."
|
"BitPay, Inc.",
|
||||||
|
"Jack Grigg"
|
||||||
],
|
],
|
||||||
"description": "A pure, powerful core for your bitcoin project.",
|
"description": "A pure, powerful core for your zcash project.",
|
||||||
"moduleType": [
|
"moduleType": [
|
||||||
"globals"
|
"globals"
|
||||||
],
|
],
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"bitcoin",
|
"zcash",
|
||||||
"bitcore",
|
"bitcore",
|
||||||
"btc",
|
"btc",
|
||||||
"satoshi"
|
"satoshi"
|
||||||
|
|
|
@ -50,7 +50,7 @@ if (Address.isValid(input, Networks.testnet){
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate that an input field is a valid livenet pubkeyhash
|
// validate that an input field is a valid livenet pubkeyhash
|
||||||
if (Address.isValid(input, Networks.livenet, Address.Pay2PubKeyHash){
|
if (Address.isValid(input, Networks.livenet, Address.PayToPublicKeyHash){
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,23 @@ Bitcore provides support for the main bitcoin network as well as for `testnet3`,
|
||||||
|
|
||||||
The `Network` namespace has a function, `get(...)` that returns an instance of a `Network` or `undefined`. The only argument to this function is some kind of identifier of the network: either its name, a reference to a Network object, or a number used as a magic constant to identify the network (for example, the value `0` that gives bitcoin addresses the distinctive `'1'` at its beginning on livenet, is a `0x6F` for testnet).
|
The `Network` namespace has a function, `get(...)` that returns an instance of a `Network` or `undefined`. The only argument to this function is some kind of identifier of the network: either its name, a reference to a Network object, or a number used as a magic constant to identify the network (for example, the value `0` that gives bitcoin addresses the distinctive `'1'` at its beginning on livenet, is a `0x6F` for testnet).
|
||||||
|
|
||||||
|
## Regtest
|
||||||
|
|
||||||
|
The regtest network is useful for development as it's possible to programmatically and instantly generate blocks for testing. It's currently supported as a variation of testnet. Here is an example of how to use regtest with the Bitcore Library:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Standard testnet
|
||||||
|
> bitcore.Networks.testnet.networkMagic;
|
||||||
|
<Buffer 0b 11 09 07>
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Enabling testnet to use the regtest port and magicNumber
|
||||||
|
> bitcore.Networks.enableRegtest();
|
||||||
|
> bitcore.Networks.testnet.networkMagic;
|
||||||
|
<Buffer fa bf b5 da>
|
||||||
|
```
|
||||||
|
|
||||||
## Setting the Default Network
|
## Setting the Default Network
|
||||||
Most projects will only need to work with one of the networks. The value of `Networks.defaultNetwork` can be set to `Networks.testnet` if the project will need to only to work on testnet (the default is `Networks.livenet`).
|
Most projects will only need to work with one of the networks. The value of `Networks.defaultNetwork` can be set to `Networks.testnet` if the project will need to only to work on testnet (the default is `Networks.livenet`).
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
|
|
||||||
var bitcoreTasks = require('bitcore-build');
|
var bitcoreTasks = require('bitcore-build-zcash');
|
||||||
|
|
||||||
bitcoreTasks('lib');
|
bitcoreTasks('lib');
|
||||||
|
|
9
index.js
9
index.js
|
@ -6,10 +6,11 @@ var bitcore = module.exports;
|
||||||
bitcore.version = 'v' + require('./package.json').version;
|
bitcore.version = 'v' + require('./package.json').version;
|
||||||
bitcore.versionGuard = function(version) {
|
bitcore.versionGuard = function(version) {
|
||||||
if (version !== undefined) {
|
if (version !== undefined) {
|
||||||
var message = 'More than one instance of bitcore-lib found. ' +
|
var message = 'More than one instance of bitcore-lib-zcash found. ' +
|
||||||
'Please make sure to require bitcore-lib and check that submodules do' +
|
'Please make sure to require bitcore-lib-zcash and check that submodules do' +
|
||||||
' not also include their own bitcore-lib dependency.';
|
' not also include their own bitcore-lib-zcash dependency.';
|
||||||
throw new Error(message);
|
// TODO: put this back if we start versioning again
|
||||||
|
//throw new Error(message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
bitcore.versionGuard(global._bitcore);
|
bitcore.versionGuard(global._bitcore);
|
||||||
|
|
|
@ -162,8 +162,9 @@ Address._transformObject = function(data) {
|
||||||
Address._classifyFromVersion = function(buffer) {
|
Address._classifyFromVersion = function(buffer) {
|
||||||
var version = {};
|
var version = {};
|
||||||
|
|
||||||
var pubkeyhashNetwork = Networks.get(buffer[0], 'pubkeyhash');
|
var prefix = buffer[0]*256 + buffer[1];
|
||||||
var scripthashNetwork = Networks.get(buffer[0], 'scripthash');
|
var pubkeyhashNetwork = Networks.get(prefix, 'pubkeyhash');
|
||||||
|
var scripthashNetwork = Networks.get(prefix, 'scripthash');
|
||||||
|
|
||||||
if (pubkeyhashNetwork) {
|
if (pubkeyhashNetwork) {
|
||||||
version.network = pubkeyhashNetwork;
|
version.network = pubkeyhashNetwork;
|
||||||
|
@ -191,8 +192,8 @@ Address._transformBuffer = function(buffer, network, type) {
|
||||||
if (!(buffer instanceof Buffer) && !(buffer instanceof Uint8Array)) {
|
if (!(buffer instanceof Buffer) && !(buffer instanceof Uint8Array)) {
|
||||||
throw new TypeError('Address supplied is not a buffer.');
|
throw new TypeError('Address supplied is not a buffer.');
|
||||||
}
|
}
|
||||||
if (buffer.length !== 1 + 20) {
|
if (buffer.length !== 2 + 20) {
|
||||||
throw new TypeError('Address buffers must be exactly 21 bytes.');
|
throw new TypeError('Address buffers must be exactly 22 bytes.');
|
||||||
}
|
}
|
||||||
|
|
||||||
network = Networks.get(network);
|
network = Networks.get(network);
|
||||||
|
@ -206,7 +207,7 @@ Address._transformBuffer = function(buffer, network, type) {
|
||||||
throw new TypeError('Address has mismatched type.');
|
throw new TypeError('Address has mismatched type.');
|
||||||
}
|
}
|
||||||
|
|
||||||
info.hashBuffer = buffer.slice(1);
|
info.hashBuffer = buffer.slice(2);
|
||||||
info.network = bufferVersion.network;
|
info.network = bufferVersion.network;
|
||||||
info.type = bufferVersion.type;
|
info.type = bufferVersion.type;
|
||||||
return info;
|
return info;
|
||||||
|
@ -459,7 +460,8 @@ Address.prototype.isPayToScriptHash = function() {
|
||||||
* @returns {Buffer} Bitcoin address buffer
|
* @returns {Buffer} Bitcoin address buffer
|
||||||
*/
|
*/
|
||||||
Address.prototype.toBuffer = function() {
|
Address.prototype.toBuffer = function() {
|
||||||
var version = new Buffer([this.network[this.type]]);
|
var version = new Buffer(2);
|
||||||
|
version.writeUInt16BE(this.network[this.type], 0);
|
||||||
var buf = Buffer.concat([version, this.hashBuffer]);
|
var buf = Buffer.concat([version, this.hashBuffer]);
|
||||||
return buf;
|
return buf;
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,8 @@ var Hash = require('../crypto/hash');
|
||||||
var JSUtil = require('../util/js');
|
var JSUtil = require('../util/js');
|
||||||
var $ = require('../util/preconditions');
|
var $ = require('../util/preconditions');
|
||||||
|
|
||||||
var GENESIS_BITS = 0x1d00ffff;
|
// Mainnet 0x1f07ffff, Testnet 0x2007ffff
|
||||||
|
var GENESIS_BITS = 0x2007ffff;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiate a BlockHeader from a Buffer, JSON object, or Object with
|
* Instantiate a BlockHeader from a Buffer, JSON object, or Object with
|
||||||
|
@ -27,10 +28,12 @@ var BlockHeader = function BlockHeader(arg) {
|
||||||
this.version = info.version;
|
this.version = info.version;
|
||||||
this.prevHash = info.prevHash;
|
this.prevHash = info.prevHash;
|
||||||
this.merkleRoot = info.merkleRoot;
|
this.merkleRoot = info.merkleRoot;
|
||||||
|
this.reserved = info.reserved;
|
||||||
this.time = info.time;
|
this.time = info.time;
|
||||||
this.timestamp = info.time;
|
this.timestamp = info.time;
|
||||||
this.bits = info.bits;
|
this.bits = info.bits;
|
||||||
this.nonce = info.nonce;
|
this.nonce = info.nonce;
|
||||||
|
this.solution = info.solution;
|
||||||
|
|
||||||
if (info.hash) {
|
if (info.hash) {
|
||||||
$.checkState(
|
$.checkState(
|
||||||
|
@ -69,21 +72,35 @@ BlockHeader._fromObject = function _fromObject(data) {
|
||||||
$.checkArgument(data, 'data is required');
|
$.checkArgument(data, 'data is required');
|
||||||
var prevHash = data.prevHash;
|
var prevHash = data.prevHash;
|
||||||
var merkleRoot = data.merkleRoot;
|
var merkleRoot = data.merkleRoot;
|
||||||
|
var reserved = data.reserved;
|
||||||
|
var nonce = data.nonce;
|
||||||
|
var solution = data.solution;
|
||||||
if (_.isString(data.prevHash)) {
|
if (_.isString(data.prevHash)) {
|
||||||
prevHash = BufferUtil.reverse(new Buffer(data.prevHash, 'hex'));
|
prevHash = BufferUtil.reverse(new Buffer(data.prevHash, 'hex'));
|
||||||
}
|
}
|
||||||
if (_.isString(data.merkleRoot)) {
|
if (_.isString(data.merkleRoot)) {
|
||||||
merkleRoot = BufferUtil.reverse(new Buffer(data.merkleRoot, 'hex'));
|
merkleRoot = BufferUtil.reverse(new Buffer(data.merkleRoot, 'hex'));
|
||||||
}
|
}
|
||||||
|
if (_.isString(data.reserved)) {
|
||||||
|
reserved = BufferUtil.reverse(new Buffer(data.reserved, 'hex'));
|
||||||
|
}
|
||||||
|
if (_.isString(data.nonce)) {
|
||||||
|
nonce = BufferUtil.reverse(new Buffer(data.nonce, 'hex'));
|
||||||
|
}
|
||||||
|
if (_.isString(data.solution)) {
|
||||||
|
solution = new Buffer(data.solution, 'hex');
|
||||||
|
}
|
||||||
var info = {
|
var info = {
|
||||||
hash: data.hash,
|
hash: data.hash,
|
||||||
version: data.version,
|
version: data.version,
|
||||||
prevHash: prevHash,
|
prevHash: prevHash,
|
||||||
merkleRoot: merkleRoot,
|
merkleRoot: merkleRoot,
|
||||||
|
reserved: reserved,
|
||||||
time: data.time,
|
time: data.time,
|
||||||
timestamp: data.time,
|
timestamp: data.time,
|
||||||
bits: data.bits,
|
bits: data.bits,
|
||||||
nonce: data.nonce
|
nonce: nonce,
|
||||||
|
solution: solution
|
||||||
};
|
};
|
||||||
return info;
|
return info;
|
||||||
};
|
};
|
||||||
|
@ -139,9 +156,12 @@ BlockHeader._fromBufferReader = function _fromBufferReader(br) {
|
||||||
info.version = br.readUInt32LE();
|
info.version = br.readUInt32LE();
|
||||||
info.prevHash = br.read(32);
|
info.prevHash = br.read(32);
|
||||||
info.merkleRoot = br.read(32);
|
info.merkleRoot = br.read(32);
|
||||||
|
info.reserved = br.read(32);
|
||||||
info.time = br.readUInt32LE();
|
info.time = br.readUInt32LE();
|
||||||
info.bits = br.readUInt32LE();
|
info.bits = br.readUInt32LE();
|
||||||
info.nonce = br.readUInt32LE();
|
info.nonce = br.read(32);
|
||||||
|
var lenSolution = br.readVarintNum();
|
||||||
|
info.solution = br.read(lenSolution);
|
||||||
return info;
|
return info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -163,9 +183,11 @@ BlockHeader.prototype.toObject = BlockHeader.prototype.toJSON = function toObjec
|
||||||
version: this.version,
|
version: this.version,
|
||||||
prevHash: BufferUtil.reverse(this.prevHash).toString('hex'),
|
prevHash: BufferUtil.reverse(this.prevHash).toString('hex'),
|
||||||
merkleRoot: BufferUtil.reverse(this.merkleRoot).toString('hex'),
|
merkleRoot: BufferUtil.reverse(this.merkleRoot).toString('hex'),
|
||||||
|
reserved: BufferUtil.reverse(this.reserved).toString('hex'),
|
||||||
time: this.time,
|
time: this.time,
|
||||||
bits: this.bits,
|
bits: this.bits,
|
||||||
nonce: this.nonce
|
nonce: BufferUtil.reverse(this.nonce).toString('hex'),
|
||||||
|
solution: this.solution.toString('hex')
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -194,9 +216,12 @@ BlockHeader.prototype.toBufferWriter = function toBufferWriter(bw) {
|
||||||
bw.writeUInt32LE(this.version);
|
bw.writeUInt32LE(this.version);
|
||||||
bw.write(this.prevHash);
|
bw.write(this.prevHash);
|
||||||
bw.write(this.merkleRoot);
|
bw.write(this.merkleRoot);
|
||||||
|
bw.write(this.reserved);
|
||||||
bw.writeUInt32LE(this.time);
|
bw.writeUInt32LE(this.time);
|
||||||
bw.writeUInt32LE(this.bits);
|
bw.writeUInt32LE(this.bits);
|
||||||
bw.writeUInt32LE(this.nonce);
|
bw.write(this.nonce);
|
||||||
|
bw.writeVarintNum(this.solution.length);
|
||||||
|
bw.write(this.solution);
|
||||||
return bw;
|
return bw;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -88,9 +88,10 @@ ECDSA.prototype.deterministicK = function(badrs) {
|
||||||
var x = this.privkey.bn.toBuffer({
|
var x = this.privkey.bn.toBuffer({
|
||||||
size: 32
|
size: 32
|
||||||
});
|
});
|
||||||
k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x00]), x, this.hashbuf]), k);
|
var hashbuf = this.endian === 'little' ? BufferUtil.reverse(this.hashbuf) : this.hashbuf
|
||||||
|
k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x00]), x, hashbuf]), k);
|
||||||
v = Hash.sha256hmac(v, k);
|
v = Hash.sha256hmac(v, k);
|
||||||
k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x01]), x, this.hashbuf]), k);
|
k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x01]), x, hashbuf]), k);
|
||||||
v = Hash.sha256hmac(v, k);
|
v = Hash.sha256hmac(v, k);
|
||||||
v = Hash.sha256hmac(v, k);
|
v = Hash.sha256hmac(v, k);
|
||||||
var T = BN.fromBuffer(v);
|
var T = BN.fromBuffer(v);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var sha512 = require('sha512');
|
|
||||||
var crypto = require('crypto');
|
var crypto = require('crypto');
|
||||||
var BufferUtil = require('../util/buffer');
|
var BufferUtil = require('../util/buffer');
|
||||||
var $ = require('../util/preconditions');
|
var $ = require('../util/preconditions');
|
||||||
|
@ -38,8 +37,7 @@ Hash.sha256ripemd160 = function(buf) {
|
||||||
|
|
||||||
Hash.sha512 = function(buf) {
|
Hash.sha512 = function(buf) {
|
||||||
$.checkArgument(BufferUtil.isBuffer(buf));
|
$.checkArgument(BufferUtil.isBuffer(buf));
|
||||||
var hash = sha512(buf);
|
return crypto.createHash('sha512').update(buf).digest();
|
||||||
return new Buffer(hash);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Hash.sha512.blocksize = 1024;
|
Hash.sha512.blocksize = 1024;
|
||||||
|
|
|
@ -275,7 +275,7 @@ Signature.isTxDER = function(buf) {
|
||||||
*/
|
*/
|
||||||
Signature.prototype.hasLowS = function() {
|
Signature.prototype.hasLowS = function() {
|
||||||
if (this.s.lt(new BN(1)) ||
|
if (this.s.lt(new BN(1)) ||
|
||||||
this.s.gt(new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0'))) {
|
this.s.gt(new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex'))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
159
lib/networks.js
159
lib/networks.js
|
@ -59,6 +59,8 @@ function get(arg, keys) {
|
||||||
* @param {Number} data.scripthash - The scripthash prefix
|
* @param {Number} data.scripthash - The scripthash prefix
|
||||||
* @param {Number} data.xpubkey - The extended public key magic
|
* @param {Number} data.xpubkey - The extended public key magic
|
||||||
* @param {Number} data.xprivkey - The extended private key magic
|
* @param {Number} data.xprivkey - The extended private key magic
|
||||||
|
* @param {Number} data.zaddr - The Zcash payment address prefix
|
||||||
|
* @param {Number} data.zkey - The Zcash spending key prefix
|
||||||
* @param {Number} data.networkMagic - The network magic number
|
* @param {Number} data.networkMagic - The network magic number
|
||||||
* @param {Number} data.port - The network port
|
* @param {Number} data.port - The network port
|
||||||
* @param {Array} data.dnsSeeds - An array of dns seeds
|
* @param {Array} data.dnsSeeds - An array of dns seeds
|
||||||
|
@ -76,11 +78,27 @@ function addNetwork(data) {
|
||||||
scripthash: data.scripthash,
|
scripthash: data.scripthash,
|
||||||
xpubkey: data.xpubkey,
|
xpubkey: data.xpubkey,
|
||||||
xprivkey: data.xprivkey,
|
xprivkey: data.xprivkey,
|
||||||
networkMagic: BufferUtil.integerAsBuffer(data.networkMagic),
|
zaddr: data.zaddr,
|
||||||
port: data.port,
|
zkey: data.zkey
|
||||||
dnsSeeds: data.dnsSeeds
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (data.networkMagic) {
|
||||||
|
JSUtil.defineImmutable(network, {
|
||||||
|
networkMagic: BufferUtil.integerAsBuffer(data.networkMagic)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.port) {
|
||||||
|
JSUtil.defineImmutable(network, {
|
||||||
|
port: data.port
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.dnsSeeds) {
|
||||||
|
JSUtil.defineImmutable(network, {
|
||||||
|
dnsSeeds: data.dnsSeeds
|
||||||
|
});
|
||||||
|
}
|
||||||
_.each(network, function(value) {
|
_.each(network, function(value) {
|
||||||
if (!_.isUndefined(value) && !_.isObject(value)) {
|
if (!_.isUndefined(value) && !_.isObject(value)) {
|
||||||
networkMaps[value] = network;
|
networkMaps[value] = network;
|
||||||
|
@ -115,53 +133,128 @@ function removeNetwork(network) {
|
||||||
addNetwork({
|
addNetwork({
|
||||||
name: 'livenet',
|
name: 'livenet',
|
||||||
alias: 'mainnet',
|
alias: 'mainnet',
|
||||||
pubkeyhash: 0x00,
|
pubkeyhash: 0x1cb8,
|
||||||
privatekey: 0x80,
|
privatekey: 0x80,
|
||||||
scripthash: 0x05,
|
scripthash: 0x1cbd,
|
||||||
xpubkey: 0x0488b21e,
|
xpubkey: 0x0488b21e,
|
||||||
xprivkey: 0x0488ade4,
|
xprivkey: 0x0488ade4,
|
||||||
networkMagic: 0xf9beb4d9,
|
zaddr: 0x169a,
|
||||||
port: 8333,
|
zkey: 0xab36,
|
||||||
|
networkMagic: 0x24e92764,
|
||||||
|
port: 8233,
|
||||||
dnsSeeds: [
|
dnsSeeds: [
|
||||||
'seed.bitcoin.sipa.be',
|
'dnsseed.z.cash',
|
||||||
'dnsseed.bluematt.me',
|
'dnsseed.str4d.xyz',
|
||||||
'dnsseed.bitcoin.dashjr.org',
|
'dnsseed.znodes.org'
|
||||||
'seed.bitcoinstats.com',
|
|
||||||
'seed.bitnodes.io',
|
|
||||||
'bitseed.xf2.org'
|
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
addNetwork({
|
|
||||||
name: 'testnet',
|
|
||||||
alias: 'testnet',
|
|
||||||
pubkeyhash: 0x6f,
|
|
||||||
privatekey: 0xef,
|
|
||||||
scripthash: 0xc4,
|
|
||||||
xpubkey: 0x043587cf,
|
|
||||||
xprivkey: 0x04358394,
|
|
||||||
networkMagic: 0x0b110907,
|
|
||||||
port: 18333,
|
|
||||||
dnsSeeds: [
|
|
||||||
'testnet-seed.bitcoin.petertodd.org',
|
|
||||||
'testnet-seed.bluematt.me',
|
|
||||||
'testnet-seed.alexykot.me',
|
|
||||||
'testnet-seed.bitcoin.schildbach.de'
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @instance
|
* @instance
|
||||||
* @member Networks#livenet
|
* @member Networks#livenet
|
||||||
*/
|
*/
|
||||||
var livenet = get('livenet');
|
var livenet = get('livenet');
|
||||||
|
|
||||||
|
addNetwork({
|
||||||
|
name: 'testnet',
|
||||||
|
alias: 'regtest',
|
||||||
|
pubkeyhash: 0x1d25,
|
||||||
|
privatekey: 0xef,
|
||||||
|
scripthash: 0x1cba,
|
||||||
|
xpubkey: 0x043587cf,
|
||||||
|
xprivkey: 0x04358394,
|
||||||
|
zaddr: 0x16b6,
|
||||||
|
zkey: 0xac08,
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @instance
|
* @instance
|
||||||
* @member Networks#testnet
|
* @member Networks#testnet
|
||||||
*/
|
*/
|
||||||
var testnet = get('testnet');
|
var testnet = get('testnet');
|
||||||
|
|
||||||
|
// Add configurable values for testnet/regtest
|
||||||
|
|
||||||
|
var TESTNET = {
|
||||||
|
PORT: 18233,
|
||||||
|
NETWORK_MAGIC: BufferUtil.integerAsBuffer(0xfa1af9bf),
|
||||||
|
DNS_SEEDS: [
|
||||||
|
'dnsseed.testnet.z.cash',
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var key in TESTNET) {
|
||||||
|
if (!_.isObject(TESTNET[key])) {
|
||||||
|
networkMaps[TESTNET[key]] = testnet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var REGTEST = {
|
||||||
|
PORT: 18444,
|
||||||
|
NETWORK_MAGIC: BufferUtil.integerAsBuffer(0xaae83f5f),
|
||||||
|
DNS_SEEDS: []
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var key in REGTEST) {
|
||||||
|
if (!_.isObject(REGTEST[key])) {
|
||||||
|
networkMaps[REGTEST[key]] = testnet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(testnet, 'port', {
|
||||||
|
enumerable: true,
|
||||||
|
configurable: false,
|
||||||
|
get: function() {
|
||||||
|
if (this.regtestEnabled) {
|
||||||
|
return REGTEST.PORT;
|
||||||
|
} else {
|
||||||
|
return TESTNET.PORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(testnet, 'networkMagic', {
|
||||||
|
enumerable: true,
|
||||||
|
configurable: false,
|
||||||
|
get: function() {
|
||||||
|
if (this.regtestEnabled) {
|
||||||
|
return REGTEST.NETWORK_MAGIC;
|
||||||
|
} else {
|
||||||
|
return TESTNET.NETWORK_MAGIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(testnet, 'dnsSeeds', {
|
||||||
|
enumerable: true,
|
||||||
|
configurable: false,
|
||||||
|
get: function() {
|
||||||
|
if (this.regtestEnabled) {
|
||||||
|
return REGTEST.DNS_SEEDS;
|
||||||
|
} else {
|
||||||
|
return TESTNET.DNS_SEEDS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
* @member Networks#enableRegtest
|
||||||
|
* Will enable regtest features for testnet
|
||||||
|
*/
|
||||||
|
function enableRegtest() {
|
||||||
|
testnet.regtestEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
* @member Networks#disableRegtest
|
||||||
|
* Will disable regtest features for testnet
|
||||||
|
*/
|
||||||
|
function disableRegtest() {
|
||||||
|
testnet.regtestEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @namespace Networks
|
* @namespace Networks
|
||||||
*/
|
*/
|
||||||
|
@ -172,5 +265,7 @@ module.exports = {
|
||||||
livenet: livenet,
|
livenet: livenet,
|
||||||
mainnet: livenet,
|
mainnet: livenet,
|
||||||
testnet: testnet,
|
testnet: testnet,
|
||||||
get: get
|
get: get,
|
||||||
|
enableRegtest: enableRegtest,
|
||||||
|
disableRegtest: disableRegtest
|
||||||
};
|
};
|
||||||
|
|
|
@ -67,6 +67,7 @@ Opcode.prototype.toString = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
Opcode.smallInt = function(n) {
|
Opcode.smallInt = function(n) {
|
||||||
|
$.checkArgument(_.isNumber(n), 'Invalid Argument: n should be number');
|
||||||
$.checkArgument(n >= 0 && n <= 16, 'Invalid Argument: n must be between 0 and 16');
|
$.checkArgument(n >= 0 && n <= 16, 'Invalid Argument: n must be between 0 and 16');
|
||||||
if (n === 0) {
|
if (n === 0) {
|
||||||
return Opcode('OP_0');
|
return Opcode('OP_0');
|
||||||
|
|
|
@ -500,24 +500,54 @@ Script.types.DATA_OUT = 'Data push';
|
||||||
|
|
||||||
Script.OP_RETURN_STANDARD_SIZE = 80;
|
Script.OP_RETURN_STANDARD_SIZE = 80;
|
||||||
|
|
||||||
Script.identifiers = {};
|
|
||||||
Script.identifiers.PUBKEY_OUT = Script.prototype.isPublicKeyOut;
|
|
||||||
Script.identifiers.PUBKEY_IN = Script.prototype.isPublicKeyIn;
|
|
||||||
Script.identifiers.PUBKEYHASH_OUT = Script.prototype.isPublicKeyHashOut;
|
|
||||||
Script.identifiers.PUBKEYHASH_IN = Script.prototype.isPublicKeyHashIn;
|
|
||||||
Script.identifiers.MULTISIG_OUT = Script.prototype.isMultisigOut;
|
|
||||||
Script.identifiers.MULTISIG_IN = Script.prototype.isMultisigIn;
|
|
||||||
Script.identifiers.SCRIPTHASH_OUT = Script.prototype.isScriptHashOut;
|
|
||||||
Script.identifiers.SCRIPTHASH_IN = Script.prototype.isScriptHashIn;
|
|
||||||
Script.identifiers.DATA_OUT = Script.prototype.isDataOut;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {object} The Script type if it is a known form,
|
* @returns {object} The Script type if it is a known form,
|
||||||
* or Script.UNKNOWN if it isn't
|
* or Script.UNKNOWN if it isn't
|
||||||
*/
|
*/
|
||||||
Script.prototype.classify = function() {
|
Script.prototype.classify = function() {
|
||||||
for (var type in Script.identifiers) {
|
if (this._isInput) {
|
||||||
if (Script.identifiers[type].bind(this)()) {
|
return this.classifyInput();
|
||||||
|
} else if (this._isOutput) {
|
||||||
|
return this.classifyOutput();
|
||||||
|
} else {
|
||||||
|
var outputType = this.classifyOutput();
|
||||||
|
return outputType != Script.types.UNKNOWN ? outputType : this.classifyInput();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Script.outputIdentifiers = {};
|
||||||
|
Script.outputIdentifiers.PUBKEY_OUT = Script.prototype.isPublicKeyOut;
|
||||||
|
Script.outputIdentifiers.PUBKEYHASH_OUT = Script.prototype.isPublicKeyHashOut;
|
||||||
|
Script.outputIdentifiers.MULTISIG_OUT = Script.prototype.isMultisigOut;
|
||||||
|
Script.outputIdentifiers.SCRIPTHASH_OUT = Script.prototype.isScriptHashOut;
|
||||||
|
Script.outputIdentifiers.DATA_OUT = Script.prototype.isDataOut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {object} The Script type if it is a known form,
|
||||||
|
* or Script.UNKNOWN if it isn't
|
||||||
|
*/
|
||||||
|
Script.prototype.classifyOutput = function() {
|
||||||
|
for (var type in Script.outputIdentifiers) {
|
||||||
|
if (Script.outputIdentifiers[type].bind(this)()) {
|
||||||
|
return Script.types[type];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Script.types.UNKNOWN;
|
||||||
|
};
|
||||||
|
|
||||||
|
Script.inputIdentifiers = {};
|
||||||
|
Script.inputIdentifiers.PUBKEY_IN = Script.prototype.isPublicKeyIn;
|
||||||
|
Script.inputIdentifiers.PUBKEYHASH_IN = Script.prototype.isPublicKeyHashIn;
|
||||||
|
Script.inputIdentifiers.MULTISIG_IN = Script.prototype.isMultisigIn;
|
||||||
|
Script.inputIdentifiers.SCRIPTHASH_IN = Script.prototype.isScriptHashIn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {object} The Script type if it is a known form,
|
||||||
|
* or Script.UNKNOWN if it isn't
|
||||||
|
*/
|
||||||
|
Script.prototype.classifyInput = function() {
|
||||||
|
for (var type in Script.inputIdentifiers) {
|
||||||
|
if (Script.inputIdentifiers[type].bind(this)()) {
|
||||||
return Script.types[type];
|
return Script.types[type];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,10 @@ var Script = require('../../script');
|
||||||
var Sighash = require('../sighash');
|
var Sighash = require('../sighash');
|
||||||
var Output = require('../output');
|
var Output = require('../output');
|
||||||
|
|
||||||
|
var MAXINT = 0xffffffff; // Math.pow(2, 32) - 1;
|
||||||
var DEFAULT_SEQNUMBER = 0xFFFFFFFF;
|
var DEFAULT_RBF_SEQNUMBER = MAXINT - 2;
|
||||||
var DEFAULT_LOCKTIME_SEQNUMBER = 0x00000000;
|
var DEFAULT_SEQNUMBER = MAXINT;
|
||||||
|
var DEFAULT_LOCKTIME_SEQNUMBER = MAXINT - 1;
|
||||||
|
|
||||||
function Input(params) {
|
function Input(params) {
|
||||||
if (!(this instanceof Input)) {
|
if (!(this instanceof Input)) {
|
||||||
|
@ -24,8 +25,10 @@ function Input(params) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Input.MAXINT = MAXINT;
|
||||||
Input.DEFAULT_SEQNUMBER = DEFAULT_SEQNUMBER;
|
Input.DEFAULT_SEQNUMBER = DEFAULT_SEQNUMBER;
|
||||||
Input.DEFAULT_LOCKTIME_SEQNUMBER = DEFAULT_LOCKTIME_SEQNUMBER;
|
Input.DEFAULT_LOCKTIME_SEQNUMBER = DEFAULT_LOCKTIME_SEQNUMBER;
|
||||||
|
Input.DEFAULT_RBF_SEQNUMBER = DEFAULT_RBF_SEQNUMBER;
|
||||||
|
|
||||||
Object.defineProperty(Input.prototype, 'script', {
|
Object.defineProperty(Input.prototype, 'script', {
|
||||||
configurable: false,
|
configurable: false,
|
||||||
|
|
|
@ -0,0 +1,218 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _ = require('lodash');
|
||||||
|
var $ = require('../util/preconditions');
|
||||||
|
var BN = require('../crypto/bn');
|
||||||
|
var buffer = require('buffer');
|
||||||
|
var BufferWriter = require('../encoding/bufferwriter');
|
||||||
|
var BufferUtil = require('../util/buffer');
|
||||||
|
var JSUtil = require('../util/js');
|
||||||
|
|
||||||
|
// TODO: Update ZCProof for Groth
|
||||||
|
//var ZCProof = require('../zcash/proof');
|
||||||
|
|
||||||
|
var ZC_NUM_JS_INPUTS = 2;
|
||||||
|
var ZC_NUM_JS_OUTPUTS = 2;
|
||||||
|
|
||||||
|
// leading + v + rho + r + memo + auth
|
||||||
|
var ZC_NOTECIPHERTEXT_SIZE = 1 + 8 + 32 + 32 + 512 + 16;
|
||||||
|
|
||||||
|
function JSDescription(params) {
|
||||||
|
if (!(this instanceof JSDescription)) {
|
||||||
|
return new JSDescription(params);
|
||||||
|
}
|
||||||
|
this.nullifiers = [];
|
||||||
|
this.commitments = [];
|
||||||
|
this.ciphertexts = [];
|
||||||
|
this.macs = [];
|
||||||
|
if (params) {
|
||||||
|
return this._fromObject(params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(JSDescription.prototype, 'vpub_old', {
|
||||||
|
configurable: false,
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return this._vpub_old;
|
||||||
|
},
|
||||||
|
set: function(num) {
|
||||||
|
if (num instanceof BN) {
|
||||||
|
this._vpub_oldBN = num;
|
||||||
|
this._vpub_old = num.toNumber();
|
||||||
|
} else if (_.isString(num)) {
|
||||||
|
this._vpub_old = parseInt(num);
|
||||||
|
this._vpub_oldBN = BN.fromNumber(this._vpub_old);
|
||||||
|
} else {
|
||||||
|
$.checkArgument(
|
||||||
|
JSUtil.isNaturalNumber(num),
|
||||||
|
'vpub_old is not a natural number'
|
||||||
|
);
|
||||||
|
this._vpub_oldBN = BN.fromNumber(num);
|
||||||
|
this._vpub_old = num;
|
||||||
|
}
|
||||||
|
$.checkState(
|
||||||
|
JSUtil.isNaturalNumber(this._vpub_old),
|
||||||
|
'vpub_old is not a natural number'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(JSDescription.prototype, 'vpub_new', {
|
||||||
|
configurable: false,
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return this._vpub_new;
|
||||||
|
},
|
||||||
|
set: function(num) {
|
||||||
|
if (num instanceof BN) {
|
||||||
|
this._vpub_newBN = num;
|
||||||
|
this._vpub_new = num.toNumber();
|
||||||
|
} else if (_.isString(num)) {
|
||||||
|
this._vpub_new = parseInt(num);
|
||||||
|
this._vpub_newBN = BN.fromNumber(this._vpub_new);
|
||||||
|
} else {
|
||||||
|
$.checkArgument(
|
||||||
|
JSUtil.isNaturalNumber(num),
|
||||||
|
'vpub_new is not a natural number'
|
||||||
|
);
|
||||||
|
this._vpub_newBN = BN.fromNumber(num);
|
||||||
|
this._vpub_new = num;
|
||||||
|
}
|
||||||
|
$.checkState(
|
||||||
|
JSUtil.isNaturalNumber(this._vpub_new),
|
||||||
|
'vpub_new is not a natural number'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
JSDescription.fromObject = function(obj) {
|
||||||
|
$.checkArgument(_.isObject(obj));
|
||||||
|
var jsdesc = new JSDescription();
|
||||||
|
return jsdesc._fromObject(obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
JSDescription.prototype._fromObject = function(params) {
|
||||||
|
var nullifiers = [];
|
||||||
|
_.each(params.nullifiers, function(nullifier) {
|
||||||
|
nullifiers.push(BufferUtil.reverse(new buffer.Buffer(nullifier, 'hex')));
|
||||||
|
});
|
||||||
|
var commitments = [];
|
||||||
|
_.each(params.commitments, function(commitment) {
|
||||||
|
commitments.push(BufferUtil.reverse(new buffer.Buffer(commitment, 'hex')));
|
||||||
|
});
|
||||||
|
var ciphertexts = [];
|
||||||
|
_.each(params.ciphertexts, function(ciphertext) {
|
||||||
|
ciphertexts.push(new buffer.Buffer(ciphertext, 'hex'));
|
||||||
|
});
|
||||||
|
var macs = [];
|
||||||
|
_.each(params.macs, function(mac) {
|
||||||
|
macs.push(BufferUtil.reverse(new buffer.Buffer(mac, 'hex')));
|
||||||
|
});
|
||||||
|
this.vpub_old = params.vpub_old;
|
||||||
|
this.vpub_new = params.vpub_new;
|
||||||
|
this.anchor = BufferUtil.reverse(new buffer.Buffer(params.anchor, 'hex'));
|
||||||
|
this.nullifiers = nullifiers;
|
||||||
|
this.commitments = commitments;
|
||||||
|
this.ephemeralKey = BufferUtil.reverse(new buffer.Buffer(params.ephemeralKey, 'hex'));
|
||||||
|
this.ciphertexts = ciphertexts;
|
||||||
|
this.randomSeed = BufferUtil.reverse(new buffer.Buffer(params.randomSeed, 'hex'));
|
||||||
|
this.macs = macs;
|
||||||
|
this.proof = params.proof; // TODO: Update ZCProof for Groth: ZCProof.fromObject(params.proof);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
JSDescription.prototype.toObject = JSDescription.prototype.toJSON = function toObject() {
|
||||||
|
var nullifiers = [];
|
||||||
|
_.each(this.nullifiers, function(nullifier) {
|
||||||
|
nullifiers.push(BufferUtil.reverse(nullifier).toString('hex'));
|
||||||
|
});
|
||||||
|
var commitments = [];
|
||||||
|
_.each(this.commitments, function(commitment) {
|
||||||
|
commitments.push(BufferUtil.reverse(commitment).toString('hex'));
|
||||||
|
});
|
||||||
|
var ciphertexts = [];
|
||||||
|
_.each(this.ciphertexts, function(ciphertext) {
|
||||||
|
ciphertexts.push(ciphertext.toString('hex'));
|
||||||
|
});
|
||||||
|
var macs = [];
|
||||||
|
_.each(this.macs, function(mac) {
|
||||||
|
macs.push(BufferUtil.reverse(mac).toString('hex'));
|
||||||
|
});
|
||||||
|
var obj = {
|
||||||
|
vpub_old: this.vpub_old,
|
||||||
|
vpub_new: this.vpub_new,
|
||||||
|
anchor: BufferUtil.reverse(this.anchor).toString('hex'),
|
||||||
|
nullifiers: nullifiers,
|
||||||
|
commitments: commitments,
|
||||||
|
ephemeralKey: BufferUtil.reverse(this.ephemeralKey).toString('hex'),
|
||||||
|
ciphertexts: ciphertexts,
|
||||||
|
randomSeed: BufferUtil.reverse(this.randomSeed).toString('hex'),
|
||||||
|
macs: macs,
|
||||||
|
proof: this.proof, // TODO: Update ZCProof for Groth: this.proof.toObject(),
|
||||||
|
};
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
JSDescription.fromBufferReader = function(br, useGrothFlagParam) {
|
||||||
|
var i;
|
||||||
|
var jsdesc = new JSDescription();
|
||||||
|
jsdesc.vpub_old = br.readUInt64LEBN();
|
||||||
|
jsdesc.vpub_new = br.readUInt64LEBN();
|
||||||
|
jsdesc.anchor = br.read(32);
|
||||||
|
for (i = 0; i < ZC_NUM_JS_INPUTS; i++) {
|
||||||
|
jsdesc.nullifiers.push(br.read(32));
|
||||||
|
}
|
||||||
|
for (i = 0; i < ZC_NUM_JS_OUTPUTS; i++) {
|
||||||
|
jsdesc.commitments.push(br.read(32));
|
||||||
|
}
|
||||||
|
jsdesc.ephemeralKey = br.read(32);
|
||||||
|
jsdesc.randomSeed = br.read(32);
|
||||||
|
for (i = 0; i < ZC_NUM_JS_INPUTS; i++) {
|
||||||
|
jsdesc.macs.push(br.read(32));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default parameter requires ECMASCript 6 which might not be available, so use workaround.
|
||||||
|
var useGrothFlag = useGrothFlagParam || false;
|
||||||
|
if (!useGrothFlag) {
|
||||||
|
jsdesc.proof = br.read(296); // TODO: Update ZCProof for Groth: ZCProof.fromBufferReader(br);
|
||||||
|
} else {
|
||||||
|
jsdesc.proof = br.read(48 + 96 + 48);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ZC_NUM_JS_OUTPUTS; i++) {
|
||||||
|
jsdesc.ciphertexts.push(br.read(ZC_NOTECIPHERTEXT_SIZE));
|
||||||
|
}
|
||||||
|
return jsdesc;
|
||||||
|
};
|
||||||
|
|
||||||
|
JSDescription.prototype.toBufferWriter = function(writer) {
|
||||||
|
var i;
|
||||||
|
if (!writer) {
|
||||||
|
writer = new BufferWriter();
|
||||||
|
}
|
||||||
|
writer.writeUInt64LEBN(this._vpub_oldBN);
|
||||||
|
writer.writeUInt64LEBN(this._vpub_newBN);
|
||||||
|
writer.write(this.anchor);
|
||||||
|
for (i = 0; i < ZC_NUM_JS_INPUTS; i++) {
|
||||||
|
writer.write(this.nullifiers[i]);
|
||||||
|
}
|
||||||
|
for (i = 0; i < ZC_NUM_JS_OUTPUTS; i++) {
|
||||||
|
writer.write(this.commitments[i]);
|
||||||
|
}
|
||||||
|
writer.write(this.ephemeralKey);
|
||||||
|
writer.write(this.randomSeed);
|
||||||
|
for (i = 0; i < ZC_NUM_JS_INPUTS; i++) {
|
||||||
|
writer.write(this.macs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Update ZCProof for Groth: this.proof.toBufferWriter(writer);
|
||||||
|
writer.write(this.proof);
|
||||||
|
|
||||||
|
for (i = 0; i < ZC_NUM_JS_OUTPUTS; i++) {
|
||||||
|
writer.write(this.ciphertexts[i]);
|
||||||
|
}
|
||||||
|
return writer;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = JSDescription;
|
|
@ -0,0 +1,78 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _ = require('lodash');
|
||||||
|
var $ = require('../util/preconditions');
|
||||||
|
var BN = require('../crypto/bn');
|
||||||
|
var buffer = require('buffer');
|
||||||
|
var BufferWriter = require('../encoding/bufferwriter');
|
||||||
|
var BufferUtil = require('../util/buffer');
|
||||||
|
var JSUtil = require('../util/js');
|
||||||
|
|
||||||
|
// Sapling note magic values, copied from src/zcash/Zcash.h
|
||||||
|
var NOTEENCRYPTION_AUTH_BYTES = 16;
|
||||||
|
var ZC_NOTEPLAINTEXT_LEADING = 1;
|
||||||
|
var ZC_V_SIZE = 8;
|
||||||
|
var ZC_RHO_SIZE = 32;
|
||||||
|
var ZC_R_SIZE = 32;
|
||||||
|
var ZC_MEMO_SIZE = 512;
|
||||||
|
var ZC_DIVERSIFIER_SIZE = 11;
|
||||||
|
var ZC_JUBJUB_POINT_SIZE = 32;
|
||||||
|
var ZC_JUBJUB_SCALAR_SIZE = 32;
|
||||||
|
var ZC_NOTEPLAINTEXT_SIZE = ZC_NOTEPLAINTEXT_LEADING + ZC_V_SIZE + ZC_RHO_SIZE + ZC_R_SIZE + ZC_MEMO_SIZE;
|
||||||
|
var ZC_SAPLING_ENCPLAINTEXT_SIZE = ZC_NOTEPLAINTEXT_LEADING + ZC_DIVERSIFIER_SIZE + ZC_V_SIZE + ZC_R_SIZE + ZC_MEMO_SIZE;
|
||||||
|
var ZC_SAPLING_OUTPLAINTEXT_SIZE = ZC_JUBJUB_POINT_SIZE + ZC_JUBJUB_SCALAR_SIZE;
|
||||||
|
var ZC_SAPLING_ENCCIPHERTEXT_SIZE = ZC_SAPLING_ENCPLAINTEXT_SIZE + NOTEENCRYPTION_AUTH_BYTES;
|
||||||
|
var ZC_SAPLING_OUTCIPHERTEXT_SIZE = ZC_SAPLING_OUTPLAINTEXT_SIZE + NOTEENCRYPTION_AUTH_BYTES;
|
||||||
|
|
||||||
|
function OutputDescription(params) {
|
||||||
|
if (!(this instanceof OutputDescription)) {
|
||||||
|
return new OutputDescription(params);
|
||||||
|
}
|
||||||
|
if (params) {
|
||||||
|
return this._fromObject(params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputDescription.fromObject = function(obj) {
|
||||||
|
$.checkArgument(_.isObject(obj));
|
||||||
|
var outputdesc = new OutputDescription();
|
||||||
|
return outputdesc._fromObject(obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
OutputDescription.prototype._fromObject = function(params) {
|
||||||
|
// TODO: Populate from parameters, but for now it's ok to do nothing.
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
OutputDescription.prototype.toObject = OutputDescription.prototype.toJSON = function toObject() {
|
||||||
|
// TODO: Populate JSON object, but for now it's ok to return a placeholder.
|
||||||
|
var obj = {};
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
OutputDescription.fromBufferReader = function(br) {
|
||||||
|
var obj = new OutputDescription();
|
||||||
|
obj.cv = br.read(32);
|
||||||
|
obj.cmu = br.read(32);
|
||||||
|
obj.ephemeralKey = br.read(32);
|
||||||
|
obj.encCipherText = br.read(ZC_SAPLING_ENCCIPHERTEXT_SIZE);
|
||||||
|
obj.outCipherText = br.read(ZC_SAPLING_OUTCIPHERTEXT_SIZE);
|
||||||
|
obj.proof = br.read(48 + 96 + 48);
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
OutputDescription.prototype.toBufferWriter = function(writer) {
|
||||||
|
var i;
|
||||||
|
if (!writer) {
|
||||||
|
writer = new BufferWriter();
|
||||||
|
}
|
||||||
|
writer.write(this.cv);
|
||||||
|
writer.write(this.cmu);
|
||||||
|
writer.write(this.ephemeralKey);
|
||||||
|
writer.write(this.encCipherText);
|
||||||
|
writer.write(this.outCipherText);
|
||||||
|
writer.write(this.proof);
|
||||||
|
return writer;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = OutputDescription;
|
|
@ -0,0 +1,62 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _ = require('lodash');
|
||||||
|
var $ = require('../util/preconditions');
|
||||||
|
var BN = require('../crypto/bn');
|
||||||
|
var buffer = require('buffer');
|
||||||
|
var BufferWriter = require('../encoding/bufferwriter');
|
||||||
|
var BufferUtil = require('../util/buffer');
|
||||||
|
var JSUtil = require('../util/js');
|
||||||
|
|
||||||
|
function SpendDescription(params) {
|
||||||
|
if (!(this instanceof SpendDescription)) {
|
||||||
|
return new SpendDescription(params);
|
||||||
|
}
|
||||||
|
if (params) {
|
||||||
|
return this._fromObject(params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SpendDescription.fromObject = function(obj) {
|
||||||
|
$.checkArgument(_.isObject(obj));
|
||||||
|
var spenddesc = new SpendDescription();
|
||||||
|
return spenddesc._fromObject(obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
SpendDescription.prototype._fromObject = function(params) {
|
||||||
|
// TODO: Populate from parameters, but for now it's ok to do nothing.
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
SpendDescription.prototype.toObject = SpendDescription.prototype.toJSON = function toObject() {
|
||||||
|
// TODO: Populate JSON object, but for now it's ok to return a placeholder.
|
||||||
|
var obj = {};
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
SpendDescription.fromBufferReader = function(br) {
|
||||||
|
var obj = new SpendDescription();
|
||||||
|
obj.cv = br.read(32);
|
||||||
|
obj.anchor = br.read(32);
|
||||||
|
obj.nullifier = br.read(32);
|
||||||
|
obj.rk = br.read(32);
|
||||||
|
obj.proof = br.read(48 + 96 + 48);
|
||||||
|
obj.spendAuthSig = br.read(64);
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
SpendDescription.prototype.toBufferWriter = function(writer) {
|
||||||
|
var i;
|
||||||
|
if (!writer) {
|
||||||
|
writer = new BufferWriter();
|
||||||
|
}
|
||||||
|
writer.write(this.cv);
|
||||||
|
writer.write(this.anchor);
|
||||||
|
writer.write(this.nullifier);
|
||||||
|
writer.write(this.rk);
|
||||||
|
writer.write(this.proof);
|
||||||
|
writer.write(this.spendAuthSig);
|
||||||
|
return writer;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = SpendDescription;
|
|
@ -26,6 +26,10 @@ var Script = require('../script');
|
||||||
var PrivateKey = require('../privatekey');
|
var PrivateKey = require('../privatekey');
|
||||||
var BN = require('../crypto/bn');
|
var BN = require('../crypto/bn');
|
||||||
|
|
||||||
|
var JSDescription = require('./jsdescription');
|
||||||
|
var SpendDescription = require('./spenddescription');
|
||||||
|
var OutputDescription = require('./outputdescription');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a transaction, a set of inputs and outputs to change ownership of tokens
|
* Represents a transaction, a set of inputs and outputs to change ownership of tokens
|
||||||
*
|
*
|
||||||
|
@ -38,6 +42,11 @@ function Transaction(serialized) {
|
||||||
}
|
}
|
||||||
this.inputs = [];
|
this.inputs = [];
|
||||||
this.outputs = [];
|
this.outputs = [];
|
||||||
|
this.joinSplits = [];
|
||||||
|
|
||||||
|
this.spendDescs = [];
|
||||||
|
this.outputDescs = [];
|
||||||
|
|
||||||
this._inputAmount = undefined;
|
this._inputAmount = undefined;
|
||||||
this._outputAmount = undefined;
|
this._outputAmount = undefined;
|
||||||
|
|
||||||
|
@ -279,7 +288,19 @@ Transaction.prototype.toBuffer = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
Transaction.prototype.toBufferWriter = function(writer) {
|
Transaction.prototype.toBufferWriter = function(writer) {
|
||||||
writer.writeUInt32LE(this.version);
|
if (!this.fOverwintered) {
|
||||||
|
writer.writeUInt32LE(this.version);
|
||||||
|
} else {
|
||||||
|
// We don't use bitwise operators which expect 32 bit operands and return a 32 bit signed integer.
|
||||||
|
// For example, var header = 0x80000000 | this.version; returns -7fffffff (-2147483645).
|
||||||
|
var header = 0x80000000 + this.version;
|
||||||
|
writer.writeUInt32LE(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.fOverwintered) {
|
||||||
|
writer.writeUInt32LE(this.nVersionGroupId);
|
||||||
|
}
|
||||||
|
|
||||||
writer.writeVarintNum(this.inputs.length);
|
writer.writeVarintNum(this.inputs.length);
|
||||||
_.each(this.inputs, function(input) {
|
_.each(this.inputs, function(input) {
|
||||||
input.toBufferWriter(writer);
|
input.toBufferWriter(writer);
|
||||||
|
@ -289,6 +310,38 @@ Transaction.prototype.toBufferWriter = function(writer) {
|
||||||
output.toBufferWriter(writer);
|
output.toBufferWriter(writer);
|
||||||
});
|
});
|
||||||
writer.writeUInt32LE(this.nLockTime);
|
writer.writeUInt32LE(this.nLockTime);
|
||||||
|
|
||||||
|
if (this.fOverwintered) {
|
||||||
|
writer.writeUInt32LE(this.nExpiryHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.version >= 4) {
|
||||||
|
writer.writeUInt64LEBN(this.valueBalance);
|
||||||
|
writer.writeVarintNum(this.spendDescs.length);
|
||||||
|
_.each(this.spendDescs, function(desc) {
|
||||||
|
desc.toBufferWriter(writer);
|
||||||
|
});
|
||||||
|
writer.writeVarintNum(this.outputDescs.length);
|
||||||
|
_.each(this.outputDescs, function(desc) {
|
||||||
|
desc.toBufferWriter(writer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.version >= 2) {
|
||||||
|
writer.writeVarintNum(this.joinSplits.length);
|
||||||
|
_.each(this.joinSplits, function(jsdesc) {
|
||||||
|
jsdesc.toBufferWriter(writer);
|
||||||
|
});
|
||||||
|
if (this.joinSplits.length > 0) {
|
||||||
|
writer.write(this.joinSplitPubKey);
|
||||||
|
writer.write(this.joinSplitSig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.version >= 4 && !(this.spendDescs.length==0 && this.outputDescs.length==0)) {
|
||||||
|
writer.write(this.bindingSig);
|
||||||
|
}
|
||||||
|
|
||||||
return writer;
|
return writer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -299,9 +352,20 @@ Transaction.prototype.fromBuffer = function(buffer) {
|
||||||
|
|
||||||
Transaction.prototype.fromBufferReader = function(reader) {
|
Transaction.prototype.fromBufferReader = function(reader) {
|
||||||
$.checkArgument(!reader.finished(), 'No transaction data received');
|
$.checkArgument(!reader.finished(), 'No transaction data received');
|
||||||
var i, sizeTxIns, sizeTxOuts;
|
var i, sizeTxIns, sizeTxOuts, sizeJSDescs, sizeSpendDescs, sizeOutputDescs;
|
||||||
|
var header = reader.readUInt32LE();
|
||||||
|
|
||||||
|
this.fOverwintered = ((header >>> 31) == 1);
|
||||||
|
if (this.fOverwintered == true) {
|
||||||
|
this.version = header & 0x7fffffff;
|
||||||
|
} else {
|
||||||
|
this.version = header;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.version >= 3 ){
|
||||||
|
this.nVersionGroupId = reader.readUInt32LE();
|
||||||
|
}
|
||||||
|
|
||||||
this.version = reader.readUInt32LE();
|
|
||||||
sizeTxIns = reader.readVarintNum();
|
sizeTxIns = reader.readVarintNum();
|
||||||
for (i = 0; i < sizeTxIns; i++) {
|
for (i = 0; i < sizeTxIns; i++) {
|
||||||
var input = Input.fromBufferReader(reader);
|
var input = Input.fromBufferReader(reader);
|
||||||
|
@ -311,7 +375,43 @@ Transaction.prototype.fromBufferReader = function(reader) {
|
||||||
for (i = 0; i < sizeTxOuts; i++) {
|
for (i = 0; i < sizeTxOuts; i++) {
|
||||||
this.outputs.push(Output.fromBufferReader(reader));
|
this.outputs.push(Output.fromBufferReader(reader));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.nLockTime = reader.readUInt32LE();
|
this.nLockTime = reader.readUInt32LE();
|
||||||
|
|
||||||
|
if (this.version >= 3) {
|
||||||
|
this.nExpiryHeight = reader.readUInt32LE();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.version >= 4) {
|
||||||
|
this.valueBalance = reader.readUInt64LEBN();
|
||||||
|
sizeSpendDescs = reader.readVarintNum();
|
||||||
|
for (i = 0; i < sizeSpendDescs; i++) {
|
||||||
|
var spend = SpendDescription.fromBufferReader(reader);
|
||||||
|
this.spendDescs.push(spend);
|
||||||
|
}
|
||||||
|
sizeOutputDescs = reader.readVarintNum();
|
||||||
|
for (i = 0; i < sizeOutputDescs; i++) {
|
||||||
|
var output = OutputDescription.fromBufferReader(reader);
|
||||||
|
this.outputDescs.push(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var useGrothFlag = (this.version >= 4);
|
||||||
|
if (this.version >= 2) {
|
||||||
|
sizeJSDescs = reader.readVarintNum();
|
||||||
|
for (i = 0; i < sizeJSDescs; i++) {
|
||||||
|
this.joinSplits.push(JSDescription.fromBufferReader(reader, useGrothFlag));
|
||||||
|
}
|
||||||
|
if (sizeJSDescs > 0) {
|
||||||
|
this.joinSplitPubKey = reader.read(32);
|
||||||
|
this.joinSplitSig = reader.read(64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.version >=4 && !(sizeSpendDescs==0 && sizeOutputDescs==0)) {
|
||||||
|
this.bindingSig = reader.read(64);
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -326,11 +426,50 @@ Transaction.prototype.toObject = Transaction.prototype.toJSON = function toObjec
|
||||||
});
|
});
|
||||||
var obj = {
|
var obj = {
|
||||||
hash: this.hash,
|
hash: this.hash,
|
||||||
|
fOverwintered: this.fOverwintered,
|
||||||
version: this.version,
|
version: this.version,
|
||||||
inputs: inputs,
|
inputs: inputs,
|
||||||
outputs: outputs,
|
outputs: outputs,
|
||||||
nLockTime: this.nLockTime
|
nLockTime: this.nLockTime
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (this.fOverwintered) {
|
||||||
|
obj.nVersionGroupId = this.nVersionGroupId;
|
||||||
|
obj.nExpiryHeight = this.nExpiryHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.version >= 4) {
|
||||||
|
obj.valueBalance - this.valueBalance;
|
||||||
|
|
||||||
|
var spendDescs = [];
|
||||||
|
this.spendDescs.forEach(function(desc) {
|
||||||
|
spendDescs.push(desc.toObject());
|
||||||
|
});
|
||||||
|
obj.spendDescs = spendDescs;
|
||||||
|
|
||||||
|
var outputDescs = [];
|
||||||
|
this.outputDescs.forEach(function(desc) {
|
||||||
|
outputDescs.push(desc.toObject());
|
||||||
|
});
|
||||||
|
obj.outputDescs = outputDescs;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.version >= 2) {
|
||||||
|
var joinSplits = [];
|
||||||
|
this.joinSplits.forEach(function(joinSplit) {
|
||||||
|
joinSplits.push(joinSplit.toObject());
|
||||||
|
});
|
||||||
|
obj.joinSplits = joinSplits;
|
||||||
|
if (this.joinSplits.length > 0) {
|
||||||
|
obj.joinSplitPubKey = BufferUtil.reverse(this.joinSplitPubKey).toString('hex');
|
||||||
|
obj.joinSplitSig = this.joinSplitSig.toString('hex');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.version >=4 && !(this.spendDescs.length==0 && this.outputDescs.length==0)) {
|
||||||
|
obj.bindingSig = this.bindingSig.toString('hex');
|
||||||
|
}
|
||||||
|
|
||||||
if (this._changeScript) {
|
if (this._changeScript) {
|
||||||
obj.changeScript = this._changeScript.toString();
|
obj.changeScript = this._changeScript.toString();
|
||||||
}
|
}
|
||||||
|
@ -366,6 +505,8 @@ Transaction.prototype.fromObject = function fromObject(arg) {
|
||||||
txin = new Input.MultiSigScriptHash(
|
txin = new Input.MultiSigScriptHash(
|
||||||
input, input.publicKeys, input.threshold, input.signatures
|
input, input.publicKeys, input.threshold, input.signatures
|
||||||
);
|
);
|
||||||
|
} else if (script.isPublicKeyOut()) {
|
||||||
|
txin = new Input.PublicKey(input);
|
||||||
} else {
|
} else {
|
||||||
throw new errors.Transaction.Input.UnsupportedScript(input.output.script);
|
throw new errors.Transaction.Input.UnsupportedScript(input.output.script);
|
||||||
}
|
}
|
||||||
|
@ -385,6 +526,38 @@ Transaction.prototype.fromObject = function fromObject(arg) {
|
||||||
}
|
}
|
||||||
this.nLockTime = transaction.nLockTime;
|
this.nLockTime = transaction.nLockTime;
|
||||||
this.version = transaction.version;
|
this.version = transaction.version;
|
||||||
|
|
||||||
|
|
||||||
|
this.fOverwintered = transaction.fOverwintered;
|
||||||
|
if (this.fOverwintered) {
|
||||||
|
this.nExpiryHeight = transaction.nExpiryHeight;
|
||||||
|
this.nVersionGroupId = transaction.nVersionGroupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.version >= 4) {
|
||||||
|
this.valueBalance = transaction.valueBalance;
|
||||||
|
_.each(transaction.spendDescs, function(desc) {
|
||||||
|
self.spendDescs.push(new SpendDescription(desc));
|
||||||
|
});
|
||||||
|
_.each(transaction.outputDescs, function(desc) {
|
||||||
|
self.outputDescs.push(new OutputDescription(desc));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.version >= 2) {
|
||||||
|
_.each(transaction.joinSplits, function(joinSplit) {
|
||||||
|
self.joinSplits.push(new JSDescription(joinSplit));
|
||||||
|
});
|
||||||
|
if (self.joinSplits.length > 0) {
|
||||||
|
self.joinSplitPubKey = BufferUtil.reverse(new Buffer(transaction.joinSplitPubKey, 'hex'));
|
||||||
|
self.joinSplitSig = new Buffer(transaction.joinSplitSig, 'hex');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.version >=4 && !(transaction.spendDescs.length==0 && transaction.outputDescs.length==0)) {
|
||||||
|
this.bindingSig = transaction.bindingSig;
|
||||||
|
}
|
||||||
|
|
||||||
this._checkConsistency(arg);
|
this._checkConsistency(arg);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
@ -544,7 +717,7 @@ Transaction.prototype.from = function(utxo, pubkeys, threshold) {
|
||||||
return input.prevTxId.toString('hex') === utxo.txId && input.outputIndex === utxo.outputIndex;
|
return input.prevTxId.toString('hex') === utxo.txId && input.outputIndex === utxo.outputIndex;
|
||||||
});
|
});
|
||||||
if (exists) {
|
if (exists) {
|
||||||
return;
|
return this;
|
||||||
}
|
}
|
||||||
if (pubkeys && threshold) {
|
if (pubkeys && threshold) {
|
||||||
this._fromMultisigUtxo(utxo, pubkeys, threshold);
|
this._fromMultisigUtxo(utxo, pubkeys, threshold);
|
||||||
|
@ -1195,5 +1368,34 @@ Transaction.prototype.isCoinbase = function() {
|
||||||
return (this.inputs.length === 1 && this.inputs[0].isNull());
|
return (this.inputs.length === 1 && this.inputs[0].isNull());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if this transaction can be replaced in the mempool with another
|
||||||
|
* transaction that provides a sufficiently higher fee (RBF).
|
||||||
|
*/
|
||||||
|
Transaction.prototype.isRBF = function() {
|
||||||
|
for (var i = 0; i < this.inputs.length; i++) {
|
||||||
|
var input = this.inputs[i];
|
||||||
|
if (input.sequenceNumber < Input.MAXINT - 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable this transaction to be replaced in the mempool (RBF) if a transaction
|
||||||
|
* includes a sufficiently higher fee. It will set the sequenceNumber to
|
||||||
|
* DEFAULT_RBF_SEQNUMBER for all inputs if the sequence number does not
|
||||||
|
* already enable RBF.
|
||||||
|
*/
|
||||||
|
Transaction.prototype.enableRBF = function() {
|
||||||
|
for (var i = 0; i < this.inputs.length; i++) {
|
||||||
|
var input = this.inputs[i];
|
||||||
|
if (input.sequenceNumber >= Input.MAXINT - 1) {
|
||||||
|
input.sequenceNumber = Input.DEFAULT_RBF_SEQNUMBER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = Transaction;
|
module.exports = Transaction;
|
||||||
|
|
|
@ -110,8 +110,8 @@ URI.isValid = function(arg, knownParams) {
|
||||||
URI.parse = function(uri) {
|
URI.parse = function(uri) {
|
||||||
var info = URL.parse(uri, true);
|
var info = URL.parse(uri, true);
|
||||||
|
|
||||||
if (info.protocol !== 'bitcoin:') {
|
if (info.protocol !== 'zcash:') {
|
||||||
throw new TypeError('Invalid bitcoin URI');
|
throw new TypeError('Invalid zcash URI');
|
||||||
}
|
}
|
||||||
|
|
||||||
// workaround to host insensitiveness
|
// workaround to host insensitiveness
|
||||||
|
@ -135,7 +135,7 @@ URI.prototype._fromObject = function(obj) {
|
||||||
/* jshint maxcomplexity: 10 */
|
/* jshint maxcomplexity: 10 */
|
||||||
|
|
||||||
if (!Address.isValid(obj.address)) {
|
if (!Address.isValid(obj.address)) {
|
||||||
throw new TypeError('Invalid bitcoin address');
|
throw new TypeError('Invalid zcash address');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.address = new Address(obj.address);
|
this.address = new Address(obj.address);
|
||||||
|
@ -205,7 +205,7 @@ URI.prototype.toString = function() {
|
||||||
_.extend(query, this.extras);
|
_.extend(query, this.extras);
|
||||||
|
|
||||||
return URL.format({
|
return URL.format({
|
||||||
protocol: 'bitcoin:',
|
protocol: 'zcash:',
|
||||||
host: this.address,
|
host: this.address,
|
||||||
query: query
|
query: query
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var $ = require('../util/preconditions');
|
||||||
|
var buffer = require('buffer');
|
||||||
|
var BufferWriter = require('../encoding/bufferwriter');
|
||||||
|
|
||||||
|
var G1_PREFIX_MASK = 0x02;
|
||||||
|
var G2_PREFIX_MASK = 0x0a;
|
||||||
|
|
||||||
|
function CompressedG1(params) {
|
||||||
|
if (!(this instanceof CompressedG1)) {
|
||||||
|
return new CompressedG1(params);
|
||||||
|
}
|
||||||
|
if (params) {
|
||||||
|
return this._fromObject(params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompressedG1.fromObject = function(obj) {
|
||||||
|
$.checkArgument(_.isObject(obj));
|
||||||
|
var pt = new CompressedG1();
|
||||||
|
return pt._fromObject(obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
CompressedG1.prototype._fromObject = function(params) {
|
||||||
|
this.y_lsb = params.y_lsb;
|
||||||
|
this.x = new buffer.Buffer(params.x, 'hex');
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
CompressedG1.prototype.toObject = CompressedG1.prototype.toJSON = function toObject() {
|
||||||
|
var obj = {
|
||||||
|
y_lsb: this.y_lsb,
|
||||||
|
x: this.x.toString('hex'),
|
||||||
|
};
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
CompressedG1.fromBufferReader = function(br) {
|
||||||
|
var pt = new CompressedG1();
|
||||||
|
var y_lsb = br.readUInt8();
|
||||||
|
pt.y_lsb = y_lsb & 1;
|
||||||
|
pt.x = br.read(32);
|
||||||
|
return pt;
|
||||||
|
};
|
||||||
|
|
||||||
|
CompressedG1.prototype.toBufferWriter = function(writer) {
|
||||||
|
if (!writer) {
|
||||||
|
writer = new BufferWriter();
|
||||||
|
}
|
||||||
|
writer.writeUInt8(G1_PREFIX_MASK | this.y_lsb);
|
||||||
|
writer.write(this.x);
|
||||||
|
return writer;
|
||||||
|
};
|
||||||
|
|
||||||
|
function CompressedG2(params) {
|
||||||
|
if (!(this instanceof CompressedG2)) {
|
||||||
|
return new CompressedG2(params);
|
||||||
|
}
|
||||||
|
if (params) {
|
||||||
|
return this._fromObject(params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompressedG2.fromObject = function(obj) {
|
||||||
|
$.checkArgument(_.isObject(obj));
|
||||||
|
var pt = new CompressedG2();
|
||||||
|
return pt._fromObject(obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
CompressedG2.prototype._fromObject = function(params) {
|
||||||
|
this.y_gt = params.y_gt;
|
||||||
|
this.x = new buffer.Buffer(params.x, 'hex');
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
CompressedG2.prototype.toObject = CompressedG2.prototype.toJSON = function toObject() {
|
||||||
|
var obj = {
|
||||||
|
y_gt: this.y_gt,
|
||||||
|
x: this.x.toString('hex'),
|
||||||
|
};
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
CompressedG2.fromBufferReader = function(br) {
|
||||||
|
var pt = new CompressedG2();
|
||||||
|
var y_gt = br.readUInt8();
|
||||||
|
pt.y_gt = y_gt & 1;
|
||||||
|
pt.x = br.read(64);
|
||||||
|
return pt;
|
||||||
|
};
|
||||||
|
|
||||||
|
CompressedG2.prototype.toBufferWriter = function(writer) {
|
||||||
|
if (!writer) {
|
||||||
|
writer = new BufferWriter();
|
||||||
|
}
|
||||||
|
writer.writeUInt8(G2_PREFIX_MASK | this.y_gt);
|
||||||
|
writer.write(this.x);
|
||||||
|
return writer;
|
||||||
|
};
|
||||||
|
|
||||||
|
function ZCProof(params) {
|
||||||
|
if (!(this instanceof ZCProof)) {
|
||||||
|
return new ZCProof(params);
|
||||||
|
}
|
||||||
|
if (params) {
|
||||||
|
return this._fromObject(params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ZCProof.fromObject = function(obj) {
|
||||||
|
$.checkArgument(_.isObject(obj));
|
||||||
|
var proof = new ZCProof();
|
||||||
|
return proof._fromObject(obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
ZCProof.prototype._fromObject = function(params) {
|
||||||
|
this.g_A = CompressedG1.fromObject(params.g_A);
|
||||||
|
this.g_A_prime = CompressedG1.fromObject(params.g_A_prime);
|
||||||
|
this.g_B = CompressedG2.fromObject(params.g_B);
|
||||||
|
this.g_B_prime = CompressedG1.fromObject(params.g_B_prime);
|
||||||
|
this.g_C = CompressedG1.fromObject(params.g_C);
|
||||||
|
this.g_C_prime = CompressedG1.fromObject(params.g_C_prime);
|
||||||
|
this.g_K = CompressedG1.fromObject(params.g_K);
|
||||||
|
this.g_H = CompressedG1.fromObject(params.g_H);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
ZCProof.prototype.toObject = ZCProof.prototype.toJSON = function toObject() {
|
||||||
|
var obj = {
|
||||||
|
g_A: this.g_A.toObject(),
|
||||||
|
g_A_prime: this.g_A_prime.toObject(),
|
||||||
|
g_B: this.g_B.toObject(),
|
||||||
|
g_B_prime: this.g_B_prime.toObject(),
|
||||||
|
g_C: this.g_C.toObject(),
|
||||||
|
g_C_prime: this.g_C_prime.toObject(),
|
||||||
|
g_K: this.g_K.toObject(),
|
||||||
|
g_H: this.g_H.toObject(),
|
||||||
|
};
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
ZCProof.fromBufferReader = function(br) {
|
||||||
|
var proof = new ZCProof();
|
||||||
|
proof.g_A = CompressedG1.fromBufferReader(br);
|
||||||
|
proof.g_A_prime = CompressedG1.fromBufferReader(br);
|
||||||
|
proof.g_B = CompressedG2.fromBufferReader(br);
|
||||||
|
proof.g_B_prime = CompressedG1.fromBufferReader(br);
|
||||||
|
proof.g_C = CompressedG1.fromBufferReader(br);
|
||||||
|
proof.g_C_prime = CompressedG1.fromBufferReader(br);
|
||||||
|
proof.g_K = CompressedG1.fromBufferReader(br);
|
||||||
|
proof.g_H = CompressedG1.fromBufferReader(br);
|
||||||
|
return proof;
|
||||||
|
};
|
||||||
|
|
||||||
|
ZCProof.prototype.toBufferWriter = function(writer) {
|
||||||
|
if (!writer) {
|
||||||
|
writer = new BufferWriter();
|
||||||
|
}
|
||||||
|
this.g_A.toBufferWriter(writer);
|
||||||
|
this.g_A_prime.toBufferWriter(writer);
|
||||||
|
this.g_B.toBufferWriter(writer);
|
||||||
|
this.g_B_prime.toBufferWriter(writer);
|
||||||
|
this.g_C.toBufferWriter(writer);
|
||||||
|
this.g_C_prime.toBufferWriter(writer);
|
||||||
|
this.g_K.toBufferWriter(writer);
|
||||||
|
this.g_H.toBufferWriter(writer);
|
||||||
|
return writer;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = ZCProof;
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "bitcore",
|
"name": "bitcore",
|
||||||
"version": "0.13.10",
|
"version": "0.13.19",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bn.js": {
|
"bn.js": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
|
@ -43,11 +43,6 @@
|
||||||
"version": "3.10.1",
|
"version": "3.10.1",
|
||||||
"from": "lodash@=3.10.1",
|
"from": "lodash@=3.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz"
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz"
|
||||||
},
|
|
||||||
"sha512": {
|
|
||||||
"version": "0.0.1",
|
|
||||||
"from": "sha512@=0.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/sha512/-/sha512-0.0.1.tgz"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
27
package.json
27
package.json
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "bitcore-lib",
|
"name": "bitcore-lib-zcash",
|
||||||
"version": "0.13.11",
|
"version": "0.13.19",
|
||||||
"description": "A pure and powerful JavaScript Bitcoin library.",
|
"description": "A pure and powerful JavaScript Zcash library.",
|
||||||
"author": "BitPay <dev@bitpay.com>",
|
"author": "BitPay <dev@bitpay.com>",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -54,10 +54,22 @@
|
||||||
{
|
{
|
||||||
"name": "Wei Lu",
|
"name": "Wei Lu",
|
||||||
"email": "luwei.here@gmail.com"
|
"email": "luwei.here@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jack Grigg",
|
||||||
|
"email": "jack@z.cash"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Simon Liu",
|
||||||
|
"email": "simon@z.cash"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ian Munoz",
|
||||||
|
"email": "ian.org@gmail.com"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"bitcoin",
|
"zcash",
|
||||||
"transaction",
|
"transaction",
|
||||||
"address",
|
"address",
|
||||||
"p2p",
|
"p2p",
|
||||||
|
@ -74,7 +86,7 @@
|
||||||
],
|
],
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/bitpay/bitcore-lib.git"
|
"url": "https://github.com/zcash-hackworks/bitcore-lib-zcash.git"
|
||||||
},
|
},
|
||||||
"browser": {
|
"browser": {
|
||||||
"request": "browser-request"
|
"request": "browser-request"
|
||||||
|
@ -85,11 +97,10 @@
|
||||||
"buffer-compare": "=1.0.0",
|
"buffer-compare": "=1.0.0",
|
||||||
"elliptic": "=3.0.3",
|
"elliptic": "=3.0.3",
|
||||||
"inherits": "=2.0.1",
|
"inherits": "=2.0.1",
|
||||||
"lodash": "=3.10.1",
|
"lodash": "=3.10.1"
|
||||||
"sha512": "=0.0.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"bitcore-build": "bitpay/bitcore-build",
|
"bitcore-build-zcash": "zcash-hackworks/bitcore-build-zcash",
|
||||||
"brfs": "^1.2.0",
|
"brfs": "^1.2.0",
|
||||||
"chai": "^1.10.0",
|
"chai": "^1.10.0",
|
||||||
"gulp": "^3.8.10",
|
"gulp": "^3.8.10",
|
||||||
|
|
|
@ -211,6 +211,15 @@ describe('ECDSA', function() {
|
||||||
called.should.equal(1);
|
called.should.equal(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should generate right K', function() {
|
||||||
|
var msg1 = new Buffer('52204d20fd0131ae1afd173fd80a3a746d2dcc0cddced8c9dc3d61cc7ab6e966', 'hex');
|
||||||
|
var msg2 = [].reverse.call(new Buffer(msg1))
|
||||||
|
var pk = new Buffer('16f243e962c59e71e54189e67e66cf2440a1334514c09c00ddcc21632bac9808', 'hex');
|
||||||
|
var signature1 = ECDSA.sign(msg1, Privkey.fromBuffer(pk)).toBuffer().toString('hex');
|
||||||
|
var signature2 = ECDSA.sign(msg2, Privkey.fromBuffer(pk), 'little').toBuffer().toString('hex');
|
||||||
|
signature1.should.equal(signature2);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#toString', function() {
|
describe('#toString', function() {
|
||||||
|
|
|
@ -278,18 +278,30 @@ describe('Signature', function() {
|
||||||
describe('#hasLowS', function() {
|
describe('#hasLowS', function() {
|
||||||
it('should detect high and low S', function() {
|
it('should detect high and low S', function() {
|
||||||
var r = new BN('63173831029936981022572627018246571655303050627048489594159321588908385378810');
|
var r = new BN('63173831029936981022572627018246571655303050627048489594159321588908385378810');
|
||||||
var s = new BN('4331694221846364448463828256391194279133231453999942381442030409253074198130');
|
|
||||||
var s2 = new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B2000');
|
|
||||||
var sig = new Signature({
|
var sig = new Signature({
|
||||||
r: r,
|
r: r,
|
||||||
s: s
|
s: new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A1', 'hex')
|
||||||
});
|
});
|
||||||
|
sig.hasLowS().should.equal(false);
|
||||||
|
|
||||||
var sig2 = new Signature({
|
var sig2 = new Signature({
|
||||||
r: r,
|
r: r,
|
||||||
s: s2
|
s: new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex')
|
||||||
});
|
});
|
||||||
sig2.hasLowS().should.equal(true);
|
sig2.hasLowS().should.equal(true);
|
||||||
sig.hasLowS().should.equal(false);
|
|
||||||
|
var sig3 = new Signature({
|
||||||
|
r: r,
|
||||||
|
s: new BN(1)
|
||||||
|
});
|
||||||
|
sig3.hasLowS().should.equal(true);
|
||||||
|
|
||||||
|
var sig4 = new Signature({
|
||||||
|
r: r,
|
||||||
|
s: new BN(0)
|
||||||
|
});
|
||||||
|
sig4.hasLowS().should.equal(false);
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
}],
|
}],
|
||||||
"to", ["mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc", 1010000],
|
"to", ["mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc", 1010000],
|
||||||
"sign", ["cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY"],
|
"sign", ["cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY"],
|
||||||
"serialize", "01000000015884e5db9de218238671572340b207ee85b628074e7e467096c267266baf77a4000000006a473044022013fa3089327b50263029265572ae1b022a91d10ac80eb4f32f291c914533670b02200d8a5ed5f62634a7e1a0dc9188a3cc460a986267ae4d58faf50c79105431327501210223078d2942df62c45621d209fab84ea9a7a23346201b7727b9b45a29c4e76f5effffffff0150690f00000000001976a9147821c0a3768aa9d1a37e16cf76002aef5373f1a888ac00000000"
|
"serialize", "01000000015884e5db9de218238671572340b207ee85b628074e7e467096c267266baf77a4000000006b4830450221009972100061da4a17a471ac1906c18bb5445c03da2a0be52c59aca6c58f1e342302202b7a19a22572cabb6e55c368ebdb5921541358fa969d5c76b5e0d6ad3f26a7d701210223078d2942df62c45621d209fab84ea9a7a23346201b7727b9b45a29c4e76f5effffffff0150690f00000000001976a9147821c0a3768aa9d1a37e16cf76002aef5373f1a888ac00000000"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"from", [{
|
"from", [{
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
"to", ["mn9new5vPYWuVN5m3gUBujfKh1uPQvR9mf", 500000],
|
"to", ["mn9new5vPYWuVN5m3gUBujfKh1uPQvR9mf", 500000],
|
||||||
"to", ["mw5ctwgEaNRbxkM4JhXH3rp5AyGvTWDZCD", 570000],
|
"to", ["mw5ctwgEaNRbxkM4JhXH3rp5AyGvTWDZCD", 570000],
|
||||||
"sign", ["cSQUuwwJBAg6tYQhzqqLWW115D1s5KFZDyhCF2ffrnukZxMK6rNZ"],
|
"sign", ["cSQUuwwJBAg6tYQhzqqLWW115D1s5KFZDyhCF2ffrnukZxMK6rNZ"],
|
||||||
"serialize", "0100000001863957ca797bf847eae50f6999e4c3616dc64b1e6661b16d9da2b57d184724e4010000006b4830450221009d23f7c1e790ecf839e0e53248dacfa559194735e477aa3ee5897fd74fe3ec0402205eff578518e7c59beeb03ee85e5c4b5bc2730addca2f0321d80aadfbcc1976de0121039dd446bbc85db6917f39c0b4c295b0f8cce76d1926fa76d7b84e3f7ff1c5eec5ffffffff0220a10700000000001976a91448c819246ae5645ceecd41fbe1aa6202a0a9b5ca88ac90b20800000000001976a914aab76ba4877d696590d94ea3e02948b55294815188ac00000000"
|
"serialize", "0100000001863957ca797bf847eae50f6999e4c3616dc64b1e6661b16d9da2b57d184724e4010000006b483045022100855691c90510edf83ab632f0a0b17f5202d2cf7071050dcf0c2778325ed403cd022014ee7a4e787da8bc088d2ece43108a7b8d7112eba89876a27bb44195a0715a910121039dd446bbc85db6917f39c0b4c295b0f8cce76d1926fa76d7b84e3f7ff1c5eec5ffffffff0220a10700000000001976a91448c819246ae5645ceecd41fbe1aa6202a0a9b5ca88ac90b20800000000001976a914aab76ba4877d696590d94ea3e02948b55294815188ac00000000"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"from", [
|
"from", [
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
"sign", [
|
"sign", [
|
||||||
["cPGbA2C54ZZ1sw4dc2ckBE1WqkdrNSbEV8Tkjhi2p1J15oErdgP2", "cSpyve5bXAuyHrNeV9MjTdFz3HLw739yUjjUAUSMe3ppf2qzj2hw"]
|
["cPGbA2C54ZZ1sw4dc2ckBE1WqkdrNSbEV8Tkjhi2p1J15oErdgP2", "cSpyve5bXAuyHrNeV9MjTdFz3HLw739yUjjUAUSMe3ppf2qzj2hw"]
|
||||||
],
|
],
|
||||||
"serialize", "0100000002b3028cf4ae5b4b6d8f79ab6fc0dd251b28ab28287d33861e35c90f6e5684dba9000000006a47304402205d591b93871b63205ea80f6976b4d76ce23ca95c825d0c74b44e9816c9488ae8022012476dd8a2780028ed3e72ac1f2620580e82a25c22d1c31afca6fb14b125a35c0121030253c73236acf5ea9085d408220141197f6094de07426bd0d32c7a543614fdd7ffffffffb3028cf4ae5b4b6d8f79ab6fc0dd251b28ab28287d33861e35c90f6e5684dba9010000006a4730440220320367535c9bc525c581939b36ebe70dd0845851e68fa9e3cf2d90642bf551b3022055d6fcaef32d9b584eea757fa633c31449f43272d131588ddd87a22d16dd7129012102977a001a0a7bbfd1f8a647c7d46e13e8f6920635b328390b43b3303977101149ffffffff01a02c1000000000001976a91493abf1e9e4a20c125b93f93ee39efc16b6e4bc4688ac00000000"
|
"serialize", "0100000002b3028cf4ae5b4b6d8f79ab6fc0dd251b28ab28287d33861e35c90f6e5684dba9000000006a4730440220635e95e1981bbb360feaf4c232f626a0af8eb5c043a99749a21b0e37fd0048fd02201c5db8a93f1f5c268be6167da7c92f5030481acf65bef750c81ec9907aba3b170121030253c73236acf5ea9085d408220141197f6094de07426bd0d32c7a543614fdd7ffffffffb3028cf4ae5b4b6d8f79ab6fc0dd251b28ab28287d33861e35c90f6e5684dba9010000006a4730440220319a0b5ee9c67ccb7de4222234f31059354be4f239c99ca24bff30adfec8e8ec02204ad4c6dedebb20d100f9484b9ea6c5ba36712e9da155c24509e793c02e4805fd012102977a001a0a7bbfd1f8a647c7d46e13e8f6920635b328390b43b3303977101149ffffffff01a02c1000000000001976a91493abf1e9e4a20c125b93f93ee39efc16b6e4bc4688ac00000000"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"from", [{
|
"from", [{
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
}],
|
}],
|
||||||
"to", ["n3riXZowrjGnY74rx7Hdi9wCyvgyJC28zZ", 990000],
|
"to", ["n3riXZowrjGnY74rx7Hdi9wCyvgyJC28zZ", 990000],
|
||||||
"sign", ["cPwWtDztEgRCMCU8pMQp4HgphvyadrAsYBrCjXUZuDSmnZkyoyNF"],
|
"sign", ["cPwWtDztEgRCMCU8pMQp4HgphvyadrAsYBrCjXUZuDSmnZkyoyNF"],
|
||||||
"serialize", "0100000001dc8b68f2b4263d77ee30468da161242be499283a21dfd7eb38a4a9cdce130ef5010000006a4730440220337e09c2729423302abe5e386d5e0f060ae8c006693f87342322bb1fe50065ff0220217a12de44139c57f01d35e988ffe3b0f86005d0cefcecf877b54c67473211d2012103e26b47e7c0d8946954bf9dd4bc7f9e415437eb98271d05f69e78cef8fc6c9a54ffffffff01301b0f00000000001976a914f50f9826ef186074c6fe206cca6b71472ff07ba888ac00000000"
|
"serialize", "0100000001dc8b68f2b4263d77ee30468da161242be499283a21dfd7eb38a4a9cdce130ef5010000006a473044022012610834051e6af8594dd5d9c47123d6ce03537d321f9fe3f6ff244b23f47dd5022034901bb0d83688758a9248fdef48bd2000b55cf70111cbef8f206e72a31aaf61012103e26b47e7c0d8946954bf9dd4bc7f9e415437eb98271d05f69e78cef8fc6c9a54ffffffff01301b0f00000000001976a914f50f9826ef186074c6fe206cca6b71472ff07ba888ac00000000"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"from", [{
|
"from", [{
|
||||||
|
@ -68,7 +68,7 @@
|
||||||
}, ["03411e021210a933c247ea9c8dad4bbead281597d508ad84e899de13e4ce98b4ba", "03bda2c3cc11a391b36e3d695b03ab42b96fe04086b2349056108d858983e60dab", "03c16e6ecf4e02bf9db23d3247ab92db8881f0866133ffb530c3470f6d8dea7330"], 2],
|
}, ["03411e021210a933c247ea9c8dad4bbead281597d508ad84e899de13e4ce98b4ba", "03bda2c3cc11a391b36e3d695b03ab42b96fe04086b2349056108d858983e60dab", "03c16e6ecf4e02bf9db23d3247ab92db8881f0866133ffb530c3470f6d8dea7330"], 2],
|
||||||
"to", ["3BazTqvkvEBcWk7J4sbgRnxUw6rjYrogf9", 300299],
|
"to", ["3BazTqvkvEBcWk7J4sbgRnxUw6rjYrogf9", 300299],
|
||||||
"sign", [["L3y1PAXfjayeB3w6NP7qfNxPbuPpQFA6hd6gj4BUKa2xSdLwoVSZ", "L3a57fiNjqfbXBdYvvGYPQ1HiDX463mwA2xFGTYVkXYdooaz9Z2u"]],
|
"sign", [["L3y1PAXfjayeB3w6NP7qfNxPbuPpQFA6hd6gj4BUKa2xSdLwoVSZ", "L3a57fiNjqfbXBdYvvGYPQ1HiDX463mwA2xFGTYVkXYdooaz9Z2u"]],
|
||||||
"serialize", "010000000166fa5be19ea8965b3a9d841500277b82d94729e9a20ef3aa79e894ccb281320700000000fdfd0000483045022100a8090c2dba42c087f925163d365e19c730f28b4eb8435d611cd2232e0763b95d02203ae76cccaf27af17287bc765dd5e87ccb782aff0ec6afc27161205c09d6db6040147304402201d90977bc2e8cd2d050565eb1fb2daa05ee2f4279ea264514ed3f6241f74b6c102201ee7eb75c47f0fe138b61f21e9645ed0e0fa117c263cac0a6df395922eff166f014c69522103411e021210a933c247ea9c8dad4bbead281597d508ad84e899de13e4ce98b4ba2103bda2c3cc11a391b36e3d695b03ab42b96fe04086b2349056108d858983e60dab2103c16e6ecf4e02bf9db23d3247ab92db8881f0866133ffb530c3470f6d8dea733053aeffffffff010b9504000000000017a9146c8d8b04c6a1e664b1ec20ec932760760c97688e8700000000"
|
"serialize", "010000000166fa5be19ea8965b3a9d841500277b82d94729e9a20ef3aa79e894ccb281320700000000fc0047304402202f66fcfc0d5bff109ec12327ca37e0bc7722d08da9538f12468994799534bed602203a0b374f3a6810b0ee26028c390e14f5b6bada8fa390f4364d70d04aee240d350147304402206757f710f25937cd846fd8c56687c463a4561e9e0421fc173c78eaf2de9b9a7d02204995db6b81513b67a42b09dabab6ed4cb90901c52f6f945b768827a9390bda60014c69522103411e021210a933c247ea9c8dad4bbead281597d508ad84e899de13e4ce98b4ba2103bda2c3cc11a391b36e3d695b03ab42b96fe04086b2349056108d858983e60dab2103c16e6ecf4e02bf9db23d3247ab92db8881f0866133ffb530c3470f6d8dea733053aeffffffff010b9504000000000017a9146c8d8b04c6a1e664b1ec20ec932760760c97688e8700000000"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"from", [{"address":"3BazTqvkvEBcWk7J4sbgRnxUw6rjYrogf9","txid":"afbf98ca4a43db8915d75184b5204fbe71d916482adfe85cb0ed3635764fc220","vout":0,"ts":1418878108,"scriptPubKey":"a9146c8d8b04c6a1e664b1ec20ec932760760c97688e87","amount":0.00318512,"confirmationsFromCache":false}, ["020483ebb834d91d494a3b649cf0e8f5c9c4fcec5f194ab94341cc99bb440007f2", "0271ebaeef1c2bf0c1a4772d1391eab03e4d96a6e9b48551ab4e4b0d2983eb452b", "03a659828aabe443e2dedabb1db5a22335c5ace5b5b7126998a288d63c99516dd8"], 2
|
"from", [{"address":"3BazTqvkvEBcWk7J4sbgRnxUw6rjYrogf9","txid":"afbf98ca4a43db8915d75184b5204fbe71d916482adfe85cb0ed3635764fc220","vout":0,"ts":1418878108,"scriptPubKey":"a9146c8d8b04c6a1e664b1ec20ec932760760c97688e87","amount":0.00318512,"confirmationsFromCache":false}, ["020483ebb834d91d494a3b649cf0e8f5c9c4fcec5f194ab94341cc99bb440007f2", "0271ebaeef1c2bf0c1a4772d1391eab03e4d96a6e9b48551ab4e4b0d2983eb452b", "03a659828aabe443e2dedabb1db5a22335c5ace5b5b7126998a288d63c99516dd8"], 2
|
||||||
|
@ -80,6 +80,6 @@
|
||||||
"change", ["3BazTqvkvEBcWk7J4sbgRnxUw6rjYrogf9"],
|
"change", ["3BazTqvkvEBcWk7J4sbgRnxUw6rjYrogf9"],
|
||||||
"sign", ["L2U9m5My3cdyN5qX1PH4B7XstGDZFWwyukdX8gj8vsJ3fkrqArQo"],
|
"sign", ["L2U9m5My3cdyN5qX1PH4B7XstGDZFWwyukdX8gj8vsJ3fkrqArQo"],
|
||||||
"sign", ["L4jFVcDaqZCkknP5KQWjCBgiLFxKxRxywNGTucm3jC3ozByZcbZv"],
|
"sign", ["L4jFVcDaqZCkknP5KQWjCBgiLFxKxRxywNGTucm3jC3ozByZcbZv"],
|
||||||
"serialize", "010000000220c24f763536edb05ce8df2a4816d971be4f20b58451d71589db434aca98bfaf00000000fdfd000047304402202c34fd898bbea3521c5f88fdeef4bb65f36ce01142633c1121e9b7bef307938902205e1aad62a66bd294898dc71678a4a5448281126baad90bfd9b4139663e852d26014830450221009d9f2b46595dc2578f4c4ac65c779e45e493bcc4649ef6786477e40df40d21fc02206da8a0f80fa2aa2d2b89d56951761c8f0506fdafd53ef6fe7d5c878251bb216b014c695221020483ebb834d91d494a3b649cf0e8f5c9c4fcec5f194ab94341cc99bb440007f2210271ebaeef1c2bf0c1a4772d1391eab03e4d96a6e9b48551ab4e4b0d2983eb452b2103a659828aabe443e2dedabb1db5a22335c5ace5b5b7126998a288d63c99516dd853aeffffffffa0644cd1606e081c59eb65fe69d4a83a3a822da423bc392c91712fb77a192edc00000000fdfd000047304402202e64f052cd5be367f2f9efb31d3a34d0f8339700beff426d31b53c9a776a0368022057c714fda22a5ec301765dd187be3c522bcfe040127e857067163a5fb9ed46c001483045022100bf7a1e5a9e7204361e70312e15746efc95c7be8957a66c76574d2a07db359c550220318dc70b703c84a76fe3a460e96d466462f4c1c54b9fbfb75157b1afe2c51f8e014c695221020483ebb834d91d494a3b649cf0e8f5c9c4fcec5f194ab94341cc99bb440007f2210271ebaeef1c2bf0c1a4772d1391eab03e4d96a6e9b48551ab4e4b0d2983eb452b2103a659828aabe443e2dedabb1db5a22335c5ace5b5b7126998a288d63c99516dd853aeffffffff03f04902000000000017a9144de752833233fe69a20064f29b2ca0f6399c8af387007102000000000017a9144de752833233fe69a20064f29b2ca0f6399c8af3873b8f04000000000017a9146c8d8b04c6a1e664b1ec20ec932760760c97688e8700000000"
|
"serialize", "010000000220c24f763536edb05ce8df2a4816d971be4f20b58451d71589db434aca98bfaf00000000fc00473044022077fca9eb2544894068c47028855b0cf147526e9a54d993b7aa028908526944ea02203223ca379fa06b5544c02ed74b3ebb9734e2a9e09bca9b572aa56443a3be4d8d0147304402205caaf5666489ab005f280d30afbcda4d8f6f7195b0a13de89bc1e80f58219f5e02205414938c9d0496f5b45c1f45c028c019b3a956549938c09d983a3cc03e819f05014c695221020483ebb834d91d494a3b649cf0e8f5c9c4fcec5f194ab94341cc99bb440007f2210271ebaeef1c2bf0c1a4772d1391eab03e4d96a6e9b48551ab4e4b0d2983eb452b2103a659828aabe443e2dedabb1db5a22335c5ace5b5b7126998a288d63c99516dd853aeffffffffa0644cd1606e081c59eb65fe69d4a83a3a822da423bc392c91712fb77a192edc00000000fdfd0000483045022100c4c98f6cc0a313aee264ab8171927de590ab495b78f26159e56ba49fc26b1e3802206a12c4d41863756e35f72bd365d862da907272bcb2a949d1d2f64c1867d88ce90147304402207035e6083876dcd5512b40bb3d81e2b38393a62f962f8b701efc066db446ae500220121d38105bb58d8b8ad78bbef212c1f958124d47186bcc1ddcccfc0480eb7eb8014c695221020483ebb834d91d494a3b649cf0e8f5c9c4fcec5f194ab94341cc99bb440007f2210271ebaeef1c2bf0c1a4772d1391eab03e4d96a6e9b48551ab4e4b0d2983eb452b2103a659828aabe443e2dedabb1db5a22335c5ace5b5b7126998a288d63c99516dd853aeffffffff03f04902000000000017a9144de752833233fe69a20064f29b2ca0f6399c8af387007102000000000017a9144de752833233fe69a20064f29b2ca0f6399c8af3873b8f04000000000017a9146c8d8b04c6a1e664b1ec20ec932760760c97688e8700000000"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
<title>Mocha</title>
|
<title>Mocha</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="stylesheet" href="../node_modules/bitcore-build/node_modules/mocha/mocha.css" />
|
<link rel="stylesheet" href="../node_modules/bitcore-build-zcash/node_modules/mocha/mocha.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="mocha"></div>
|
<div id="mocha"></div>
|
||||||
<script src="../node_modules/bitcore-build/node_modules/mocha/mocha.js"></script>
|
<script src="../node_modules/bitcore-build-zcash/node_modules/mocha/mocha.js"></script>
|
||||||
<script>mocha.setup('bdd')</script>
|
<script>mocha.setup('bdd')</script>
|
||||||
<script src="../tests.js"></script>
|
<script src="../tests.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -15,6 +15,29 @@ describe('Networks', function() {
|
||||||
should.exist(networks.defaultNetwork);
|
should.exist(networks.defaultNetwork);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('will enable/disable regtest Network', function() {
|
||||||
|
networks.enableRegtest();
|
||||||
|
networks.testnet.networkMagic.should.deep.equal(new Buffer('fabfb5da', 'hex'));
|
||||||
|
networks.testnet.port.should.equal(18444);
|
||||||
|
networks.testnet.dnsSeeds.should.deep.equal([]);
|
||||||
|
networks.testnet.regtestEnabled.should.equal(true);
|
||||||
|
|
||||||
|
networks.disableRegtest();
|
||||||
|
networks.testnet.networkMagic.should.deep.equal(new Buffer('0b110907', 'hex'));
|
||||||
|
networks.testnet.port.should.equal(18333);
|
||||||
|
networks.testnet.dnsSeeds.should.deep.equal([
|
||||||
|
'testnet-seed.bitcoin.petertodd.org',
|
||||||
|
'testnet-seed.bluematt.me',
|
||||||
|
'testnet-seed.alexykot.me',
|
||||||
|
'testnet-seed.bitcoin.schildbach.de'
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('will get network based on string "regtest" value', function() {
|
||||||
|
var network = networks.get('regtest');
|
||||||
|
network.should.equal(networks.testnet);
|
||||||
|
});
|
||||||
|
|
||||||
it('should be able to define a custom Network', function() {
|
it('should be able to define a custom Network', function() {
|
||||||
var custom = {
|
var custom = {
|
||||||
name: 'customnet',
|
name: 'customnet',
|
||||||
|
|
|
@ -120,10 +120,23 @@ describe('Opcode', function() {
|
||||||
var testSmallInt = function(n, op) {
|
var testSmallInt = function(n, op) {
|
||||||
Opcode.smallInt(n).toString().should.equal(op.toString());
|
Opcode.smallInt(n).toString().should.equal(op.toString());
|
||||||
};
|
};
|
||||||
|
|
||||||
for (var i = 0; i < smallints.length; i++) {
|
for (var i = 0; i < smallints.length; i++) {
|
||||||
var op = smallints[i];
|
var op = smallints[i];
|
||||||
it('should work for small int ' + op, testSmallInt.bind(null, i, op));
|
it('should work for small int ' + op, testSmallInt.bind(null, i, op));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it('with not number', function () {
|
||||||
|
Opcode.smallInt.bind(null, '2').should.throw('Invalid Argument');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with n equal -1', function () {
|
||||||
|
Opcode.smallInt.bind(null, -1).should.throw('Invalid Argument');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with n equal 17', function () {
|
||||||
|
Opcode.smallInt.bind(null, 17).should.throw('Invalid Argument');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe('@isSmallIntOp', function() {
|
describe('@isSmallIntOp', function() {
|
||||||
var testIsSmallInt = function(op) {
|
var testIsSmallInt = function(op) {
|
||||||
|
|
|
@ -413,6 +413,78 @@ describe('Script', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#classifyInput', function() {
|
||||||
|
it('shouldn\'t classify public key hash out', function() {
|
||||||
|
Script('OP_DUP OP_HASH160 20 0x0000000000000000000000000000000000000000 OP_EQUALVERIFY OP_CHECKSIG').classifyInput().should.equal(Script.types.UNKNOWN);
|
||||||
|
});
|
||||||
|
it('should classify public key hash in', function() {
|
||||||
|
Script('47 0x3044022077a8d81e656c4a1c1721e68ce35fa0b27f13c342998e75854858c12396a15ffa02206378a8c6959283c008c87a14a9c0ada5cf3934ac5ee29f1fef9cac6969783e9801 21 0x03993c230da7dabb956292851ae755f971c50532efc095a16bee07f83ab9d262df').classifyInput().should.equal(Script.types.PUBKEYHASH_IN);
|
||||||
|
});
|
||||||
|
it('shouldn\'t classify script hash out', function() {
|
||||||
|
Script('OP_HASH160 20 0x0000000000000000000000000000000000000000 OP_EQUAL').classifyInput().should.equal(Script.types.UNKNOWN);
|
||||||
|
});
|
||||||
|
it('should classify script hash in', function() {
|
||||||
|
Script('OP_0 73 0x30460221008ca148504190c10eea7f5f9c283c719a37be58c3ad617928011a1bb9570901d2022100ced371a23e86af6f55ff4ce705c57d2721a09c4d192ca39d82c4239825f75a9801 72 0x30450220357011fd3b3ad2b8f2f2d01e05dc6108b51d2a245b4ef40c112d6004596f0475022100a8208c93a39e0c366b983f9a80bfaf89237fcd64ca543568badd2d18ee2e1d7501 OP_PUSHDATA1 105 0x5221024c02dff2f0b8263a562a69ec875b2c95ffad860f428acf2f9e8c6492bd067d362103546324a1351a6b601c623b463e33b6103ca444707d5b278ece1692f1aa7724a42103b1ad3b328429450069cc3f9fa80d537ee66ba1120e93f3f185a5bf686fb51e0a53ae').classifyInput().should.equal(Script.types.SCRIPTHASH_IN);
|
||||||
|
});
|
||||||
|
it('shouldn\'t classify MULTISIG out', function() {
|
||||||
|
Script('OP_2 21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 OP_2 OP_CHECKMULTISIG').classifyInput().should.equal(Script.types.UNKNOWN);
|
||||||
|
});
|
||||||
|
it('should classify MULTISIG in', function() {
|
||||||
|
Script('OP_0 0x47 0x3044022002a27769ee33db258bdf7a3792e7da4143ec4001b551f73e6a190b8d1bde449d02206742c56ccd94a7a2e16ca52fc1ae4a0aa122b0014a867a80de104f9cb18e472c01').classifyInput().should.equal(Script.types.MULTISIG_IN);
|
||||||
|
});
|
||||||
|
it('shouldn\'t classify OP_RETURN data out', function() {
|
||||||
|
Script('OP_RETURN 1 0x01').classifyInput().should.equal(Script.types.UNKNOWN);
|
||||||
|
});
|
||||||
|
it('shouldn\'t classify public key out', function() {
|
||||||
|
Script('41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 OP_CHECKSIG').classifyInput().should.equal(Script.types.UNKNOWN);
|
||||||
|
});
|
||||||
|
it('should classify public key in', function() {
|
||||||
|
Script('47 0x3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501').classifyInput().should.equal(Script.types.PUBKEY_IN);
|
||||||
|
});
|
||||||
|
it('should classify unknown', function() {
|
||||||
|
Script('OP_TRUE OP_FALSE').classifyInput().should.equal(Script.types.UNKNOWN);
|
||||||
|
});
|
||||||
|
it('should classify scriptHashIn, eventhough it\'s opreturn', function() {
|
||||||
|
Script('6a1c3630fd3792f7e847ae5e27985dfb127542ef37ac2a5147c3b9cec7ba').classifyInput().should.equal(Script.types.SCRIPTHASH_IN);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#classifyOutput', function() {
|
||||||
|
it('should classify public key hash out', function() {
|
||||||
|
Script('OP_DUP OP_HASH160 20 0x0000000000000000000000000000000000000000 OP_EQUALVERIFY OP_CHECKSIG').classifyOutput().should.equal(Script.types.PUBKEYHASH_OUT);
|
||||||
|
});
|
||||||
|
it('shouldn\'t classify public key hash in', function() {
|
||||||
|
Script('47 0x3044022077a8d81e656c4a1c1721e68ce35fa0b27f13c342998e75854858c12396a15ffa02206378a8c6959283c008c87a14a9c0ada5cf3934ac5ee29f1fef9cac6969783e9801 21 0x03993c230da7dabb956292851ae755f971c50532efc095a16bee07f83ab9d262df').classifyOutput().should.equal(Script.types.UNKNOWN);
|
||||||
|
});
|
||||||
|
it('should classify script hash out', function() {
|
||||||
|
Script('OP_HASH160 20 0x0000000000000000000000000000000000000000 OP_EQUAL').classifyOutput().should.equal(Script.types.SCRIPTHASH_OUT);
|
||||||
|
});
|
||||||
|
it('shouldn\'t classify script hash in', function() {
|
||||||
|
Script('OP_0 73 0x30460221008ca148504190c10eea7f5f9c283c719a37be58c3ad617928011a1bb9570901d2022100ced371a23e86af6f55ff4ce705c57d2721a09c4d192ca39d82c4239825f75a9801 72 0x30450220357011fd3b3ad2b8f2f2d01e05dc6108b51d2a245b4ef40c112d6004596f0475022100a8208c93a39e0c366b983f9a80bfaf89237fcd64ca543568badd2d18ee2e1d7501 OP_PUSHDATA1 105 0x5221024c02dff2f0b8263a562a69ec875b2c95ffad860f428acf2f9e8c6492bd067d362103546324a1351a6b601c623b463e33b6103ca444707d5b278ece1692f1aa7724a42103b1ad3b328429450069cc3f9fa80d537ee66ba1120e93f3f185a5bf686fb51e0a53ae').classifyOutput().should.equal(Script.types.UNKNOWN);
|
||||||
|
});
|
||||||
|
it('should classify MULTISIG out', function() {
|
||||||
|
Script('OP_2 21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 OP_2 OP_CHECKMULTISIG').classifyOutput().should.equal(Script.types.MULTISIG_OUT);
|
||||||
|
});
|
||||||
|
it('shouldn\'t classify MULTISIG in', function() {
|
||||||
|
Script('OP_0 0x47 0x3044022002a27769ee33db258bdf7a3792e7da4143ec4001b551f73e6a190b8d1bde449d02206742c56ccd94a7a2e16ca52fc1ae4a0aa122b0014a867a80de104f9cb18e472c01').classifyOutput().should.equal(Script.types.UNKNOWN);
|
||||||
|
});
|
||||||
|
it('should classify OP_RETURN data out', function() {
|
||||||
|
Script('OP_RETURN 1 0x01').classifyOutput().should.equal(Script.types.DATA_OUT);
|
||||||
|
});
|
||||||
|
it('should classify public key out', function() {
|
||||||
|
Script('41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 OP_CHECKSIG').classifyOutput().should.equal(Script.types.PUBKEY_OUT);
|
||||||
|
});
|
||||||
|
it('shouldn\'t classify public key in', function() {
|
||||||
|
Script('47 0x3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501').classifyOutput().should.equal(Script.types.UNKNOWN);
|
||||||
|
});
|
||||||
|
it('should classify unknown', function() {
|
||||||
|
Script('OP_TRUE OP_FALSE').classifyOutput().should.equal(Script.types.UNKNOWN);
|
||||||
|
});
|
||||||
|
it('should classify opreturn eventhough it also looks like a scriptHashIn', function() {
|
||||||
|
Script('6a1c3630fd3792f7e847ae5e27985dfb127542ef37ac2a5147c3b9cec7ba').classifyOutput().should.equal(Script.types.DATA_OUT);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('#classify', function() {
|
describe('#classify', function() {
|
||||||
it('should classify public key hash out', function() {
|
it('should classify public key hash out', function() {
|
||||||
Script('OP_DUP OP_HASH160 20 0x0000000000000000000000000000000000000000 OP_EQUALVERIFY OP_CHECKSIG').classify().should.equal(Script.types.PUBKEYHASH_OUT);
|
Script('OP_DUP OP_HASH160 20 0x0000000000000000000000000000000000000000 OP_EQUALVERIFY OP_CHECKSIG').classify().should.equal(Script.types.PUBKEYHASH_OUT);
|
||||||
|
@ -444,6 +516,28 @@ describe('Script', function() {
|
||||||
it('should classify unknown', function() {
|
it('should classify unknown', function() {
|
||||||
Script('OP_TRUE OP_FALSE').classify().should.equal(Script.types.UNKNOWN);
|
Script('OP_TRUE OP_FALSE').classify().should.equal(Script.types.UNKNOWN);
|
||||||
});
|
});
|
||||||
|
it('should classify opreturn eventhough it also looks like a scriptHashIn', function() {
|
||||||
|
Script('6a1c3630fd3792f7e847ae5e27985dfb127542ef37ac2a5147c3b9cec7ba').classifyInput().should.equal(Script.types.SCRIPTHASH_IN);
|
||||||
|
Script('6a1c3630fd3792f7e847ae5e27985dfb127542ef37ac2a5147c3b9cec7ba').classify().should.equal(Script.types.DATA_OUT);
|
||||||
|
});
|
||||||
|
it('should classify scriptHashIn eventhough it is opreturn when script is marked is input', function() {
|
||||||
|
Script('6a1c3630fd3792f7e847ae5e27985dfb127542ef37ac2a5147c3b9cec7ba').classify().should.equal(Script.types.DATA_OUT);
|
||||||
|
var s = Script('6a1c3630fd3792f7e847ae5e27985dfb127542ef37ac2a5147c3b9cec7ba');
|
||||||
|
s._isInput = true; // this is normally set by when Script is initiated as part if Input or Output objects
|
||||||
|
s.classify().should.equal(Script.types.SCRIPTHASH_IN);
|
||||||
|
});
|
||||||
|
it('should classify unknown eventhough it is public key hash when marked as input', function() {
|
||||||
|
Script('OP_DUP OP_HASH160 20 0x0000000000000000000000000000000000000000 OP_EQUALVERIFY OP_CHECKSIG').classify().should.equal(Script.types.PUBKEYHASH_OUT);
|
||||||
|
var s = Script('OP_DUP OP_HASH160 20 0x0000000000000000000000000000000000000000 OP_EQUALVERIFY OP_CHECKSIG');
|
||||||
|
s._isInput = true; // this is normally set by when Script is initiated as part if Input or Output objects
|
||||||
|
s.classify().should.equal(Script.types.UNKNOWN);
|
||||||
|
});
|
||||||
|
it('should classify unknown eventhough it is public key hash in when marked as output', function() {
|
||||||
|
var s = Script('47 0x3044022077a8d81e656c4a1c1721e68ce35fa0b27f13c342998e75854858c12396a15ffa02206378a8c6959283c008c87a14a9c0ada5cf3934ac5ee29f1fef9cac6969783e9801 21 0x03993c230da7dabb956292851ae755f971c50532efc095a16bee07f83ab9d262df');
|
||||||
|
s.classify().should.equal(Script.types.PUBKEYHASH_IN);
|
||||||
|
s._isOutput = true; // this is normally set by when Script is initiated as part if Input or Output objects
|
||||||
|
s.classify().should.equal(Script.types.UNKNOWN);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#add and #prepend', function() {
|
describe('#add and #prepend', function() {
|
||||||
|
|
|
@ -108,6 +108,40 @@ describe('Transaction', function() {
|
||||||
txData.should.equal(tx2Data);
|
txData.should.equal(tx2Data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('fromObject with pay-to-public-key previous outputs', function() {
|
||||||
|
var tx = bitcore.Transaction({
|
||||||
|
hash: '132856bf03d6415562a556437d22ac63c37a4595fd986c796eb8e02dc031aa25',
|
||||||
|
version: 1,
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
prevTxId: 'e30ac3db24ef28500f023775d8eb06ad8a26241690080260308208a4020012a4',
|
||||||
|
outputIndex: 0,
|
||||||
|
sequenceNumber: 4294967294,
|
||||||
|
script: '473044022024dbcf41ccd4f3fe325bebb7a87d0bf359eefa03826482008e0fe7795586ad440220676f5f211ebbc311cfa631f14a8223a343cbadc6fa97d6d17f8d2531308b533201',
|
||||||
|
scriptString: '71 0x3044022024dbcf41ccd4f3fe325bebb7a87d0bf359eefa03826482008e0fe7795586ad440220676f5f211ebbc311cfa631f14a8223a343cbadc6fa97d6d17f8d2531308b533201',
|
||||||
|
output: {
|
||||||
|
satoshis: 5000000000,
|
||||||
|
script: '2103b1c65d65f1ff3fe145a4ede692460ae0606671d04e8449e99dd11c66ab55a7feac'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
outputs: [
|
||||||
|
{
|
||||||
|
satoshis: 3999999040,
|
||||||
|
script: '76a914fa1e0abfb8d26e494375f47e04b4883c44dd44d988ac'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
satoshis: 1000000000,
|
||||||
|
script: '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
nLockTime: 139
|
||||||
|
});
|
||||||
|
tx.inputs[0].should.be.instanceof(bitcore.Transaction.Input.PublicKey);
|
||||||
|
tx.inputs[0].output.satoshis.should.equal(5000000000);
|
||||||
|
tx.inputs[0].output.script.toHex().should.equal('2103b1c65d65f1ff3fe145a4ede692460ae0606671d04e8449e99dd11c66ab55a7feac');
|
||||||
|
});
|
||||||
|
|
||||||
it('constructor returns a shallow copy of another transaction', function() {
|
it('constructor returns a shallow copy of another transaction', function() {
|
||||||
var transaction = new Transaction(tx_1_hex);
|
var transaction = new Transaction(tx_1_hex);
|
||||||
var copy = new Transaction(transaction);
|
var copy = new Transaction(transaction);
|
||||||
|
@ -180,7 +214,7 @@ describe('Transaction', function() {
|
||||||
var simpleUtxoWith1BTC = {
|
var simpleUtxoWith1BTC = {
|
||||||
address: fromAddress,
|
address: fromAddress,
|
||||||
txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
|
txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
|
||||||
outputIndex: 0,
|
outputIndex: 1,
|
||||||
script: Script.buildPublicKeyHashOut(fromAddress).toString(),
|
script: Script.buildPublicKeyHashOut(fromAddress).toString(),
|
||||||
satoshis: 1e8
|
satoshis: 1e8
|
||||||
};
|
};
|
||||||
|
@ -1086,6 +1120,106 @@ describe('Transaction', function() {
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('Replace-by-fee', function() {
|
||||||
|
describe('#enableRBF', function() {
|
||||||
|
it('only enable inputs not already enabled (0xffffffff)', function() {
|
||||||
|
var tx = new Transaction()
|
||||||
|
.from(simpleUtxoWith1BTC)
|
||||||
|
.from(simpleUtxoWith100000Satoshis)
|
||||||
|
.to([{address: toAddress, satoshis: 50000}])
|
||||||
|
.fee(15000)
|
||||||
|
.change(changeAddress)
|
||||||
|
.sign(privateKey);
|
||||||
|
tx.inputs[0].sequenceNumber = 0x00000000;
|
||||||
|
tx.enableRBF();
|
||||||
|
tx.inputs[0].sequenceNumber.should.equal(0x00000000);
|
||||||
|
tx.inputs[1].sequenceNumber.should.equal(0xfffffffd);
|
||||||
|
});
|
||||||
|
it('enable for inputs with 0xffffffff and 0xfffffffe', function() {
|
||||||
|
var tx = new Transaction()
|
||||||
|
.from(simpleUtxoWith1BTC)
|
||||||
|
.from(simpleUtxoWith100000Satoshis)
|
||||||
|
.to([{address: toAddress, satoshis: 50000}])
|
||||||
|
.fee(15000)
|
||||||
|
.change(changeAddress)
|
||||||
|
.sign(privateKey);
|
||||||
|
tx.inputs[0].sequenceNumber = 0xffffffff;
|
||||||
|
tx.inputs[1].sequenceNumber = 0xfffffffe;
|
||||||
|
tx.enableRBF();
|
||||||
|
tx.inputs[0].sequenceNumber.should.equal(0xfffffffd);
|
||||||
|
tx.inputs[1].sequenceNumber.should.equal(0xfffffffd);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#isRBF', function() {
|
||||||
|
it('enable and determine opt-in', function() {
|
||||||
|
var tx = new Transaction()
|
||||||
|
.from(simpleUtxoWith100000Satoshis)
|
||||||
|
.to([{address: toAddress, satoshis: 50000}])
|
||||||
|
.fee(15000)
|
||||||
|
.change(changeAddress)
|
||||||
|
.enableRBF()
|
||||||
|
.sign(privateKey);
|
||||||
|
tx.isRBF().should.equal(true);
|
||||||
|
});
|
||||||
|
it('determine opt-out with default sequence number', function() {
|
||||||
|
var tx = new Transaction()
|
||||||
|
.from(simpleUtxoWith100000Satoshis)
|
||||||
|
.to([{address: toAddress, satoshis: 50000}])
|
||||||
|
.fee(15000)
|
||||||
|
.change(changeAddress)
|
||||||
|
.sign(privateKey);
|
||||||
|
tx.isRBF().should.equal(false);
|
||||||
|
});
|
||||||
|
it('determine opt-out with 0xfffffffe', function() {
|
||||||
|
var tx = new Transaction()
|
||||||
|
.from(simpleUtxoWith1BTC)
|
||||||
|
.from(simpleUtxoWith100000Satoshis)
|
||||||
|
.to([{address: toAddress, satoshis: 50000 + 1e8}])
|
||||||
|
.fee(15000)
|
||||||
|
.change(changeAddress)
|
||||||
|
.sign(privateKey);
|
||||||
|
tx.inputs[0].sequenceNumber = 0xfffffffe;
|
||||||
|
tx.inputs[1].sequenceNumber = 0xfffffffe;
|
||||||
|
tx.isRBF().should.equal(false);
|
||||||
|
});
|
||||||
|
it('determine opt-out with 0xffffffff', function() {
|
||||||
|
var tx = new Transaction()
|
||||||
|
.from(simpleUtxoWith1BTC)
|
||||||
|
.from(simpleUtxoWith100000Satoshis)
|
||||||
|
.to([{address: toAddress, satoshis: 50000 + 1e8}])
|
||||||
|
.fee(15000)
|
||||||
|
.change(changeAddress)
|
||||||
|
.sign(privateKey);
|
||||||
|
tx.inputs[0].sequenceNumber = 0xffffffff;
|
||||||
|
tx.inputs[1].sequenceNumber = 0xffffffff;
|
||||||
|
tx.isRBF().should.equal(false);
|
||||||
|
});
|
||||||
|
it('determine opt-in with 0xfffffffd (first input)', function() {
|
||||||
|
var tx = new Transaction()
|
||||||
|
.from(simpleUtxoWith1BTC)
|
||||||
|
.from(simpleUtxoWith100000Satoshis)
|
||||||
|
.to([{address: toAddress, satoshis: 50000 + 1e8}])
|
||||||
|
.fee(15000)
|
||||||
|
.change(changeAddress)
|
||||||
|
.sign(privateKey);
|
||||||
|
tx.inputs[0].sequenceNumber = 0xfffffffd;
|
||||||
|
tx.inputs[1].sequenceNumber = 0xffffffff;
|
||||||
|
tx.isRBF().should.equal(true);
|
||||||
|
});
|
||||||
|
it('determine opt-in with 0xfffffffd (second input)', function() {
|
||||||
|
var tx = new Transaction()
|
||||||
|
.from(simpleUtxoWith1BTC)
|
||||||
|
.from(simpleUtxoWith100000Satoshis)
|
||||||
|
.to([{address: toAddress, satoshis: 50000 + 1e8}])
|
||||||
|
.fee(15000)
|
||||||
|
.change(changeAddress)
|
||||||
|
.sign(privateKey);
|
||||||
|
tx.inputs[0].sequenceNumber = 0xffffffff;
|
||||||
|
tx.inputs[1].sequenceNumber = 0xfffffffd;
|
||||||
|
tx.isRBF().should.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue