Compare commits

...

52 Commits

Author SHA1 Message Date
Simon e97ae1dd2e Add fix for v4 joinsplits using Groth16 proof.
Closes https://github.com/zcash/zcash/issues/3636 where a tx with
multiple joinsplits would not be parsed correctly.
2018-10-28 14:48:10 -07:00
Simon c3bbbc3f08 Fix incorrect reporting of block difficulty.
The nBits value for mainnet genesis was being used instead of testnet.
2018-10-18 14:26:31 -07:00
Simon 4c6a7df8be Update package.json 2018-09-18 09:43:08 -07:00
Simon 02e607b770 Add Sapling transaction support. 2018-09-17 22:42:37 -07:00
Simon 76a1efebbf Update url to zcash-hackworks. 2018-05-09 14:26:05 -07:00
Simon 75c168836d Update contributors. 2018-05-07 23:31:33 -07:00
Simon 542b3f5893 Add support for Overwinter transactions. 2018-05-07 23:28:04 -07:00
Ian Munoz 97f7b5d3e3 added fOverwintered flag, nVersionGroupId and nExpiryHeight to transaction 2018-05-01 08:34:37 -06:00
str4d 208069bee8 Merge pull request #1 from runn1ng/patch-1
Correcting addresses for multibyte versions
2016-12-07 11:38:56 +13:00
Karel Bílek aeaa33f237 Correcting addresses for multibyte versions
Fixes https://github.com/str4d/insight-ui-zcash/issues/1
2016-11-02 19:03:23 +01:00
Jack Grigg b84f7ac683
Update network magics and genesis difficulty for v1.0.0 2016-10-28 08:55:21 -07:00
Jack Grigg 9e0ec8cc89
Update network details for v1.0.0-rc4 2016-10-27 18:59:27 -07:00
Jack Grigg 387541af3d
Update network magics and genesis block difficulty for v1.0.0-rc2 2016-10-23 00:02:31 -05:00
Jack Grigg ebb8b5683a
Update network details and address prefixes for release 1.0.0-beta2 2016-10-09 10:04:56 -05:00
Jack Grigg 1a93179609 Update network details for release 1.0.0-beta1 2016-09-10 15:43:03 +12:00
Jack Grigg 8f3a99b1be Remove versionGuard error while we are not versioning 2016-08-30 17:51:09 +12:00
Jack Grigg d7d6682eab Update network magics and genesis block difficulty to z9 2016-08-29 21:28:14 +12:00
Jack Grigg 73223235d5 Add Zcash payment address and spending key prefixes 2016-08-29 21:28:06 +12:00
Jack Grigg 53366f34fe Change RPC ports 2016-08-28 18:25:25 +12:00
Jack Grigg 80f5b45034 Implement parsing of transactions with JoinSplits (version 2) 2016-08-28 13:57:45 +12:00
Jack Grigg 8740d9e964 Implement Zcash modifications to block header 2016-08-27 23:47:16 +12:00
Jack Grigg bc8e5f4121 Zcash-ify 2016-08-27 23:22:04 +12:00
Gabe Gattis 764aa6d4e9
Merge branch 'gpg'
PR #85
2016-08-17 17:22:50 -04:00
Braydon Fuller 24df178a08
Add pgp key for @matiu 2016-08-17 17:14:48 -04:00
Braydon Fuller cdb538b94e
Update gpg keys 2016-08-17 17:01:11 -04:00
Braydon Fuller f6b0b14ac6 Bump package version to 0.13.19 2016-08-10 13:29:13 -04:00
Braydon Fuller c9e056a0a3 Bump package version to 0.13.18 2016-07-29 18:00:39 -04:00
Braydon Fuller 9e82395e71 Merge pull request #80 from rubensayshi/classify-better
`Script.classify` should first check output types before checking input types
2016-07-11 13:23:53 -04:00
Braydon Fuller 7a56719c3c Bump package version to 0.13.17 2016-07-05 13:15:42 -04:00
Ruben de Vries b655659812 `Script.classify` should first check output types before checking input types. 2016-07-05 12:32:24 +02:00
Matias Alejo Garcia d36f72857b Merge pull request #31 from braydonf/rbf
Transaction: Added replace-by-fee (RBF) support
2016-06-27 10:42:34 -03:00
Braydon Fuller 6275689f05 Bump package version to 0.13.16 2016-05-24 11:02:41 -04:00
Matias Alejo Garcia 09893632c2 Merge pull request #60 from braydonf/sha512
crypto: switch to Node.js sha512
2016-05-23 16:13:17 -03:00
Braydon Fuller 514fc8d326 crypto: switch to Node.js sha512
The sha512 library has not been updated in quite some time. This switches to
use Node.js crypto for sha512 that will use crypto-browserify, and more
recently maintained sha.js for the browser build.
2016-05-23 12:00:14 -04:00
Matias Alejo Garcia eab662c692 Merge pull request #58 from deoxen0n2/patch-1
Fix wrong property name in docs (Address.Pay2PubKeyHash)
2016-05-06 09:07:00 -03:00
Saran Siriphantnon 85666e92da Fix wrong property name in docs (Address.Pay2PubKeyHash)
Hi,

There is no `Address.Pay2PubKeyHash` property, instead it's `Address.PayToPublicKeyHash`.
2016-05-06 15:12:13 +07:00
Braydon Fuller 7fb064bde0 Bump package version to 0.13.15 2016-04-22 20:02:35 -04:00
Braydon Fuller b3b18d532f Bump package version to 0.13.14 2016-03-24 10:58:38 -04:00
Braydon Fuller 8c948ef511 Merge pull request #51 from fanatid/fix/ecdsa-k
Fix K generator in ECDSA
2016-03-24 10:31:38 -04:00
Kirill Fomichev 3579305b5e Fix K generator in ECDSA 2016-03-24 07:52:03 +03:00
Braydon Fuller 4430479cea Bump package version to 0.13.13 2016-02-05 10:11:49 -05:00
Gabe Gattis 9702105ad9 Merge pull request #44 from braydonf/add-regtest
Networks: Added regtest to networks
2016-02-04 14:58:07 -05:00
Braydon Fuller 0c983c9c4a Networks: Added regtest to networks
Brings better compatibility between "testnet" and "regtest". Services such as
Bitcore Wallet Service and wallets such as Copay that have "testnet" and not
"regtest" will be compatible with "regtest" if enabled in a Bitcore node. This
adds two new API methods to enable/disable regtest on the testnet network:
- `bitcore.Networks.enableRegtest()`
- `bitcore.Networks.disableRegtest()`
2016-02-04 10:43:03 -05:00
Braydon Fuller 8bd466373e Merge pull request #40 from fanatid/fix/opcode-smallint
Fix Opcode.smallInt
2016-02-01 11:51:35 -05:00
Kirill Fomichev af4d9aef34 Fix Opcode.smallInt 2016-02-01 20:58:59 +05:00
Braydon Fuller 6ae9b2f835 Bump package version to 0.13.12 2016-01-28 13:10:46 -05:00
Braydon Fuller 55bb6ad69f Merge pull request #17 from bitgaming/master
hasLowS validation not using correct constant as it is set in base 10 rather than hex
2016-01-21 11:18:27 -05:00
Matias Alejo Garcia 55c7296ab9 Merge pull request #37 from braydonf/bug/pay-to-public-key
Transaction: Support pay-to-public-key previous outputs with #fromObject
2016-01-18 16:11:40 -03:00
Braydon Fuller c0eec199ed Transaction: Support pay-to-public-key previous outputs with #fromObject 2016-01-18 13:36:33 -05:00
Braydon Fuller f1d19b438e Transaction: Added replace-by-fee (RBF) support
- Useful for bidding transactions as described in: https://bitpay.com/chaindb.pdf
- Reference: nSequence-based opt-in: https://github.com/bitcoin/bitcoin/pull/6871
2015-12-03 02:12:12 -05:00
Braydon Fuller 6e225ef70e Bump package version to 0.13.11 2015-12-02 21:29:21 -05:00
Ed Bosher c5a107961c Set s mid point as hex rather than decimal (bn.js default) 2015-11-10 19:42:37 +08:00
31 changed files with 1317 additions and 118 deletions

View File

@ -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).
To verify signatures, use the following PGP keys:
- @braydonf: https://pgp.mit.edu/pks/lookup?op=get&search=0x9BBF07CAC07A276D
- @pnagurny: https://pgp.mit.edu/pks/lookup?op=get&search=0x0909B33F0AA53013
- @braydonf: https://pgp.mit.edu/pks/lookup?op=get&search=0x9BBF07CAC07A276D `D909 EFE6 70B5 F6CC 89A3 607A 9BBF 07CA C07A 276D`
- @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

View File

@ -1,17 +1,18 @@
{
"name": "bitcore-lib",
"main": "./bitcore-lib.min.js",
"version": "0.13.10",
"name": "bitcore-lib-zcash",
"main": "./bitcore-lib-zcash.min.js",
"version": "0.13.19",
"homepage": "http://bitcore.io",
"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": [
"globals"
],
"keywords": [
"bitcoin",
"zcash",
"bitcore",
"btc",
"satoshi"

View File

@ -50,7 +50,7 @@ if (Address.isValid(input, Networks.testnet){
}
// 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){
...
}

View File

@ -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).
## 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
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`).

View File

@ -1,5 +1,5 @@
var bitcoreTasks = require('bitcore-build');
var bitcoreTasks = require('bitcore-build-zcash');
bitcoreTasks('lib');

View File

@ -6,10 +6,11 @@ var bitcore = module.exports;
bitcore.version = 'v' + require('./package.json').version;
bitcore.versionGuard = function(version) {
if (version !== undefined) {
var message = 'More than one instance of bitcore-lib found. ' +
'Please make sure to require bitcore-lib and check that submodules do' +
' not also include their own bitcore-lib dependency.';
throw new Error(message);
var message = 'More than one instance of bitcore-lib-zcash found. ' +
'Please make sure to require bitcore-lib-zcash and check that submodules do' +
' not also include their own bitcore-lib-zcash dependency.';
// TODO: put this back if we start versioning again
//throw new Error(message);
}
};
bitcore.versionGuard(global._bitcore);

View File

@ -162,8 +162,9 @@ Address._transformObject = function(data) {
Address._classifyFromVersion = function(buffer) {
var version = {};
var pubkeyhashNetwork = Networks.get(buffer[0], 'pubkeyhash');
var scripthashNetwork = Networks.get(buffer[0], 'scripthash');
var prefix = buffer[0]*256 + buffer[1];
var pubkeyhashNetwork = Networks.get(prefix, 'pubkeyhash');
var scripthashNetwork = Networks.get(prefix, 'scripthash');
if (pubkeyhashNetwork) {
version.network = pubkeyhashNetwork;
@ -191,8 +192,8 @@ Address._transformBuffer = function(buffer, network, type) {
if (!(buffer instanceof Buffer) && !(buffer instanceof Uint8Array)) {
throw new TypeError('Address supplied is not a buffer.');
}
if (buffer.length !== 1 + 20) {
throw new TypeError('Address buffers must be exactly 21 bytes.');
if (buffer.length !== 2 + 20) {
throw new TypeError('Address buffers must be exactly 22 bytes.');
}
network = Networks.get(network);
@ -206,7 +207,7 @@ Address._transformBuffer = function(buffer, network, type) {
throw new TypeError('Address has mismatched type.');
}
info.hashBuffer = buffer.slice(1);
info.hashBuffer = buffer.slice(2);
info.network = bufferVersion.network;
info.type = bufferVersion.type;
return info;
@ -459,7 +460,8 @@ Address.prototype.isPayToScriptHash = function() {
* @returns {Buffer} Bitcoin address buffer
*/
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]);
return buf;
};

View File

@ -9,7 +9,8 @@ var Hash = require('../crypto/hash');
var JSUtil = require('../util/js');
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
@ -27,10 +28,12 @@ var BlockHeader = function BlockHeader(arg) {
this.version = info.version;
this.prevHash = info.prevHash;
this.merkleRoot = info.merkleRoot;
this.reserved = info.reserved;
this.time = info.time;
this.timestamp = info.time;
this.bits = info.bits;
this.nonce = info.nonce;
this.solution = info.solution;
if (info.hash) {
$.checkState(
@ -69,21 +72,35 @@ BlockHeader._fromObject = function _fromObject(data) {
$.checkArgument(data, 'data is required');
var prevHash = data.prevHash;
var merkleRoot = data.merkleRoot;
var reserved = data.reserved;
var nonce = data.nonce;
var solution = data.solution;
if (_.isString(data.prevHash)) {
prevHash = BufferUtil.reverse(new Buffer(data.prevHash, 'hex'));
}
if (_.isString(data.merkleRoot)) {
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 = {
hash: data.hash,
version: data.version,
prevHash: prevHash,
merkleRoot: merkleRoot,
reserved: reserved,
time: data.time,
timestamp: data.time,
bits: data.bits,
nonce: data.nonce
nonce: nonce,
solution: solution
};
return info;
};
@ -139,9 +156,12 @@ BlockHeader._fromBufferReader = function _fromBufferReader(br) {
info.version = br.readUInt32LE();
info.prevHash = br.read(32);
info.merkleRoot = br.read(32);
info.reserved = br.read(32);
info.time = 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;
};
@ -163,9 +183,11 @@ BlockHeader.prototype.toObject = BlockHeader.prototype.toJSON = function toObjec
version: this.version,
prevHash: BufferUtil.reverse(this.prevHash).toString('hex'),
merkleRoot: BufferUtil.reverse(this.merkleRoot).toString('hex'),
reserved: BufferUtil.reverse(this.reserved).toString('hex'),
time: this.time,
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.write(this.prevHash);
bw.write(this.merkleRoot);
bw.write(this.reserved);
bw.writeUInt32LE(this.time);
bw.writeUInt32LE(this.bits);
bw.writeUInt32LE(this.nonce);
bw.write(this.nonce);
bw.writeVarintNum(this.solution.length);
bw.write(this.solution);
return bw;
};

View File

@ -88,9 +88,10 @@ ECDSA.prototype.deterministicK = function(badrs) {
var x = this.privkey.bn.toBuffer({
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);
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);
var T = BN.fromBuffer(v);

View File

@ -1,6 +1,5 @@
'use strict';
var sha512 = require('sha512');
var crypto = require('crypto');
var BufferUtil = require('../util/buffer');
var $ = require('../util/preconditions');
@ -38,8 +37,7 @@ Hash.sha256ripemd160 = function(buf) {
Hash.sha512 = function(buf) {
$.checkArgument(BufferUtil.isBuffer(buf));
var hash = sha512(buf);
return new Buffer(hash);
return crypto.createHash('sha512').update(buf).digest();
};
Hash.sha512.blocksize = 1024;

View File

@ -275,7 +275,7 @@ Signature.isTxDER = function(buf) {
*/
Signature.prototype.hasLowS = function() {
if (this.s.lt(new BN(1)) ||
this.s.gt(new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0'))) {
this.s.gt(new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex'))) {
return false;
}
return true;

View File

@ -59,6 +59,8 @@ function get(arg, keys) {
* @param {Number} data.scripthash - The scripthash prefix
* @param {Number} data.xpubkey - The extended public 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.port - The network port
* @param {Array} data.dnsSeeds - An array of dns seeds
@ -76,11 +78,27 @@ function addNetwork(data) {
scripthash: data.scripthash,
xpubkey: data.xpubkey,
xprivkey: data.xprivkey,
networkMagic: BufferUtil.integerAsBuffer(data.networkMagic),
port: data.port,
dnsSeeds: data.dnsSeeds
zaddr: data.zaddr,
zkey: data.zkey
});
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) {
if (!_.isUndefined(value) && !_.isObject(value)) {
networkMaps[value] = network;
@ -115,53 +133,128 @@ function removeNetwork(network) {
addNetwork({
name: 'livenet',
alias: 'mainnet',
pubkeyhash: 0x00,
pubkeyhash: 0x1cb8,
privatekey: 0x80,
scripthash: 0x05,
scripthash: 0x1cbd,
xpubkey: 0x0488b21e,
xprivkey: 0x0488ade4,
networkMagic: 0xf9beb4d9,
port: 8333,
zaddr: 0x169a,
zkey: 0xab36,
networkMagic: 0x24e92764,
port: 8233,
dnsSeeds: [
'seed.bitcoin.sipa.be',
'dnsseed.bluematt.me',
'dnsseed.bitcoin.dashjr.org',
'seed.bitcoinstats.com',
'seed.bitnodes.io',
'bitseed.xf2.org'
'dnsseed.z.cash',
'dnsseed.str4d.xyz',
'dnsseed.znodes.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
* @member Networks#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
* @member Networks#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
*/
@ -172,5 +265,7 @@ module.exports = {
livenet: livenet,
mainnet: livenet,
testnet: testnet,
get: get
get: get,
enableRegtest: enableRegtest,
disableRegtest: disableRegtest
};

View File

@ -67,6 +67,7 @@ Opcode.prototype.toString = function() {
};
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');
if (n === 0) {
return Opcode('OP_0');

View File

@ -500,24 +500,54 @@ Script.types.DATA_OUT = 'Data push';
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,
* or Script.UNKNOWN if it isn't
*/
Script.prototype.classify = function() {
for (var type in Script.identifiers) {
if (Script.identifiers[type].bind(this)()) {
if (this._isInput) {
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];
}
}

View File

@ -11,9 +11,10 @@ var Script = require('../../script');
var Sighash = require('../sighash');
var Output = require('../output');
var DEFAULT_SEQNUMBER = 0xFFFFFFFF;
var DEFAULT_LOCKTIME_SEQNUMBER = 0x00000000;
var MAXINT = 0xffffffff; // Math.pow(2, 32) - 1;
var DEFAULT_RBF_SEQNUMBER = MAXINT - 2;
var DEFAULT_SEQNUMBER = MAXINT;
var DEFAULT_LOCKTIME_SEQNUMBER = MAXINT - 1;
function Input(params) {
if (!(this instanceof Input)) {
@ -24,8 +25,10 @@ function Input(params) {
}
}
Input.MAXINT = MAXINT;
Input.DEFAULT_SEQNUMBER = DEFAULT_SEQNUMBER;
Input.DEFAULT_LOCKTIME_SEQNUMBER = DEFAULT_LOCKTIME_SEQNUMBER;
Input.DEFAULT_RBF_SEQNUMBER = DEFAULT_RBF_SEQNUMBER;
Object.defineProperty(Input.prototype, 'script', {
configurable: false,

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -26,6 +26,10 @@ var Script = require('../script');
var PrivateKey = require('../privatekey');
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
*
@ -38,6 +42,11 @@ function Transaction(serialized) {
}
this.inputs = [];
this.outputs = [];
this.joinSplits = [];
this.spendDescs = [];
this.outputDescs = [];
this._inputAmount = undefined;
this._outputAmount = undefined;
@ -279,7 +288,19 @@ Transaction.prototype.toBuffer = function() {
};
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);
_.each(this.inputs, function(input) {
input.toBufferWriter(writer);
@ -289,6 +310,38 @@ Transaction.prototype.toBufferWriter = function(writer) {
output.toBufferWriter(writer);
});
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;
};
@ -299,9 +352,20 @@ Transaction.prototype.fromBuffer = function(buffer) {
Transaction.prototype.fromBufferReader = function(reader) {
$.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();
for (i = 0; i < sizeTxIns; i++) {
var input = Input.fromBufferReader(reader);
@ -311,7 +375,43 @@ Transaction.prototype.fromBufferReader = function(reader) {
for (i = 0; i < sizeTxOuts; i++) {
this.outputs.push(Output.fromBufferReader(reader));
}
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;
};
@ -326,11 +426,50 @@ Transaction.prototype.toObject = Transaction.prototype.toJSON = function toObjec
});
var obj = {
hash: this.hash,
fOverwintered: this.fOverwintered,
version: this.version,
inputs: inputs,
outputs: outputs,
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) {
obj.changeScript = this._changeScript.toString();
}
@ -366,6 +505,8 @@ Transaction.prototype.fromObject = function fromObject(arg) {
txin = new Input.MultiSigScriptHash(
input, input.publicKeys, input.threshold, input.signatures
);
} else if (script.isPublicKeyOut()) {
txin = new Input.PublicKey(input);
} else {
throw new errors.Transaction.Input.UnsupportedScript(input.output.script);
}
@ -385,6 +526,38 @@ Transaction.prototype.fromObject = function fromObject(arg) {
}
this.nLockTime = transaction.nLockTime;
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);
return this;
};
@ -544,7 +717,7 @@ Transaction.prototype.from = function(utxo, pubkeys, threshold) {
return input.prevTxId.toString('hex') === utxo.txId && input.outputIndex === utxo.outputIndex;
});
if (exists) {
return;
return this;
}
if (pubkeys && threshold) {
this._fromMultisigUtxo(utxo, pubkeys, threshold);
@ -1195,5 +1368,34 @@ Transaction.prototype.isCoinbase = function() {
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;

View File

@ -110,8 +110,8 @@ URI.isValid = function(arg, knownParams) {
URI.parse = function(uri) {
var info = URL.parse(uri, true);
if (info.protocol !== 'bitcoin:') {
throw new TypeError('Invalid bitcoin URI');
if (info.protocol !== 'zcash:') {
throw new TypeError('Invalid zcash URI');
}
// workaround to host insensitiveness
@ -135,7 +135,7 @@ URI.prototype._fromObject = function(obj) {
/* jshint maxcomplexity: 10 */
if (!Address.isValid(obj.address)) {
throw new TypeError('Invalid bitcoin address');
throw new TypeError('Invalid zcash address');
}
this.address = new Address(obj.address);
@ -205,7 +205,7 @@ URI.prototype.toString = function() {
_.extend(query, this.extras);
return URL.format({
protocol: 'bitcoin:',
protocol: 'zcash:',
host: this.address,
query: query
});

171
lib/zcash/proof.js Normal file
View File

@ -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;

7
npm-shrinkwrap.json generated
View File

@ -1,6 +1,6 @@
{
"name": "bitcore",
"version": "0.13.10",
"version": "0.13.19",
"dependencies": {
"bn.js": {
"version": "2.0.4",
@ -43,11 +43,6 @@
"version": "3.10.1",
"from": "lodash@=3.10.1",
"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"
}
}
}

View File

@ -1,7 +1,7 @@
{
"name": "bitcore-lib",
"version": "0.13.10",
"description": "A pure and powerful JavaScript Bitcoin library.",
"name": "bitcore-lib-zcash",
"version": "0.13.19",
"description": "A pure and powerful JavaScript Zcash library.",
"author": "BitPay <dev@bitpay.com>",
"main": "index.js",
"scripts": {
@ -54,10 +54,22 @@
{
"name": "Wei Lu",
"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": [
"bitcoin",
"zcash",
"transaction",
"address",
"p2p",
@ -74,7 +86,7 @@
],
"repository": {
"type": "git",
"url": "https://github.com/bitpay/bitcore-lib.git"
"url": "https://github.com/zcash-hackworks/bitcore-lib-zcash.git"
},
"browser": {
"request": "browser-request"
@ -85,11 +97,10 @@
"buffer-compare": "=1.0.0",
"elliptic": "=3.0.3",
"inherits": "=2.0.1",
"lodash": "=3.10.1",
"sha512": "=0.0.1"
"lodash": "=3.10.1"
},
"devDependencies": {
"bitcore-build": "bitpay/bitcore-build",
"bitcore-build-zcash": "zcash-hackworks/bitcore-build-zcash",
"brfs": "^1.2.0",
"chai": "^1.10.0",
"gulp": "^3.8.10",

View File

@ -211,6 +211,15 @@ describe('ECDSA', function() {
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() {
@ -296,7 +305,7 @@ describe('ECDSA', function() {
ecdsa.sigError().should.equal(obj.exception);
});
});
vectors.deterministicK.forEach(function(obj, i) {
it('should validate deterministicK vector ' + i, function() {
var hashbuf = Hash.sha256(new Buffer(obj.message));

View File

@ -278,18 +278,30 @@ describe('Signature', function() {
describe('#hasLowS', function() {
it('should detect high and low S', function() {
var r = new BN('63173831029936981022572627018246571655303050627048489594159321588908385378810');
var s = new BN('4331694221846364448463828256391194279133231453999942381442030409253074198130');
var s2 = new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B2000');
var sig = new Signature({
r: r,
s: s
});
s: new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A1', 'hex')
});
sig.hasLowS().should.equal(false);
var sig2 = new Signature({
r: r,
s: s2
});
s: new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex')
});
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);
});
});

View File

@ -9,7 +9,7 @@
}],
"to", ["mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc", 1010000],
"sign", ["cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY"],
"serialize", "01000000015884e5db9de218238671572340b207ee85b628074e7e467096c267266baf77a4000000006a473044022013fa3089327b50263029265572ae1b022a91d10ac80eb4f32f291c914533670b02200d8a5ed5f62634a7e1a0dc9188a3cc460a986267ae4d58faf50c79105431327501210223078d2942df62c45621d209fab84ea9a7a23346201b7727b9b45a29c4e76f5effffffff0150690f00000000001976a9147821c0a3768aa9d1a37e16cf76002aef5373f1a888ac00000000"
"serialize", "01000000015884e5db9de218238671572340b207ee85b628074e7e467096c267266baf77a4000000006b4830450221009972100061da4a17a471ac1906c18bb5445c03da2a0be52c59aca6c58f1e342302202b7a19a22572cabb6e55c368ebdb5921541358fa969d5c76b5e0d6ad3f26a7d701210223078d2942df62c45621d209fab84ea9a7a23346201b7727b9b45a29c4e76f5effffffff0150690f00000000001976a9147821c0a3768aa9d1a37e16cf76002aef5373f1a888ac00000000"
],
[
"from", [{
@ -22,7 +22,7 @@
"to", ["mn9new5vPYWuVN5m3gUBujfKh1uPQvR9mf", 500000],
"to", ["mw5ctwgEaNRbxkM4JhXH3rp5AyGvTWDZCD", 570000],
"sign", ["cSQUuwwJBAg6tYQhzqqLWW115D1s5KFZDyhCF2ffrnukZxMK6rNZ"],
"serialize", "0100000001863957ca797bf847eae50f6999e4c3616dc64b1e6661b16d9da2b57d184724e4010000006b4830450221009d23f7c1e790ecf839e0e53248dacfa559194735e477aa3ee5897fd74fe3ec0402205eff578518e7c59beeb03ee85e5c4b5bc2730addca2f0321d80aadfbcc1976de0121039dd446bbc85db6917f39c0b4c295b0f8cce76d1926fa76d7b84e3f7ff1c5eec5ffffffff0220a10700000000001976a91448c819246ae5645ceecd41fbe1aa6202a0a9b5ca88ac90b20800000000001976a914aab76ba4877d696590d94ea3e02948b55294815188ac00000000"
"serialize", "0100000001863957ca797bf847eae50f6999e4c3616dc64b1e6661b16d9da2b57d184724e4010000006b483045022100855691c90510edf83ab632f0a0b17f5202d2cf7071050dcf0c2778325ed403cd022014ee7a4e787da8bc088d2ece43108a7b8d7112eba89876a27bb44195a0715a910121039dd446bbc85db6917f39c0b4c295b0f8cce76d1926fa76d7b84e3f7ff1c5eec5ffffffff0220a10700000000001976a91448c819246ae5645ceecd41fbe1aa6202a0a9b5ca88ac90b20800000000001976a914aab76ba4877d696590d94ea3e02948b55294815188ac00000000"
],
[
"from", [
@ -48,7 +48,7 @@
"sign", [
["cPGbA2C54ZZ1sw4dc2ckBE1WqkdrNSbEV8Tkjhi2p1J15oErdgP2", "cSpyve5bXAuyHrNeV9MjTdFz3HLw739yUjjUAUSMe3ppf2qzj2hw"]
],
"serialize", "0100000002b3028cf4ae5b4b6d8f79ab6fc0dd251b28ab28287d33861e35c90f6e5684dba9000000006a47304402205d591b93871b63205ea80f6976b4d76ce23ca95c825d0c74b44e9816c9488ae8022012476dd8a2780028ed3e72ac1f2620580e82a25c22d1c31afca6fb14b125a35c0121030253c73236acf5ea9085d408220141197f6094de07426bd0d32c7a543614fdd7ffffffffb3028cf4ae5b4b6d8f79ab6fc0dd251b28ab28287d33861e35c90f6e5684dba9010000006a4730440220320367535c9bc525c581939b36ebe70dd0845851e68fa9e3cf2d90642bf551b3022055d6fcaef32d9b584eea757fa633c31449f43272d131588ddd87a22d16dd7129012102977a001a0a7bbfd1f8a647c7d46e13e8f6920635b328390b43b3303977101149ffffffff01a02c1000000000001976a91493abf1e9e4a20c125b93f93ee39efc16b6e4bc4688ac00000000"
"serialize", "0100000002b3028cf4ae5b4b6d8f79ab6fc0dd251b28ab28287d33861e35c90f6e5684dba9000000006a4730440220635e95e1981bbb360feaf4c232f626a0af8eb5c043a99749a21b0e37fd0048fd02201c5db8a93f1f5c268be6167da7c92f5030481acf65bef750c81ec9907aba3b170121030253c73236acf5ea9085d408220141197f6094de07426bd0d32c7a543614fdd7ffffffffb3028cf4ae5b4b6d8f79ab6fc0dd251b28ab28287d33861e35c90f6e5684dba9010000006a4730440220319a0b5ee9c67ccb7de4222234f31059354be4f239c99ca24bff30adfec8e8ec02204ad4c6dedebb20d100f9484b9ea6c5ba36712e9da155c24509e793c02e4805fd012102977a001a0a7bbfd1f8a647c7d46e13e8f6920635b328390b43b3303977101149ffffffff01a02c1000000000001976a91493abf1e9e4a20c125b93f93ee39efc16b6e4bc4688ac00000000"
],
[
"from", [{
@ -60,7 +60,7 @@
}],
"to", ["n3riXZowrjGnY74rx7Hdi9wCyvgyJC28zZ", 990000],
"sign", ["cPwWtDztEgRCMCU8pMQp4HgphvyadrAsYBrCjXUZuDSmnZkyoyNF"],
"serialize", "0100000001dc8b68f2b4263d77ee30468da161242be499283a21dfd7eb38a4a9cdce130ef5010000006a4730440220337e09c2729423302abe5e386d5e0f060ae8c006693f87342322bb1fe50065ff0220217a12de44139c57f01d35e988ffe3b0f86005d0cefcecf877b54c67473211d2012103e26b47e7c0d8946954bf9dd4bc7f9e415437eb98271d05f69e78cef8fc6c9a54ffffffff01301b0f00000000001976a914f50f9826ef186074c6fe206cca6b71472ff07ba888ac00000000"
"serialize", "0100000001dc8b68f2b4263d77ee30468da161242be499283a21dfd7eb38a4a9cdce130ef5010000006a473044022012610834051e6af8594dd5d9c47123d6ce03537d321f9fe3f6ff244b23f47dd5022034901bb0d83688758a9248fdef48bd2000b55cf70111cbef8f206e72a31aaf61012103e26b47e7c0d8946954bf9dd4bc7f9e415437eb98271d05f69e78cef8fc6c9a54ffffffff01301b0f00000000001976a914f50f9826ef186074c6fe206cca6b71472ff07ba888ac00000000"
],
[
"from", [{
@ -68,7 +68,7 @@
}, ["03411e021210a933c247ea9c8dad4bbead281597d508ad84e899de13e4ce98b4ba", "03bda2c3cc11a391b36e3d695b03ab42b96fe04086b2349056108d858983e60dab", "03c16e6ecf4e02bf9db23d3247ab92db8881f0866133ffb530c3470f6d8dea7330"], 2],
"to", ["3BazTqvkvEBcWk7J4sbgRnxUw6rjYrogf9", 300299],
"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
@ -80,6 +80,6 @@
"change", ["3BazTqvkvEBcWk7J4sbgRnxUw6rjYrogf9"],
"sign", ["L2U9m5My3cdyN5qX1PH4B7XstGDZFWwyukdX8gj8vsJ3fkrqArQo"],
"sign", ["L4jFVcDaqZCkknP5KQWjCBgiLFxKxRxywNGTucm3jC3ozByZcbZv"],
"serialize", "010000000220c24f763536edb05ce8df2a4816d971be4f20b58451d71589db434aca98bfaf00000000fdfd000047304402202c34fd898bbea3521c5f88fdeef4bb65f36ce01142633c1121e9b7bef307938902205e1aad62a66bd294898dc71678a4a5448281126baad90bfd9b4139663e852d26014830450221009d9f2b46595dc2578f4c4ac65c779e45e493bcc4649ef6786477e40df40d21fc02206da8a0f80fa2aa2d2b89d56951761c8f0506fdafd53ef6fe7d5c878251bb216b014c695221020483ebb834d91d494a3b649cf0e8f5c9c4fcec5f194ab94341cc99bb440007f2210271ebaeef1c2bf0c1a4772d1391eab03e4d96a6e9b48551ab4e4b0d2983eb452b2103a659828aabe443e2dedabb1db5a22335c5ace5b5b7126998a288d63c99516dd853aeffffffffa0644cd1606e081c59eb65fe69d4a83a3a822da423bc392c91712fb77a192edc00000000fdfd000047304402202e64f052cd5be367f2f9efb31d3a34d0f8339700beff426d31b53c9a776a0368022057c714fda22a5ec301765dd187be3c522bcfe040127e857067163a5fb9ed46c001483045022100bf7a1e5a9e7204361e70312e15746efc95c7be8957a66c76574d2a07db359c550220318dc70b703c84a76fe3a460e96d466462f4c1c54b9fbfb75157b1afe2c51f8e014c695221020483ebb834d91d494a3b649cf0e8f5c9c4fcec5f194ab94341cc99bb440007f2210271ebaeef1c2bf0c1a4772d1391eab03e4d96a6e9b48551ab4e4b0d2983eb452b2103a659828aabe443e2dedabb1db5a22335c5ace5b5b7126998a288d63c99516dd853aeffffffff03f04902000000000017a9144de752833233fe69a20064f29b2ca0f6399c8af387007102000000000017a9144de752833233fe69a20064f29b2ca0f6399c8af3873b8f04000000000017a9146c8d8b04c6a1e664b1ec20ec932760760c97688e8700000000"
"serialize", "010000000220c24f763536edb05ce8df2a4816d971be4f20b58451d71589db434aca98bfaf00000000fc00473044022077fca9eb2544894068c47028855b0cf147526e9a54d993b7aa028908526944ea02203223ca379fa06b5544c02ed74b3ebb9734e2a9e09bca9b572aa56443a3be4d8d0147304402205caaf5666489ab005f280d30afbcda4d8f6f7195b0a13de89bc1e80f58219f5e02205414938c9d0496f5b45c1f45c028c019b3a956549938c09d983a3cc03e819f05014c695221020483ebb834d91d494a3b649cf0e8f5c9c4fcec5f194ab94341cc99bb440007f2210271ebaeef1c2bf0c1a4772d1391eab03e4d96a6e9b48551ab4e4b0d2983eb452b2103a659828aabe443e2dedabb1db5a22335c5ace5b5b7126998a288d63c99516dd853aeffffffffa0644cd1606e081c59eb65fe69d4a83a3a822da423bc392c91712fb77a192edc00000000fdfd0000483045022100c4c98f6cc0a313aee264ab8171927de590ab495b78f26159e56ba49fc26b1e3802206a12c4d41863756e35f72bd365d862da907272bcb2a949d1d2f64c1867d88ce90147304402207035e6083876dcd5512b40bb3d81e2b38393a62f962f8b701efc066db446ae500220121d38105bb58d8b8ad78bbef212c1f958124d47186bcc1ddcccfc0480eb7eb8014c695221020483ebb834d91d494a3b649cf0e8f5c9c4fcec5f194ab94341cc99bb440007f2210271ebaeef1c2bf0c1a4772d1391eab03e4d96a6e9b48551ab4e4b0d2983eb452b2103a659828aabe443e2dedabb1db5a22335c5ace5b5b7126998a288d63c99516dd853aeffffffff03f04902000000000017a9144de752833233fe69a20064f29b2ca0f6399c8af387007102000000000017a9144de752833233fe69a20064f29b2ca0f6399c8af3873b8f04000000000017a9146c8d8b04c6a1e664b1ec20ec932760760c97688e8700000000"
]
]

View File

@ -4,11 +4,11 @@
<title>Mocha</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<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>
<body>
<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 src="../tests.js"></script>
<script>

View File

@ -15,6 +15,29 @@ describe('Networks', function() {
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() {
var custom = {
name: 'customnet',

View File

@ -120,10 +120,23 @@ describe('Opcode', function() {
var testSmallInt = function(n, op) {
Opcode.smallInt(n).toString().should.equal(op.toString());
};
for (var i = 0; i < smallints.length; i++) {
var op = smallints[i];
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() {
var testIsSmallInt = function(op) {

View File

@ -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() {
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);
@ -444,6 +516,28 @@ describe('Script', function() {
it('should classify unknown', function() {
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() {

View File

@ -108,6 +108,40 @@ describe('Transaction', function() {
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() {
var transaction = new Transaction(tx_1_hex);
var copy = new Transaction(transaction);
@ -180,7 +214,7 @@ describe('Transaction', function() {
var simpleUtxoWith1BTC = {
address: fromAddress,
txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
outputIndex: 0,
outputIndex: 1,
script: Script.buildPublicKeyHashOut(fromAddress).toString(),
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);
});
});
});
});