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
|
||||||
|
|
||||||
|
|
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.10",
|
"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.10",
|
"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