Merge branch 'generators'

This commit is contained in:
Christopher Jeffrey 2016-10-04 13:33:53 -07:00
commit 74fde4bc51
No known key found for this signature in database
GPG key ID: 8962AB9DE6666BBD
141 changed files with 18147 additions and 17841 deletions

9
.babelrc Normal file
View file

@ -0,0 +1,9 @@
{
"presets": ["es2015"],
"plugins": [
["transform-runtime", {
"polyfill": true,
"regenerator": true
}]
]
}

View file

@ -1,5 +1,6 @@
{
"bitwise": false,
"esversion": 6,
"curly": false,
"eqeqeq": true,
"freeze": true,

167
README.md
View file

@ -114,30 +114,19 @@ var miner = new bcoin.miner({ chain: chain, mempool: mempool });
// Open the miner (initialize the databases, etc).
// Miner will implicitly call `open` on chain and mempool.
miner.open(function(err) {
if (err)
throw err;
miner.open().then(function() {
// Create a block "attempt".
miner.createBlock(function(err, attempt) {
if (err)
throw err;
// Mine the block on the worker pool (use mine() for the master process)
attempt.mineAsync(function(err, block) {
if (err)
throw err;
// Add the block to the chain
chain.add(block, function(err) {
if (err)
throw err;
console.log('Added %s to the blockchain.', block.rhash);
console.log(block);
});
});
});
return miner.createBlock();
}).then(function(attempt) {
// Mine the block on the worker pool (use mine() for the master process)
return attempt.mineAsync();
}).then(function(block) {
// Add the block to the chain
console.log('Adding %s to the blockchain.', block.rhash);
console.log(block);
return chain.add(block);
}).then(function() {
console.log('Added block!');
});
```
@ -157,10 +146,7 @@ var mempool = new bcoin.mempool({ chain: chain });
var pool = new bcoin.pool({ chain: chain, mempool: mempool, maxPeers: 8 });
// Open the pool (implicitly opens mempool and chain).
pool.open(function(err) {
if (err)
throw err;
pool.open().then(function() {
// Connect, start retrieving and relaying txs
pool.connect();
@ -204,10 +190,7 @@ var tpool = new bcoin.pool({
size: 8
});
tpool.open(function(err) {
if (err)
throw err;
tpool.open().then(function() {
// Connect, start retrieving and relaying txs
tpool.connect();
@ -252,38 +235,29 @@ var pool = new bcoin.pool({
var walletdb = new bcoin.walletdb({ db: 'memory' });
pool.open(function(err) {
if (err)
throw err;
pool.open().then(function() {
return walletdb.open();
}).then(function() {
return walletdb.create();
}).then(function(wallet) {
console.log('Created wallet with address %s', wallet.getAddress('base58'));
walletdb.open(function(err) {
if (err)
throw err;
// Add our address to the spv filter.
pool.watchAddress(wallet.getAddress());
walletdb.create(function(err, wallet) {
if (err)
throw err;
// Connect, start retrieving and relaying txs
pool.connect();
console.log('Created wallet with address %s', wallet.getAddress('base58'));
// Start the blockchain sync.
pool.startSync();
// Add our address to the spv filter.
pool.watchAddress(wallet.getAddress());
pool.on('tx', function(tx) {
wallet.addTX(tx);
});
// Connect, start retrieving and relaying txs
pool.connect();
// Start the blockchain sync.
pool.startSync();
pool.on('tx', function(tx) {
wallet.addTX(tx);
});
wallet.on('balance', function(balance) {
console.log('Balance updated.');
console.log(bcoin.utils.btc(balance.unconfirmed));
});
});
wallet.on('balance', function(balance) {
console.log('Balance updated.');
console.log(bcoin.utils.btc(balance.unconfirmed));
});
});
```
@ -310,10 +284,7 @@ node.on('error', function(err) {
});
// Start the node
node.open(function(err) {
if (err)
throw err;
node.open().then(function() {
// Create a new wallet (or get an existing one with the same ID)
var options = {
id: 'mywallet',
@ -322,48 +293,33 @@ node.open(function(err) {
type: 'pubkeyhash'
};
node.walletdb.create(options, function(err, wallet) {
if (err)
throw err;
return node.walletdb.create(options);
}).then(function(wallet) {
console.log('Created wallet with address: %s', wallet.getAddress('base58'));
console.log('Created wallet with address: %s', wallet.getAddress('base58'));
// Start syncing the blockchain
node.startSync();
// Start syncing the blockchain
node.startSync();
// Wait for balance and send it to a new address.
wallet.once('balance', function(balance) {
// Create a transaction, fill
// it with coins, and sign it.
var options = {
subtractFee: true,
outputs: [{
address: newReceiving,
value: balance.total
}]
};
wallet.createTX(options, function(err, tx) {
if (err)
throw err;
// Need to pass our passphrase back in to sign!
wallet.sign(tx, 'foo', function(err) {
if (err)
throw err;
console.log('sending tx:');
console.log(tx);
node.sendTX(tx, function(err) {
if (err) {
// Could be a reject
// packet or a timeout.
return console.log(err);
}
console.log('tx sent!');
});
});
});
// Wait for balance and send it to a new address.
wallet.once('balance', function(balance) {
// Create a transaction, fill
// it with coins, and sign it.
var options = {
subtractFee: true,
outputs: [{
address: newReceiving,
value: balance.total
}]
};
wallet.createTX(options).then(function(tx) {
// Need to pass our passphrase back in to sign!
return wallet.sign(tx, 'foo');
}).then(function(tx) {
console.log('sending tx:');
console.log(tx);
return node.sendTX(tx);
}).then(function() {
console.log('tx sent!');
});
});
});
@ -377,12 +333,7 @@ node.mempool.on('tx', function(tx) {
});
node.chain.on('full', function() {
node.mempool.getHistory(function(err, txs) {
if (err)
throw err;
console.log(txs);
});
node.mempool.getHistory().then(console.log);
});
```

View file

@ -1,20 +1,19 @@
'use strict';
var bn = require('bn.js');
var bcoin = require('../').set('main');
var constants = bcoin.constants;
var utils = bcoin.utils;
var constants = require('../lib/protocol/constants');
var utils = require('../lib/utils/utils');
var assert = require('assert');
var scriptTypes = constants.scriptTypes;
var bench = require('./bench');
var fs = require('fs');
bcoin.cache();
var Coins = require('../lib/chain/coins');
var TX = require('../lib/primitives/tx');
var wtx = fs.readFileSync(__dirname + '/../test/data/wtx.hex', 'utf8');
wtx = bcoin.tx.fromRaw(wtx.trim(), 'hex');
wtx = tx.fromRaw(wtx.trim(), 'hex');
var coins = bcoin.coins.fromTX(wtx);
var coins = Coins.fromTX(wtx);
var raw;
var end = bench('serialize');
@ -24,16 +23,16 @@ end(i);
var end = bench('parse');
for (var i = 0; i < 10000; i++)
bcoin.coins.fromRaw(raw);
Coins.fromRaw(raw);
end(i);
var end = bench('parse-single');
var hash = wtx.hash('hex');
for (var i = 0; i < 10000; i++)
bcoin.coins.parseCoin(raw, hash, 5);
Coins.parseCoin(raw, hash, 5);
end(i);
var coins = bcoin.coins.fromRaw(raw);
var coins = Coins.fromRaw(raw);
var end = bench('get');
var j;

View file

@ -7,6 +7,7 @@ var utils = bcoin.utils;
var assert = require('assert');
var scriptTypes = constants.scriptTypes;
var bench = require('./bench');
var co = require('../lib/utils/co');
bcoin.cache();
@ -35,115 +36,85 @@ var walletdb = new bcoin.walletdb({
// db: 'leveldb'
db: 'memory'
});
var wallet;
var addrs = [];
function runBench(callback) {
utils.serial([
function(next) {
walletdb.create(function(err, w) {
assert.ifError(err);
wallet = w;
next();
});
},
function(next) {
var end = bench('accounts');
utils.forRange(0, 1000, function(i, next) {
wallet.createAccount({}, function(err, account) {
assert.ifError(err);
addrs.push(account.receiveAddress.getAddress());
next();
});
}, function(err) {
assert.ifError(err);
end(1000);
next();
});
},
function(next) {
var end = bench('addrs');
utils.forRange(0, 1000, function(i, next) {
utils.forRange(0, 10, function(j, next) {
wallet.createReceive(i, function(err, addr) {
assert.ifError(err);
addrs.push(addr);
next();
});
}, next);
}, function(err) {
assert.ifError(err);
end(1000 * 10);
next();
});
},
function(next) {
var nonce = new bn(0);
var end;
utils.forRange(0, 10000, function(i, next) {
var t1 = bcoin.mtx()
.addOutput(addrs[(i + 0) % addrs.length], 50460)
.addOutput(addrs[(i + 1) % addrs.length], 50460)
.addOutput(addrs[(i + 2) % addrs.length], 50460)
.addOutput(addrs[(i + 3) % addrs.length], 50460);
var runBench = co(function* runBench() {
var i, j, wallet, addrs, jobs, end;
var result, nonce, tx, options;
t1.addInput(dummyInput);
nonce.addn(1);
t1.inputs[0].script.set(0, nonce);
t1.inputs[0].script.compile();
// Open and Create
yield walletdb.open();
wallet = yield walletdb.create();
addrs = [];
walletdb.addTX(t1.toTX(), function(err) {
assert.ifError(err);
next();
});
}, function(err) {
assert.ifError(err);
end(10000);
next();
});
end = bench('tx');
},
function(next) {
var end = bench('balance');
wallet.getBalance(function(err, balance) {
assert.ifError(err);
end(1);
next();
});
},
function(next) {
var end = bench('coins');
wallet.getCoins(function(err) {
assert.ifError(err);
end(1);
next();
});
},
function(next) {
var end = bench('create');
var options = {
rate: 10000,
outputs: [{
value: 50460,
address: addrs[0]
}]
};
wallet.createTX(options, function(err) {
assert.ifError(err);
end(1);
next();
});
}
], function(err) {
assert.ifError(err);
callback();
});
}
// Accounts
jobs = [];
for (i = 0; i < 1000; i++)
jobs.push(wallet.createAccount({}));
walletdb.open(function(err) {
assert.ifError(err);
runBench(function(err) {
assert.ifError(err);
process.exit(0);
});
end = bench('accounts');
result = yield Promise.all(jobs);
end(1000);
for (i = 0; i < result.length; i++)
addrs.push(result[i].receive.getAddress());
// Addresses
jobs = [];
for (i = 0; i < 1000; i++) {
for (j = 0; j < 10; j++)
jobs.push(wallet.createReceive(i));
}
end = bench('addrs');
result = yield Promise.all(jobs);
end(1000 * 10);
for (i = 0; i < result.length; i++)
addrs.push(result[i].getAddress());
// TX
jobs = [];
nonce = new bn(0);
for (i = 0; i < 10000; i++) {
tx = bcoin.mtx()
.addOutput(addrs[(i + 0) % addrs.length], 50460)
.addOutput(addrs[(i + 1) % addrs.length], 50460)
.addOutput(addrs[(i + 2) % addrs.length], 50460)
.addOutput(addrs[(i + 3) % addrs.length], 50460);
tx.addInput(dummyInput);
nonce.addn(1);
tx.inputs[0].script.set(0, nonce);
tx.inputs[0].script.compile();
jobs.push(walletdb.addTX(tx.toTX()));
}
end = bench('tx');
result = yield Promise.all(jobs);
end(10000);
// Balance
end = bench('balance');
result = yield wallet.getBalance();
end(1);
// Coins
end = bench('coins');
result = yield wallet.getCoins();
end(1);
// Create
end = bench('create');
options = {
rate: 10000,
outputs: [{
value: 50460,
address: addrs[0]
}]
};
yield wallet.createTX(options);
end(1);
});
runBench().then(process.exit);

622
bin/cli
View file

@ -4,9 +4,11 @@
var config = require('../lib/node/config');
var utils = require('../lib/utils/utils');
var co = require('../lib/utils/co');
var Client = require('../lib/http/client');
var Wallet = require('../lib/http/wallet');
var assert = utils.assert;
var assert = require('assert');
var main;
function CLI() {
this.config = config({
@ -26,9 +28,9 @@ CLI.prototype.log = function log(json) {
console.log(JSON.stringify(json, null, 2));
};
CLI.prototype.createWallet = function createWallet(callback) {
var self = this;
CLI.prototype.createWallet = co(function* createWallet() {
var options = { id: this.argv[0] };
var wallet;
if (this.config.type)
options.type = this.config.type;
@ -51,170 +53,118 @@ CLI.prototype.createWallet = function createWallet(callback) {
if (this.config.passphrase)
options.passphrase = this.config.passphrase;
this.client.createWallet(options, function(err, wallet) {
if (err)
return callback(err);
self.log(wallet);
callback();
});
};
wallet = yield this.client.createWallet(options);
this.log(wallet);
});
CLI.prototype.addKey = function addKey(callback) {
var self = this;
CLI.prototype.addKey = co(function* addKey() {
var key = this.argv[0];
this.wallet.addKey(this.config.account, key, function(err, wallet) {
if (err)
return callback(err);
self.log('added');
callback();
});
};
yield this.wallet.addKey(this.config.account, key);
this.log('added');
});
CLI.prototype.removeKey = function removeKey(callback) {
var self = this;
CLI.prototype.removeKey = co(function* removeKey() {
var key = this.argv[0];
this.wallet.removeKey(this.config.account, key, function(err) {
if (err)
return callback(err);
self.log('removed');
callback();
});
};
yield this.wallet.removeKey(this.config.account, key);
this.log('removed');
});
CLI.prototype.getAccount = function getAccount(callback) {
var self = this;
CLI.prototype.getAccount = co(function* getAccount() {
var account = this.argv[0] || this.config.account;
this.wallet.getAccount(account, function(err, account) {
if (err)
return callback(err);
self.log(account);
callback();
});
};
yield this.wallet.getAccount(account);
this.log(account);
});
CLI.prototype.createAccount = function createAccount(callback) {
var self = this;
CLI.prototype.createAccount = co(function* createAccount() {
var name = this.argv[0];
var account = yield this.wallet.createAccount(name);
this.log(account);
});
CLI.prototype.createAddress = co(function* createAddress() {
var account = this.argv[0];
this.wallet.createAccount(account, function(err, account) {
if (err)
return callback(err);
self.log(account);
callback();
});
};
var addr = yield this.wallet.createAddress(account);
this.log(addr);
});
CLI.prototype.createAddress = function createAddress(callback) {
var self = this;
CLI.prototype.createNested = co(function* createNested() {
var account = this.argv[0];
this.wallet.createAddress(account, function(err, account) {
if (err)
return callback(err);
self.log(account);
callback();
});
};
var addr = yield this.wallet.createNested(account);
this.log(addr);
});
CLI.prototype.getAccounts = function getAccounts(callback) {
var self = this;
this.wallet.getAccounts(function(err, accounts) {
if (err)
return callback(err);
self.log(accounts);
callback();
});
};
CLI.prototype.getAccounts = co(function* getAccounts() {
var accounts = yield this.wallet.getAccounts();
this.log(accounts);
});
CLI.prototype.getWallet = function getWallet(callback) {
var self = this;
this.wallet.getInfo(function(err, wallet) {
if (err)
return callback(err);
self.log(wallet);
callback();
});
};
CLI.prototype.getWallet = co(function* getWallet() {
var info = yield this.wallet.getInfo();
this.log(info);
});
CLI.prototype.getTX = function getTX(callback) {
var self = this;
CLI.prototype.getTX = co(function* getTX() {
var hash = this.argv[0];
var txs, tx;
if (utils.isBase58(hash)) {
return this.client.getTXByAddress(hash, function(err, txs) {
if (err)
return callback(err);
self.log(txs);
callback();
});
txs = yield this.client.getTXByAddress(hash);
this.log(txs);
return;
}
this.client.getTX(hash, function(err, tx) {
if (err)
return callback(err);
if (!tx) {
self.log('TX not found.');
return callback();
}
tx = yield this.client.getTX(hash);
self.log(tx);
callback();
});
};
if (!tx) {
this.log('TX not found.');
return;
}
CLI.prototype.getBlock = function getBlock(callback) {
var self = this;
this.log(tx);
});
CLI.prototype.getBlock = co(function* getBlock() {
var hash = this.argv[0];
if (hash.length !== 64)
hash = +hash;
this.client.getBlock(hash, function(err, block) {
if (err)
return callback(err);
if (!block) {
self.log('Block not found.');
return callback();
}
block = yield this.client.getBlock(hash);
self.log(block);
callback();
});
};
if (!block) {
this.log('Block not found.');
return
}
CLI.prototype.getCoin = function getCoin(callback) {
var self = this;
this.log(block);
});
CLI.prototype.getCoin = co(function* getCoin() {
var hash = this.argv[0];
var index = this.argv[1];
var coins, coin;
if (utils.isBase58(hash)) {
return this.client.getCoinsByAddress(hash, function(err, coins) {
if (err)
return callback(err);
self.log(coins);
callback();
});
coins = yield this.client.getCoinsByAddress(hash);
this.log(coins);
return;
}
this.client.getCoin(hash, index, function(err, coin) {
if (err)
return callback(err);
if (!coin) {
self.log('Coin not found.');
return callback();
}
coin = yield this.client.getCoin(hash, index);
self.log(coin);
callback();
});
};
if (!coin) {
this.log('Coin not found.');
return;
}
CLI.prototype.getWalletHistory = function getWalletHistory(callback) {
var self = this;
this.wallet.getHistory(this.config.account, function(err, txs) {
if (err)
return callback(err);
self.log(txs);
callback();
});
};
this.log(coin);
});
CLI.prototype.listenWallet = function listenWallet(callback) {
CLI.prototype.getWalletHistory = co(function* getWalletHistory() {
var txs = yield this.wallet.getHistory(this.config.account);
this.log(txs);
});
CLI.prototype.listenWallet = function listenWallet() {
var self = this;
this.wallet.on('tx', function(details) {
self.log('TX:');
@ -240,32 +190,22 @@ CLI.prototype.listenWallet = function listenWallet(callback) {
self.log('Balance:');
self.log(balance);
});
return new Promise(function() {});
};
CLI.prototype.getBalance = function getBalance(callback) {
var self = this;
this.wallet.getBalance(this.config.account, function(err, balance) {
if (err)
return callback(err);
self.log(balance);
callback();
});
};
CLI.prototype.getBalance = co(function* getBalance() {
var balance = yield this.wallet.getBalance(this.config.account);
this.log(balance);
});
CLI.prototype.getMempool = function getMempool(callback) {
var self = this;
this.client.getMempool(function(err, txs) {
if (err)
return callback(err);
self.log(txs);
callback();
});
};
CLI.prototype.getMempool = co(function* getMempool() {
var txs = yield this.client.getMempool();
this.log(txs);
});
CLI.prototype.sendTX = function sendTX(callback) {
var self = this;
CLI.prototype.sendTX = co(function* sendTX() {
var output = {};
var options;
var options, tx;
if (this.config.script) {
output.script = this.config.script;
@ -281,18 +221,14 @@ CLI.prototype.sendTX = function sendTX(callback) {
outputs: [output]
};
this.wallet.send(options, function(err, tx) {
if (err)
return callback(err);
self.log(tx);
callback();
});
};
tx = yield this.wallet.send(options);
CLI.prototype.createTX = function createTX(callback) {
var self = this;
this.log(tx);
});
CLI.prototype.createTX = co(function* createTX() {
var output = {};
var options;
var options, tx;
if (this.config.script) {
output.script = this.config.script;
@ -308,86 +244,53 @@ CLI.prototype.createTX = function createTX(callback) {
outputs: [output]
};
this.wallet.createTX(options, function(err, tx) {
if (err)
return callback(err);
self.log(tx);
callback();
});
};
tx = yield this.wallet.createTX(options);
CLI.prototype.signTX = function signTX(callback) {
var self = this;
this.log(tx);
});
CLI.prototype.signTX = co(function* signTX() {
var options = { passphrase: this.config.passphrase };
var tx = options.tx || this.argv[0];
this.wallet.sign(tx, options, function(err, tx) {
if (err)
return callback(err);
self.log(tx);
callback();
});
};
var raw = options.tx || this.argv[0];
var tx = yield this.wallet.sign(raw, options);
this.log(tx);
});
CLI.prototype.zap = function zap(callback) {
var self = this;
CLI.prototype.zap = co(function* zap() {
var age = (this.config.age >>> 0) || 72 * 60 * 60;
this.wallet.zap(this.config.account, age, function(err) {
if (err)
return callback(err);
self.log('Zapped!');
callback();
});
};
yield this.wallet.zap(this.config.account, age);
this.log('Zapped!');
});
CLI.prototype.broadcast = function broadcast(callback) {
CLI.prototype.broadcast = co(function* broadcast() {
var self = this;
var tx = this.argv[0] || this.config.tx;
this.client.broadcast(tx, function(err, tx) {
if (err)
return callback(err);
self.log('Broadcasted:');
self.log(tx);
callback();
});
};
var raw = this.argv[0] || this.config.tx;
var tx = yield this.client.broadcast(raw);
this.log('Broadcasted:');
this.log(tx);
});
CLI.prototype.viewTX = function viewTX(callback) {
var self = this;
var tx = this.argv[0] || this.config.tx;
this.wallet.fill(tx, function(err, tx) {
if (err)
return callback(err);
self.log(tx);
callback();
});
};
CLI.prototype.viewTX = co(function* viewTX() {
var raw = this.argv[0] || this.config.tx;
var tx = yield this.wallet.fill(raw);
this.log(tx);
});
CLI.prototype.getDetails = function getDetails(callback) {
var self = this;
CLI.prototype.getDetails = co(function* getDetails() {
var hash = this.argv[0];
this.wallet.getTX(hash, function(err, tx) {
if (err)
return callback(err);
self.log(tx);
callback();
});
};
var details = yield this.wallet.getTX(hash);
this.log(details);
});
CLI.prototype.retoken = function retoken(callback) {
var self = this;
this.wallet.retoken(function(err, result) {
if (err)
return callback(err);
self.log(result);
callback();
});
};
CLI.prototype.retoken = co(function* retoken() {
var result = yield this.wallet.retoken();
this.log(result);
});
CLI.prototype.rpc = function rpc(callback) {
var self = this;
CLI.prototype.rpc = co(function* rpc() {
var method = this.argv.shift();
var params = [];
var i, arg, param;
var i, arg, param, result;
for (i = 0; i < this.argv.length; i++) {
arg = this.argv[i];
@ -399,17 +302,12 @@ CLI.prototype.rpc = function rpc(callback) {
params.push(param);
}
this.client.rpc.call(method, params, function(err, result) {
if (err)
return callback(err);
self.log(result);
callback();
});
};
result = yield this.client.rpc.call(method, params);
CLI.prototype.handleWallet = function handleWallet(callback) {
var self = this;
this.log(result);
});
CLI.prototype.handleWallet = co(function* handleWallet() {
var options = {
id: this.config.id || 'primary',
token: this.config.token
@ -421,81 +319,81 @@ CLI.prototype.handleWallet = function handleWallet(callback) {
network: this.config.network
});
this.wallet.open(options, function(err) {
if (err)
return callback(err);
yield this.wallet.open(options);
switch (self.argv.shift()) {
case 'listen':
return self.listenWallet(callback);
case 'get':
return self.getWallet(callback);
case 'addkey':
return self.addKey(callback);
case 'rmkey':
return self.removeKey(callback);
case 'balance':
return self.getBalance(callback);
case 'history':
return self.getWalletHistory(callback);
case 'account':
if (self.argv[0] === 'list') {
self.argv.shift();
return self.getAccounts(callback);
}
if (self.argv[0] === 'create') {
self.argv.shift();
return self.createAccount(callback);
}
if (self.argv[0] === 'get')
self.argv.shift();
return self.getAccount(callback);
case 'address':
return self.createAddress(callback);
case 'retoken':
return self.retoken(callback);
case 'sign':
return self.signTX(callback);
case 'mktx':
return self.createTX(callback);
case 'send':
return self.sendTX(callback);
case 'zap':
return self.zap(callback);
case 'tx':
return self.getDetails(callback);
case 'view':
return self.viewTX(callback);
default:
self.log('Unrecognized command.');
self.log('Commands:');
self.log(' $ listen: Listen for events.');
self.log(' $ get: View wallet.');
self.log(' $ addkey [xpubkey]: Add key to wallet.');
self.log(' $ rmkey [xpubkey]: Remove key from wallet.');
self.log(' $ balance: Get wallet balance.');
self.log(' $ history: View wallet TX history.');
self.log(' $ account list: List account names.');
self.log(' $ account create [account-name]: Create account.');
self.log(' $ account get [account-name]: Get account details.');
self.log(' $ address: Derive new address.');
self.log(' $ retoken: Create new api key.');
self.log(' $ send [address] [value]: Send transaction.');
self.log(' $ mktx [address] [value]: Create transaction.');
self.log(' $ sign [tx-hex]: Sign transaction.');
self.log(' $ zap --age [age]: Zap pending wallet TXs.');
self.log(' $ tx [hash]: View transaction details.');
self.log(' $ view [tx-hex]: Parse and view transaction.');
self.log('Other Options:');
self.log(' --passphrase [passphrase]: For signing and account creation.');
self.log(' --account [account-name]: Account name.');
return callback();
}
});
};
switch (this.argv.shift()) {
case 'listen':
return yield this.listenWallet();
case 'get':
return yield this.getWallet();
case 'addkey':
return yield this.addKey();
case 'rmkey':
return yield this.removeKey();
case 'balance':
return yield this.getBalance();
case 'history':
return yield this.getWalletHistory();
case 'account':
if (this.argv[0] === 'list') {
this.argv.shift();
return yield this.getAccounts();
}
if (this.argv[0] === 'create') {
this.argv.shift();
return yield this.createAccount();
}
if (this.argv[0] === 'get')
this.argv.shift();
return yield this.getAccount();
case 'address':
return yield this.createAddress();
case 'nested':
return yield this.createNested();
case 'retoken':
return yield this.retoken();
case 'sign':
return yield this.signTX();
case 'mktx':
return yield this.createTX();
case 'send':
return yield this.sendTX();
case 'zap':
return yield this.zap();
case 'tx':
return yield this.getDetails();
case 'view':
return yield this.viewTX();
default:
this.log('Unrecognized command.');
this.log('Commands:');
this.log(' $ listen: Listen for events.');
this.log(' $ get: View wallet.');
this.log(' $ addkey [xpubkey]: Add key to wallet.');
this.log(' $ rmkey [xpubkey]: Remove key from wallet.');
this.log(' $ balance: Get wallet balance.');
this.log(' $ history: View wallet TX history.');
this.log(' $ account list: List account names.');
this.log(' $ account create [account-name]: Create account.');
this.log(' $ account get [account-name]: Get account details.');
this.log(' $ address: Derive new address.');
this.log(' $ nested: Derive new nested address.');
this.log(' $ retoken: Create new api key.');
this.log(' $ send [address] [value]: Send transaction.');
this.log(' $ mktx [address] [value]: Create transaction.');
this.log(' $ sign [tx-hex]: Sign transaction.');
this.log(' $ zap --age [age]: Zap pending wallet TXs.');
this.log(' $ tx [hash]: View transaction details.');
this.log(' $ view [tx-hex]: Parse and view transaction.');
this.log('Other Options:');
this.log(' --passphrase [passphrase]: For signing and account creation.');
this.log(' --account [account-name]: Account name.');
return;
}
});
CLI.prototype.handleNode = function handleNode(callback) {
var self = this;
CLI.prototype.handleNode = co(function* handleNode() {
var info;
this.client = new Client({
uri: this.config.url || this.config.uri,
@ -503,75 +401,67 @@ CLI.prototype.handleNode = function handleNode(callback) {
network: this.config.network
});
this.client.getInfo(function(err, info) {
if (err)
return callback(err);
info = yield this.client.getInfo();
switch (self.argv.shift()) {
case 'mkwallet':
return self.createWallet(callback);
case 'broadcast':
return self.broadcast(callback);
case 'mempool':
return self.getMempool(callback);
case 'tx':
return self.getTX(callback);
case 'coin':
return self.getCoin(callback);
case 'block':
return self.getBlock(callback);
case 'rpc':
return self.rpc(callback);
default:
self.log('Unrecognized command.');
self.log('Commands:');
self.log(' $ wallet create [id]: Create wallet.');
self.log(' $ broadcast [tx-hex]: Broadcast transaction.');
self.log(' $ mempool: Get mempool snapshot.');
self.log(' $ tx [hash/address]: View transactions.');
self.log(' $ coin [hash+index/address]: View coins.');
self.log(' $ block [hash/height]: View block.');
return callback();
}
});
};
switch (this.argv.shift()) {
case 'mkwallet':
return yield this.createWallet();
case 'broadcast':
return yield this.broadcast();
case 'mempool':
return yield this.getMempool();
case 'tx':
return yield this.getTX();
case 'coin':
return yield this.getCoin();
case 'block':
return yield this.getBlock();
case 'rpc':
return yield this.rpc();
default:
this.log('Unrecognized command.');
this.log('Commands:');
this.log(' $ wallet create [id]: Create wallet.');
this.log(' $ broadcast [tx-hex]: Broadcast transaction.');
this.log(' $ mempool: Get mempool snapshot.');
this.log(' $ tx [hash/address]: View transactions.');
this.log(' $ coin [hash+index/address]: View coins.');
this.log(' $ block [hash/height]: View block.');
this.log(' $ rpc [command] [args]: Execute RPC command.');
return;
}
});
CLI.prototype.open = function open(callback) {
CLI.prototype.open = co(function* open() {
switch (this.argv[0]) {
case 'w':
case 'wallet':
this.argv.shift();
if (this.argv[0] === 'create') {
this.argv[0] = 'mkwallet';
return this.handleNode(callback);
return yield this.handleNode();
}
return this.handleWallet(callback);
return yield this.handleWallet();
default:
return this.handleNode(callback);
return yield this.handleNode();
}
};
});
CLI.prototype.destroy = function destroy(callback) {
CLI.prototype.destroy = function destroy() {
if (this.wallet && !this.wallet.client.loading)
this.wallet.client.destroy();
if (this.client && !this.client.loading)
this.client.destroy();
callback();
return Promise.resolve(null);
};
function main(callback) {
main = co(function* main() {
var cli = new CLI();
cli.open(function(err) {
if (err)
return callback(err);
cli.destroy(callback);
});
}
main(function(err) {
if (err) {
console.error(err.stack + '');
return process.exit(1);
}
return process.exit(0);
yield cli.open();
yield cli.destroy();
});
main().then(process.exit).catch(function(err) {
console.error(err.stack + '');
return process.exit(1);
});

View file

@ -6,7 +6,7 @@ process.title = 'bcoin';
var bcoin = require('../');
var utils = bcoin.utils;
var assert = utils.assert;
var assert = require('assert');
var options = bcoin.config({
config: true,
@ -32,10 +32,7 @@ process.on('uncaughtException', function(err) {
process.exit(1);
});
node.open(function(err) {
if (err)
throw err;
node.open().then(function() {
node.pool.connect();
node.startSync();
});

View file

@ -6,7 +6,7 @@ process.title = 'bcoin';
var bcoin = require('../');
var utils = bcoin.utils;
var assert = utils.assert;
var assert = require('assert');
var options = bcoin.config({
config: true,
@ -25,10 +25,13 @@ node.on('error', function(err) {
;
});
node.open(function(err) {
if (err)
throw err;
process.on('uncaughtException', function(err) {
node.logger.debug(err.stack);
node.logger.error(err);
process.exit(1);
});
node.open().then(function() {
if (process.argv.indexOf('--test') !== -1) {
node.pool.watchAddress('1VayNert3x1KzbpzMGt2qdqrAThiRovi8');
node.pool.watch(bcoin.outpoint().toRaw());

View file

@ -32,7 +32,7 @@
margin-top: 10px;
font: 1em monospace;
}
.send {
.rpc, .send {
padding: 5px;
margin-left: 5px;
margin-top: 10px;
@ -84,6 +84,10 @@ more bitcoin magic).</small>
<div id="tx"></div>
</div>
<div id="log" class="log"></div>
<form id="rpc" class="rpc" action="#">
<input type="text" name="cmd" id="cmd"
placeholder="RPC command (e.g. getblockchaininfo)">
</form>
<div id="wallet" class="wallet"></div>
<form id="send" class="send" action="#">
<input type="text" name="address" id="address" placeholder="Address">
@ -92,220 +96,6 @@ more bitcoin magic).</small>
</form>
<input type="button" id="newaddr" value="New Address">
<div id="floating" class="floating"></div>
<script>
;(function() {
'use strict';
var utils = bcoin.utils;
var body = document.getElementsByTagName('body')[0];
var log = document.getElementById('log');
var wdiv = document.getElementById('wallet');
var tdiv = document.getElementById('tx');
var floating = document.getElementById('floating');
var send = document.getElementById('send');
var newaddr = document.getElementById('newaddr');
var chainState = document.getElementById('state');
var items = [];
var scrollback = 0;
var logger, node, options;
body.onmouseup = function() {
floating.style.display = 'none';
};
floating.onmouseup = function(ev) {
ev.stopPropagation();
return false;
};
function show(obj) {
floating.innerHTML = escape(utils.inspectify(obj, false));
floating.style.display = 'block';
}
logger = new bcoin.logger({ level: 'debug' });
logger.writeConsole = function(level, args) {
var msg = utils.format(args, false);
if (++scrollback > 1000) {
log.innerHTML = '';
scrollback = 1;
}
log.innerHTML += '<span style="color:blue;">' + utils.now() + '</span> ';
if (level === 'error')
log.innerHTML += '<span style="color:red;">[' + level + ']</span> ';
else
log.innerHTML += '[' + level + '] ';
log.innerHTML += escape(msg) + '\n';
log.scrollTop = log.scrollHeight;
};
send.onsubmit = function(ev) {
var value = document.getElementById('amount').value;
var address = document.getElementById('address').value;
var options = {
outputs: [{
address: address,
value: utils.satoshi(value)
}]
};
node.wallet.createTX(options, function(err, tx) {
if (err)
return node.logger.error(err);
node.wallet.sign(tx, function(err) {
if (err)
return node.logger.error(err);
node.sendTX(tx, function(err) {
if (err)
return node.logger.error(err);
show(tx);
});
});
});
ev.preventDefault();
ev.stopPropagation();
return false;
};
newaddr.onmouseup = function() {
node.wallet.createReceive(function(err) {
if (err)
throw err;
formatWallet(node.wallet);
});
};
function kb(size) {
size /= 1000;
return size.toFixed(2) + 'kb';
}
function create(html) {
var el = document.createElement('div');
el.innerHTML = html;
return el.firstChild;
}
function escape(html, encode) {
return html
.replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function addItem(tx) {
var el;
if (items.length === 20) {
el = items.shift();
tdiv.removeChild(el);
el.onmouseup = null;
}
el = create('<a style="display:block;" href="#'
+ tx.rhash + '">' + tx.rhash + ' (' + tx.height
+ ' - ' + kb(tx.getSize()) + ')</a>');
tdiv.appendChild(el);
el.onmouseup = function(ev) {
show(tx);
ev.stopPropagation();
return false;
};
items.push(el);
chainState.innerHTML = ''
+ 'tx=' + node.chain.db.state.tx
+ ' coin=' + node.chain.db.state.coin
+ ' value=' + utils.btc(node.chain.db.state.value);
}
function formatWallet(wallet) {
var html = '';
var key = wallet.master.toJSON().key;
html += '<b>Wallet</b><br>';
if (bcoin.network.get().type === 'segnet4') {
html += 'Current Address (p2wpkh): <b>' + wallet.getAddress() + '</b><br>';
html += 'Current Address (p2wpkh behind p2sh): <b>' + wallet.getProgramAddress() + '</b><br>';
} else {
html += 'Current Address: <b>' + wallet.getAddress() + '</b><br>';
}
html += 'Extended Private Key: <b>' + key.xprivkey + '</b><br>';
html += 'Mnemonic: <b>' + key.mnemonic.phrase + '</b><br>';
wallet.getBalance(function(err, balance) {
if (err)
throw err;
html += 'Confirmed Balance: <b>' + utils.btc(balance.confirmed) + '</b><br>';
html += 'Unconfirmed Balance: <b>' + utils.btc(balance.unconfirmed) + '</b><br>';
html += 'Balance: <b>' + utils.btc(balance.total) + '</b><br>';
wallet.getHistory(function(err, txs) {
if (err)
throw err;
wallet.toDetails(txs, function(err, txs) {
if (err)
throw err;
html += 'TXs:\n';
wdiv.innerHTML = html;
txs.forEach(function(tx) {
var el = create('<a style="display:block;" href="#' + tx.hash + '">' + tx.hash + '</a>');
wdiv.appendChild(el);
el.onmouseup = function(ev) {
show(tx.toJSON());
ev.stopPropagation();
return false;
};
});
});
});
});
}
options = bcoin.config({
query: true,
network: 'segnet4',
db: 'leveldb',
useWorkers: true,
coinCache: true,
logger: logger
});
bcoin.set(options);
node = new bcoin.fullnode(options);
node.on('error', function(err) {
;
});
node.chain.on('block', addItem);
node.mempool.on('tx', addItem);
node.open(function(err) {
if (err)
throw err;
node.startSync();
formatWallet(node.wallet);
node.wallet.on('update', function() {
formatWallet(node.wallet);
});
});
})();
</script>
<script src="/index.js"></script>
</body>
</html>

245
browser/index.js Normal file
View file

@ -0,0 +1,245 @@
;(function() {
'use strict';
var utils = bcoin.utils;
var body = document.getElementsByTagName('body')[0];
var log = document.getElementById('log');
var wdiv = document.getElementById('wallet');
var tdiv = document.getElementById('tx');
var floating = document.getElementById('floating');
var send = document.getElementById('send');
var newaddr = document.getElementById('newaddr');
var chainState = document.getElementById('state');
var rpc = document.getElementById('rpc');
var cmd = document.getElementById('cmd');
var items = [];
var scrollback = 0;
var logger, node, options;
body.onmouseup = function() {
floating.style.display = 'none';
};
floating.onmouseup = function(ev) {
ev.stopPropagation();
return false;
};
function show(obj) {
floating.innerHTML = escape(utils.inspectify(obj, false));
floating.style.display = 'block';
}
logger = new bcoin.logger({ level: 'debug' });
logger.writeConsole = function(level, args) {
var msg = utils.format(args, false);
if (++scrollback > 1000) {
log.innerHTML = '';
scrollback = 1;
}
log.innerHTML += '<span style="color:blue;">' + utils.now() + '</span> ';
if (level === 'error')
log.innerHTML += '<span style="color:red;">[' + level + ']</span> ';
else
log.innerHTML += '[' + level + '] ';
log.innerHTML += escape(msg) + '\n';
log.scrollTop = log.scrollHeight;
};
rpc.onsubmit = function(ev) {
var text = cmd.value || '';
var argv = text.trim().split(/\s+/);
var method = argv.shift();
var params = [];
var i, arg, param;
cmd.value = '';
for (i = 0; i < argv.length; i++) {
arg = argv[i];
try {
param = JSON.parse(arg);
} catch (e) {
param = arg;
}
params.push(param);
}
node.rpc.execute({ method: method, params: params }).then(show, show);
ev.preventDefault();
ev.stopPropagation();
return false;
};
send.onsubmit = function(ev) {
var value = document.getElementById('amount').value;
var address = document.getElementById('address').value;
var tx, options;
options = {
outputs: [{
address: address,
value: utils.satoshi(value)
}]
};
node.wallet.createTX(options).then(function(mtx) {
tx = mtx;
return node.wallet.sign(tx);
}).then(function() {
return node.sendTX(tx);
}).then(function() {
show(tx);
});
ev.preventDefault();
ev.stopPropagation();
return false;
};
newaddr.onmouseup = function() {
node.wallet.createReceive().then(function() {
formatWallet(node.wallet);
});
};
function kb(size) {
size /= 1000;
return size.toFixed(2) + 'kb';
}
function create(html) {
var el = document.createElement('div');
el.innerHTML = html;
return el.firstChild;
}
function escape(html, encode) {
return html
.replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function addItem(tx) {
var el;
if (items.length === 20) {
el = items.shift();
tdiv.removeChild(el);
el.onmouseup = null;
}
el = create('<a style="display:block;" href="#'
+ tx.rhash + '">' + tx.rhash + ' (' + tx.height
+ ' - ' + kb(tx.getSize()) + ')</a>');
tdiv.appendChild(el);
setMouseup(el, tx);
items.push(el);
chainState.innerHTML = ''
+ 'tx=' + node.chain.db.state.tx
+ ' coin=' + node.chain.db.state.coin
+ ' value=' + utils.btc(node.chain.db.state.value);
}
function setMouseup(el, obj) {
el.onmouseup = function(ev) {
show(obj);
ev.stopPropagation();
return false;
};
}
function formatWallet(wallet) {
var html = '';
var key = wallet.master.toJSON().key;
var i, tx, el;
html += '<b>Wallet</b><br>';
if (bcoin.network.primary.witness) {
html += 'Current Address (p2wpkh): <b>'
+ wallet.getAddress()
+ '</b><br>';
html += 'Current Address (p2wpkh behind p2sh): <b>'
+ wallet.getProgramAddress()
+ '</b><br>';
} else {
html += 'Current Address: <b>' + wallet.getAddress() + '</b><br>';
}
html += 'Extended Private Key: <b>' + key.xprivkey + '</b><br>';
html += 'Mnemonic: <b>' + key.mnemonic.phrase + '</b><br>';
wallet.getBalance().then(function(balance) {
html += 'Confirmed Balance: <b>'
+ utils.btc(balance.confirmed)
+ '</b><br>';
html += 'Unconfirmed Balance: <b>'
+ utils.btc(balance.unconfirmed)
+ '</b><br>';
html += 'Balance: <b>' + utils.btc(balance.total) + '</b><br>';
return wallet.getHistory();
}).then(function(txs) {
return wallet.toDetails(txs);
}).then(function(txs) {
html += 'TXs:\n';
wdiv.innerHTML = html;
for (i = 0; i < txs.length; i++) {
tx = txs[i];
el = create(
'<a style="display:block;" href="#' + tx.hash + '">'
+ tx.hash + '</a>');
wdiv.appendChild(el);
setMouseup(el, tx.toJSON());
}
});
}
options = bcoin.config({
query: true,
network: 'segnet4',
db: 'leveldb',
useWorkers: true,
coinCache: true,
logger: logger
});
bcoin.set(options);
node = new bcoin.fullnode(options);
node.rpc = new bcoin.rpc(node);
node.on('error', function(err) {
;
});
node.chain.on('block', addItem);
node.mempool.on('tx', addItem);
node.open().then(function() {
node.startSync();
formatWallet(node.wallet);
node.wallet.on('balance', function() {
formatWallet(node.wallet);
});
});
})();

View file

@ -15,22 +15,27 @@ proxy.on('error', function(err) {
});
var index = fs.readFileSync(__dirname + '/index.html');
var indexjs = fs.readFileSync(__dirname + '/index.js');
var bcoin = fs.readFileSync(__dirname + '/bcoin.js');
var worker = fs.readFileSync(__dirname + '/../lib/workers/worker.js');
server.get('/favicon.ico', function(req, res, next, send) {
server.get('/favicon.ico', function(req, res, send, next) {
send(404, '', 'text');
});
server.get('/', function(req, res, next, send) {
server.get('/', function(req, res, send, next) {
send(200, index, 'html');
});
server.get('/bcoin.js', function(req, res, next, send) {
server.get('/index.js', function(req, res, send, next) {
send(200, indexjs, 'js');
});
server.get('/bcoin.js', function(req, res, send, next) {
send(200, bcoin, 'js');
});
server.get('/bcoin-worker.js', function(req, res, next, send) {
server.get('/bcoin-worker.js', function(req, res, send, next) {
send(200, worker, 'js');
});

75
browser/transform.js Normal file
View file

@ -0,0 +1,75 @@
var Transform = require('stream').Transform;
var path = require('path');
var assert = require('assert');
var fs = require('fs');
var StringDecoder = require('string_decoder').StringDecoder;
function nil() {
var stream = new Transform();
stream._transform = function(chunk, encoding, callback) {
callback(null, chunk);
};
stream._flush = function(callback) {
callback();
};
return stream;
}
function processEnv(str) {
return str.replace(
/^( *)this\.require\('(\w+)', '([^']+)'\)/gm,
'$1this.$2 = require(\'$3\')');
}
function processLazy(str) {
str.replace(
/^( *)lazy\('(\w+)', '([^']+)'\)/gm,
function(_, sp, w1, w2) {
str += sp + 'if (0) require(\'' + w2 + '\');\n';
return '';
}
);
return str;
}
function transformer(file, process) {
var stream = new Transform();
var decoder = new StringDecoder('utf8');
var str = '';
stream._transform = function(chunk, encoding, callback) {
assert(Buffer.isBuffer(chunk));
str += decoder.write(chunk);
callback(null, new Buffer(0));
};
stream._flush = function(callback) {
str = process(str);
stream.push(new Buffer(str, 'utf8'));
callback();
};
return stream;
}
function end(file, offset) {
return path.normalize(file).split(path.sep).slice(-offset).join('/');
}
module.exports = function(file) {
if (end(file, 3) === 'lib/utils/utils.js')
return transformer(file, processLazy);
if (end(file, 3) === 'lib/crypto/crypto.js')
return transformer(file, processLazy);
if (end(file, 2) === 'lib/env.js')
return transformer(file, processEnv);
return nil();
};

View file

@ -52,7 +52,6 @@ known-peers: ./known-peers
# Miner
# payout-address: 1111111111111111111114oLvT2
# coinbase-flags: mined by bcoin
# parallel: false
# HTTP
# ssl-cert: @/ssl/cert.crt

View file

@ -1,589 +0,0 @@
/*!
* bip70.js - bip70 for bcoin
* Copyright (c) 2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var bcoin = require('../env');
var assert = require('assert');
var utils = bcoin.utils;
var crypto = require('../crypto/crypto');
var x509 = require('./x509');
var asn1 = require('./asn1');
var protobuf = require('./protobuf');
var ProtoReader = protobuf.ProtoReader;
var ProtoWriter = protobuf.ProtoWriter;
function PaymentRequest(options) {
if (!(this instanceof PaymentRequest))
return new PaymentRequest(options);
this.version = -1;
this.pkiType = null;
this.pkiData = null;
this.paymentDetails = new PaymentDetails();
this.signature = null;
if (options)
this.fromOptions(options);
}
PaymentRequest.prototype.fromOptions = function fromOptions(options) {
if (options.version != null) {
assert(utils.isNumber(options.version));
this.version = options.version;
}
if (options.pkiType != null) {
assert(typeof options.pkiType === 'string');
this.pkiType = options.pkiType;
}
if (options.pkiData) {
assert(Buffer.isBuffer(options.pkiData));
this.pkiData = options.pkiData;
}
if (options.paymentDetails)
this.paymentDetails.fromOptions(options.paymentDetails);
if (options.signature) {
assert(Buffer.isBuffer(options.signature));
this.signature = options.signature;
}
if (options.chain)
this.setChain(options.chain);
return this;
};
PaymentRequest.fromOptions = function fromOptions(options) {
return new PaymentRequest().fromOptions(options);
};
PaymentRequest.prototype.fromRaw = function fromRaw(data) {
var p = new ProtoReader(data);
this.version = p.readFieldU32(1, true);
this.pkiType = p.readFieldString(2, true);
this.pkiData = p.readFieldBytes(3, true);
this.paymentDetails.fromRaw(p.readFieldBytes(4));
this.signature = p.readFieldBytes(5, true);
return this;
};
PaymentRequest.fromRaw = function fromRaw(data, enc) {
if (typeof data === 'string')
data = new Buffer(data, enc);
return new PaymentRequest().fromRaw(data);
};
PaymentRequest.prototype.toRaw = function toRaw(writer) {
var p = new ProtoWriter(writer);
if (this.version !== -1)
p.writeFieldU32(1, this.version);
if (this.pkiType != null)
p.writeFieldString(2, this.pkiType);
if (this.pkiData)
p.writeFieldBytes(3, this.pkiData);
p.writeFieldBytes(4, this.paymentDetails.toRaw());
if (this.signature)
p.writeFieldBytes(5, this.signature);
if (!writer)
p = p.render();
return p;
};
PaymentRequest.prototype.getAlgorithm = function getAlgorithm() {
var parts;
if (!this.pkiType)
return;
parts = this.pkiType.split('+');
if (parts.length !== 2)
return;
if (parts[0] !== 'x509')
return;
if (parts[1] !== 'sha1' && parts[1] !== 'sha256')
return;
return { key: parts[0], hash: parts[1] };
};
PaymentRequest.prototype.signatureData = function signatureData() {
var signature = this.signature;
var data;
this.signature = new Buffer(0);
data = this.toRaw();
this.signature = signature;
return data;
};
PaymentRequest.prototype.signatureHash = function signatureHash() {
var alg = this.getAlgorithm();
assert(alg, 'No hash algorithm available.');
return crypto.hash(alg.hash, this.signatureData());
};
PaymentRequest.prototype.setChain = function setChain(chain) {
var p = new ProtoWriter();
var i, cert, pem;
if (!Array.isArray(chain))
chain = [chain];
for (i = 0; i < chain.length; i++) {
cert = chain[i];
if (typeof cert === 'string') {
pem = asn1.fromPEM(cert);
assert(pem.type === 'certificate', 'Bad certificate PEM.');
cert = pem.data;
}
assert(Buffer.isBuffer(cert), 'Certificates must be PEM or DER.');
p.writeFieldBytes(1, cert);
}
this.pkiData = p.render();
};
PaymentRequest.prototype.getChain = function getChain() {
var chain = [];
var p;
if (!this.pkiData)
return chain;
p = new ProtoReader(this.pkiData);
while (p.nextTag() === 1)
chain.push(p.readFieldBytes(1));
return chain;
};
PaymentRequest.prototype.sign = function sign(key, chain) {
var alg, msg;
if (chain)
this.setChain(chain);
if (!this.pkiType)
this.pkiType = 'x509+sha256';
alg = this.getAlgorithm();
assert(alg, 'No hash algorithm available.');
msg = this.signatureData();
chain = this.getChain();
this.signature = x509.signSubject(alg.hash, msg, key, chain);
};
PaymentRequest.prototype.verify = function verify() {
var alg, msg, sig, chain;
if (!this.pkiType || this.pkiType === 'none')
return true;
if (!this.signature)
return false;
alg = this.getAlgorithm();
if (!alg)
return false;
msg = this.signatureData();
sig = this.signature;
chain = this.getChain();
return x509.verifySubject(alg.hash, msg, sig, chain);
};
PaymentRequest.prototype.verifyChain = function verifyChain() {
if (!this.pkiType || this.pkiType === 'none')
return true;
return x509.verifyChain(this.getChain());
};
PaymentRequest.prototype.getCA = function getCA() {
var chain, root;
if (!this.pkiType || this.pkiType === 'none')
return;
chain = this.getChain();
if (chain.length === 0)
return;
root = x509.parse(chain[chain.length - 1]);
if (!root)
return;
return {
name: x509.getCAName(root),
trusted: x509.isTrusted(root),
cert: root
};
};
function PaymentDetails(options) {
if (!(this instanceof PaymentDetails))
return new PaymentDetails(options);
this.network = null;
this.outputs = [];
this.time = utils.now();
this.expires = -1;
this.memo = null;
this.paymentUrl = null;
this.merchantData = null;
if (options)
this.fromOptions(options);
}
PaymentDetails.prototype.fromOptions = function fromOptions(options) {
var i, output;
if (options.network != null) {
assert(typeof options.network === 'string');
this.network = options.network;
}
if (options.outputs) {
assert(Array.isArray(options.outputs));
for (i = 0; i < options.outputs.length; i++) {
output = new bcoin.output(options.outputs[i]);
this.outputs.push(output);
}
}
if (options.time != null) {
assert(utils.isNumber(options.time));
this.time = options.time;
}
if (options.expires != null) {
assert(utils.isNumber(options.expires));
this.expires = options.expires;
}
if (options.memo != null) {
assert(typeof options.memo === 'string');
this.memo = options.memo;
}
if (options.paymentUrl != null) {
assert(typeof options.paymentUrl === 'string');
this.paymentUrl = options.paymentUrl;
}
if (options.merchantData)
this.setData(options.merchantData);
return this;
};
PaymentDetails.fromOptions = function fromOptions(options) {
return new PaymentDetails().fromOptions(options);
};
PaymentDetails.prototype.isExpired = function isExpired() {
if (this.expires === -1)
return false;
return utils.now() > this.expires;
};
PaymentDetails.prototype.setData = function setData(data, enc) {
if (data == null || Buffer.isBuffer(data)) {
this.merchantData = data;
return;
}
if (typeof data !== 'string') {
assert(!enc || enc === 'json');
this.merchantData = new Buffer(JSON.stringify(data), 'utf8');
return;
}
this.merchantData = new Buffer(data, enc);
};
PaymentDetails.prototype.getData = function getData(enc) {
var data = this.merchantData;
if (!data)
return;
if (!enc)
return data;
if (enc === 'json') {
data = data.toString('utf8');
try {
data = JSON.parse(data);
} catch (e) {
return;
}
return data;
}
return data.toString(enc);
};
PaymentDetails.prototype.fromRaw = function fromRaw(data) {
var p = new ProtoReader(data);
var op, output;
this.network = p.readFieldString(1, true);
while (p.nextTag() === 2) {
op = new ProtoReader(p.readFieldBytes(2));
output = new bcoin.output();
output.value = op.readFieldU64(1, true);
output.script.fromRaw(op.readFieldBytes(2, true));
this.outputs.push(output);
}
this.time = p.readFieldU64(3);
this.expires = p.readFieldU64(4, true);
this.memo = p.readFieldString(5, true);
this.paymentUrl = p.readFieldString(6, true);
this.merchantData = p.readFieldBytes(7, true);
return this;
};
PaymentDetails.fromRaw = function fromRaw(data, enc) {
if (typeof data === 'string')
data = new Buffer(data, enc);
return new PaymentDetails().fromRaw(data);
};
PaymentDetails.prototype.toRaw = function toRaw(writer) {
var p = new ProtoWriter(writer);
var i, op, output;
if (this.network != null)
p.writeFieldString(1, this.network);
for (i = 0; i < this.outputs.length; i++) {
output = this.outputs[i];
op = new ProtoWriter();
op.writeFieldU64(1, output.value);
op.writeFieldBytes(2, output.script.toRaw());
p.writeFieldBytes(2, op.render());
}
p.writeFieldU64(3, this.time);
if (this.expires !== -1)
p.writeFieldU64(4, this.expires);
if (this.memo != null)
p.writeFieldString(5, this.memo);
if (this.paymentUrl != null)
p.writeFieldString(6, this.paymentUrl);
if (this.merchantData)
p.writeFieldString(7, this.merchantData);
if (!writer)
p = p.render();
return p;
};
function Payment(options) {
if (!(this instanceof Payment))
return new Payment(options);
this.merchantData = null;
this.transactions = [];
this.refundTo = [];
this.memo = null;
if (options)
this.fromOptions(options);
}
Payment.prototype.fromOptions = function fromOptions(options) {
var i, tx, output;
if (options.merchantData)
this.setData(options.merchantData);
if (options.transactions) {
assert(Array.isArray(options.transactions));
for (i = 0; i < options.transactions.length; i++) {
tx = new bcoin.tx(options.transactions[i]);
this.transactions.push(tx);
}
}
if (options.refundTo) {
assert(Array.isArray(options.refundTo));
for (i = 0; i < options.refundTo.length; i++) {
output = new bcoin.output(options.refundTo[i]);
this.refundTo.push(output);
}
}
if (options.memo != null) {
assert(typeof options.memo === 'string');
this.memo = options.memo;
}
return this;
};
Payment.fromOptions = function fromOptions(options) {
return new Payment().fromOptions(options);
};
Payment.prototype.setData = PaymentDetails.prototype.setData;
Payment.prototype.getData = PaymentDetails.prototype.getData;
Payment.prototype.fromRaw = function fromRaw(data) {
var p = new ProtoReader(data);
var tx, op, output;
this.merchantData = p.readFieldBytes(1, true);
while (p.nextTag() === 2) {
tx = bcoin.tx.fromRaw(p.readFieldBytes(2));
this.transactions.push(tx);
}
while (p.nextTag() === 3) {
op = new ProtoReader(p.readFieldBytes(3));
output = new bcoin.output();
output.value = op.readFieldU64(1, true);
output.script = bcoin.script.fromRaw(op.readFieldBytes(2, true));
this.refundTo.push(output);
}
this.memo = p.readFieldString(4, true);
return this;
};
Payment.fromRaw = function fromRaw(data, enc) {
if (typeof data === 'string')
data = new Buffer(data, enc);
return new Payment().fromRaw(data);
};
Payment.prototype.toRaw = function toRaw(writer) {
var p = new ProtoWriter(writer);
var i, tx, op, output;
if (this.merchantData)
p.writeFieldBytes(1, this.merchantData);
for (i = 0; i < this.transactions.length; i++) {
tx = this.transactions[i];
this.writeFieldBytes(2, tx.toRaw());
}
for (i = 0; i < this.refundTo.length; i++) {
op = new ProtoWriter();
output = this.refundTo[i];
op.writeFieldU64(1, output.value);
op.writeFieldBytes(2, output.script.toRaw());
p.writeFieldBytes(3, op.render());
}
if (this.memo != null)
p.writeFieldString(4, this.memo);
if (!writer)
p = p.render();
return p;
};
function PaymentACK(options) {
if (!(this instanceof PaymentACK))
return new PaymentACK(options);
this.payment = new Payment();
this.memo = null;
if (options)
this.fromOptions(options);
}
PaymentACK.prototype.fromOptions = function fromOptions(options) {
if (options.payment)
this.payment.fromOptions(options.payment);
if (options.memo != null) {
assert(typeof options.memo === 'string');
this.memo = options.memo;
}
return this;
};
PaymentACK.fromOptions = function fromOptions(options) {
return new PaymentACK().fromOptions(options);
};
PaymentACK.prototype.fromRaw = function fromRaw(data) {
var p = new ProtoReader(data);
this.payment.fromRaw(p.readFieldBytes(1));
this.memo = p.readFieldString(2, true);
return this;
};
PaymentACK.fromRaw = function fromRaw(data, enc) {
if (typeof data === 'string')
data = new Buffer(data, enc);
return new PaymentACK().fromRaw(data);
};
PaymentACK.prototype.toRaw = function toRaw(writer) {
var p = new ProtoWriter(writer);
p.writeFieldBytes(1, this.payment.toRaw());
if (this.memo != null)
p.writeFieldString(2, this.memo);
if (!writer)
p = p.render();
return p;
};
exports.PaymentRequest = PaymentRequest;
exports.PaymentDetails = PaymentDetails;
exports.Payment = Payment;
exports.PaymentACK = PaymentACK;

15
lib/bip70/index.js Normal file
View file

@ -0,0 +1,15 @@
/*!
* bip70.js - bip70 for bcoin
* Copyright (c) 2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
exports.PaymentRequest = require('./paymentrequest');
exports.PaymentDetails = require('./paymentdetails');
exports.Payment = require('./payment');
exports.PaymentACK = require('./paymentack');
exports.asn1 = require('./asn1');
exports.x509 = require('./x509');
exports.pk = require('./pk');

127
lib/bip70/payment.js Normal file
View file

@ -0,0 +1,127 @@
/*!
* payment.js - bip70 payment for bcoin
* Copyright (c) 2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var assert = require('assert');
var Output = require('../primitives/output');
var TX = require('../primitives/tx');
var Script = require('../script/script');
var protobuf = require('./protobuf');
var PaymentDetails = require('./paymentdetails');
var ProtoReader = protobuf.ProtoReader;
var ProtoWriter = protobuf.ProtoWriter;
function Payment(options) {
if (!(this instanceof Payment))
return new Payment(options);
this.merchantData = null;
this.transactions = [];
this.refundTo = [];
this.memo = null;
if (options)
this.fromOptions(options);
}
Payment.prototype.fromOptions = function fromOptions(options) {
var i, tx, output;
if (options.merchantData)
this.setData(options.merchantData);
if (options.transactions) {
assert(Array.isArray(options.transactions));
for (i = 0; i < options.transactions.length; i++) {
tx = new TX(options.transactions[i]);
this.transactions.push(tx);
}
}
if (options.refundTo) {
assert(Array.isArray(options.refundTo));
for (i = 0; i < options.refundTo.length; i++) {
output = new Output(options.refundTo[i]);
this.refundTo.push(output);
}
}
if (options.memo != null) {
assert(typeof options.memo === 'string');
this.memo = options.memo;
}
return this;
};
Payment.fromOptions = function fromOptions(options) {
return new Payment().fromOptions(options);
};
Payment.prototype.setData = PaymentDetails.prototype.setData;
Payment.prototype.getData = PaymentDetails.prototype.getData;
Payment.prototype.fromRaw = function fromRaw(data) {
var p = new ProtoReader(data);
var tx, op, output;
this.merchantData = p.readFieldBytes(1, true);
while (p.nextTag() === 2) {
tx = TX.fromRaw(p.readFieldBytes(2));
this.transactions.push(tx);
}
while (p.nextTag() === 3) {
op = new ProtoReader(p.readFieldBytes(3));
output = new Output();
output.value = op.readFieldU64(1, true);
output.script = Script.fromRaw(op.readFieldBytes(2, true));
this.refundTo.push(output);
}
this.memo = p.readFieldString(4, true);
return this;
};
Payment.fromRaw = function fromRaw(data, enc) {
if (typeof data === 'string')
data = new Buffer(data, enc);
return new Payment().fromRaw(data);
};
Payment.prototype.toRaw = function toRaw(writer) {
var p = new ProtoWriter(writer);
var i, tx, op, output;
if (this.merchantData)
p.writeFieldBytes(1, this.merchantData);
for (i = 0; i < this.transactions.length; i++) {
tx = this.transactions[i];
this.writeFieldBytes(2, tx.toRaw());
}
for (i = 0; i < this.refundTo.length; i++) {
op = new ProtoWriter();
output = this.refundTo[i];
op.writeFieldU64(1, output.value);
op.writeFieldBytes(2, output.script.toRaw());
p.writeFieldBytes(3, op.render());
}
if (this.memo != null)
p.writeFieldString(4, this.memo);
if (!writer)
p = p.render();
return p;
};
module.exports = Payment;

71
lib/bip70/paymentack.js Normal file
View file

@ -0,0 +1,71 @@
/*!
* paymentack.js - bip70 paymentack for bcoin
* Copyright (c) 2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var assert = require('assert');
var protobuf = require('./protobuf');
var Payment = require('./payment');
var ProtoReader = protobuf.ProtoReader;
var ProtoWriter = protobuf.ProtoWriter;
function PaymentACK(options) {
if (!(this instanceof PaymentACK))
return new PaymentACK(options);
this.payment = new Payment();
this.memo = null;
if (options)
this.fromOptions(options);
}
PaymentACK.prototype.fromOptions = function fromOptions(options) {
if (options.payment)
this.payment.fromOptions(options.payment);
if (options.memo != null) {
assert(typeof options.memo === 'string');
this.memo = options.memo;
}
return this;
};
PaymentACK.fromOptions = function fromOptions(options) {
return new PaymentACK().fromOptions(options);
};
PaymentACK.prototype.fromRaw = function fromRaw(data) {
var p = new ProtoReader(data);
this.payment.fromRaw(p.readFieldBytes(1));
this.memo = p.readFieldString(2, true);
return this;
};
PaymentACK.fromRaw = function fromRaw(data, enc) {
if (typeof data === 'string')
data = new Buffer(data, enc);
return new PaymentACK().fromRaw(data);
};
PaymentACK.prototype.toRaw = function toRaw(writer) {
var p = new ProtoWriter(writer);
p.writeFieldBytes(1, this.payment.toRaw());
if (this.memo != null)
p.writeFieldString(2, this.memo);
if (!writer)
p = p.render();
return p;
};
module.exports = PaymentACK;

185
lib/bip70/paymentdetails.js Normal file
View file

@ -0,0 +1,185 @@
/*!
* paymentdetails.js - bip70 paymentdetails for bcoin
* Copyright (c) 2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var assert = require('assert');
var utils = require('../utils/utils');
var Output = require('../primitives/output');
var protobuf = require('./protobuf');
var ProtoReader = protobuf.ProtoReader;
var ProtoWriter = protobuf.ProtoWriter;
function PaymentDetails(options) {
if (!(this instanceof PaymentDetails))
return new PaymentDetails(options);
this.network = null;
this.outputs = [];
this.time = utils.now();
this.expires = -1;
this.memo = null;
this.paymentUrl = null;
this.merchantData = null;
if (options)
this.fromOptions(options);
}
PaymentDetails.prototype.fromOptions = function fromOptions(options) {
var i, output;
if (options.network != null) {
assert(typeof options.network === 'string');
this.network = options.network;
}
if (options.outputs) {
assert(Array.isArray(options.outputs));
for (i = 0; i < options.outputs.length; i++) {
output = new Output(options.outputs[i]);
this.outputs.push(output);
}
}
if (options.time != null) {
assert(utils.isNumber(options.time));
this.time = options.time;
}
if (options.expires != null) {
assert(utils.isNumber(options.expires));
this.expires = options.expires;
}
if (options.memo != null) {
assert(typeof options.memo === 'string');
this.memo = options.memo;
}
if (options.paymentUrl != null) {
assert(typeof options.paymentUrl === 'string');
this.paymentUrl = options.paymentUrl;
}
if (options.merchantData)
this.setData(options.merchantData);
return this;
};
PaymentDetails.fromOptions = function fromOptions(options) {
return new PaymentDetails().fromOptions(options);
};
PaymentDetails.prototype.isExpired = function isExpired() {
if (this.expires === -1)
return false;
return utils.now() > this.expires;
};
PaymentDetails.prototype.setData = function setData(data, enc) {
if (data == null || Buffer.isBuffer(data)) {
this.merchantData = data;
return;
}
if (typeof data !== 'string') {
assert(!enc || enc === 'json');
this.merchantData = new Buffer(JSON.stringify(data), 'utf8');
return;
}
this.merchantData = new Buffer(data, enc);
};
PaymentDetails.prototype.getData = function getData(enc) {
var data = this.merchantData;
if (!data)
return;
if (!enc)
return data;
if (enc === 'json') {
data = data.toString('utf8');
try {
data = JSON.parse(data);
} catch (e) {
return;
}
return data;
}
return data.toString(enc);
};
PaymentDetails.prototype.fromRaw = function fromRaw(data) {
var p = new ProtoReader(data);
var op, output;
this.network = p.readFieldString(1, true);
while (p.nextTag() === 2) {
op = new ProtoReader(p.readFieldBytes(2));
output = new Output();
output.value = op.readFieldU64(1, true);
output.script.fromRaw(op.readFieldBytes(2, true));
this.outputs.push(output);
}
this.time = p.readFieldU64(3);
this.expires = p.readFieldU64(4, true);
this.memo = p.readFieldString(5, true);
this.paymentUrl = p.readFieldString(6, true);
this.merchantData = p.readFieldBytes(7, true);
return this;
};
PaymentDetails.fromRaw = function fromRaw(data, enc) {
if (typeof data === 'string')
data = new Buffer(data, enc);
return new PaymentDetails().fromRaw(data);
};
PaymentDetails.prototype.toRaw = function toRaw(writer) {
var p = new ProtoWriter(writer);
var i, op, output;
if (this.network != null)
p.writeFieldString(1, this.network);
for (i = 0; i < this.outputs.length; i++) {
output = this.outputs[i];
op = new ProtoWriter();
op.writeFieldU64(1, output.value);
op.writeFieldBytes(2, output.script.toRaw());
p.writeFieldBytes(2, op.render());
}
p.writeFieldU64(3, this.time);
if (this.expires !== -1)
p.writeFieldU64(4, this.expires);
if (this.memo != null)
p.writeFieldString(5, this.memo);
if (this.paymentUrl != null)
p.writeFieldString(6, this.paymentUrl);
if (this.merchantData)
p.writeFieldString(7, this.merchantData);
if (!writer)
p = p.render();
return p;
};
module.exports = PaymentDetails;

252
lib/bip70/paymentrequest.js Normal file
View file

@ -0,0 +1,252 @@
/*!
* paymentrequest.js - bip70 paymentrequest for bcoin
* Copyright (c) 2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var assert = require('assert');
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var x509 = require('./x509');
var asn1 = require('./asn1');
var protobuf = require('./protobuf');
var PaymentDetails = require('./paymentdetails');
var ProtoReader = protobuf.ProtoReader;
var ProtoWriter = protobuf.ProtoWriter;
function PaymentRequest(options) {
if (!(this instanceof PaymentRequest))
return new PaymentRequest(options);
this.version = -1;
this.pkiType = null;
this.pkiData = null;
this.paymentDetails = new PaymentDetails();
this.signature = null;
if (options)
this.fromOptions(options);
}
PaymentRequest.prototype.fromOptions = function fromOptions(options) {
if (options.version != null) {
assert(utils.isNumber(options.version));
this.version = options.version;
}
if (options.pkiType != null) {
assert(typeof options.pkiType === 'string');
this.pkiType = options.pkiType;
}
if (options.pkiData) {
assert(Buffer.isBuffer(options.pkiData));
this.pkiData = options.pkiData;
}
if (options.paymentDetails)
this.paymentDetails.fromOptions(options.paymentDetails);
if (options.signature) {
assert(Buffer.isBuffer(options.signature));
this.signature = options.signature;
}
if (options.chain)
this.setChain(options.chain);
return this;
};
PaymentRequest.fromOptions = function fromOptions(options) {
return new PaymentRequest().fromOptions(options);
};
PaymentRequest.prototype.fromRaw = function fromRaw(data) {
var p = new ProtoReader(data);
this.version = p.readFieldU32(1, true);
this.pkiType = p.readFieldString(2, true);
this.pkiData = p.readFieldBytes(3, true);
this.paymentDetails.fromRaw(p.readFieldBytes(4));
this.signature = p.readFieldBytes(5, true);
return this;
};
PaymentRequest.fromRaw = function fromRaw(data, enc) {
if (typeof data === 'string')
data = new Buffer(data, enc);
return new PaymentRequest().fromRaw(data);
};
PaymentRequest.prototype.toRaw = function toRaw(writer) {
var p = new ProtoWriter(writer);
if (this.version !== -1)
p.writeFieldU32(1, this.version);
if (this.pkiType != null)
p.writeFieldString(2, this.pkiType);
if (this.pkiData)
p.writeFieldBytes(3, this.pkiData);
p.writeFieldBytes(4, this.paymentDetails.toRaw());
if (this.signature)
p.writeFieldBytes(5, this.signature);
if (!writer)
p = p.render();
return p;
};
PaymentRequest.prototype.getAlgorithm = function getAlgorithm() {
var parts;
if (!this.pkiType)
return;
parts = this.pkiType.split('+');
if (parts.length !== 2)
return;
if (parts[0] !== 'x509')
return;
if (parts[1] !== 'sha1' && parts[1] !== 'sha256')
return;
return { key: parts[0], hash: parts[1] };
};
PaymentRequest.prototype.signatureData = function signatureData() {
var signature = this.signature;
var data;
this.signature = new Buffer(0);
data = this.toRaw();
this.signature = signature;
return data;
};
PaymentRequest.prototype.signatureHash = function signatureHash() {
var alg = this.getAlgorithm();
assert(alg, 'No hash algorithm available.');
return crypto.hash(alg.hash, this.signatureData());
};
PaymentRequest.prototype.setChain = function setChain(chain) {
var p = new ProtoWriter();
var i, cert, pem;
if (!Array.isArray(chain))
chain = [chain];
for (i = 0; i < chain.length; i++) {
cert = chain[i];
if (typeof cert === 'string') {
pem = asn1.fromPEM(cert);
assert(pem.type === 'certificate', 'Bad certificate PEM.');
cert = pem.data;
}
assert(Buffer.isBuffer(cert), 'Certificates must be PEM or DER.');
p.writeFieldBytes(1, cert);
}
this.pkiData = p.render();
};
PaymentRequest.prototype.getChain = function getChain() {
var chain = [];
var p;
if (!this.pkiData)
return chain;
p = new ProtoReader(this.pkiData);
while (p.nextTag() === 1)
chain.push(p.readFieldBytes(1));
return chain;
};
PaymentRequest.prototype.sign = function sign(key, chain) {
var alg, msg;
if (chain)
this.setChain(chain);
if (!this.pkiType)
this.pkiType = 'x509+sha256';
alg = this.getAlgorithm();
assert(alg, 'No hash algorithm available.');
msg = this.signatureData();
chain = this.getChain();
this.signature = x509.signSubject(alg.hash, msg, key, chain);
};
PaymentRequest.prototype.verify = function verify() {
var alg, msg, sig, chain;
if (!this.pkiType || this.pkiType === 'none')
return true;
if (!this.signature)
return false;
alg = this.getAlgorithm();
if (!alg)
return false;
msg = this.signatureData();
sig = this.signature;
chain = this.getChain();
return x509.verifySubject(alg.hash, msg, sig, chain);
};
PaymentRequest.prototype.verifyChain = function verifyChain() {
if (!this.pkiType || this.pkiType === 'none')
return true;
return x509.verifyChain(this.getChain());
};
PaymentRequest.prototype.getCA = function getCA() {
var chain, root;
if (!this.pkiType || this.pkiType === 'none')
return;
chain = this.getChain();
if (chain.length === 0)
return;
root = x509.parse(chain[chain.length - 1]);
if (!root)
return;
return {
name: x509.getCAName(root),
trusted: x509.isTrusted(root),
cert: root
};
};
module.exports = PaymentRequest;

View file

@ -7,7 +7,7 @@
'use strict';
var utils = require('../utils/utils');
var assert = utils.assert;
var assert = require('assert');
var BufferReader = require('../utils/reader');
var BufferWriter = require('../utils/writer');

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -7,14 +7,17 @@
'use strict';
var bcoin = require('../env');
var bn = require('bn.js');
var constants = bcoin.constants;
var Network = require('../protocol/network');
var constants = require('../protocol/constants');
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var assert = utils.assert;
var assert = require('assert');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
var Headers = require('../primitives/headers');
var InvItem = require('../primitives/invitem');
var co = require('../utils/co');
/**
* Represents an entry in the chain. Unlike
@ -46,7 +49,7 @@ function ChainEntry(chain, options, prev) {
return new ChainEntry(chain, options, prev);
this.chain = chain;
this.network = chain ? chain.network : bcoin.network.get();
this.network = chain ? chain.network : Network.primary;
this.hash = constants.NULL_HASH;
this.version = 1;
@ -156,10 +159,10 @@ ChainEntry.prototype.isGenesis = function isGenesis() {
* majority window. These ancestors will be stored
* in the `ancestors` array and enable use of synchronous
* ChainEntry methods.
* @param {Function} callback
* @returns {Promise}
*/
ChainEntry.prototype.getRetargetAncestors = function getRetargetAncestors(callback) {
ChainEntry.prototype.getRetargetAncestors = function getRetargetAncestors() {
var majorityWindow = this.network.block.majorityWindow;
var medianTimespan = constants.block.MEDIAN_TIMESPAN;
var powDiffInterval = this.network.pow.retargetInterval;
@ -167,22 +170,22 @@ ChainEntry.prototype.getRetargetAncestors = function getRetargetAncestors(callba
var max = Math.max(majorityWindow, medianTimespan);
if ((this.height + 1) % powDiffInterval === 0 || diffReset)
max = Math.max(max, powDiffInterval);
this.getAncestors(max, callback);
return this.getAncestors(max);
};
/**
* Collect ancestors.
* @param {Number} max - Number of ancestors.
* @param {Function} callback - Returns [Error, ChainEntry[]].
* @returns {Promise} - Returns ChainEntry[].
*/
ChainEntry.prototype.getAncestors = function getAncestors(max, callback) {
ChainEntry.prototype.getAncestors = co(function* getAncestors(max) {
var entry = this;
var ancestors = [];
var cached;
if (max === 0)
return callback(null, ancestors);
return ancestors;
assert(utils.isNumber(max));
@ -192,7 +195,7 @@ ChainEntry.prototype.getAncestors = function getAncestors(max, callback) {
ancestors.push(entry);
if (ancestors.length >= max)
return callback(null, ancestors);
return ancestors;
cached = this.chain.db.getCache(entry.prevBlock);
@ -204,66 +207,54 @@ ChainEntry.prototype.getAncestors = function getAncestors(max, callback) {
entry = cached;
}
(function next(err, entry) {
if (err)
return callback(err);
if (!entry)
return callback(null, ancestors);
while (entry) {
ancestors.push(entry);
if (ancestors.length >= max)
return callback(null, ancestors);
break;
entry = yield entry.getPrevious();
}
entry.getPrevious(next);
})(null, entry);
};
return ancestors;
});
/**
* Test whether the entry is in the main chain.
* @param {Function} callback - Return [Error, Boolean].
* @returns {Promise} - Return Boolean.
*/
ChainEntry.prototype.isMainChain = function isMainChain(callback) {
this.chain.db.isMainChain(this, callback);
ChainEntry.prototype.isMainChain = function isMainChain() {
return this.chain.db.isMainChain(this);
};
/**
* Collect ancestors up to `height`.
* @param {Number} height
* @param {Function} callback - Returns [Error, ChainEntry[]].
* @returns {Promise} - Returns ChainEntry[].
*/
ChainEntry.prototype.getAncestorByHeight = function getAncestorByHeight(height, callback) {
var self = this;
ChainEntry.prototype.getAncestorByHeight = co(function* getAncestorByHeight(height) {
var main, entry;
if (height < 0)
return utils.nextTick(callback);
return yield co.wait();
assert(height >= 0);
assert(height <= this.height);
this.isMainChain(function(err, main) {
if (err)
return callback(err);
main = yield this.isMainChain();
if (main)
return self.chain.db.get(height, callback);
if (main)
return yield this.chain.db.get(height);
self.getAncestor(self.height - height, function(err, entry) {
if (err)
return callback(err);
entry = yield this.getAncestor(this.height - height);
if (!entry)
return callback();
if (!entry)
return;
assert(entry.height === height);
assert(entry.height === height);
callback(null, entry);
});
});
};
return entry;
});
/**
* Get a single ancestor by index. Note that index-0 is
@ -273,45 +264,39 @@ ChainEntry.prototype.getAncestorByHeight = function getAncestorByHeight(height,
* @returns {Function} callback - Returns [Error, ChainEntry].
*/
ChainEntry.prototype.getAncestor = function getAncestor(index, callback) {
ChainEntry.prototype.getAncestor = co(function* getAncestor(index) {
var ancestors;
assert(index >= 0);
this.getAncestors(index + 1, function(err, ancestors) {
if (err)
return callback(err);
if (ancestors.length < index + 1)
return callback();
ancestors = yield this.getAncestors(index + 1);
callback(null, ancestors[index]);
});
};
if (ancestors.length < index + 1)
return;
return ancestors[index];
});
/**
* Get previous entry.
* @param {Function} callback - Returns [Error, ChainEntry].
* @returns {Promise} - Returns ChainEntry.
*/
ChainEntry.prototype.getPrevious = function getPrevious(callback) {
this.chain.db.get(this.prevBlock, callback);
ChainEntry.prototype.getPrevious = function getPrevious() {
return this.chain.db.get(this.prevBlock);
};
/**
* Get next entry.
* @param {Function} callback - Returns [Error, ChainEntry].
* @returns {Promise} - Returns ChainEntry.
*/
ChainEntry.prototype.getNext = function getNext(callback) {
var self = this;
this.chain.db.getNextHash(this.hash, function(err, hash) {
if (err)
return callback(err);
if (!hash)
return callback();
self.chain.db.get(hash, callback);
});
};
ChainEntry.prototype.getNext = co(function* getNext() {
var hash = yield this.chain.db.getNextHash(this.hash);
if (!hash)
return;
return yield this.chain.db.get(hash);
});
/**
* Get median time past.
@ -336,20 +321,14 @@ ChainEntry.prototype.getMedianTime = function getMedianTime(ancestors) {
/**
* Get median time past asynchronously (see {@link ChainEntry#getMedianTime}).
* @param {Function} callback - Returns [Error, Number].
* @returns {Promise} - Returns Number.
*/
ChainEntry.prototype.getMedianTimeAsync = function getMedianTimeAsync(callback) {
var self = this;
ChainEntry.prototype.getMedianTimeAsync = co(function* getMedianTimeAsync() {
var MEDIAN_TIMESPAN = constants.block.MEDIAN_TIMESPAN;
this.getAncestors(MEDIAN_TIMESPAN, function(err, ancestors) {
if (err)
return callback(err);
callback(null, self.getMedianTime(ancestors));
});
};
var ancestors = yield this.getAncestors(MEDIAN_TIMESPAN);
return this.getMedianTime(ancestors);
});
/**
* Check isSuperMajority against majorityRejectOutdated.
@ -367,14 +346,13 @@ ChainEntry.prototype.isOutdated = function isOutdated(version, ancestors) {
/**
* Check {@link ChainEntry#isUpgraded asynchronously}.
* @param {Number} version
* @param {Function} callback - Returns [Error, Boolean].
* @returns {Promise} - Returns Boolean.
* @returns {Boolean}
*/
ChainEntry.prototype.isOutdatedAsync = function isOutdatedAsync(version, callback) {
this.isSuperMajorityAsync(version,
this.network.block.majorityRejectOutdated,
callback);
ChainEntry.prototype.isOutdatedAsync = function isOutdatedAsync(version) {
return this.isSuperMajorityAsync(version,
this.network.block.majorityRejectOutdated);
};
/**
@ -393,14 +371,13 @@ ChainEntry.prototype.isUpgraded = function isUpgraded(version, ancestors) {
/**
* Check {@link ChainEntry#isUpgraded} asynchronously.
* @param {Number} version
* @param {Function} callback
* @returns {Promise}
* @returns {Boolean}
*/
ChainEntry.prototype.isUpgradedAsync = function isUpgradedAsync(version, callback) {
this.isSuperMajorityAsync(version,
this.network.block.majorityEnforceUpgrade,
callback);
ChainEntry.prototype.isUpgradedAsync = function isUpgradedAsync(version) {
return this.isSuperMajorityAsync(version,
this.network.block.majorityEnforceUpgrade);
};
/**
@ -430,24 +407,19 @@ ChainEntry.prototype.isSuperMajority = function isSuperMajority(version, require
* Calculate {@link ChainEntry#isSuperMajority asynchronously}.
* @param {Number} version
* @param {Number} required
* @param {Function} callback - Returns [Error, Boolean].
* @returns {Promise} - Returns Boolean.
* @returns {Boolean}
*/
ChainEntry.prototype.isSuperMajorityAsync = function isSuperMajorityAsync(version, required, callback) {
var self = this;
ChainEntry.prototype.isSuperMajorityAsync = co(function* isSuperMajorityAsync(version, required) {
var majorityWindow = this.network.block.majorityWindow;
this.getAncestors(majorityWindow, function(err, ancestors) {
if (err)
return callback(err);
callback(null, self.isSuperMajority(version, required, ancestors));
});
};
var ancestors = yield this.getAncestors(majorityWindow);
return this.isSuperMajority(version, required, ancestors);
});
/**
* Test whether the entry is potentially an ancestor of a checkpoint.
* Test whether the entry is potentially
* an ancestor of a checkpoint.
* @returns {Boolean}
*/
@ -459,6 +431,19 @@ ChainEntry.prototype.isHistorical = function isHistorical() {
return false;
};
/**
* Test whether the entry contains a version bit.
* @param {Object} deployment
* @returns {Boolean}
*/
ChainEntry.prototype.hasBit = function hasBit(deployment) {
var bits = this.version & constants.versionbits.TOP_MASK;
var topBits = constants.versionbits.TOP_BITS;
var mask = 1 << deployment.bit;
return bits === topBits && (this.version & mask) !== 0;
};
ChainEntry.prototype.__defineGetter__('rhash', function() {
return utils.revHex(this.hash);
});
@ -506,7 +491,7 @@ ChainEntry.fromBlock = function fromBlock(chain, block, prev) {
ChainEntry.prototype.toRaw = function toRaw(writer) {
var p = new BufferWriter(writer);
p.write32(this.version);
p.writeU32(this.version);
p.writeHash(this.prevBlock);
p.writeHash(this.merkleRoot);
p.writeU32(this.ts);
@ -624,7 +609,7 @@ ChainEntry.fromJSON = function fromJSON(chain, json) {
*/
ChainEntry.prototype.toHeaders = function toHeaders() {
return bcoin.headers.fromEntry(this);
return Headers.fromEntry(this);
};
/**
@ -633,7 +618,7 @@ ChainEntry.prototype.toHeaders = function toHeaders() {
*/
ChainEntry.prototype.toInv = function toInv() {
return new bcoin.invitem(constants.inv.BLOCK, this.hash);
return new InvItem(constants.inv.BLOCK, this.hash);
};
/**

View file

@ -1,18 +1,20 @@
/*!
* coins.js - coins object for bcoin
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var bcoin = require('../env');
var utils = bcoin.utils;
var assert = utils.assert;
var constants = bcoin.constants;
var utils = require('../utils/utils');
var assert = require('assert');
var constants = require('../protocol/constants');
var Coin = require('../primitives/coin');
var BufferReader = require('../utils/reader');
var BufferWriter = require('../utils/writer');
var compressor = require('./compress');
var compress = compressor.compress;
var decompress = compressor.decompress;
/**
* Represents the outputs for a single transaction.
@ -280,7 +282,7 @@ Coins.prototype.toRaw = function toRaw(writer) {
continue;
}
compressScript(output.script, p);
compress.script(output.script, p);
p.writeVarint(output.value);
}
@ -449,7 +451,7 @@ Coins.prototype.fromTX = function fromTX(tx) {
this.outputs.push(null);
continue;
}
this.outputs.push(bcoin.coin.fromTX(tx, i));
this.outputs.push(Coin.fromTX(tx, i));
}
return this;
@ -502,7 +504,7 @@ function CompressedCoin(offset, size, raw) {
CompressedCoin.prototype.toCoin = function toCoin(coins, index) {
var p = new BufferReader(this.raw);
var coin = new bcoin.coin();
var coin = new Coin();
// Load in all necessary properties
// from the parent Coins object.
@ -515,7 +517,7 @@ CompressedCoin.prototype.toCoin = function toCoin(coins, index) {
// Seek to the coin's offset.
p.seek(this.offset);
decompressScript(p, coin.script);
decompress.script(p, coin.script);
coin.value = p.readVarint();
@ -532,236 +534,8 @@ CompressedCoin.prototype.toRaw = function toRaw() {
return this.raw.slice(this.offset, this.offset + this.size);
};
/*
* Compression
*/
/**
* Compress a script, write directly to the buffer.
* @param {Script} script
* @param {BufferWriter} p
*/
function compressScript(script, p) {
var prefix = 0;
var data;
// Attempt to compress the output scripts.
// We can _only_ ever compress them if
// they are serialized as minimaldata, as
// we need to recreate them when we read
// them.
if (script.isPubkeyhash(true)) {
prefix = 1;
data = script.code[2].data;
} else if (script.isScripthash()) {
prefix = 2;
data = script.code[1].data;
} else if (script.isPubkey(true)) {
prefix = 3;
data = script.code[0].data;
// Try to compress the key.
data = compressKey(data);
// If we can't compress it,
// just store the script.
if (!data)
prefix = 0;
}
p.writeU8(prefix);
if (prefix === 0)
p.writeVarBytes(script.toRaw());
else
p.writeBytes(data);
}
/**
* Decompress a script from buffer reader.
* @param {BufferReader} p
* @param {Script} script
*/
function decompressScript(p, script) {
var key;
// Decompress the script.
switch (p.readU8()) {
case 0:
script.fromRaw(p.readVarBytes());
break;
case 1:
script.fromPubkeyhash(p.readBytes(20));
break;
case 2:
script.fromScripthash(p.readBytes(20));
break;
case 3:
// Decompress the key. If this fails,
// we have database corruption!
key = decompressKey(p.readBytes(33));
script.fromPubkey(key);
break;
default:
throw new Error('Bad prefix.');
}
}
/**
* Compress value using an exponent. Takes advantage of
* the fact that many bitcoin values are divisible by 10.
* @see https://github.com/btcsuite/btcd/blob/master/blockchain/compress.go
* @param {Amount} value
* @returns {Number}
*/
function compressValue(value) {
var exp, last;
if (value === 0)
return 0;
exp = 0;
while (value % 10 === 0 && exp < 9) {
value /= 10;
exp++;
}
if (exp < 9) {
last = value % 10;
value = (value - last) / 10;
return 1 + 10 * (9 * value + last - 1) + exp;
}
return 10 + 10 * (value - 1);
}
/**
* Decompress value.
* @param {Number} value - Compressed value.
* @returns {Amount} value
*/
function decompressValue(value) {
var exp, n, last;
if (value === 0)
return 0;
value--;
exp = value % 10;
value = (value - exp) / 10;
if (exp < 9) {
last = value % 9;
value = (value - last) / 9;
n = value * 10 + last + 1;
} else {
n = value + 1;
}
while (exp > 0) {
n *= 10;
exp--;
}
return n;
}
/**
* Compress a public key to coins compression format.
* @param {Buffer} key
* @returns {Buffer}
*/
function compressKey(key) {
var out;
// We can't compress it if it's not valid.
if (!bcoin.ec.publicKeyVerify(key))
return;
switch (key[0]) {
case 0x02:
case 0x03:
// Key is already compressed.
out = key;
break;
case 0x04:
case 0x06:
case 0x07:
// Compress the key normally.
out = bcoin.ec.publicKeyConvert(key, true);
// Store the original format (which
// may be a hybrid byte) in the hi
// 3 bits so we can restore it later.
// The hi bits being set also lets us
// know that this key was originally
// decompressed.
out[0] |= key[0] << 2;
break;
default:
throw new Error('Bad point format.');
}
assert(out.length === 33);
return out;
}
/**
* Decompress a public key from the coins compression format.
* @param {Buffer} key
* @returns {Buffer}
*/
function decompressKey(key) {
var format = key[0] >>> 2;
var out;
assert(key.length === 33);
// Hi bits are not set. This key
// is not meant to be decompressed.
if (format === 0)
return key;
// Decompress the key, and off the
// low bits so publicKeyConvert
// actually understands it.
key[0] &= 0x03;
out = bcoin.ec.publicKeyConvert(key, false);
// Reset the hi bits so as not to
// mutate the original buffer.
key[0] |= format << 2;
// Set the original format, which
// may have been a hybrid prefix byte.
out[0] = format;
return out;
}
/*
* Expose
*/
exports = Coins;
exports.compress = {
script: compressScript,
value: compressValue,
key: compressKey
};
exports.decompress = {
script: decompressScript,
value: decompressValue,
key: decompressKey
};
module.exports = exports;
module.exports = Coins;

View file

@ -1,15 +1,13 @@
/*!
* coinview.js - coinview object for bcoin
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var bcoin = require('../env');
var utils = bcoin.utils;
var assert = utils.assert;
var assert = require('assert');
var Coins = require('./coins');
/**
* A collections of {@link Coins} objects.
@ -43,7 +41,7 @@ CoinView.prototype.add = function add(coins) {
CoinView.prototype.addCoin = function addCoin(coin) {
assert(typeof coin.hash === 'string');
if (!this.coins[coin.hash])
this.coins[coin.hash] = new bcoin.coins();
this.coins[coin.hash] = new Coins();
this.coins[coin.hash].add(coin);
};
@ -53,7 +51,7 @@ CoinView.prototype.addCoin = function addCoin(coin) {
*/
CoinView.prototype.addTX = function addTX(tx) {
this.add(bcoin.coins.fromTX(tx));
this.add(Coins.fromTX(tx));
};
/**

240
lib/chain/compress.js Normal file
View file

@ -0,0 +1,240 @@
/*!
* compress.js - coin compressor for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var assert = require('assert');
var ec = require('../crypto/ec');
/*
* Compression
*/
/**
* Compress a script, write directly to the buffer.
* @param {Script} script
* @param {BufferWriter} p
*/
function compressScript(script, p) {
var prefix = 0;
var data;
// Attempt to compress the output scripts.
// We can _only_ ever compress them if
// they are serialized as minimaldata, as
// we need to recreate them when we read
// them.
if (script.isPubkeyhash(true)) {
prefix = 1;
data = script.code[2].data;
} else if (script.isScripthash()) {
prefix = 2;
data = script.code[1].data;
} else if (script.isPubkey(true)) {
prefix = 3;
data = script.code[0].data;
// Try to compress the key.
data = compressKey(data);
// If we can't compress it,
// just store the script.
if (!data)
prefix = 0;
}
p.writeU8(prefix);
if (prefix === 0)
p.writeVarBytes(script.toRaw());
else
p.writeBytes(data);
}
/**
* Decompress a script from buffer reader.
* @param {BufferReader} p
* @param {Script} script
*/
function decompressScript(p, script) {
var key;
// Decompress the script.
switch (p.readU8()) {
case 0:
script.fromRaw(p.readVarBytes());
break;
case 1:
script.fromPubkeyhash(p.readBytes(20));
break;
case 2:
script.fromScripthash(p.readBytes(20));
break;
case 3:
// Decompress the key. If this fails,
// we have database corruption!
key = decompressKey(p.readBytes(33));
script.fromPubkey(key);
break;
default:
throw new Error('Bad prefix.');
}
}
/**
* Compress value using an exponent. Takes advantage of
* the fact that many bitcoin values are divisible by 10.
* @see https://github.com/btcsuite/btcd/blob/master/blockchain/compress.go
* @param {Amount} value
* @returns {Number}
*/
function compressValue(value) {
var exp, last;
if (value === 0)
return 0;
exp = 0;
while (value % 10 === 0 && exp < 9) {
value /= 10;
exp++;
}
if (exp < 9) {
last = value % 10;
value = (value - last) / 10;
return 1 + 10 * (9 * value + last - 1) + exp;
}
return 10 + 10 * (value - 1);
}
/**
* Decompress value.
* @param {Number} value - Compressed value.
* @returns {Amount} value
*/
function decompressValue(value) {
var exp, n, last;
if (value === 0)
return 0;
value--;
exp = value % 10;
value = (value - exp) / 10;
if (exp < 9) {
last = value % 9;
value = (value - last) / 9;
n = value * 10 + last + 1;
} else {
n = value + 1;
}
while (exp > 0) {
n *= 10;
exp--;
}
return n;
}
/**
* Compress a public key to coins compression format.
* @param {Buffer} key
* @returns {Buffer}
*/
function compressKey(key) {
var out;
// We can't compress it if it's not valid.
if (!ec.publicKeyVerify(key))
return;
switch (key[0]) {
case 0x02:
case 0x03:
// Key is already compressed.
out = key;
break;
case 0x04:
case 0x06:
case 0x07:
// Compress the key normally.
out = ec.publicKeyConvert(key, true);
// Store the original format (which
// may be a hybrid byte) in the hi
// 3 bits so we can restore it later.
// The hi bits being set also lets us
// know that this key was originally
// decompressed.
out[0] |= key[0] << 2;
break;
default:
throw new Error('Bad point format.');
}
assert(out.length === 33);
return out;
}
/**
* Decompress a public key from the coins compression format.
* @param {Buffer} key
* @returns {Buffer}
*/
function decompressKey(key) {
var format = key[0] >>> 2;
var out;
assert(key.length === 33);
// Hi bits are not set. This key
// is not meant to be decompressed.
if (format === 0)
return key;
// Decompress the key, and off the
// low bits so publicKeyConvert
// actually understands it.
key[0] &= 0x03;
out = ec.publicKeyConvert(key, false);
// Reset the hi bits so as not to
// mutate the original buffer.
key[0] |= format << 2;
// Set the original format, which
// may have been a hybrid prefix byte.
out[0] = format;
return out;
}
/*
* Expose
*/
exports.compress = {
script: compressScript,
value: compressValue,
key: compressKey
};
exports.decompress = {
script: decompressScript,
value: decompressValue,
key: decompressKey
};

8
lib/chain/index.js Normal file
View file

@ -0,0 +1,8 @@
'use strict';
exports.Chain = require('./chain');
exports.ChainDB = require('./chaindb');
exports.ChainEntry = require('./chainentry');
exports.Coins = require('./coins');
exports.CoinView = require('./coinview');
exports.compressor = require('./compress');

View file

@ -490,7 +490,7 @@ AESCipher.prototype.update = function update(data) {
var i, len, trailing, block;
if (this.waiting) {
data = Buffer.concat([this.waiting, data]);
data = concat(this.waiting, data);
this.waiting = null;
}
@ -529,7 +529,7 @@ AESCipher.prototype.final = function final() {
left = 16 - block.length;
pad = new Buffer(left);
pad.fill(left);
block = Buffer.concat([block, pad]);
block = concat(block, pad);
}
// Encrypt the last block,
@ -577,7 +577,7 @@ AESDecipher.prototype.update = function update(data) {
var i, chunk, block, len, trailing;
if (this.waiting) {
data = Buffer.concat([this.waiting, data]);
data = concat(this.waiting, data);
this.waiting = null;
}
@ -656,10 +656,7 @@ AESDecipher.prototype.final = function final() {
AES.encrypt = function encrypt(data, key, iv, bits, mode) {
var cipher = new AESCipher(key, iv, bits, mode);
return Buffer.concat([
cipher.update(data),
cipher.final()
]);
return concat(cipher.update(data), cipher.final());
};
/**
@ -674,10 +671,7 @@ AES.encrypt = function encrypt(data, key, iv, bits, mode) {
AES.decrypt = function decrypt(data, key, iv, bits, mode) {
var decipher = new AESDecipher(key, iv, bits, mode);
return Buffer.concat([
decipher.update(data),
decipher.final()
]);
return concat(decipher.update(data), decipher.final());
};
/**
@ -771,6 +765,13 @@ function writeU32(data, value, i) {
data[i + 3] = value & 0xff;
}
function concat(a, b) {
var data = new Buffer(a.length + b.length);
a.copy(data, 0);
b.copy(data, a.length);
return data;
}
/*
* Tables
*/

View file

@ -12,15 +12,17 @@ var random = require('./random');
var scrypt = require('./scrypt');
var scryptAsync = require('./scrypt-async');
var utils = require('../utils/utils');
var co = require('../utils/co');
var native = require('../utils/native');
var nativeCrypto, hash, aes;
var lazy = require('../utils/lazy')(require, exports);
var nodeCrypto, hash, aes;
var isBrowser =
(typeof process !== 'undefined' && process.browser)
|| typeof window !== 'undefined';
if (!isBrowser) {
nativeCrypto = require('crypto');
nodeCrypto = require('crypto');
} else {
hash = require('hash.js');
aes = require('./aes');
@ -40,10 +42,10 @@ var crypto = exports;
*/
crypto.hash = function _hash(alg, data) {
if (!nativeCrypto)
if (!nodeCrypto)
return new Buffer(hash[alg]().update(data).digest());
return nativeCrypto.createHash(alg).update(data).digest();
return nodeCrypto.createHash(alg).update(data).digest();
};
if (native)
@ -129,12 +131,12 @@ crypto.checksum = function checksum(data) {
crypto.hmac = function hmac(alg, data, salt) {
var hmac;
if (!nativeCrypto) {
if (!nodeCrypto) {
hmac = hash.hmac(hash[alg], salt);
return new Buffer(hmac.update(data).digest());
}
hmac = nativeCrypto.createHmac(alg, salt);
hmac = nodeCrypto.createHmac(alg, salt);
return hmac.update(data).digest();
};
@ -158,8 +160,8 @@ crypto.pbkdf2 = function pbkdf2(key, salt, iter, len, alg) {
if (typeof salt === 'string')
salt = new Buffer(salt, 'utf8');
if (nativeCrypto && nativeCrypto.pbkdf2Sync)
return nativeCrypto.pbkdf2Sync(key, salt, iter, len, alg);
if (nodeCrypto && nodeCrypto.pbkdf2Sync)
return nodeCrypto.pbkdf2Sync(key, salt, iter, len, alg);
return crypto._pbkdf2(key, salt, iter, len, alg);
};
@ -171,10 +173,10 @@ crypto.pbkdf2 = function pbkdf2(key, salt, iter, len, alg) {
* @param {Number} iter
* @param {Number} len
* @param {String} alg
* @param {Function} callback
* @returns {Promise}
*/
crypto.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg, callback) {
crypto.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg) {
var result;
if (typeof key === 'string')
@ -183,16 +185,19 @@ crypto.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg, callback) {
if (typeof salt === 'string')
salt = new Buffer(salt, 'utf8');
if (nativeCrypto && nativeCrypto.pbkdf2)
return nativeCrypto.pbkdf2(key, salt, iter, len, alg, callback);
if (nodeCrypto && nodeCrypto.pbkdf2) {
return new Promise(function(resolve, reject) {
nodeCrypto.pbkdf2(key, salt, iter, len, alg, co.wrap(resolve, reject));
});
}
try {
result = crypto._pbkdf2(key, salt, iter, len, alg);
} catch (e) {
return callback(e);
return Promise.reject(e);
}
return callback(null, result);
return Promise.resolve(result);
};
/**
@ -224,27 +229,29 @@ crypto.scrypt = function _scrypt(passwd, salt, N, r, p, len) {
* @param {Number} r
* @param {Number} p
* @param {Number} len
* @param {Function} callback
* @returns {Promise}
*/
crypto.scryptAsync = function _scrypt(passwd, salt, N, r, p, len, callback) {
crypto.scryptAsync = function _scrypt(passwd, salt, N, r, p, len) {
if (typeof passwd === 'string')
passwd = new Buffer(passwd, 'utf8');
if (typeof salt === 'string')
salt = new Buffer(salt, 'utf8');
return scryptAsync(passwd, salt, N, r, p, len, callback);
return new Promise(function(resolve, reject) {
scryptAsync(passwd, salt, N, r, p, len, co.wrap(resolve, reject));
});
};
/**
* Derive a key using pbkdf2 with 50,000 iterations.
* @param {Buffer|String} passphrase
* @param {Function} callback
* @returns {Promise}
*/
crypto.derive = function derive(passphrase, callback) {
crypto.pbkdf2Async(passphrase, 'bcoin', 50000, 32, 'sha256', callback);
crypto.derive = function derive(passphrase) {
return crypto.pbkdf2Async(passphrase, 'bcoin', 50000, 32, 'sha256');
};
/**
@ -252,30 +259,29 @@ crypto.derive = function derive(passphrase, callback) {
* @param {Buffer} data
* @param {Buffer|String} passphrase
* @param {Buffer} iv - 128 bit initialization vector.
* @param {Function} callback
* @returns {Promise}
*/
crypto.encrypt = function encrypt(data, passphrase, iv, callback) {
crypto.encrypt = co(function* encrypt(data, passphrase, iv) {
var key;
assert(Buffer.isBuffer(data));
assert(passphrase, 'No passphrase.');
assert(Buffer.isBuffer(iv));
crypto.derive(passphrase, function(err, key) {
if (err)
return callback(err);
try {
data = crypto.encipher(data, key, iv);
} catch (e) {
key.fill(0);
return callback(e);
}
key = yield crypto.derive(passphrase);
try {
data = crypto.encipher(data, key, iv);
} catch (e) {
key.fill(0);
throw e;
}
return callback(null, data);
});
};
key.fill(0);
return data;
});
/**
* Encrypt with aes-256-cbc.
@ -288,15 +294,12 @@ crypto.encrypt = function encrypt(data, passphrase, iv, callback) {
crypto.encipher = function encipher(data, key, iv) {
var cipher;
if (!nativeCrypto)
if (!nodeCrypto)
return aes.cbc.encrypt(data, key, iv);
cipher = nativeCrypto.createCipheriv('aes-256-cbc', key, iv);
cipher = nodeCrypto.createCipheriv('aes-256-cbc', key, iv);
return Buffer.concat([
cipher.update(data),
cipher.final()
]);
return utils.concat(cipher.update(data), cipher.final());
};
/**
@ -304,27 +307,29 @@ crypto.encipher = function encipher(data, key, iv) {
* @param {Buffer} data
* @param {Buffer|String} passphrase
* @param {Buffer} iv - 128 bit initialization vector.
* @param {Function} callback
* @returns {Promise}
*/
crypto.decrypt = function decrypt(data, passphrase, iv, callback) {
crypto.decrypt = co(function* decrypt(data, passphrase, iv) {
var key;
assert(Buffer.isBuffer(data));
assert(passphrase, 'No passphrase.');
assert(Buffer.isBuffer(iv));
crypto.derive(passphrase, function(err, key) {
if (err)
return callback(err);
key = yield crypto.derive(passphrase);
try {
data = crypto.decipher(data, key, iv);
} catch (e) {
return callback(e);
}
try {
data = crypto.decipher(data, key, iv);
} catch (e) {
key.fill(0);
throw e;
}
return callback(null, data, key);
});
};
key.fill(0);
return data;
});
/**
* Decrypt with aes-256-cbc.
@ -337,15 +342,12 @@ crypto.decrypt = function decrypt(data, passphrase, iv, callback) {
crypto.decipher = function decipher(data, key, iv) {
var decipher;
if (!nativeCrypto)
if (!nodeCrypto)
return aes.cbc.decrypt(data, key, iv);
decipher = nativeCrypto.createDecipheriv('aes-256-cbc', key, iv);
decipher = nodeCrypto.createDecipheriv('aes-256-cbc', key, iv);
return Buffer.concat([
decipher.update(data),
decipher.final()
]);
return utils.concat(decipher.update(data), decipher.final());
};
/**
@ -632,3 +634,13 @@ crypto.randomRange = random.randomRange;
*/
crypto.randomInt = random.randomInt;
/*
* Expose other objects.
*/
lazy('aes', './aes');
lazy('chachapoly', './chachapoly');
lazy('ec', './ec');
lazy('schnorr', './schnorr');
lazy('siphash', './siphash');

View file

@ -11,7 +11,7 @@ var elliptic = require('elliptic');
var bn = require('bn.js');
var utils = require('../utils/utils');
var crypto = require('./crypto');
var assert = utils.assert;
var assert = require('assert');
var secp256k1;
try {
@ -21,6 +21,19 @@ try {
;
}
/*
* Constants
*/
var ZERO_S = new Buffer(
'0000000000000000000000000000000000000000000000000000000000000000',
'hex'
);
var HALF_ORDER = new Buffer(
'7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0',
'hex');
/**
* @exports ec
*/
@ -173,8 +186,7 @@ ec.ecdh = function ecdh(pub, priv) {
if (secp256k1) {
point = secp256k1.ecdhUnsafe(pub, priv, true);
point = ec.curve.decodePoint(point);
return point.getX().toArrayLike(Buffer, 'be', 32);
return point.slice(1, 33);
}
priv = ec.elliptic.keyPair({ priv: priv });
@ -204,11 +216,13 @@ ec.recover = function recover(msg, sig, j, compressed) {
} catch (e) {
return;
}
try {
key = secp256k1.recover(msg, sig, j, compressed);
} catch (e) {
return;
}
return key;
}
@ -248,22 +262,16 @@ ec.verify = function verify(msg, sig, key, historical, high) {
if (key.length === 0)
return false;
// Attempt to normalize the signature
// length before passing to elliptic.
// Note: We only do this for historical data!
// https://github.com/indutny/elliptic/issues/78
if (historical)
sig = ec.normalizeLength(sig);
if (secp256k1) {
// secp256k1 fails on high s values. This is
// bad for verifying historical data.
if (high)
sig = ec.toLowS(sig);
try {
// Import from DER.
sig = secp256k1.signatureImport(sig);
if (historical)
sig = secp256k1.signatureImportLax(sig);
else
sig = secp256k1.signatureImport(sig);
if (high)
sig = secp256k1.signatureNormalize(sig);
result = secp256k1.verify(msg, sig, key);
} catch (e) {
result = false;
@ -272,6 +280,13 @@ ec.verify = function verify(msg, sig, key, historical, high) {
return result;
}
// Attempt to normalize the signature
// length before passing to elliptic.
// Note: We only do this for historical data!
// https://github.com/indutny/elliptic/issues/78
if (historical)
sig = ec.normalizeLength(sig);
// Make elliptic mimic secp256k1's
// failure with high S values.
if (!high && !ec.isLowS(sig))
@ -446,14 +461,36 @@ ec.normalizeLength = function normalizeLength(sig) {
*/
ec.isLowS = function isLowS(sig) {
if (Buffer.isBuffer(sig)) {
var rs, s;
if (secp256k1) {
try {
sig = new ec.signature(sig);
rs = secp256k1.signatureImport(sig);
s = rs.slice(32, 64);
} catch (e) {
return false;
}
if (utils.equal(s, ZERO_S))
return false;
// If S is greater than half the order,
// it's too high.
if (utils.cmp(s, HALF_ORDER) > 0)
return false;
return true;
}
try {
sig = new ec.signature(sig);
} catch (e) {
return false;
}
if (sig.s.cmpn(0) === 0)
return false;
// If S is greater than half the order,
// it's too high.
if (sig.s.cmp(ec.elliptic.nh) > 0)
@ -462,30 +499,6 @@ ec.isLowS = function isLowS(sig) {
return true;
};
/**
* Lower the S value of a signature (used
* for verifying historical data).
* @param {Buffer} sig - DER formatted.
* @returns {Buffer}
*/
ec.toLowS = function toLowS(sig) {
if (Buffer.isBuffer(sig)) {
try {
sig = new ec.signature(sig);
} catch (e) {
return sig;
}
}
// If S is greater than half the order,
// it's too high.
if (sig.s.cmp(ec.elliptic.nh) > 0)
sig.s = ec.curve.n.sub(sig.s);
return new Buffer(sig.toDER());
};
/*
* Helpers
*/

3
lib/crypto/index.js Normal file
View file

@ -0,0 +1,3 @@
'use strict';
module.exports = require('./crypto');

11
lib/db/index.js Normal file
View file

@ -0,0 +1,11 @@
'use strict';
var utils = require('../utils/utils');
exports.ldb = require('./ldb');
if (utils.isBrowser)
exports.level = require('./level');
exports.LowlevelUp = require('./lowlevelup');
exports.RBT = require('./rbt');

View file

@ -11,7 +11,7 @@
var LowlevelUp = require('./lowlevelup');
var utils = require('../utils/utils');
var assert = utils.assert;
var assert = require('assert');
/**
* @param {Object} options

View file

@ -8,8 +8,9 @@
'use strict';
var utils = require('../utils/utils');
var assert = utils.assert;
var assert = require('assert');
var AsyncObject = require('../utils/async');
var co = require('../utils/co');
var VERSION_ERROR;
/**
@ -57,148 +58,193 @@ utils.inherits(LowlevelUp, AsyncObject);
/**
* Open the database (recallable).
* @alias LowlevelUp#open
* @param {Function} callback
* @returns {Promise}
*/
LowlevelUp.prototype._open = function open(callback) {
this.binding.open(this.options, callback);
LowlevelUp.prototype._open = function open() {
var self = this;
return new Promise(function(resolve, reject) {
self.binding.open(self.options, co.wrap(resolve, reject));
});
};
/**
* Close the database (recallable).
* @alias LowlevelUp#close
* @param {Function} callback
* @returns {Promise}
*/
LowlevelUp.prototype._close = function close(callback) {
this.binding.close(callback);
LowlevelUp.prototype._close = function close() {
var self = this;
return new Promise(function(resolve, reject) {
self.binding.close(co.wrap(resolve, reject));
});
};
/**
* Destroy the database.
* @param {Function} callback
* @returns {Promise}
*/
LowlevelUp.prototype.destroy = function destroy(callback) {
LowlevelUp.prototype.destroy = function destroy() {
var self = this;
assert(!this.loading);
assert(!this.closing);
assert(!this.loaded);
if (!this.backend.destroy)
return utils.asyncify(callback)(new Error('Cannot destroy.'));
this.backend.destroy(this.location, callback);
return new Promise(function(resolve, reject) {
if (!self.backend.destroy)
return reject(new Error('Cannot destroy.'));
self.backend.destroy(self.location, co.wrap(resolve, reject));
});
};
/**
* Repair the database.
* @param {Function} callback
* @returns {Promise}
*/
LowlevelUp.prototype.repair = function repair(callback) {
LowlevelUp.prototype.repair = function repair() {
var self = this;
assert(!this.loading);
assert(!this.closing);
assert(!this.loaded);
if (!this.backend.repair)
return utils.asyncify(callback)(new Error('Cannot repair.'));
this.backend.repair(this.location, callback);
return new Promise(function(resolve, reject) {
if (!self.backend.repair)
return reject(new Error('Cannot repair.'));
self.backend.repair(self.location, co.wrap(resolve, reject));
});
};
/**
* Backup the database.
* @param {String} path
* @param {Function} callback
* @returns {Promise}
*/
LowlevelUp.prototype.backup = function backup(path, callback) {
LowlevelUp.prototype.backup = function backup(path) {
var self = this;
assert(!this.loading);
assert(!this.closing);
assert(this.loaded);
if (!this.binding.backup)
return this.clone(path, callback);
return this.clone(path);
this.binding.backup(path, callback);
return new Promise(function(resolve, reject) {
self.binding.backup(path, co.wrap(resolve, reject));
});
};
/**
* Retrieve a record from the database.
* @param {String} key
* @param {Object?} options
* @param {Function} callback - Returns [Error, Buffer].
* @param {String|Buffer} key
* @returns {Promise} - Returns Buffer.
*/
LowlevelUp.prototype.get = function get(key, options, callback) {
LowlevelUp.prototype.get = function get(key) {
var self = this;
assert(this.loaded, 'Cannot use database before it is loaded.');
if (typeof options === 'function') {
callback = options;
options = {};
}
this.binding.get(key, options, function(err, result) {
if (err) {
if (isNotFound(err))
return callback();
return callback(err);
}
return callback(null, result);
return new Promise(function(resolve, reject) {
self.binding.get(key, function(err, result) {
if (err) {
if (isNotFound(err))
return resolve();
return reject(err);
}
return resolve(result);
});
});
};
/**
* Store a record in the database.
* @param {String} key
* @param {String|Buffer} key
* @param {Buffer} value
* @param {Object?} options
* @param {Function} callback
* @returns {Promise}
*/
LowlevelUp.prototype.put = function put(key, value, options, callback) {
LowlevelUp.prototype.put = function put(key, value) {
var self = this;
assert(this.loaded, 'Cannot use database before it is loaded.');
this.binding.put(key, value, options, callback);
return new Promise(function(resolve, reject) {
self.binding.put(key, value, co.wrap(resolve, reject));
});
};
/**
* Remove a record from the database.
* @param {String} key
* @param {Object?} options
* @param {Function} callback
* @param {String|Buffer} key
* @returns {Promise}
*/
LowlevelUp.prototype.del = function del(key, options, callback) {
LowlevelUp.prototype.del = function del(key) {
var self = this;
assert(this.loaded, 'Cannot use database before it is loaded.');
this.binding.del(key, options, callback);
return new Promise(function(resolve, reject) {
self.binding.del(key, co.wrap(resolve, reject));
});
};
/**
* Create an atomic batch.
* @param {Array?} ops
* @param {Object?} options
* @param {Function} callback
* @returns {Leveldown.Batch}
* @returns {Batch}
*/
LowlevelUp.prototype.batch = function batch(ops, options, callback) {
LowlevelUp.prototype.batch = function batch(ops) {
var self = this;
assert(this.loaded, 'Cannot use database before it is loaded.');
if (!ops)
return this.binding.batch();
return new Batch(this);
this.binding.batch(ops, options, callback);
return new Promise(function(resolve, reject) {
self.binding.batch(ops, co.wrap(resolve, reject));
});
};
/**
* Create an iterator.
* @param {Object} options
* @returns {Leveldown.Iterator}
* @returns {Iterator}
*/
LowlevelUp.prototype.iterator = function iterator(options) {
var opt;
assert(this.loaded, 'Cannot use database before it is loaded.');
return this.db.iterator(options);
opt = {
gte: options.gte,
lte: options.lte,
keys: options.keys !== false,
values: options.values || false,
fillCache: options.fillCache || false,
keyAsBuffer: this.bufferKeys,
valueAsBuffer: true,
reverse: options.reverse || false,
highWaterMark: options.highWaterMark || 16 * 1024
};
// Workaround for a leveldown
// bug I haven't fixed yet.
if (options.limit != null)
opt.limit = options.limit;
if (options.keyAsBuffer != null)
opt.keyAsBuffer = options.keyAsBuffer;
assert(opt.keys || opt.values, 'Keys and/or values must be chosen.');
return new Iterator(this, opt);
};
/**
@ -220,199 +266,215 @@ LowlevelUp.prototype.getProperty = function getProperty(name) {
* Calculate approximate database size.
* @param {String} start - Start key.
* @param {String} end - End key.
* @param {Function} callback - Returns [Error, Number].
* @returns {Promise} - Returns Number.
*/
LowlevelUp.prototype.approximateSize = function approximateSize(start, end, callback) {
LowlevelUp.prototype.approximateSize = function approximateSize(start, end) {
var self = this;
assert(this.loaded, 'Cannot use database before it is loaded.');
if (!this.binding.approximateSize)
return utils.asyncify(callback)(new Error('Cannot get size.'));
return new Promise(function(resolve, reject) {
if (!self.binding.approximateSize)
return reject(new Error('Cannot get size.'));
this.binding.approximateSize(start, end, callback);
self.binding.approximateSize(start, end, co.wrap(resolve, reject));
});
};
/**
* Test whether a key exists.
* @param {String} key
* @param {Function} callback - Returns [Error, Boolean].
* @returns {Promise} - Returns Boolean.
*/
LowlevelUp.prototype.has = function has(key, callback) {
this.get(key, function(err, value) {
if (err)
return callback(err);
return callback(null, value != null);
});
};
/**
* Get and deserialize a record with a callback.
* @param {String} key
* @param {Function} parse - Accepts [Buffer(data), String(key)].
* Return value should be the parsed object.
* @param {Function} callback - Returns [Error, Object].
*/
LowlevelUp.prototype.fetch = function fetch(key, parse, callback) {
this.get(key, function(err, value) {
if (err)
return callback(err);
if (!value)
return callback();
try {
value = parse(value, key);
} catch (e) {
return callback(e);
}
return callback(null, value);
});
};
/**
* Iterate over each record.
* @param {Object} options
* @param {Function} handler
* @param {Function} callback - Returns [Error, Object].
*/
LowlevelUp.prototype.each = function each(options, handler, callback) {
var i = 0;
var opt, iter;
opt = {
gte: options.gte,
lte: options.lte,
keys: options.keys !== false,
values: options.values || false,
fillCache: options.fillCache || false,
keyAsBuffer: this.bufferKeys,
valueAsBuffer: true,
reverse: options.reverse || false
};
// Workaround for a leveldown
// bug I haven't fixed yet.
if (options.limit != null)
opt.limit = options.limit;
if (options.keyAsBuffer != null)
opt.keyAsBuffer = options.keyAsBuffer;
assert(opt.keys || opt.values, 'Keys and/or values must be chosen.');
iter = this.iterator(opt);
function next(err, key) {
if (err && typeof err !== 'boolean') {
return iter.end(function() {
callback(err);
});
}
if (err === false)
return iter.end(callback);
if (err === true) {
try {
iter.seek(key);
} catch (e) {
return iter.end(function() {
callback(e);
});
}
}
iter.next(onNext);
}
function onNext(err, key, value) {
if (err) {
return iter.end(function() {
callback(err);
});
}
if (key === undefined && value === undefined)
return iter.end(callback);
try {
handler(key, value, next, i++);
} catch (e) {
return iter.end(function() {
callback(e);
});
}
}
next();
};
LowlevelUp.prototype.has = co(function* has(key) {
var value = yield this.get(key);
return value != null;
});
/**
* Collect all keys from iterator options.
* @param {Object} options - Iterator options.
* @param {Function} callback - Returns [Error, Array].
* @returns {Promise} - Returns Array.
*/
LowlevelUp.prototype.iterate = function iterate(options, callback) {
LowlevelUp.prototype.range = co(function* range(options) {
var items = [];
assert(typeof options.parse === 'function', 'Parse must be a function.');
this.each(options, function(key, value, next) {
var result = options.parse(key, value);
if (result)
items.push(result);
next();
}, function(err) {
if (err)
return callback(err);
callback(null, items);
var parse = options.parse;
var iter, item;
iter = this.iterator({
gte: options.gte,
lte: options.lte,
keys: true,
values: true
});
};
for (;;) {
item = yield iter.next();
if (!item)
break;
if (parse) {
try {
item = parse(item.key, item.value);
} catch (e) {
yield iter.end();
throw e;
}
}
if (item)
items.push(item);
}
return items;
});
/**
* Collect all keys from iterator options.
* @param {Object} options - Iterator options.
* @returns {Promise} - Returns Array.
*/
LowlevelUp.prototype.keys = co(function* keys(options) {
var keys = [];
var parse = options.parse;
var iter, item, key;
iter = this.iterator({
gte: options.gte,
lte: options.lte,
keys: true,
values: false
});
for (;;) {
item = yield iter.next();
if (!item)
break;
key = item.key;
if (parse) {
try {
key = parse(key);
} catch (e) {
yield iter.end();
throw e;
}
}
if (key)
keys.push(key);
}
return keys;
});
/**
* Collect all keys from iterator options.
* @param {Object} options - Iterator options.
* @returns {Promise} - Returns Array.
*/
LowlevelUp.prototype.values = co(function* values(options) {
var values = [];
var parse = options.parse;
var iter, item, value;
iter = this.iterator({
gte: options.gte,
lte: options.lte,
keys: false,
values: true
});
for (;;) {
item = yield iter.next();
if (!item)
break;
value = item.value;
if (parse) {
try {
value = parse(value);
} catch (e) {
yield iter.end();
throw e;
}
}
if (value)
values.push(value);
}
return values;
});
/**
* Dump database (for debugging).
* @returns {Promise} - Returns Object.
*/
LowlevelUp.prototype.dump = co(function* dump() {
var records = {};
var i, items, item, key, value;
items = yield this.range({
gte: new Buffer([0x00]),
lte: new Buffer([0xff])
});
for (i = 0; i < items.length; i++) {
item = items[i];
key = item.key.toString('hex');
value = item.value.toString('hex');
records[key] = value;
}
return records;
});
/**
* Write and assert a version number for the database.
* @param {Number} version
* @param {Function} callback
* @returns {Promise}
*/
LowlevelUp.prototype.checkVersion = function checkVersion(key, version, callback) {
var self = this;
this.get(key, function(err, data) {
if (err)
return callback(err);
LowlevelUp.prototype.checkVersion = co(function* checkVersion(key, version) {
var data = yield this.get(key);
if (!data) {
data = new Buffer(4);
data.writeUInt32LE(version, 0, true);
return self.put(key, data, callback);
}
if (!data) {
data = new Buffer(4);
data.writeUInt32LE(version, 0, true);
yield this.put(key, data);
return;
}
data = data.readUInt32LE(0, true);
data = data.readUInt32LE(0, true);
if (data !== version)
return callback(new Error(VERSION_ERROR));
callback();
});
};
if (data !== version)
throw new Error(VERSION_ERROR);
});
/**
* Clone the database.
* @param {String} path
* @param {Function} callback
* @returns {Promise}
*/
LowlevelUp.prototype.clone = function clone(path, callback) {
var self = this;
var iter = { keys: true, values: true };
LowlevelUp.prototype.clone = co(function* clone(path) {
var options = utils.merge({}, this.options);
var opt = { keys: true, values: true };
var hwm = 256 << 20;
var total = 0;
var tmp, batch;
var tmp, batch, iter, item;
assert(!this.loading);
assert(!this.closing);
@ -423,50 +485,159 @@ LowlevelUp.prototype.clone = function clone(path, callback) {
tmp = new LowlevelUp(path, options);
function done(err) {
tmp.close(function(e) {
if (e)
return callback(e);
callback(err);
});
yield tmp.open();
batch = tmp.batch();
iter = this.iterator(opt);
for (;;) {
item = yield iter.next();
if (!item)
break;
batch.put(item.key, item.value);
total += item.value.length;
if (total >= hwm) {
total = 0;
try {
yield batch.write();
} catch (e) {
yield iter.end();
yield tmp.close();
throw e;
}
batch = tmp.batch();
}
}
tmp.open(function(err) {
if (err)
return callback(err);
try {
yield batch.write();
} finally {
yield tmp.close();
}
});
batch = tmp.batch();
/**
* Batch
* @constructor
* @param {LowlevelUp} db
*/
self.each(iter, function(key, value, next) {
batch.put(key, value);
function Batch(db) {
this.batch = db.binding.batch();
}
total += value.length;
/**
* Write a value to the batch.
* @param {String|Buffer} key
* @param {Buffer} value
*/
if (total >= hwm) {
total = 0;
batch.write(function(err) {
if (err)
return next(err);
batch = tmp.batch();
next();
Batch.prototype.put = function(key, value) {
this.batch.put(key, value);
return this;
};
/**
* Delete a value from the batch.
* @param {String|Buffer} key
*/
Batch.prototype.del = function del(key) {
this.batch.del(key);
return this;
};
/**
* Write batch to database.
* @returns {Promise}
*/
Batch.prototype.write = function write() {
var self = this;
return new Promise(function(resolve, reject) {
self.batch.write(co.wrap(resolve, reject));
});
};
/**
* Clear the batch.
*/
Batch.prototype.clear = function clear() {
this.batch.clear();
return this;
};
/**
* Iterator
* @constructor
* @param {LowlevelUp} db
* @param {Object} options
*/
function Iterator(db, options) {
this.iter = db.db.iterator(options);
}
/**
* Seek to the next key.
* @returns {Promise}
*/
Iterator.prototype.next = function() {
var self = this;
return new Promise(function(resolve, reject) {
self.iter.next(function(err, key, value) {
if (err) {
self.iter.end(function() {
reject(err);
});
return;
}
next();
}, function(err) {
if (err)
return done(err);
if (key === undefined && value === undefined) {
self.iter.end(co.wrap(resolve, reject));
return;
}
batch.write(done);
resolve(new KeyValue(key, value));
});
});
};
/**
* Seek to an arbitrary key.
* @param {String|Buffer}
*/
Iterator.prototype.seek = function seek(key) {
this.iter.seek(key);
};
/**
* End the iterator.
* @returns {Promise}
*/
Iterator.prototype.end = function end() {
var self = this;
return new Promise(function(resolve, reject) {
self.iter.end(co.wrap(resolve, reject));
});
};
/*
* Helpers
*/
function KeyValue(key, value) {
this.key = key;
this.value = value;
}
function isNotFound(err) {
if (!err)
return false;

View file

@ -7,7 +7,7 @@
'use strict';
var utils = require('../utils/utils');
var assert = utils.assert;
var assert = require('assert');
var DUMMY = new Buffer([0]);
var RED = 0;
var BLACK = 1;
@ -15,9 +15,9 @@ var SENTINEL;
/**
* An iterative red black tree.
* Used for the mempool. Many of its
* options, parameters, and methods
* mimic the leveldown interface.
* Many of its options, parameters,
* and methods mimic the leveldown
* interface.
* @exports RBT
* @constructor
* @param {String?} location - Phony location.
@ -572,7 +572,7 @@ RBT.prototype.range = function range(gte, lte) {
/**
* Open the database (leveldown method).
* @param {Object?} options
* @param {Function} callback
* @returns {Promise}
*/
RBT.prototype.open = function open(options, callback) {
@ -586,23 +586,23 @@ RBT.prototype.open = function open(options, callback) {
this.options = options;
return utils.nextTick(callback);
utils.nextTick(callback);
};
/**
* Close the database (leveldown method).
* @param {Function} callback
* @returns {Promise}
*/
RBT.prototype.close = function close(callback) {
return utils.nextTick(callback);
utils.nextTick(callback);
};
/**
* Retrieve a record (leveldown method).
* @param {Buffer|String} key
* @param {Object?} options
* @param {Function} callback - Returns [Error, Buffer].
* @returns {Promise} - Returns Buffer.
*/
RBT.prototype.get = function get(key, options, callback) {
@ -622,13 +622,18 @@ RBT.prototype.get = function get(key, options, callback) {
err = new Error('RBT_NOTFOUND: Key not found.');
err.notFound = true;
err.type = 'NotFoundError';
return utils.asyncify(callback)(err);
utils.nextTick(function() {
callback(err);
});
return;
}
if (options.asBuffer === false)
value = value.toString('utf8');
return utils.asyncify(callback)(null, value);
utils.nextTick(function() {
callback(null, value);
});
};
/**
@ -636,7 +641,7 @@ RBT.prototype.get = function get(key, options, callback) {
* @param {Buffer|String} key
* @param {Buffer} value
* @param {Object?} options
* @param {Function} callback
* @returns {Promise}
*/
RBT.prototype.put = function put(key, value, options, callback) {
@ -647,14 +652,14 @@ RBT.prototype.put = function put(key, value, options, callback) {
this.insert(key, value);
return utils.nextTick(callback);
utils.nextTick(callback);
};
/**
* Remove a record (leveldown method).
* @param {Buffer|String} key
* @param {Object?} options
* @param {Function} callback
* @returns {Promise}
*/
RBT.prototype.del = function del(key, options, callback) {
@ -665,7 +670,7 @@ RBT.prototype.del = function del(key, options, callback) {
this.remove(key);
return utils.nextTick(callback);
utils.nextTick(callback);
};
/**
@ -673,7 +678,7 @@ RBT.prototype.del = function del(key, options, callback) {
* @see Leveldown.Batch
* @param {Object[]?} ops
* @param {Object?} options
* @param {Function} callback
* @returns {Promise}
* @returns {Leveldown.Batch}
*/
@ -722,7 +727,7 @@ RBT.prototype.getProperty = function getProperty(name) {
* Calculate approximate database size (leveldown method).
* @param {Buffer|String} start - Start key.
* @param {Buffer|String} end - End key.
* @param {Function} callback - Returns [Error, Number].
* @returns {Promise} - Returns Number.
*/
RBT.prototype.approximateSize = function approximateSize(start, end, callback) {
@ -736,27 +741,29 @@ RBT.prototype.approximateSize = function approximateSize(start, end, callback) {
size += item.value.length;
}
return utils.asyncify(callback)(null, size);
utils.nextTick(function() {
callback(null, size);
});
};
/**
* Destroy the database (leveldown function) (NOP).
* @param {String} location
* @param {Function} callback
* @returns {Promise}
*/
RBT.destroy = function destroy(location, callback) {
return utils.nextTick(callback);
utils.nextTick(callback);
};
/**
* Repair the database (leveldown function) (NOP).
* @param {String} location
* @param {Function} callback
* @returns {Promise}
*/
RBT.repair = function repair(location, callback) {
return utils.nextTick(callback);
utils.nextTick(callback);
};
/**
@ -934,23 +941,34 @@ Batch.prototype.del = function del(key) {
/**
* Commit the batch.
* @param {Function} callback
* @returns {Promise}
*/
Batch.prototype.write = function write(callback) {
var i, op;
if (!this.tree)
return callback(new Error('Already written.'));
if (!this.tree) {
utils.nextTick(function() {
callback(new Error('Already written.'));
});
return;
}
for (i = 0; i < this.ops.length; i++) {
op = this.ops[i];
if (op.type === 'put')
this.tree.insert(op.key, op.value);
else if (op.type === 'del')
this.tree.remove(op.key);
else
assert(false);
switch (op.type) {
case 'put':
this.tree.insert(op.key, op.value);
break;
case 'del':
this.tree.remove(op.key);
break;
default:
utils.nextTick(function() {
callback(new Error('Bad operation: ' + op.type));
});
return;
}
}
this.ops.length = 0;
@ -1023,14 +1041,18 @@ function Iterator(tree, options) {
/**
* Seek to the next key.
* @param {Function} callback
* @returns {Promise}
*/
Iterator.prototype.next = function(callback) {
var item, key, value;
if (this.ended)
return utils.asyncify(callback)(new Error('Cannot call next after end.'));
if (this.ended) {
utils.nextTick(function() {
callback(new Error('Cannot call next after end.'));
});
return;
}
if (this.options.reverse)
item = this.snapshot[this.index--];
@ -1040,13 +1062,15 @@ Iterator.prototype.next = function(callback) {
if (this.options.limit != null) {
if (this.total++ >= this.options.limit) {
this._end();
return utils.nextTick(callback);
utils.nextTick(callback);
return;
}
}
if (!item) {
this._end();
return utils.nextTick(callback);
utils.nextTick(callback);
return;
}
key = item.key;
@ -1064,7 +1088,9 @@ Iterator.prototype.next = function(callback) {
if (this.options.valueAsBuffer === false)
value = value.toString('utf8');
utils.asyncify(callback)(null, key, value);
utils.nextTick(function() {
callback(null, key, value);
});
};
/**
@ -1105,13 +1131,17 @@ Iterator.prototype._end = function end() {
*/
Iterator.prototype.end = function end(callback) {
if (this.ended)
return utils.asyncify(callback)(new Error('Already ended.'));
if (this.ended) {
utils.nextTick(function() {
callback(new Error('Already ended.'));
});
return;
}
this.ended = true;
this._end();
return utils.nextTick(callback);
utils.nextTick(callback);
};
/*

View file

@ -7,9 +7,6 @@
'use strict';
var utils = require('./utils/utils');
var global = utils.global;
/**
* A BCoin "environment" which is used for
* bootstrapping the initial `bcoin` module.
@ -126,13 +123,11 @@ function Environment() {
this.require('bloom', './utils/bloom');
this.require('uri', './utils/uri');
this.require('errors', './utils/errors');
this.require('co', './utils/co');
// Crypto
this.require('ec', './crypto/ec');
this.require('crypto', './crypto/crypto');
this.require('chachapoly', './crypto/chachapoly');
this.require('scrypt', './crypto/scrypt');
this.require('siphash', './crypto/siphash');
// DB
this.require('lowlevelup', './db/lowlevelup');
@ -145,7 +140,6 @@ function Environment() {
this.require('stack', './script/stack');
this.require('witness', './script/witness');
this.require('program', './script/program');
this.require('sc', './script/sigcache');
// Primitives
this.require('address', './primitives/address');
@ -156,8 +150,6 @@ function Environment() {
this.require('invitem', './primitives/invitem');
this.require('tx', './primitives/tx');
this.require('mtx', './primitives/mtx');
this.require('abstractblock', './primitives/abstractblock');
this.require('memblock', './primitives/memblock');
this.require('block', './primitives/block');
this.require('merkleblock', './primitives/merkleblock');
this.require('headers', './primitives/headers');
@ -175,7 +167,7 @@ function Environment() {
this.require('fullnode', './node/fullnode');
// Net
this.require('timedata', './net/timedata');
this.require('time', './net/timedata');
this.require('packets', './net/packets');
this.require('bip150', './net/bip150');
this.require('bip151', './net/bip151');
@ -184,8 +176,6 @@ function Environment() {
this.require('pool', './net/pool');
// Chain
this.require('coins', './chain/coins');
this.require('coinview', './chain/coinview');
this.require('chainentry', './chain/chainentry');
this.require('chaindb', './chain/chaindb');
this.require('chain', './chain/chain');
@ -193,7 +183,7 @@ function Environment() {
// Mempool
this.require('fees', './mempool/fees');
this.require('mempool', './mempool/mempool');
this.expose('mempoolentry', 'mempool', 'MempoolEntry');
this.require('mempoolentry', './mempool/mempoolentry');
// Miner
this.require('miner', './miner/miner');
@ -204,34 +194,18 @@ function Environment() {
this.require('account', './wallet/account');
this.require('walletdb', './wallet/walletdb');
this.require('path', './wallet/path');
this.require('masterkey', './wallet/masterkey');
this.require('walletkey', './wallet/walletkey');
// HTTP
this.require('http', './http');
this.require('rpc', './http/rpc');
// Workers
this.require('workers', './workers/workers');
// Horrible BIP
this.require('bip70', './bip70/bip70');
// Global Instances
this.instance('sigcache', 'sc', 0);
this.instance('time', 'timedata');
this.instance('defaultLogger', 'logger', 'none');
this.instance('workerPool', 'workers');
// Global Worker Properties
this.useWorkers = false;
this.master = null;
// Initialize the environment.
this.set({
network: process.env.BCOIN_NETWORK || 'main',
useWorkers: +process.env.BCOIN_USE_WORKERS === 1,
maxWorkers: +process.env.BCOIN_MAX_WORKERS,
workerTimeout: +process.env.BCOIN_WORKER_TIMEOUT,
sigcacheSize: +process.env.BCOIN_SIGCACHE_SIZE
});
this.require('bip70', './bip70');
}
/**
@ -249,38 +223,6 @@ Environment.prototype.require = function _require(key, path) {
});
};
/**
* Assign a property for a lazily required module.
* @param {String} key
* @param {String} object
* @param {String} property
*/
Environment.prototype.expose = function expose(key, object, property) {
var cache;
this.__defineGetter__(key, function() {
if (!cache)
cache = this[object][property];
return cache;
});
};
/**
* Assign an object instance for a lazily assigned property.
* @param {String} key
* @param {String} object
* @param {String} property
*/
Environment.prototype.instance = function instance(key, object, arg) {
var cache;
this.__defineGetter__(key, function() {
if (!cache)
cache = new this[object](arg);
return cache;
});
};
/**
* Set the default network.
* @param {String} options
@ -296,21 +238,9 @@ Environment.prototype.set = function set(options) {
if (options.network)
this.network.set(options.network);
if (typeof options.useWorkers === 'boolean')
this.useWorkers = options.useWorkers;
this.workers.set(options);
if (utils.isNumber(options.maxWorkers))
this.workerPool.size = options.maxWorkers;
if (utils.isNumber(options.workerTimeout))
this.workerPool.timeout = options.workerTimeout;
if (utils.isBrowser && this.useWorkers) {
this.useWorkers = typeof global.Worker === 'function'
|| typeof global.postMessage === 'function';
}
if (utils.isNumber(options.sigcacheSize))
if (options.sigcacheSize != null)
this.sigcache.resize(options.sigcacheSize);
return this;
@ -327,80 +257,15 @@ Environment.prototype.now = function now() {
/**
* Cache all necessary modules.
* Used for benchmarks and browserify.
*/
Environment.prototype.cache = function cache() {
require('bn.js');
require('./protocol/constants');
require('./protocol/networks');
require('./protocol/network');
require('./utils/utils');
require('./utils/locker');
require('./utils/reader');
require('./utils/writer');
require('./utils/lru');
require('./utils/bloom');
require('./utils/uri');
require('./utils/errors');
require('./crypto/ec');
require('./crypto/crypto');
require('./crypto/chachapoly');
require('./crypto/scrypt');
require('./crypto/siphash');
require('./db/lowlevelup');
require('./db/ldb');
require('./db/rbt');
require('./script/script');
require('./script/opcode');
require('./script/stack');
require('./script/witness');
require('./script/program');
require('./script/sigcache');
require('./primitives/address');
require('./primitives/outpoint');
require('./primitives/input');
require('./primitives/output');
require('./primitives/coin');
require('./primitives/invitem');
require('./primitives/tx');
require('./primitives/mtx');
require('./primitives/abstractblock');
require('./primitives/memblock');
require('./primitives/block');
require('./primitives/merkleblock');
require('./primitives/headers');
require('./primitives/keyring');
require('./primitives/netaddress');
require('./hd/hd');
require('./node/logger');
require('./node/config');
require('./node/node');
require('./node/spvnode');
require('./node/fullnode');
require('./net/timedata');
require('./net/packets');
require('./net/bip150');
require('./net/bip151');
require('./net/bip152');
require('./net/peer');
require('./net/pool');
require('./chain/coins');
require('./chain/coinview');
require('./chain/chainentry');
require('./chain/chaindb');
require('./chain/chain');
require('./mempool/fees');
require('./mempool/mempool');
require('./miner/miner');
require('./miner/minerblock');
require('./wallet/wallet');
require('./wallet/account');
require('./wallet/walletdb');
require('./wallet/path');
require('./node/spvnode');
require('./http');
require('./workers/workers');
require('./bip70/bip70');
require('./crypto/schnorr');
require('./utils/uri');
require('./bip70');
};
/*
@ -409,12 +274,8 @@ Environment.prototype.cache = function cache() {
*/
exports.require = Environment.prototype.require;
exports.expose = Environment.prototype.expose;
exports.instance = Environment.prototype.instance;
exports.cache = Environment.prototype.cache;
exports.set = Environment.prototype.set;
exports.now = Environment.prototype.now;
Environment.call(exports);
utils.fastProp(exports);

View file

@ -6,10 +6,8 @@
'use strict';
var bcoin = require('../env');
var utils = require('../utils/utils');
var assert = utils.assert;
var constants = bcoin.constants;
var assert = require('assert');
var constants = require('../protocol/constants');
var LRU = require('../utils/lru');
var Mnemonic = require('./mnemonic');
var HDPrivateKey = require('./private');
@ -114,26 +112,21 @@ HD.fromExtended = function fromExtended(data) {
*/
HD.from = function from(options, network) {
var xkey;
assert(options, 'Options required.');
if (options.xkey)
xkey = options.xkey;
else if (options.xpubkey)
xkey = options.xpubkey;
else if (options.xprivkey)
xkey = options.xprivkey;
else
xkey = options;
if (HD.isHD(options))
return options;
if (HD.isExtended(xkey))
return HD.fromBase58(xkey);
if (HD.isExtended(options))
return HD.fromBase58(options);
if (HD.hasPrefix(options))
return HD.fromRaw(options);
return HD.fromMnemonic(options, network);
if (options && typeof options === 'object')
return HD.fromMnemonic(options, network);
throw new Error('Cannot create HD key from bad options.');
};
/**

3
lib/hd/index.js Normal file
View file

@ -0,0 +1,3 @@
'use strict';
module.exports = require('./hd');

View file

@ -6,11 +6,10 @@
'use strict';
var bcoin = require('../env');
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var assert = utils.assert;
var constants = bcoin.constants;
var assert = require('assert');
var constants = require('../protocol/constants');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
var HD = require('./hd');

View file

@ -6,13 +6,13 @@
'use strict';
var bcoin = require('../env');
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var ec = require('../crypto/ec');
var assert = utils.assert;
var constants = bcoin.constants;
var networks = bcoin.networks;
var assert = require('assert');
var constants = require('../protocol/constants');
var networks = require('../protocol/networks');
var Network = require('../protocol/network');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
var HD = require('./hd');
@ -52,7 +52,7 @@ function HDPrivateKey(options) {
if (!(this instanceof HDPrivateKey))
return new HDPrivateKey(options);
this.network = bcoin.network.get();
this.network = Network.primary;
this.depth = 0;
this.parentFingerPrint = FINGER_PRINT;
this.childIndex = 0;
@ -89,7 +89,7 @@ HDPrivateKey.prototype.fromOptions = function fromOptions(options) {
assert(options.depth <= 0xff, 'Depth is too high.');
if (options.network)
this.network = bcoin.network.get(options.network);
this.network = Network.get(options.network);
this.depth = options.depth;
this.parentFingerPrint = options.parentFingerPrint;
@ -187,11 +187,19 @@ HDPrivateKey.prototype.destroy = function destroy(pub) {
* @returns {HDPrivateKey}
*/
HDPrivateKey.prototype.derive = function derive(index, hardened) {
HDPrivateKey.prototype.derive = function derive(index, hardened, cache) {
var p, id, data, hash, left, right, key, child;
if (typeof hardened !== 'boolean') {
cache = hardened;
hardened = false;
}
if (!cache)
cache = HD.cache;
if (typeof index === 'string')
return this.derivePath(index);
return this.derivePath(index, cache);
hardened = index >= constants.hd.HARDENED ? true : hardened;
@ -204,11 +212,12 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
if (this.depth >= 0xff)
throw new Error('Depth too high.');
id = this.getID(index);
child = HD.cache.get(id);
if (child)
return child;
if (cache) {
id = this.getID(index);
child = cache.get(id);
if (child)
return child;
}
p = new BufferWriter();
@ -230,7 +239,7 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
try {
key = ec.privateKeyTweakAdd(this.privateKey, left);
} catch (e) {
return this.derive(index + 1);
return this.derive(index + 1, cache);
}
if (!this.fingerPrint)
@ -245,7 +254,8 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
child.privateKey = key;
child.publicKey = ec.publicKeyCreate(key, true);
HD.cache.set(id, child);
if (cache)
cache.set(id, child);
return child;
};
@ -270,13 +280,13 @@ HDPrivateKey.prototype.getID = function getID(index) {
* @throws Error if key is not a master key.
*/
HDPrivateKey.prototype.deriveAccount44 = function deriveAccount44(accountIndex) {
HDPrivateKey.prototype.deriveAccount44 = function deriveAccount44(accountIndex, cache) {
assert(utils.isNumber(accountIndex), 'Account index must be a number.');
assert(this.isMaster(), 'Cannot derive account index.');
return this
.derive(44, true)
.derive(this.network.keyPrefix.coinType, true)
.derive(accountIndex, true);
.derive(44, true, cache)
.derive(this.network.keyPrefix.coinType, true, cache)
.derive(accountIndex, true, cache);
};
/**
@ -284,9 +294,9 @@ HDPrivateKey.prototype.deriveAccount44 = function deriveAccount44(accountIndex)
* @returns {HDPrivateKey}
*/
HDPrivateKey.prototype.derivePurpose45 = function derivePurpose45() {
HDPrivateKey.prototype.derivePurpose45 = function derivePurpose45(cache) {
assert(this.isMaster(), 'Cannot derive purpose 45.');
return this.derive(45, true);
return this.derive(45, true, cache);
};
/**
@ -395,13 +405,13 @@ HDPrivateKey.isValidPath = function isValidPath(path) {
* @throws Error if `path` is not a valid path.
*/
HDPrivateKey.prototype.derivePath = function derivePath(path) {
HDPrivateKey.prototype.derivePath = function derivePath(path, cache) {
var indexes = HD.parsePath(path, constants.hd.MAX_INDEX);
var key = this;
var i;
for (i = 0; i < indexes.length; i++)
key = key.derive(indexes[i]);
key = key.derive(indexes[i], cache);
return key;
};
@ -490,7 +500,7 @@ HDPrivateKey.prototype.fromSeed = function fromSeed(seed, network) {
if (!ec.privateKeyVerify(left))
throw new Error('Master private key is invalid.');
this.network = bcoin.network.get(network);
this.network = Network.get(network);
this.depth = 0;
this.parentFingerPrint = new Buffer([0, 0, 0, 0]);
this.childIndex = 0;
@ -549,7 +559,7 @@ HDPrivateKey.fromMnemonic = function fromMnemonic(mnemonic, network) {
HDPrivateKey.prototype.fromKey = function fromKey(key, entropy, network) {
assert(Buffer.isBuffer(key) && key.length === 32);
assert(Buffer.isBuffer(entropy) && entropy.length === 32);
this.network = bcoin.network.get(network);
this.network = Network.get(network);
this.depth = 0;
this.parentFingerPrint = new Buffer([0, 0, 0, 0]);
this.childIndex = 0;
@ -624,7 +634,7 @@ HDPrivateKey.prototype.fromRaw = function fromRaw(raw) {
assert(i < networks.types.length, 'Network not found.');
this.publicKey = ec.publicKeyCreate(this.privateKey, true);
this.network = bcoin.network.get(type);
this.network = Network.get(type);
return this;
};
@ -651,7 +661,7 @@ HDPrivateKey.prototype.toRaw = function toRaw(network, writer) {
if (!network)
network = this.network;
network = bcoin.network.get(network);
network = Network.get(network);
p.writeU32BE(network.keyPrefix.xprivkey);
p.writeU8(this.depth);

View file

@ -6,13 +6,13 @@
'use strict';
var bcoin = require('../env');
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var ec = require('../crypto/ec');
var assert = utils.assert;
var constants = bcoin.constants;
var networks = bcoin.networks;
var assert = require('assert');
var constants = require('../protocol/constants');
var networks = require('../protocol/networks');
var Network = require('../protocol/network');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
var HD = require('./hd');
@ -47,7 +47,7 @@ function HDPublicKey(options) {
if (!(this instanceof HDPublicKey))
return new HDPublicKey(options);
this.network = bcoin.network.get();
this.network = Network.primary;
this.depth = 0;
this.parentFingerPrint = FINGER_PRINT;
this.childIndex = 0;
@ -80,7 +80,7 @@ HDPublicKey.prototype.fromOptions = function fromOptions(options) {
assert(Buffer.isBuffer(options.publicKey));
if (options.network)
this.network = bcoin.network.get(options.network);
this.network = Network.get(options.network);
this.depth = options.depth;
this.parentFingerPrint = options.parentFingerPrint;
@ -140,11 +140,19 @@ HDPublicKey.prototype.destroy = function destroy() {
* @throws on `hardened`
*/
HDPublicKey.prototype.derive = function derive(index, hardened) {
HDPublicKey.prototype.derive = function derive(index, hardened, cache) {
var p, id, data, hash, left, right, key, child;
if (typeof hardened !== 'boolean') {
cache = hardened;
hardened = false;
}
if (!cache)
cache = HD.cache;
if (typeof index === 'string')
return this.derivePath(index);
return this.derivePath(index, cache);
if (index >= constants.hd.HARDENED || hardened)
throw new Error('Index out of range.');
@ -155,11 +163,12 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
if (this.depth >= 0xff)
throw new Error('Depth too high.');
id = this.getID(index);
child = HD.cache.get(id);
if (child)
return child;
if (cache) {
id = this.getID(index);
child = cache.get(id);
if (child)
return child;
}
p = new BufferWriter();
p.writeBytes(this.publicKey);
@ -173,7 +182,7 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
try {
key = ec.publicKeyTweakAdd(this.publicKey, left, true);
} catch (e) {
return this.derive(index + 1);
return this.derive(index + 1, cache);
}
if (!this.fingerPrint)
@ -187,7 +196,8 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
child.chainCode = right;
child.publicKey = key;
HD.cache.set(id, child);
if (cache)
cache.set(id, child);
return child;
};
@ -288,13 +298,13 @@ HDPublicKey.isValidPath = function isValidPath(path) {
* @throws Error if hardened.
*/
HDPublicKey.prototype.derivePath = function derivePath(path) {
HDPublicKey.prototype.derivePath = function derivePath(path, cache) {
var indexes = HD.parsePath(path, constants.hd.HARDENED);
var key = this;
var i;
for (i = 0; i < indexes.length; i++)
key = key.derive(indexes[i]);
key = key.derive(indexes[i], cache);
return key;
};
@ -475,7 +485,7 @@ HDPublicKey.prototype.fromRaw = function fromRaw(raw) {
assert(i < networks.types.length, 'Network not found.');
this.network = bcoin.network.get(type);
this.network = Network.get(type);
return this;
};
@ -502,7 +512,7 @@ HDPublicKey.prototype.toRaw = function toRaw(network, writer) {
if (!network)
network = this.network;
network = bcoin.network.get(network);
network = Network.get(network);
p.writeU32BE(network.keyPrefix.xpubkey);
p.writeU8(this.depth);

View file

@ -9,7 +9,7 @@
var AsyncObject = require('../utils/async');
var utils = require('../utils/utils');
var assert = utils.assert;
var assert = require('assert');
/**
* HTTPBase
@ -162,7 +162,7 @@ HTTPBase.prototype._initRouter = function _initRouter() {
// Avoid stack overflows
utils.nextTick(function() {
try {
callback(req, res, next, _send);
callback.call(route.ctx, req, res, _send, next);
} catch (e) {
done(e);
}
@ -208,28 +208,36 @@ HTTPBase.prototype._initIO = function _initIO() {
/**
* Open the server.
* @alias HTTPBase#open
* @param {Function} callback
* @returns {Promise}
*/
HTTPBase.prototype._open = function open(callback) {
HTTPBase.prototype._open = function open() {
assert(typeof this.options.port === 'number', 'Port required.');
this.listen(this.options.port, this.options.host, callback);
return this.listen(this.options.port, this.options.host);
};
/**
* Close the server.
* @alias HTTPBase#close
* @param {Function} callback
* @returns {Promise}
*/
HTTPBase.prototype._close = function close(callback) {
if (this.io) {
this.server.once('close', callback);
this.io.close();
return;
}
var self = this;
this.server.close(callback);
return new Promise(function(resolve, reject) {
if (self.io) {
self.server.once('close', resolve);
self.io.close();
return;
}
self.server.close(function(err) {
if (err)
return reject(err);
resolve();
});
});
};
/**
@ -237,7 +245,7 @@ HTTPBase.prototype._close = function close(callback) {
* @param {HTTPRequest} req
* @param {HTTPResponse} res
* @param {Function} _send
* @param {Function} callback
* @returns {Promise}
* @private
*/
@ -256,11 +264,11 @@ HTTPBase.prototype._handle = function _handle(req, res, _send, callback) {
handler = self.stack[i++];
utils.nextTick(function() {
if (handler.path && req.pathname.indexOf(handler.path) === -1)
if (handler.path && req.pathname.indexOf(handler.path) !== 0)
return next();
try {
handler.callback(req, res, next, _send);
handler.callback.call(handler.ctx, req, res, _send, next);
} catch (e) {
next(e);
}
@ -283,7 +291,7 @@ HTTPBase.prototype._handle = function _handle(req, res, _send, callback) {
* @param {RouteCallback} callback
*/
HTTPBase.prototype.use = function use(path, callback) {
HTTPBase.prototype.use = function use(path, callback, ctx) {
if (!callback) {
callback = path;
path = null;
@ -291,12 +299,12 @@ HTTPBase.prototype.use = function use(path, callback) {
if (Array.isArray(path)) {
path.forEach(function(path) {
this.use(path, callback);
this.use(path, callback, ctx);
}, this);
return;
}
this.stack.push({ path: path, callback: callback });
this.stack.push({ ctx: ctx, path: path, callback: callback });
};
/**
@ -305,14 +313,14 @@ HTTPBase.prototype.use = function use(path, callback) {
* @param {RouteCallback} callback
*/
HTTPBase.prototype.get = function get(path, callback) {
HTTPBase.prototype.get = function get(path, callback, ctx) {
if (Array.isArray(path)) {
path.forEach(function(path) {
this.get(path, callback);
this.get(path, callback, ctx);
}, this);
return;
}
this.routes.get.push({ path: path, callback: callback });
this.routes.get.push({ ctx: ctx, path: path, callback: callback });
};
/**
@ -321,14 +329,14 @@ HTTPBase.prototype.get = function get(path, callback) {
* @param {RouteCallback} callback
*/
HTTPBase.prototype.post = function post(path, callback) {
HTTPBase.prototype.post = function post(path, callback, ctx) {
if (Array.isArray(path)) {
path.forEach(function(path) {
this.post(path, callback);
this.post(path, callback, ctx);
}, this);
return;
}
this.routes.post.push({ path: path, callback: callback });
this.routes.post.push({ ctx: ctx, path: path, callback: callback });
};
/**
@ -337,14 +345,14 @@ HTTPBase.prototype.post = function post(path, callback) {
* @param {RouteCallback} callback
*/
HTTPBase.prototype.put = function put(path, callback) {
HTTPBase.prototype.put = function put(path, callback, ctx) {
if (Array.isArray(path)) {
path.forEach(function(path) {
this.put(path, callback);
this.put(path, callback, ctx);
}, this);
return;
}
this.routes.put.push({ path: path, callback: callback });
this.routes.put.push({ ctx: ctx, path: path, callback: callback });
};
/**
@ -353,14 +361,14 @@ HTTPBase.prototype.put = function put(path, callback) {
* @param {RouteCallback} callback
*/
HTTPBase.prototype.del = function del(path, callback) {
HTTPBase.prototype.del = function del(path, callback, ctx) {
if (Array.isArray(path)) {
path.forEach(function(path) {
this.del(path, callback);
this.del(path, callback, ctx);
}, this);
return;
}
this.routes.del.push({ path: path, callback: callback });
this.routes.del.push({ ctx: ctx, path: path, callback: callback });
};
/**
@ -376,26 +384,24 @@ HTTPBase.prototype.address = function address() {
* Listen on port and host.
* @param {Number} port
* @param {String?} host
* @param {Function} callback
* @returns {Promise}
*/
HTTPBase.prototype.listen = function listen(port, host, callback) {
HTTPBase.prototype.listen = function listen(port, host) {
var self = this;
var addr;
return new Promise(function(resolve, reject) {
var addr;
this.server.listen(port, host, function(err) {
if (err) {
if (callback)
return callback(err);
throw err;
}
self.server.listen(port, host, function(err) {
if (err)
return reject(err);
addr = self.address();
addr = self.address();
self.emit('listening', addr);
self.emit('listening', addr);
if (callback)
callback(null, addr);
resolve(addr);
});
});
};

View file

@ -11,8 +11,9 @@ var Network = require('../protocol/network');
var AsyncObject = require('../utils/async');
var RPCClient = require('./rpcclient');
var utils = require('../utils/utils');
var assert = utils.assert;
var request = require('./request');
var co = require('../utils/co');
var assert = require('assert');
var request = require('./request').promise;
/**
* BCoin HTTP client.
@ -44,7 +45,7 @@ function HTTPClient(options) {
this.rpc = new RPCClient(options);
// Open automatically.
this.open();
// this.open();
}
utils.inherits(HTTPClient, AsyncObject);
@ -52,10 +53,10 @@ utils.inherits(HTTPClient, AsyncObject);
/**
* Open the client, wait for socket to connect.
* @alias HTTPClient#open
* @param {Function} callback
* @returns {Promise}
*/
HTTPClient.prototype._open = function _open(callback) {
HTTPClient.prototype._open = co(function* _open() {
var self = this;
var IOClient;
@ -66,7 +67,7 @@ HTTPClient.prototype._open = function _open(callback) {
}
if (!IOClient)
return callback();
return;
this.socket = new IOClient(this.uri, {
transports: ['websocket'],
@ -115,11 +116,24 @@ HTTPClient.prototype._open = function _open(callback) {
});
});
this.socket.on('connect', function() {
yield this._onConnect();
yield this._sendAuth();
});
HTTPClient.prototype._onConnect = function _onConnect() {
var self = this;
return new Promise(function(resolve, reject) {
self.socket.once('connect', resolve);
});
};
HTTPClient.prototype._sendAuth = function _sendAuth() {
var self = this;
return new Promise(function(resolve, reject) {
self.socket.emit('auth', self.apiKey, function(err) {
if (err)
return callback(new Error(err.error));
callback();
return reject(new Error(err.error));
resolve();
});
});
};
@ -127,17 +141,17 @@ HTTPClient.prototype._open = function _open(callback) {
/**
* Close the client, wait for the socket to close.
* @alias HTTPClient#close
* @param {Function} callback
* @returns {Promise}
*/
HTTPClient.prototype._close = function close(callback) {
HTTPClient.prototype._close = function close() {
if (!this.socket)
return utils.nextTick(callback);
return Promise.resolve(null);
this.socket.disconnect();
this.socket = null;
utils.nextTick(callback);
return Promise.resolve(null);
};
/**
@ -146,17 +160,11 @@ HTTPClient.prototype._close = function close(callback) {
* @param {String} method
* @param {String} endpoint - Path.
* @param {Object} json - Body or query depending on method.
* @param {Function} callback - Returns [Error, Object?].
* @returns {Promise} - Returns Object?.
*/
HTTPClient.prototype._request = function _request(method, endpoint, json, callback) {
var self = this;
var query, network, height;
if (!callback) {
callback = json;
json = null;
}
HTTPClient.prototype._request = co(function* _request(method, endpoint, json) {
var query, network, height, res;
if (this.token) {
if (!json)
@ -169,7 +177,7 @@ HTTPClient.prototype._request = function _request(method, endpoint, json, callba
json = null;
}
request({
res = yield request({
method: method,
uri: this.uri + endpoint,
query: query,
@ -179,50 +187,43 @@ HTTPClient.prototype._request = function _request(method, endpoint, json, callba
password: this.apiKey || ''
},
expect: 'json'
}, function(err, res, body) {
if (err)
return callback(err);
network = res.headers['x-bcoin-network'];
if (network !== self.network.type)
return callback(new Error('Wrong network.'));
height = +res.headers['x-bcoin-height'];
if (utils.isNumber(height))
self.network.updateHeight(height);
if (res.statusCode === 404)
return callback();
if (!body)
return callback(new Error('No body.'));
if (res.statusCode !== 200) {
if (body.error)
return callback(new Error(body.error));
return callback(new Error('Status code: ' + res.statusCode));
}
try {
return callback(null, body);
} catch (e) {
return callback(e);
}
});
};
network = res.headers['x-bcoin-network'];
if (network !== this.network.type)
throw new Error('Wrong network.');
height = +res.headers['x-bcoin-height'];
if (utils.isNumber(height))
this.network.updateHeight(height);
if (res.statusCode === 404)
return;
if (!res.body)
throw new Error('No body.');
if (res.statusCode !== 200) {
if (res.body.error)
throw new Error(res.body.error);
throw new Error('Status code: ' + res.statusCode);
}
return res.body;
});
/**
* Make a GET http request to endpoint.
* @private
* @param {String} endpoint - Path.
* @param {Object} json - Querystring.
* @param {Function} callback - Returns [Error, Object?].
* @returns {Promise} - Returns Object?.
*/
HTTPClient.prototype._get = function _get(endpoint, json, callback) {
this._request('get', endpoint, json, callback);
HTTPClient.prototype._get = function _get(endpoint, json) {
return this._request('get', endpoint, json);
};
/**
@ -230,11 +231,11 @@ HTTPClient.prototype._get = function _get(endpoint, json, callback) {
* @private
* @param {String} endpoint - Path.
* @param {Object} json - Body.
* @param {Function} callback - Returns [Error, Object?].
* @returns {Promise} - Returns Object?.
*/
HTTPClient.prototype._post = function _post(endpoint, json, callback) {
this._request('post', endpoint, json, callback);
HTTPClient.prototype._post = function _post(endpoint, json) {
return this._request('post', endpoint, json);
};
/**
@ -242,11 +243,11 @@ HTTPClient.prototype._post = function _post(endpoint, json, callback) {
* @private
* @param {String} endpoint - Path.
* @param {Object} json - Body.
* @param {Function} callback - Returns [Error, Object?].
* @returns {Promise} - Returns Object?.
*/
HTTPClient.prototype._put = function _put(endpoint, json, callback) {
this._request('put', endpoint, json, callback);
HTTPClient.prototype._put = function _put(endpoint, json) {
return this._request('put', endpoint, json);
};
/**
@ -254,41 +255,41 @@ HTTPClient.prototype._put = function _put(endpoint, json, callback) {
* @private
* @param {String} endpoint - Path.
* @param {Object} json - Body.
* @param {Function} callback - Returns [Error, Object?].
* @returns {Promise} - Returns Object?.
*/
HTTPClient.prototype._del = function _del(endpoint, json, callback) {
this._request('delete', endpoint, json, callback);
HTTPClient.prototype._del = function _del(endpoint, json) {
return this._request('delete', endpoint, json);
};
/**
* Get a mempool snapshot.
* @param {Function} callback - Returns [Error, {@link TX}[]].
* @returns {Promise} - Returns {@link TX}[].
*/
HTTPClient.prototype.getMempool = function getMempool(callback) {
this._get('/mempool', callback);
HTTPClient.prototype.getMempool = function getMempool() {
return this._get('/mempool');
};
/**
* Get some info about the server (network and version).
* @param {Function} callback - Returns [Error, Object].
* @returns {Promise} - Returns Object.
*/
HTTPClient.prototype.getInfo = function getInfo(callback) {
this._get('/', callback);
HTTPClient.prototype.getInfo = function getInfo() {
return this._get('/');
};
/**
* Get coins that pertain to an address from the mempool or chain database.
* Takes into account spent coins in the mempool.
* @param {Base58Address|Base58Address[]} addresses
* @param {Function} callback - Returns [Error, {@link Coin}[]].
* @returns {Promise} - Returns {@link Coin}[].
*/
HTTPClient.prototype.getCoinsByAddress = function getCoinsByAddress(address, callback) {
HTTPClient.prototype.getCoinsByAddress = function getCoinsByAddress(address) {
var body = { address: address };
this._post('/coin/address', body, callback);
return this._post('/coin/address', body);
};
/**
@ -296,56 +297,55 @@ HTTPClient.prototype.getCoinsByAddress = function getCoinsByAddress(address, cal
* Takes into account spent coins in the mempool.
* @param {Hash} hash
* @param {Number} index
* @param {Function} callback - Returns [Error, {@link Coin}].
* @returns {Promise} - Returns {@link Coin}.
*/
HTTPClient.prototype.getCoin = function getCoin(hash, index, callback) {
this._get('/coin/' + hash + '/' + index, callback);
HTTPClient.prototype.getCoin = function getCoin(hash, index) {
return this._get('/coin/' + hash + '/' + index);
};
/**
* Retrieve transactions pertaining to an
* address from the mempool or chain database.
* @param {Base58Address|Base58Address[]} addresses
* @param {Function} callback - Returns [Error, {@link TX}[]].
* @returns {Promise} - Returns {@link TX}[].
*/
HTTPClient.prototype.getTXByAddress = function getTXByAddress(address, callback) {
HTTPClient.prototype.getTXByAddress = function getTXByAddress(address) {
var body = { address: address };
this._post('/tx/address', body, callback);
return this._post('/tx/address', body);
};
/**
* Retrieve a transaction from the mempool or chain database.
* @param {Hash} hash
* @param {Function} callback - Returns [Error, {@link TX}].
* @returns {Promise} - Returns {@link TX}.
*/
HTTPClient.prototype.getTX = function getTX(hash, callback) {
this._get('/tx/' + hash, callback);
HTTPClient.prototype.getTX = function getTX(hash) {
return this._get('/tx/' + hash);
};
/**
* Retrieve a block from the chain database.
* @param {Hash} hash
* @param {Function} callback - Returns [Error, {@link Block}].
* @returns {Promise} - Returns {@link Block}.
*/
HTTPClient.prototype.getBlock = function getBlock(hash, callback) {
this._get('/block/' + hash, callback);
HTTPClient.prototype.getBlock = function getBlock(hash) {
return this._get('/block/' + hash);
};
/**
* Add a transaction to the mempool and broadcast it.
* @param {TX} tx
* @param {Function} callback
* @returns {Promise}
*/
HTTPClient.prototype.broadcast = function broadcast(tx, callback) {
HTTPClient.prototype.broadcast = function broadcast(tx) {
var body = { tx: toHex(tx) };
this._post('/broadcast', body, callback);
return this._post('/broadcast', body);
};
/**
@ -353,11 +353,19 @@ HTTPClient.prototype.broadcast = function broadcast(tx, callback) {
* @param {WalletID} id
*/
HTTPClient.prototype.join = function join(id, token, callback) {
if (!this.socket)
return callback();
HTTPClient.prototype.join = function join(id, token) {
var self = this;
this.socket.emit('wallet join', id, token, callback);
if (!this.socket)
return Promise.resolve(null);
return new Promise(function(resolve, reject) {
self.socket.emit('wallet join', id, token, function(err) {
if (err)
return reject(new Error(err.error));
resolve();
});
});
};
/**
@ -365,145 +373,113 @@ HTTPClient.prototype.join = function join(id, token, callback) {
* @param {WalletID} id
*/
HTTPClient.prototype.leave = function leave(id, callback) {
if (!this.socket)
return callback();
HTTPClient.prototype.leave = function leave(id) {
var self = this;
this.socket.emit('wallet leave', id, callback);
if (!this.socket)
return Promise.resolve(null);
return new Promise(function(resolve, reject) {
self.socket.emit('wallet leave', id, function(err) {
if (err)
return reject(new Error(err.error));
resolve();
});
});
};
/**
* Listen for events on all wallets.
*/
HTTPClient.prototype.all = function all(token, callback) {
this.join('!all', token, callback);
HTTPClient.prototype.all = function all(token) {
return this.join('!all', token);
};
/**
* Unlisten for events on all wallets.
*/
HTTPClient.prototype.none = function none(callback) {
this.leave('!all', callback);
HTTPClient.prototype.none = function none() {
return this.leave('!all');
};
/**
* Request the raw wallet JSON (will create wallet if it does not exist).
* @private
* @param {Object} options - See {@link Wallet}.
* @param {Function} callback - Returns [Error, Object].
* @returns {Promise} - Returns Object.
*/
HTTPClient.prototype.createWallet = function createWallet(options, callback) {
this._post('/wallet', options, callback);
HTTPClient.prototype.createWallet = function createWallet(options) {
return this._post('/wallet', options);
};
/**
* Get the raw wallet JSON.
* @private
* @param {WalletID} id
* @param {Function} callback - Returns [Error, Object].
* @returns {Promise} - Returns Object.
*/
HTTPClient.prototype.getWallet = function getWallet(id, callback) {
this._get('/wallet/' + id, callback);
HTTPClient.prototype.getWallet = function getWallet(id) {
return this._get('/wallet/' + id);
};
/**
* Get wallet transaction history.
* @param {WalletID} id
* @param {Function} callback - Returns [Error, {@link TX}[]].
* @returns {Promise} - Returns {@link TX}[].
*/
HTTPClient.prototype.getHistory = function getHistory(id, account, callback) {
var options;
if (typeof account === 'function') {
callback = account;
account = null;
}
options = { account: account };
this._get('/wallet/' + id + '/tx/history', options, callback);
HTTPClient.prototype.getHistory = function getHistory(id, account) {
var options = { account: account };
return this._get('/wallet/' + id + '/tx/history', options);
};
/**
* Get wallet coins.
* @param {WalletID} id
* @param {Function} callback - Returns [Error, {@link Coin}[]].
* @returns {Promise} - Returns {@link Coin}[].
*/
HTTPClient.prototype.getCoins = function getCoins(id, account, callback) {
var options;
if (typeof account === 'function') {
callback = account;
account = null;
}
options = { account: account };
this._get('/wallet/' + id + '/coin', options, callback);
HTTPClient.prototype.getCoins = function getCoins(id, account) {
var options = { account: account };
return this._get('/wallet/' + id + '/coin', options);
};
/**
* Get all unconfirmed transactions.
* @param {WalletID} id
* @param {Function} callback - Returns [Error, {@link TX}[]].
* @returns {Promise} - Returns {@link TX}[].
*/
HTTPClient.prototype.getUnconfirmed = function getUnconfirmed(id, account, callback) {
var options;
if (typeof account === 'function') {
callback = account;
account = null;
}
options = { account: account };
this._get('/wallet/' + id + '/tx/unconfirmed', options, callback);
HTTPClient.prototype.getUnconfirmed = function getUnconfirmed(id, account) {
var options = { account: account };
return this._get('/wallet/' + id + '/tx/unconfirmed', options);
};
/**
* Calculate wallet balance.
* @param {WalletID} id
* @param {Function} callback - Returns [Error, {@link Balance}].
* @returns {Promise} - Returns {@link Balance}.
*/
HTTPClient.prototype.getBalance = function getBalance(id, account, callback) {
var options;
if (typeof account === 'function') {
callback = account;
account = null;
}
options = { account: account };
this._get('/wallet/' + id + '/balance', options, callback);
HTTPClient.prototype.getBalance = function getBalance(id, account) {
var options = { account: account };
return this._get('/wallet/' + id + '/balance', options);
};
/**
* Get last N wallet transactions.
* @param {WalletID} id
* @param {Number} limit - Max number of transactions.
* @param {Function} callback - Returns [Error, {@link TX}[]].
* @returns {Promise} - Returns {@link TX}[].
*/
HTTPClient.prototype.getLast = function getLast(id, account, limit, callback) {
var options;
if (typeof account === 'function') {
callback = account;
account = null;
}
options = { account: account, limit: limit };
this._get('/wallet/' + id + '/tx/last', options, callback);
HTTPClient.prototype.getLast = function getLast(id, account, limit) {
var options = { account: account, limit: limit };
return this._get('/wallet/' + id + '/tx/last', options);
};
/**
@ -514,16 +490,10 @@ HTTPClient.prototype.getLast = function getLast(id, account, limit, callback) {
* @param {Number} options.end - End time.
* @param {Number?} options.limit - Max number of records.
* @param {Boolean?} options.reverse - Reverse order.
* @param {Function} callback - Returns [Error, {@link TX}[]].
* @returns {Promise} - Returns {@link TX}[].
*/
HTTPClient.prototype.getRange = function getRange(id, account, options, callback) {
if (typeof options === 'function') {
callback = options;
options = account;
account = null;
}
HTTPClient.prototype.getRange = function getRange(id, account, options) {
options = {
account: account,
start: options.start,
@ -531,8 +501,7 @@ HTTPClient.prototype.getRange = function getRange(id, account, options, callback
limit: options.limit,
reverse: options.reverse
};
this._get('/wallet/' + id + '/tx/range', options, callback);
return this._get('/wallet/' + id + '/tx/range', options);
};
/**
@ -540,21 +509,12 @@ HTTPClient.prototype.getRange = function getRange(id, account, options, callback
* is available in the wallet history).
* @param {WalletID} id
* @param {Hash} hash
* @param {Function} callback - Returns [Error, {@link TX}[]].
* @returns {Promise} - Returns {@link TX}[].
*/
HTTPClient.prototype.getWalletTX = function getWalletTX(id, account, hash, callback) {
var options;
if (typeof hash === 'function') {
callback = hash;
hash = account;
account = null;
}
options = { account: account };
this._get('/wallet/' + id + '/tx/' + hash, options, callback);
HTTPClient.prototype.getWalletTX = function getWalletTX(id, account, hash) {
var options = { account: account };
return this._get('/wallet/' + id + '/tx/' + hash, options);
};
/**
@ -563,24 +523,13 @@ HTTPClient.prototype.getWalletTX = function getWalletTX(id, account, hash, callb
* @param {WalletID} id
* @param {Hash} hash
* @param {Number} index
* @param {Function} callback - Returns [Error, {@link Coin}[]].
* @returns {Promise} - Returns {@link Coin}[].
*/
HTTPClient.prototype.getWalletCoin = function getWalletCoin(id, account, hash, index, callback) {
var options, path;
if (typeof hash === 'function') {
callback = index;
index = hash;
hash = account;
account = null;
}
options = { account: account };
path = '/wallet/' + id + '/coin/' + hash + '/' + index;
this._get(path, options, callback);
HTTPClient.prototype.getWalletCoin = function getWalletCoin(id, account, hash, index) {
var path = '/wallet/' + id + '/coin/' + hash + '/' + index;
var options = { account: account };
return this._get(path, options);
};
/**
@ -589,10 +538,10 @@ HTTPClient.prototype.getWalletCoin = function getWalletCoin(id, account, hash, i
* @param {Object} options
* @param {Base58Address} options.address
* @param {Amount} options.value
* @param {Function} callback - Returns [Error, {@link TX}].
* @returns {Promise} - Returns {@link TX}.
*/
HTTPClient.prototype.send = function send(id, options, callback) {
HTTPClient.prototype.send = function send(id, options) {
options = utils.merge({}, options);
options.outputs = options.outputs || [];
@ -607,54 +556,41 @@ HTTPClient.prototype.send = function send(id, options, callback) {
};
});
this._post('/wallet/' + id + '/send', options, callback);
return this._post('/wallet/' + id + '/send', options);
};
/**
* Generate a new token.
* @param {(String|Buffer)?} passphrase
* @param {Function} callback
* @returns {Promise}
*/
HTTPClient.prototype.retoken = function retoken(id, passphrase, callback) {
var options;
if (typeof passphrase === 'function') {
callback = passphrase;
passphrase = null;
}
options = { passphrase: passphrase };
this._post('/wallet/' + id + '/retoken', options, function(err, body) {
if (err)
return callback(err);
return callback(null, body.token);
});
};
HTTPClient.prototype.retoken = co(function* retoken(id, passphrase) {
var options = { passphrase: passphrase };
var body = yield this._post('/wallet/' + id + '/retoken', options);
return body.token;
});
/**
* Change or set master key's passphrase.
* @param {(String|Buffer)?} old
* @param {String|Buffer} new_
* @param {Function} callback
* @returns {Promise}
*/
HTTPClient.prototype.setPassphrase = function setPassphrase(id, old, new_, callback) {
HTTPClient.prototype.setPassphrase = function setPassphrase(id, old, new_) {
var options = { old: old, passphrase: new_ };
this._post('/wallet/' + id + '/passphrase', options, callback);
return this._post('/wallet/' + id + '/passphrase', options);
};
/**
* Create a transaction, fill.
* @param {WalletID} id
* @param {Object} options
* @param {Function} callback - Returns [Error, {@link TX}].
* @returns {Promise} - Returns {@link TX}.
*/
HTTPClient.prototype.createTX = function createTX(id, options, callback) {
HTTPClient.prototype.createTX = function createTX(id, options) {
options = utils.merge({}, options);
if (options.rate)
@ -668,7 +604,7 @@ HTTPClient.prototype.createTX = function createTX(id, options, callback) {
};
});
this._post('/wallet/' + id + '/create', options, callback);
return this._post('/wallet/' + id + '/create', options);
};
/**
@ -676,61 +612,46 @@ HTTPClient.prototype.createTX = function createTX(id, options, callback) {
* @param {WalletID} id
* @param {TX} tx
* @param {Object} options
* @param {Function} callback - Returns [Error, {@link TX}].
* @returns {Promise} - Returns {@link TX}.
*/
HTTPClient.prototype.sign = function sign(id, tx, options, callback) {
HTTPClient.prototype.sign = function sign(id, tx, options) {
var body;
if (typeof options === 'function') {
callback = options;
options = null;
}
if (!options)
options = {};
body = utils.merge({}, options);
body.tx = toHex(tx);
this._post('/wallet/' + id + '/sign', body, callback);
return this._post('/wallet/' + id + '/sign', body);
};
/**
* Fill a transaction with coins.
* @param {TX} tx
* @param {Function} callback - Returns [Error, {@link TX}].
* @returns {Promise} - Returns {@link TX}.
*/
HTTPClient.prototype.fillCoins = function fillCoins(id, tx, callback) {
HTTPClient.prototype.fillCoins = function fillCoins(id, tx) {
var body = { tx: toHex(tx) };
this._post('/wallet/' + id + '/fill', body, callback);
return this._post('/wallet/' + id + '/fill', body);
};
/**
* @param {WalletID} id
* @param {Number} now - Current time.
* @param {Number} age - Age delta (delete transactions older than `now - age`).
* @param {Function} callback
* @returns {Promise}
*/
HTTPClient.prototype.zap = function zap(id, account, age, callback) {
var body;
if (typeof age === 'function') {
callback = age;
age = account;
account = null;
}
body = {
HTTPClient.prototype.zap = function zap(id, account, age) {
var body = {
account: account,
age: age
};
assert(utils.isNumber(age));
this._post('/wallet/' + id + '/zap', body, callback);
return this._post('/wallet/' + id + '/zap', body);
};
/**
@ -739,22 +660,16 @@ HTTPClient.prototype.zap = function zap(id, account, age, callback) {
* @param {(String|Number)?} account
* @param {HDPublicKey|Base58String} key - Account (bip44) or
* Purpose (bip45) key (can be in base58 form).
* @param {Function} callback
* @returns {Promise}
*/
HTTPClient.prototype.addKey = function addKey(id, account, key, callback) {
HTTPClient.prototype.addKey = function addKey(id, account, key) {
var options;
if (typeof key === 'function') {
callback = key;
key = account;
account = null;
}
key = key.xpubkey || key;
options = { account: account, key: key };
this._put('/wallet/' + id + '/key', options, callback);
return this._put('/wallet/' + id + '/key', options);
};
/**
@ -763,62 +678,51 @@ HTTPClient.prototype.addKey = function addKey(id, account, key, callback) {
* @param {(String|Number)?} account
* @param {HDPublicKey|Base58String} key - Account (bip44) or Purpose
* (bip45) key (can be in base58 form).
* @param {Function} callback
* @returns {Promise}
*/
HTTPClient.prototype.removeKey = function removeKey(id, account, key, callback) {
HTTPClient.prototype.removeKey = function removeKey(id, account, key) {
var options;
if (typeof key === 'function') {
callback = key;
key = account;
account = null;
}
key = key.xpubkey || key;
options = { account: account, key: key };
this._del('/wallet/' + id + '/key', options, callback);
return this._del('/wallet/' + id + '/key', options);
};
/**
* Get wallet accounts.
* @param {WalletID} id
* @param {Function} callback - Returns [Error, Array].
* @returns {Promise} - Returns Array.
*/
HTTPClient.prototype.getAccounts = function getAccounts(id, callback) {
HTTPClient.prototype.getAccounts = function getAccounts(id) {
var path = '/wallet/' + id + '/account';
this._get(path, callback);
return this._get(path);
};
/**
* Get wallet account.
* @param {WalletID} id
* @param {String} account
* @param {Function} callback - Returns [Error, Array].
* @returns {Promise} - Returns Array.
*/
HTTPClient.prototype.getAccount = function getAccount(id, account, callback) {
HTTPClient.prototype.getAccount = function getAccount(id, account) {
var path = '/wallet/' + id + '/account/' + account;
this._get(path, callback);
return this._get(path);
};
/**
* Create account.
* @param {WalletID} id
* @param {Object} options
* @param {Function} callback - Returns [Error, Array].
* @returns {Promise} - Returns Array.
*/
HTTPClient.prototype.createAccount = function createAccount(id, options, callback) {
HTTPClient.prototype.createAccount = function createAccount(id, options) {
var path;
if (typeof options === 'function') {
callback = options;
options = null;
}
if (!options)
options = {};
@ -827,24 +731,19 @@ HTTPClient.prototype.createAccount = function createAccount(id, options, callbac
path = '/wallet/' + id + '/account';
this._post(path, options, callback);
return this._post(path, options);
};
/**
* Create address.
* @param {WalletID} id
* @param {Object} options
* @param {Function} callback - Returns [Error, Array].
* @returns {Promise} - Returns Array.
*/
HTTPClient.prototype.createAddress = function createAddress(id, options, callback) {
HTTPClient.prototype.createAddress = function createAddress(id, options) {
var path;
if (typeof options === 'function') {
callback = options;
options = null;
}
if (!options)
options = {};
@ -853,7 +752,28 @@ HTTPClient.prototype.createAddress = function createAddress(id, options, callbac
path = '/wallet/' + id + '/address';
this._post(path, options, callback);
return this._post(path, options);
};
/**
* Create address.
* @param {WalletID} id
* @param {Object} options
* @returns {Promise} - Returns Array.
*/
HTTPClient.prototype.createNested = function createNested(id, options) {
var path;
if (!options)
options = {};
if (typeof options === 'string')
options = { account: options };
path = '/wallet/' + id + '/nested';
return this._post(path, options);
};
/*

View file

@ -11,8 +11,12 @@ var utils = require('../utils/utils');
if (!utils.isBrowser) {
exports.request = require('./request');
exports.client = require('./client');
exports.wallet = require('./wallet');
exports.base = require('./base');
exports.server = require('./server');
exports.Client = require('./client');
exports.RPCClient = require('./rpcclient');
exports.Wallet = require('./wallet');
exports.Base = require('./base');
exports.RPC = require('./rpc');
exports.Server = require('./server');
} else {
exports.RPC = require('./rpc');
}

View file

@ -14,7 +14,7 @@
*/
var Stream = require('stream').Stream;
var assert = require('../utils/utils').assert;
var assert = require('assert');
// Spoof by default
var USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1)'
@ -301,6 +301,17 @@ request._buffer = function(options, callback) {
return stream;
};
request.promise = function promise(options) {
return new Promise(function(resolve, reject) {
request(options, function(err, res, body) {
if (err)
return reject(err);
res.body = body;
resolve(res);
});
});
};
/*
* ReqStream
*/

File diff suppressed because it is too large Load diff

View file

@ -8,6 +8,7 @@
var Network = require('../protocol/network');
var request = require('./request');
var co = require('../utils/co');
/**
* BCoin RPC client.
@ -40,11 +41,11 @@ function RPCClient(options) {
* @private
* @param {String} method - RPC method name.
* @param {Array} params - RPC parameters.
* @param {Function} callback - Returns [Error, Object?].
* @returns {Promise} - Returns Object?.
*/
RPCClient.prototype.call = function call(method, params, callback) {
request({
RPCClient.prototype.call = co(function* call(method, params) {
var res = yield request.promise({
method: 'POST',
uri: this.uri,
json: {
@ -57,25 +58,22 @@ RPCClient.prototype.call = function call(method, params, callback) {
password: this.apiKey || ''
},
expect: 'json'
}, function(err, res, body) {
if (err)
return callback(err);
if (!body)
return callback();
if (res.statusCode === 400)
return callback(null, body.result);
if (res.statusCode !== 200) {
if (body.error)
return callback(new Error(body.error.message));
return callback(new Error('Status code: ' + res.statusCode));
}
return callback(null, body.result);
});
};
if (!res.body)
return;
if (res.statusCode === 400)
return res.body.result;
if (res.statusCode !== 200) {
if (res.body.error)
throw new Error(res.body.error.message);
throw new Error('Status code: ' + res.statusCode);
}
return res.body.result;
});
/*
* Expose

File diff suppressed because it is too large Load diff

View file

@ -11,6 +11,7 @@ var Network = require('../protocol/network');
var EventEmitter = require('events').EventEmitter;
var utils = require('../utils/utils');
var co = require('../utils/co');
var Client = require('./client');
/**
@ -85,11 +86,11 @@ HTTPWallet.prototype._init = function _init() {
/**
* Open the client and get a wallet.
* @alias HTTPWallet#open
* @param {Function} callback
* @returns {Promise}
*/
HTTPWallet.prototype.open = function open(options, callback) {
var self = this;
HTTPWallet.prototype.open = co(function* open(options) {
var wallet;
this.id = options.id;
@ -100,159 +101,143 @@ HTTPWallet.prototype.open = function open(options, callback) {
this.client.token = this.token;
}
this.client.open(function(err) {
if (err)
return callback(err);
yield this.client.open();
self.client.getWallet(self.id, function(err, wallet) {
if (err)
return callback(err);
self.client.join(self.id, wallet.token, function(err) {
if (err)
return callback(new Error(err.error));
callback(null, wallet);
});
});
});
};
wallet = yield this.client.getWallet(this.id);
yield this.client.join(this.id, wallet.token);
return wallet;
});
/**
* Open the client and create a wallet.
* @alias HTTPWallet#open
* @param {Function} callback
* @returns {Promise}
*/
HTTPWallet.prototype.create = function create(options, callback) {
var self = this;
this.client.open(function(err) {
if (err)
return callback(err);
self.client.createWallet(options, function(err, wallet) {
if (err)
return callback(err);
self.open({
id: wallet.id,
token: wallet.token
}, callback);
});
HTTPWallet.prototype.create = co(function* create(options) {
var wallet;
yield this.client.open();
wallet = yield this.client.createWallet(options);
return yield this.open({
id: wallet.id,
token: wallet.token
});
};
});
/**
* Close the client, wait for the socket to close.
* @alias HTTPWallet#close
* @param {Function} callback
* @returns {Promise}
*/
HTTPWallet.prototype.close = function close(callback) {
this.client.close(callback);
HTTPWallet.prototype.close = function close() {
return this.client.close();
};
/**
* @see Wallet#getHistory
*/
HTTPWallet.prototype.getHistory = function getHistory(account, callback) {
this.client.getHistory(this.id, account, callback);
HTTPWallet.prototype.getHistory = function getHistory(account) {
return this.client.getHistory(this.id, account);
};
/**
* @see Wallet#getCoins
*/
HTTPWallet.prototype.getCoins = function getCoins(account, callback) {
this.client.getCoins(this.id, account, callback);
HTTPWallet.prototype.getCoins = function getCoins(account) {
return this.client.getCoins(this.id, account);
};
/**
* @see Wallet#getUnconfirmed
*/
HTTPWallet.prototype.getUnconfirmed = function getUnconfirmed(account, callback) {
this.client.getUnconfirmed(this.id, account, callback);
HTTPWallet.prototype.getUnconfirmed = function getUnconfirmed(account) {
return this.client.getUnconfirmed(this.id, account);
};
/**
* @see Wallet#getBalance
*/
HTTPWallet.prototype.getBalance = function getBalance(account, callback) {
this.client.getBalance(this.id, account, callback);
HTTPWallet.prototype.getBalance = function getBalance(account) {
return this.client.getBalance(this.id, account);
};
/**
* @see Wallet#getLast
*/
HTTPWallet.prototype.getLast = function getLast(account, limit, callback) {
this.client.getLast(this.id, account, limit, callback);
HTTPWallet.prototype.getLast = function getLast(account, limit) {
return this.client.getLast(this.id, account, limit);
};
/**
* @see Wallet#getRange
*/
HTTPWallet.prototype.getRange = function getRange(account, options, callback) {
this.client.getRange(this.id, account, options, callback);
HTTPWallet.prototype.getRange = function getRange(account, options) {
return this.client.getRange(this.id, account, options);
};
/**
* @see Wallet#getTX
*/
HTTPWallet.prototype.getTX = function getTX(account, hash, callback) {
this.client.getWalletTX(this.id, account, hash, callback);
HTTPWallet.prototype.getTX = function getTX(account, hash) {
return this.client.getWalletTX(this.id, account, hash);
};
/**
* @see Wallet#getCoin
*/
HTTPWallet.prototype.getCoin = function getCoin(account, hash, index, callback) {
this.client.getWalletCoin(this.id, account, hash, index, callback);
HTTPWallet.prototype.getCoin = function getCoin(account, hash, index) {
return this.client.getWalletCoin(this.id, account, hash, index);
};
/**
* @see Wallet#zap
*/
HTTPWallet.prototype.zap = function zap(account, age, callback) {
this.client.zap(this.id, account, age, callback);
HTTPWallet.prototype.zap = function zap(account, age) {
return this.client.zap(this.id, account, age);
};
/**
* @see Wallet#createTX
*/
HTTPWallet.prototype.createTX = function createTX(options, outputs, callback) {
this.client.createTX(this.id, options, outputs, callback);
HTTPWallet.prototype.createTX = function createTX(options, outputs) {
return this.client.createTX(this.id, options, outputs);
};
/**
* @see HTTPClient#walletSend
*/
HTTPWallet.prototype.send = function send(options, callback) {
this.client.send(this.id, options, callback);
HTTPWallet.prototype.send = function send(options) {
return this.client.send(this.id, options);
};
/**
* @see Wallet#sign
*/
HTTPWallet.prototype.sign = function sign(tx, options, callback) {
this.client.sign(this.id, tx, options, callback);
HTTPWallet.prototype.sign = function sign(tx, options) {
return this.client.sign(this.id, tx, options);
};
/**
* @see Wallet#fillCoins
*/
HTTPWallet.prototype.fillCoins = function fillCoins(tx, callback) {
this.client.fillCoins(tx, callback);
HTTPWallet.prototype.fillCoins = function fillCoins(tx) {
return this.client.fillCoins(tx);
};
/**
@ -260,7 +245,7 @@ HTTPWallet.prototype.fillCoins = function fillCoins(tx, callback) {
*/
HTTPWallet.prototype.getInfo = function getInfo(callback) {
this.client.getWallet(this.id, callback);
return this.client.getWallet(this.id);
};
/**
@ -268,63 +253,61 @@ HTTPWallet.prototype.getInfo = function getInfo(callback) {
*/
HTTPWallet.prototype.getAccounts = function getAccounts(callback) {
this.client.getAccounts(this.id, callback);
return this.client.getAccounts(this.id);
};
/**
* @see Wallet#getAccount
*/
HTTPWallet.prototype.getAccount = function getAccount(account, callback) {
this.client.getAccount(this.id, account, callback);
HTTPWallet.prototype.getAccount = function getAccount(account) {
return this.client.getAccount(this.id, account);
};
/**
* @see Wallet#createAccount
*/
HTTPWallet.prototype.createAccount = function createAccount(options, callback) {
this.client.createAccount(this.id, options, callback);
HTTPWallet.prototype.createAccount = function createAccount(options) {
return this.client.createAccount(this.id, options);
};
/**
* @see Wallet#createAddress
*/
HTTPWallet.prototype.createAddress = function createAddress(account, callback) {
this.client.createAddress(this.id, account, callback);
HTTPWallet.prototype.createAddress = function createAddress(account) {
return this.client.createAddress(this.id, account);
};
/**
* @see Wallet#createAddress
*/
HTTPWallet.prototype.createNested = function createNested(account) {
return this.client.createNested(this.id, account);
};
/**
* @see Wallet#setPassphrase
*/
HTTPWallet.prototype.setPassphrase = function setPassphrase(old, new_, callback) {
this.client.setPassphrase(this.id, old, new_, callback);
HTTPWallet.prototype.setPassphrase = function setPassphrase(old, new_) {
return this.client.setPassphrase(this.id, old, new_);
};
/**
* @see Wallet#retoken
*/
HTTPWallet.prototype.retoken = function retoken(passphrase, callback) {
var self = this;
HTTPWallet.prototype.retoken = co(function* retoken(passphrase) {
var token = yield this.client.retoken(this.id, passphrase);
if (typeof passphrase === 'function') {
callback = passphrase;
passphrase = null;
}
this.token = token;
this.client.token = token;
this.client.retoken(this.id, passphrase, function(err, token) {
if (err)
return callback(err);
self.token = token;
self.client.token = token;
return callback(null, token);
});
};
return token;
});
/*
* Expose

View file

@ -8,13 +8,14 @@
'use strict';
var bcoin = require('../env');
var utils = bcoin.utils;
var utils = require('../utils/utils');
var assert = require('assert');
var constants = bcoin.constants;
var constants = require('../protocol/constants');
var BufferReader = require('../utils/reader');
var BufferWriter = require('../utils/writer');
var global = bcoin.utils.global;
var Logger = require('../node/logger');
var Network = require('../protocol/network');
var global = utils.global;
var Float64Array = global.Float64Array || Array;
var Int32Array = global.Int32Array || Array;
@ -54,7 +55,7 @@ function ConfirmStats(buckets, maxConfirms, decay, type, logger) {
if (!(this instanceof ConfirmStats))
return new ConfirmStats(buckets, maxConfirms, decay, type, logger);
this.logger = logger || bcoin.defaultLogger;
this.logger = logger || Logger.global;
this.maxConfirms = maxConfirms;
this.decay = decay;
this.type = type;
@ -399,8 +400,8 @@ function PolicyEstimator(minRelay, network, logger) {
fee = [];
priority = [];
this.network = bcoin.network.get(network);
this.logger = logger || bcoin.defaultLogger;
this.network = Network.get(network);
this.logger = logger || Logger.global;
this.minTrackedFee = minRelay < MIN_FEERATE
? MIN_FEERATE
@ -776,7 +777,7 @@ PolicyEstimator.prototype.toRaw = function toRaw(writer) {
PolicyEstimator.fromRaw = function fromRaw(minRelay, data, logger) {
var p = new BufferReader(data);
var network = bcoin.network.fromMagic(p.readU32());
var network = Network.fromMagic(p.readU32());
var bestHeight = p.readU32();
var estimator = new PolicyEstimator(minRelay, network, logger);
var feeStats = ConfirmStats.fromRaw(p.readVarBytes(), 'FeeRate', logger);

5
lib/mempool/index.js Normal file
View file

@ -0,0 +1,5 @@
'use strict';
exports.Mempool = require('./mempool');
exports.MempoolEntry = require('./mempoolentry');
exports.Fees = require('./fees');

File diff suppressed because it is too large Load diff

191
lib/mempool/mempoolentry.js Normal file
View file

@ -0,0 +1,191 @@
/*!
* mempoolentry.js - mempool entry object for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var constants = require('../protocol/constants');
var utils = require('../utils/utils');
var TX = require('../primitives/tx');
/**
* Represents a mempool entry.
* @exports MempoolEntry
* @constructor
* @param {Object} options
* @param {TX} options.tx - Transaction in mempool.
* @param {Number} options.height - Entry height.
* @param {Number} options.priority - Entry priority.
* @param {Number} options.ts - Entry time.
* @param {Amount} options.chainValue - Value of on-chain coins.
* @param {Number} options.count - Number of descendants (includes tx).
* @param {Number} options.size - TX and descendant modified size.
* @param {Amount} options.fees - TX and descendant delta-applied fees.
* @property {TX} tx
* @property {Number} height
* @property {Number} priority
* @property {Number} ts
* @property {Amount} chainValue
* @property {Number} count
* @property {Number} size
* @property {Amount} fees
*/
function MempoolEntry(options) {
if (!(this instanceof MempoolEntry))
return new MempoolEntry(options);
this.tx = null;
this.height = -1;
this.size = 0;
this.priority = 0;
this.fee = 0;
this.ts = 0;
this.chainValue = 0;
this.count = 0;
this.sizes = 0;
this.fees = 0;
this.dependencies = false;
if (options)
this.fromOptions(options);
}
/**
* Inject properties from options object.
* @private
* @param {Object} options
*/
MempoolEntry.prototype.fromOptions = function fromOptions(options) {
this.tx = options.tx;
this.height = options.height;
this.size = options.size;
this.priority = options.priority;
this.fee = options.fee;
this.ts = options.ts;
this.chainValue = options.chainValue;
this.count = options.count;
this.sizes = options.sizes;
this.fees = options.fees;
this.dependencies = options.dependencies;
return this;
};
/**
* Instantiate mempool entry from options.
* @param {Object} options
* @returns {MempoolEntry}
*/
MempoolEntry.fromOptions = function fromOptions(options) {
return new MempoolEntry().fromOptions(options);
};
/**
* Inject properties from transaction.
* @private
* @param {TX} tx
* @param {Number} height
*/
MempoolEntry.prototype.fromTX = function fromTX(tx, height) {
var priority = tx.getPriority(height);
var value = tx.getChainValue(height);
var dependencies = false;
var size = tx.getVirtualSize();
var fee = tx.getFee();
var i;
for (i = 0; i < tx.inputs.length; i++) {
if (tx.inputs[i].coin.height === -1) {
dependencies = true;
break;
}
}
this.tx = tx;
this.height = height;
this.size = size;
this.priority = priority;
this.fee = fee;
this.chainValue = value;
this.ts = utils.now();
this.count = 1;
this.sizes = size;
this.fees = fee;
this.dependencies = dependencies;
return this;
};
/**
* Create a mempool entry from a TX.
* @param {TX} tx
* @param {Number} height - Entry height.
* @returns {MempoolEntry}
*/
MempoolEntry.fromTX = function fromTX(tx, height) {
return new MempoolEntry().fromTX(tx, height);
};
/**
* Calculate priority, taking into account
* the entry height delta, modified size,
* and chain value.
* @param {Number} height
* @returns {Number} Priority.
*/
MempoolEntry.prototype.getPriority = function getPriority(height) {
var heightDelta = height - this.height;
var modSize = this.tx.getModifiedSize(this.size);
var deltaPriority = (heightDelta * this.chainValue) / modSize;
var result = this.priority + Math.floor(deltaPriority);
if (result < 0)
result = 0;
return result;
};
/**
* Get fee.
* @returns {Amount}
*/
MempoolEntry.prototype.getFee = function getFee() {
return this.fee;
};
/**
* Calculate fee rate.
* @returns {Rate}
*/
MempoolEntry.prototype.getRate = function getRate() {
return TX.getRate(this.size, this.fee);
};
/**
* Test whether the entry is free with
* the current priority (calculated by
* current height).
* @param {Number} height
* @returns {Boolean}
*/
MempoolEntry.prototype.isFree = function isFree(height) {
var priority = this.getPriority(height);
return priority > constants.tx.FREE_THRESHOLD;
};
/*
* Expose
*/
module.exports = MempoolEntry;

4
lib/miner/index.js Normal file
View file

@ -0,0 +1,4 @@
'use strict';
exports.Miner = require('./miner');
exports.MinerBlock = require('./minerblock');

View file

@ -7,11 +7,14 @@
'use strict';
var bcoin = require('../env');
var utils = require('../utils/utils');
var assert = utils.assert;
var co = require('../utils/co');
var assert = require('assert');
var AsyncObject = require('../utils/async');
var MinerBlock = require('./minerblock');
var Address = require('../primitives/address');
var Workers = require('../workers/workers');
var time = require('../net/timedata');
/**
* A bitcoin miner (supports mining witness blocks).
@ -36,7 +39,7 @@ function Miner(options) {
options = {};
this.options = options;
this.address = bcoin.address(this.options.address);
this.address = Address(this.options.address);
this.coinbaseFlags = this.options.coinbaseFlags || 'mined by bcoin';
this.version = null;
@ -111,9 +114,9 @@ Miner.prototype._init = function _init() {
stat.best);
});
if (bcoin.useWorkers) {
this.workerPool = new bcoin.workers({
size: this.options.parallel ? 2 : 1,
if (Workers.enabled) {
this.workerPool = new Workers({
size: 1,
timeout: -1
});
@ -130,38 +133,27 @@ Miner.prototype._init = function _init() {
/**
* Open the miner, wait for the chain and mempool to load.
* @alias Miner#open
* @param {Function} callback
* @returns {Promise}
*/
Miner.prototype._open = function open(callback) {
var self = this;
Miner.prototype._open = co(function* open() {
if (this.mempool)
yield this.mempool.open();
else
yield this.chain.open();
function open(callback) {
if (self.mempool)
self.mempool.open(callback);
else
self.chain.open(callback);
}
open(function(err) {
if (err)
return callback(err);
self.logger.info('Miner loaded (flags=%s).',
self.coinbaseFlags.toString('utf8'));
callback();
});
};
this.logger.info('Miner loaded (flags=%s).',
this.coinbaseFlags.toString('utf8'));
});
/**
* Close the miner.
* @alias Miner#close
* @param {Function} callback
* @returns {Promise}
*/
Miner.prototype._close = function close(callback) {
callback();
Miner.prototype._close = function close() {
return Promise.resolve(null);
};
/**
@ -169,53 +161,57 @@ Miner.prototype._close = function close(callback) {
* @param {Number?} version - Custom block version.
*/
Miner.prototype.start = function start() {
Miner.prototype.start = co(function* start() {
var self = this;
var attempt, block;
this.stop();
this.running = true;
// Create a new block and start hashing
this.createBlock(function(err, attempt) {
if (err)
return self.emit('error', err);
try {
attempt = yield this.createBlock();
} catch (e) {
this.emit('error', e);
return;
}
if (!self.running)
return;
if (!this.running)
return;
self.attempt = attempt;
this.attempt = attempt;
attempt.on('status', function(status) {
self.emit('status', status);
});
attempt.mineAsync(function(err, block) {
if (err) {
if (!self.running)
return;
self.emit('error', err);
return self.start();
}
// Add our block to the chain
self.chain.add(block, function(err) {
if (err) {
if (err.type === 'VerifyError')
self.logger.warning('%s could not be added to chain.', block.rhash);
self.emit('error', err);
return self.start();
}
// Emit our newly found block
self.emit('block', block);
// `tip` will now be emitted by chain
// and the whole process starts over.
});
});
attempt.on('status', function(status) {
self.emit('status', status);
});
};
try {
block = yield attempt.mineAsync();
} catch (e) {
if (!this.running)
return;
this.emit('error', e);
return this.start();
}
// Add our block to the chain
try {
yield this.chain.add(block);
} catch (err) {
if (err.type === 'VerifyError')
this.logger.warning('%s could not be added to chain.', block.rhash);
this.emit('error', err);
this.start();
return;
}
// Emit our newly found block
this.emit('block', block);
// `tip` will now be emitted by chain
// and the whole process starts over.
});
/**
* Stop mining.
@ -239,97 +235,67 @@ Miner.prototype.stop = function stop() {
/**
* Create a block "attempt".
* @param {Number?} version - Custom block version.
* @param {Function} callback - Returns [Error, {@link MinerBlock}].
* @returns {Promise} - Returns {@link MinerBlock}.
*/
Miner.prototype.createBlock = function createBlock(tip, callback) {
var self = this;
var i, ts, attempt, txs, tx;
Miner.prototype.createBlock = co(function* createBlock(tip) {
var i, ts, attempt, txs, tx, target, version;
if (typeof tip === 'function') {
callback = tip;
tip = null;
}
if (!this.loaded)
yield this.open();
if (!tip)
tip = this.chain.tip;
ts = Math.max(bcoin.now(), tip.ts + 1);
function computeVersion(callback) {
if (self.version != null)
return callback(null, self.version);
self.chain.computeBlockVersion(tip, callback);
}
if (!this.loaded) {
this.open(function(err) {
if (err)
return callback(err);
self.createBlock(tip, callback);
});
return;
}
assert(tip);
ts = Math.max(time.now(), tip.ts + 1);
// Find target
this.chain.getTargetAsync(ts, tip, function(err, target) {
if (err)
return callback(err);
target = yield this.chain.getTargetAsync(ts, tip);
if (this.version != null) {
version = this.version;
} else {
// Calculate version with versionbits
computeVersion(function(err, version) {
if (err)
return callback(err);
version = yield this.chain.computeBlockVersion(tip);
}
attempt = new MinerBlock({
workerPool: self.workerPool,
tip: tip,
version: version,
target: target,
address: self.address,
coinbaseFlags: self.coinbaseFlags,
witness: self.chain.segwitActive,
parallel: self.options.parallel,
network: self.network
});
if (!self.mempool)
return callback(null, attempt);
txs = self.mempool.getHistory();
for (i = 0; i < txs.length; i++) {
tx = txs[i];
attempt.addTX(tx);
}
callback(null, attempt);
});
attempt = new MinerBlock({
workerPool: this.workerPool,
tip: tip,
version: version,
target: target,
address: this.address,
coinbaseFlags: this.coinbaseFlags,
witness: this.chain.segwitActive,
network: this.network
});
};
if (!this.mempool)
return attempt;
txs = this.mempool.getHistory();
for (i = 0; i < txs.length; i++) {
tx = txs[i];
attempt.addTX(tx);
}
return attempt;
});
/**
* Mine a single block.
* @param {Number?} version - Custom block version.
* @param {Function} callback - Returns [Error, [{@link Block}]].
* @returns {Promise} - Returns [{@link Block}].
*/
Miner.prototype.mineBlock = function mineBlock(tip, callback) {
if (typeof tip === 'function') {
callback = tip;
tip = null;
}
Miner.prototype.mineBlock = co(function* mineBlock(tip) {
// Create a new block and start hashing
this.createBlock(tip, function(err, attempt) {
if (err)
return callback(err);
attempt.mineAsync(callback);
});
};
var attempt = yield this.createBlock(tip);
return yield attempt.mineAsync();
});
/*
* Expose

View file

@ -7,15 +7,23 @@
'use strict';
var bcoin = require('../env');
var utils = require('../utils/utils');
var co = require('../utils/co');
var crypto = require('../crypto/crypto');
var assert = utils.assert;
var constants = bcoin.constants;
var assert = require('assert');
var constants = require('../protocol/constants');
var Network = require('../protocol/network');
var bn = require('bn.js');
var EventEmitter = require('events').EventEmitter;
var BufferReader = require('../utils/reader');
var BufferWriter = require('../utils/writer');
var TX = require('../primitives/tx');
var Address = require('../primitives/address');
var Block = require('../primitives/block');
var Input = require('../primitives/input');
var Output = require('../primitives/output');
var time = require('../net/timedata');
var ChainEntry = require('../chain/chainentry');
/**
* MinerBlock
@ -53,17 +61,16 @@ function MinerBlock(options) {
this.coinbaseFlags = options.coinbaseFlags;
this.witness = options.witness;
this.address = options.address;
this.network = bcoin.network.get(options.network);
this.network = Network.get(options.network);
this.timeout = null;
this.callback = null;
if (typeof this.coinbaseFlags === 'string')
this.coinbaseFlags = new Buffer(this.coinbaseFlags, 'utf8');
this.coinbase = new bcoin.tx();
this.coinbase = new TX();
this.coinbase.mutable = true;
this.block = new bcoin.block();
this.block = new Block();
this.block.mutable = true;
this._init();
@ -83,7 +90,7 @@ MinerBlock.prototype._init = function _init() {
var i, input, output, hash, witnessNonce;
// Coinbase input.
input = new bcoin.input();
input = new Input();
// Height (required in v2+ blocks)
input.script.set(0, new bn(this.height));
@ -108,7 +115,7 @@ MinerBlock.prototype._init = function _init() {
cb.inputs.push(input);
// Reward output.
output = new bcoin.output();
output = new Output();
output.script.fromAddress(this.address);
cb.outputs.push(output);
@ -126,14 +133,14 @@ MinerBlock.prototype._init = function _init() {
input.witness.compile();
// Commitment output.
cb.outputs.push(new bcoin.output());
cb.outputs.push(new Output());
}
// Setup our block.
block.version = options.version;
block.prevBlock = this.tip.hash;
block.merkleRoot = constants.NULL_HASH;
block.ts = Math.max(bcoin.now(), this.tip.ts + 1);
block.ts = Math.max(time.now(), this.tip.ts + 1);
block.bits = this.bits;
block.nonce = 0;
block.height = this.height;
@ -190,7 +197,7 @@ MinerBlock.prototype.updateCoinbase = function updateCoinbase() {
*/
MinerBlock.prototype.updateNonce = function updateNonce() {
this.block.ts = Math.max(bcoin.now(), this.tip.ts + 1);
this.block.ts = Math.max(time.now(), this.tip.ts + 1);
// Overflow the nonce and increment the extraNonce.
this.block.nonce = 0;
@ -216,7 +223,7 @@ MinerBlock.prototype.updateMerkle = function updateMerkle() {
this.updateCommitment();
// Update timestamp.
this.block.ts = Math.max(bcoin.now(), this.tip.ts + 1);
this.block.ts = Math.max(time.now(), this.tip.ts + 1);
// Recalculate merkle root.
this.block.merkleRoot = this.block.getMerkleRoot('hex');
@ -306,7 +313,7 @@ MinerBlock.prototype.findNonce = function findNonce() {
// update the timestamp. This improves
// performance because we do not have to
// recalculate the merkle root.
now = bcoin.now();
now = time.now();
if (now > block.ts && now > tip.ts) {
block.ts = now;
// Overflow the nonce
@ -346,19 +353,34 @@ MinerBlock.prototype.sendStatus = function sendStatus() {
/**
* Mine until the block is found. Will take a breather
* for 100ms every time the nonce overflows.
* @param {Function} callback - Returns [Error, {@link Block}].
* @returns {Promise} - Returns {@link Block}.
*/
MinerBlock.prototype.mine = function mine(callback) {
MinerBlock.prototype.mine = co(function* mine() {
yield this.wait(100);
// Try to find a block: do one iteration of extraNonce
if (!this.findNonce()) {
yield this.mine();
return;
}
return this.block;
});
/**
* Wait for a timeout.
* @param {Number} time
* @returns {Promise}
*/
MinerBlock.prototype.wait = function wait(time) {
var self = this;
this.timeout = setTimeout(function() {
// Try to find a block: do one iteration of extraNonce
if (!self.findNonce())
return self.mine(callback);
callback(null, self.block);
}, 100);
return new Promise(function(resolve, reject) {
self.timeout = setTimeout(function() {
resolve();
}, time);
});
};
/**
@ -373,33 +395,21 @@ MinerBlock.prototype.mineSync = function mineSync() {
/**
* Attempt to mine the block on the worker pool.
* @param {Function} callback - Returns [Error, {@link Block}].
* @returns {Promise} - Returns {@link Block}.
*/
MinerBlock.prototype.mineAsync = function mine(callback) {
var self = this;
MinerBlock.prototype.mineAsync = co(function* mineAsync() {
var block;
if (!this.workerPool)
return this.mine(callback);
return yield this.mine();
callback = utils.once(callback);
block = yield this.workerPool.mine(this);
this.callback = callback;
this.workerPool.destroy();
function done(err, block) {
self.workerPool.destroy();
callback(err, block);
}
if (this.options.parallel) {
done = utils.once(done);
this.workerPool.mine(this, done);
this.workerPool.mine(this, done);
return;
}
this.workerPool.mine(this, callback);
};
return block;
});
/**
* Destroy the minerblock. Stop mining. Clear timeout.
@ -410,10 +420,6 @@ MinerBlock.prototype.destroy = function destroy() {
clearTimeout(this.timeout);
this.timeout = null;
}
if (this.callback) {
this.callback(new Error('Destroyed.'));
this.callback = null;
}
this.block = null;
};
@ -452,11 +458,11 @@ MinerBlock.prototype.toRaw = function toRaw(writer) {
MinerBlock.fromRaw = function fromRaw(data) {
var p = new BufferReader(data);
var network = bcoin.network.fromMagic(p.readU32());
var tip = bcoin.chainentry.fromRaw(null, p);
var network = Network.fromMagic(p.readU32());
var tip = ChainEntry.fromRaw(null, p);
var version = p.readU32();
var bits = p.readU32();
var address = bcoin.address.fromRaw(p.readVarBytes());
var address = Address.fromRaw(p.readVarBytes());
var coinbaseFlags = p.readVarBytes();
var witness = p.readU8() === 1;
var count = p.readVarint();
@ -464,7 +470,7 @@ MinerBlock.fromRaw = function fromRaw(data) {
var i;
for (i = 0; i < count; i++)
txs.push(bcoin.tx.fromRaw(p));
txs.push(TX.fromRaw(p));
tip.network = network;

View file

@ -9,12 +9,14 @@
'use strict';
var EventEmitter = require('events').EventEmitter;
var bcoin = require('../env');
var utils = require('../utils/utils');
var co = require('../utils/co');
var crypto = require('../crypto/crypto');
var packets = require('./packets');
var assert = utils.assert;
var constants = bcoin.constants;
var assert = require('assert');
var constants = require('../protocol/constants');
var ec = require('../crypto/ec');
var BufferWriter = require('../utils/writer');
/**
* Represents a BIP150 input and output stream.
@ -54,7 +56,7 @@ function BIP150(bip151, hostname, outbound, db, identity) {
// Identity keypair
this.privateKey = identity;
this.publicKey = bcoin.ec.publicKeyCreate(identity, true);
this.publicKey = ec.publicKeyCreate(identity, true);
this.challengeReceived = false;
this.replyReceived = false;
@ -95,10 +97,10 @@ BIP150.prototype.challenge = function challenge(hash) {
this.emit('auth');
}
sig = bcoin.ec.sign(msg, this.privateKey);
sig = ec.sign(msg, this.privateKey);
// authreply
return bcoin.ec.fromDER(sig);
return ec.fromDER(sig);
};
BIP150.prototype.reply = function reply(data) {
@ -115,10 +117,10 @@ BIP150.prototype.reply = function reply(data) {
if (!this.peerIdentity)
return crypto.randomBytes(32);
sig = bcoin.ec.toDER(data);
sig = ec.toDER(data);
msg = this.hash(this.output.sid, type, this.peerIdentity);
result = bcoin.ec.verify(msg, sig, this.peerIdentity);
result = ec.verify(msg, sig, this.peerIdentity);
if (!result)
return crypto.randomBytes(32);
@ -247,7 +249,14 @@ BIP150.prototype.complete = function complete(err) {
this.callback = null;
};
BIP150.prototype.wait = function wait(timeout, callback) {
BIP150.prototype.wait = function wait(timeout) {
var self = this;
return new Promise(function(resolve, reject) {
self._wait(timeout, co.wrap(resolve, reject));
});
};
BIP150.prototype._wait = function wait(timeout, callback) {
var self = this;
assert(!this.auth, 'Cannot wait for init after handshake.');
@ -272,7 +281,7 @@ BIP150.prototype.getAddress = function getAddress() {
};
BIP150.address = function address(key) {
var p = new bcoin.writer();
var p = new BufferWriter();
p.writeU8(0x0f);
p.writeU16BE(0xff01);
p.writeBytes(crypto.hash160(key));

View file

@ -13,13 +13,16 @@
'use strict';
var EventEmitter = require('events').EventEmitter;
var bcoin = require('../env');
var utils = require('../utils/utils');
var co = require('../utils/co');
var crypto = require('../crypto/crypto');
var assert = utils.assert;
var constants = bcoin.constants;
var assert = require('assert');
var constants = require('../protocol/constants');
var chachapoly = require('../crypto/chachapoly');
var packets = require('./packets');
var ec = require('../crypto/ec');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
var EncinitPacket = packets.EncinitPacket;
var EncackPacket = packets.EncackPacket;
@ -58,7 +61,7 @@ function BIP151Stream(cipher) {
return new BIP151Stream(cipher);
this.cipher = cipher || 0;
this.privateKey = bcoin.ec.generatePrivateKey();
this.privateKey = ec.generatePrivateKey();
this.publicKey = null;
this.secret = null;
this.prk = null;
@ -86,10 +89,10 @@ function BIP151Stream(cipher) {
*/
BIP151Stream.prototype.init = function init(publicKey) {
var p = bcoin.writer();
var p = new BufferWriter();
this.publicKey = publicKey;
this.secret = bcoin.ec.ecdh(this.publicKey, this.privateKey);
this.secret = ec.ecdh(this.publicKey, this.privateKey);
p.writeBytes(this.secret);
p.writeU8(this.cipher);
@ -199,7 +202,7 @@ BIP151Stream.prototype.update = function update() {
*/
BIP151Stream.prototype.getPublicKey = function getPublicKey() {
return bcoin.ec.publicKeyCreate(this.privateKey, true);
return ec.publicKeyCreate(this.privateKey, true);
};
/**
@ -452,10 +455,22 @@ BIP151.prototype.complete = function complete(err) {
/**
* Set a timeout and wait for handshake to complete.
* @param {Number} timeout - Timeout in ms.
* @param {Function} callback
* @returns {Promise}
*/
BIP151.prototype.wait = function wait(timeout, callback) {
BIP151.prototype.wait = function wait(timeout) {
var self = this;
return new Promise(function(resolve, reject) {
self._wait(timeout, co.wrap(resolve, reject));
});
};
/**
* Set a timeout and wait for handshake to complete.
* @private
*/
BIP151.prototype._wait = function wait(timeout, callback) {
var self = this;
assert(!this.handshake, 'Cannot wait for init after handshake.');
@ -510,7 +525,7 @@ BIP151.prototype.maybeRekey = function maybeRekey(data) {
*/
BIP151.prototype.packet = function packet(cmd, body) {
var p = bcoin.writer();
var p = new BufferWriter();
var payload, packet;
p.writeVarString(cmd, 'ascii');
@ -652,7 +667,7 @@ BIP151.prototype.parse = function parse(data) {
this.input.decrypt(payload);
this.input.sequence();
p = bcoin.reader(payload);
p = new BufferReader(payload);
while (p.left()) {
try {

View file

@ -6,13 +6,17 @@
'use strict';
var bcoin = require('../env');
var utils = require('../utils/utils');
var BufferReader = require('../utils/reader');
var BufferWriter = require('../utils/writer');
var co = require('../utils/co');
var crypto = require('../crypto/crypto');
var assert = utils.assert;
var constants = bcoin.constants;
var assert = require('assert');
var constants = require('../protocol/constants');
var siphash = require('../crypto/siphash');
var AbstractBlock = bcoin.abstractblock;
var AbstractBlock = require('../primitives/abstractblock');
var TX = require('../primitives/tx');
var Block = require('../primitives/block');
/**
* Represents a compact block (bip152): `cmpctblock` packet.
@ -39,6 +43,7 @@ function CompactBlock(options) {
this.count = 0;
this.sipKey = null;
this.timeout = null;
this.callback = null;
if (options)
this.fromOptions(options);
@ -81,7 +86,7 @@ CompactBlock.fromOptions = function fromOptions(options) {
};
CompactBlock.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = new BufferReader(data);
var i, count, index, tx;
this.version = p.readU32(); // Technically signed
@ -110,7 +115,7 @@ CompactBlock.prototype.fromRaw = function fromRaw(data) {
index = p.readVarint();
assert(index <= 0xffff);
assert(index < this.totalTX);
tx = bcoin.tx.fromRaw(p);
tx = TX.fromRaw(p);
this.ptx.push([index, tx]);
}
@ -134,10 +139,10 @@ CompactBlock.prototype.toNormal = function toNormal(writer) {
};
CompactBlock.prototype.frame = function frame(witness, writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var i, id, lo, hi, ptx;
p.write32(this.version);
p.writeU32(this.version);
p.writeHash(this.prevBlock);
p.writeHash(this.merkleRoot);
p.writeU32(this.ts);
@ -306,7 +311,7 @@ CompactBlock.prototype.init = function init() {
};
CompactBlock.prototype.toBlock = function toBlock() {
var block = new bcoin.block();
var block = new Block();
var i, tx;
block.version = this.version;
@ -362,12 +367,31 @@ CompactBlock.fromBlock = function fromBlock(block, nonce) {
return new CompactBlock().fromBlock(block, nonce);
};
CompactBlock.prototype.startTimeout = function startTimeout(time, callback) {
assert(this.timeout == null);
this.timeout = setTimeout(callback, time);
CompactBlock.prototype.wait = function wait(time) {
var self = this;
return new Promise(function(resolve, reject) {
self._wait(time, co.wrap(resolve, reject));
});
};
CompactBlock.prototype.stopTimeout = function stopTimeout() {
CompactBlock.prototype._wait = function wait(time, callback) {
var self = this;
assert(this.timeout == null);
this.callback = callback;
this.timeout = setTimeout(function() {
self.complete(new Error('Timed out.'));
}, time);
};
CompactBlock.prototype.complete = function complete(err) {
if (this.timeout != null) {
clearTimeout(this.timeout);
this.timeout = null;
this.callback(err);
}
};
CompactBlock.prototype.destroy = function destroy() {
if (this.timeout != null) {
clearTimeout(this.timeout);
this.timeout = null;
@ -422,7 +446,7 @@ TXRequest.fromCompact = function fromCompact(block) {
};
TXRequest.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
var i, count, index, offset;
this.hash = p.readHash('hex');
@ -453,7 +477,7 @@ TXRequest.fromRaw = function fromRaw(data) {
};
TXRequest.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var i, index;
p.writeHash(this.hash);
@ -502,7 +526,7 @@ TXResponse.fromOptions = function fromOptions(options) {
};
TXResponse.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
var i, count;
this.hash = p.readHash('hex');
@ -510,7 +534,7 @@ TXResponse.prototype.fromRaw = function fromRaw(data) {
count = p.readVarint();
for (i = 0; i < count; i++)
this.txs.push(bcoin.tx.fromRaw(p));
this.txs.push(TX.fromRaw(p));
return this;
};
@ -547,7 +571,7 @@ TXResponse.prototype.toNormal = function toNormal(writer) {
};
TXResponse.prototype.frame = function frame(witness, writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var i, tx;
p.writeHash(this.hash);

View file

@ -7,10 +7,9 @@
'use strict';
var bcoin = require('../env');
var utils = require('../utils/utils');
var Network = require('../protocol/network');
var crypto = require('../crypto/crypto');
var assert = utils.assert;
var assert = require('assert');
/**
* Protocol packet framer
@ -28,7 +27,7 @@ function Framer(options) {
this.options = options;
this.network = bcoin.network.get(options.network);
this.network = Network.get(options.network);
this.bip151 = options.bip151;
}

12
lib/net/index.js Normal file
View file

@ -0,0 +1,12 @@
'use strict';
exports.bip150 = require('./bip150');
exports.bip151 = require('./bip151');
exports.bip152 = require('./bip152');
exports.Framer = require('./framer');
exports.packets = require('./packets');
exports.Parser = require('./parser');
exports.Peer = require('./peer');
exports.Pool = require('./pool');
exports.ProxySocket = require('./proxysocket');
exports.time = require('./timedata');

View file

@ -7,13 +7,26 @@
'use strict';
var bcoin = require('../env');
var bn = require('bn.js');
var constants = require('../protocol/constants');
var utils = require('../utils/utils');
var assert = require('assert');
var crypto = require('../crypto/crypto');
var bn = require('bn.js');
var time = require('./timedata');
var ec = require('../crypto/ec');
var Bloom = require('../utils/bloom');
var bip152 = require('./bip152');
var NetworkAddress = require('../primitives/netaddress');
var assert = utils.assert;
var Coin = require('../primitives/coin');
var Headers = require('../primitives/headers');
var InvItem = require('../primitives/invitem');
var MemBlock = require('../primitives/memblock');
var MerkleBlock = require('../primitives/merkleblock');
var Outpoint = require('../primitives/outpoint');
var Output = require('../primitives/output');
var TX = require('../primitives/tx');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
var DUMMY = new Buffer(0);
/**
@ -106,7 +119,7 @@ function VersionPacket(options) {
this.version = constants.VERSION;
this.services = constants.LOCAL_SERVICES;
this.ts = bcoin.now();
this.ts = time.now();
this.recv = new NetworkAddress();
this.from = new NetworkAddress();
this.nonce = new bn(0);
@ -176,7 +189,7 @@ VersionPacket.fromOptions = function fromOptions(options) {
*/
VersionPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.write32(this.version);
p.writeU64(this.services);
@ -256,7 +269,7 @@ VersionPacket.prototype.hasCompact = function hasCompact() {
*/
VersionPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.version = p.read32();
this.services = p.readU53();
@ -376,7 +389,7 @@ PingPacket.prototype.type = exports.types.PING;
*/
PingPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
if (this.nonce)
p.writeU64(this.nonce);
@ -394,7 +407,7 @@ PingPacket.prototype.toRaw = function toRaw(writer) {
*/
PingPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
if (p.left() >= 8)
this.nonce = p.readU64();
return this;
@ -441,7 +454,7 @@ PongPacket.prototype.type = exports.types.PONG;
*/
PongPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.writeU64(this.nonce);
@ -458,7 +471,7 @@ PongPacket.prototype.toRaw = function toRaw(writer) {
*/
PongPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.nonce = p.readU64();
return this;
};
@ -498,18 +511,18 @@ PongPacket.fromRaw = function fromRaw(data, enc) {
*/
function AlertPacket(options) {
var time;
var ts;
if (!(this instanceof AlertPacket))
return new AlertPacket(options);
Packet.call(this);
time = bcoin.now() + 7 * 86400;
ts = time.now() + 7 * 86400;
this.version = 1;
this.relayUntil = time;
this.expiration = time;
this.relayUntil = ts;
this.expiration = ts;
this.id = 1;
this.cancel = 0;
this.cancels = [];
@ -625,7 +638,7 @@ AlertPacket.prototype.toPayload = function toPayload() {
*/
AlertPacket.prototype.sign = function sign(key) {
this.signature = bcoin.ec.sign(this.hash(), key);
this.signature = ec.sign(this.hash(), key);
};
/**
@ -635,7 +648,7 @@ AlertPacket.prototype.sign = function sign(key) {
*/
AlertPacket.prototype.verify = function verify(key) {
return bcoin.ec.verify(this.hash(), this.signature, key);
return ec.verify(this.hash(), this.signature, key);
};
/**
@ -644,7 +657,7 @@ AlertPacket.prototype.verify = function verify(key) {
*/
AlertPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.writeVarBytes(this.toPayload());
p.writeVarBytes(this.signature);
@ -662,7 +675,7 @@ AlertPacket.prototype.toRaw = function toRaw(writer) {
*/
AlertPacket.prototype.framePayload = function framePayload(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var i;
p.write32(this.version);
@ -700,13 +713,13 @@ AlertPacket.prototype.framePayload = function framePayload(writer) {
*/
AlertPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
var i, count;
this._payload = p.readVarBytes();
this.signature = p.readVarBytes();
p = bcoin.reader(this._payload);
p = BufferReader(this._payload);
this.version = p.read32();
this.relayUntil = p.read53();
@ -824,7 +837,7 @@ AddrPacket.prototype.type = exports.types.ADDR;
*/
AddrPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var i;
p.writeVarint(this.items.length);
@ -845,7 +858,7 @@ AddrPacket.prototype.toRaw = function toRaw(writer) {
*/
AddrPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
var i, count;
count = p.readVarint();
@ -897,7 +910,7 @@ InvPacket.prototype.type = exports.types.INV;
*/
InvPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var i;
p.writeVarint(this.items.length);
@ -918,13 +931,13 @@ InvPacket.prototype.toRaw = function toRaw(writer) {
*/
InvPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
var i, count;
count = p.readVarint();
for (i = 0; i < count; i++)
this.items.push(bcoin.invitem.fromRaw(p));
this.items.push(InvItem.fromRaw(p));
return this;
};
@ -1040,7 +1053,7 @@ GetBlocksPacket.prototype.type = exports.types.GETBLOCKS;
*/
GetBlocksPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var i;
p.writeU32(this.version);
@ -1064,7 +1077,7 @@ GetBlocksPacket.prototype.toRaw = function toRaw(writer) {
*/
GetBlocksPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
var i, count;
this.version = p.readU32();
@ -1157,7 +1170,7 @@ HeadersPacket.prototype.type = exports.types.HEADERS;
*/
HeadersPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var i;
p.writeVarint(this.items.length);
@ -1178,13 +1191,13 @@ HeadersPacket.prototype.toRaw = function toRaw(writer) {
*/
HeadersPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
var i, count;
count = p.readVarint();
for (i = 0; i < count; i++)
this.items.push(bcoin.headers.fromRaw(p));
this.items.push(Headers.fromRaw(p));
return this;
};
@ -1268,7 +1281,7 @@ function BlockPacket(block, witness) {
Packet.call(this);
this.block = block || new bcoin.memblock();
this.block = block || new MemBlock();
this.witness = witness || false;
}
@ -1328,7 +1341,7 @@ function TXPacket(tx, witness) {
Packet.call(this);
this.tx = tx || new bcoin.tx();
this.tx = tx || new TX();
this.witness = witness || false;
}
@ -1450,7 +1463,7 @@ RejectPacket.fromOptions = function fromOptions(options) {
*/
RejectPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
assert(this.message.length <= 12);
assert(this.reason.length <= 111);
@ -1475,7 +1488,7 @@ RejectPacket.prototype.toRaw = function toRaw(writer) {
*/
RejectPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.message = p.readVarString('ascii', 12);
this.code = p.readU8();
@ -1525,7 +1538,7 @@ RejectPacket.prototype.fromReason = function fromReason(code, reason, obj) {
this.reason = reason;
if (obj) {
this.message = (obj instanceof bcoin.tx) ? 'tx' : 'block';
this.message = (obj instanceof TX) ? 'tx' : 'block';
this.data = obj.hash('hex');
}
@ -1639,10 +1652,14 @@ function FilterLoadPacket(filter, n, tweak, update) {
Packet.call(this);
this.filter = filter || DUMMY;
this.n = n || 0;
this.tweak = tweak || 0;
this.update = update || 0;
if (filter instanceof Bloom) {
this.fromFilter(filter);
} else {
this.filter = filter || DUMMY;
this.n = n || 0;
this.tweak = tweak || 0;
this.update = update || 0;
}
}
utils.inherits(FilterLoadPacket, Packet);
@ -1656,7 +1673,7 @@ FilterLoadPacket.prototype.type = exports.types.FILTERLOAD;
*/
FilterLoadPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.writeVarBytes(this.filter);
p.writeU32(this.n);
@ -1675,7 +1692,7 @@ FilterLoadPacket.prototype.toRaw = function toRaw(writer) {
*/
FilterLoadPacket.prototype.toFilter = function toFilter() {
return new bcoin.bloom(this.filter, this.n, this.tweak, this.update);
return new Bloom(this.filter, this.n, this.tweak, this.update);
};
/**
@ -1685,7 +1702,7 @@ FilterLoadPacket.prototype.toFilter = function toFilter() {
*/
FilterLoadPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.filter = p.readVarBytes();
this.n = p.readU32();
@ -1778,7 +1795,7 @@ FilterAddPacket.prototype.type = exports.types.FILTERADD;
*/
FilterAddPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.writeVarBytes(this.data);
@ -1795,7 +1812,7 @@ FilterAddPacket.prototype.toRaw = function toRaw(writer) {
*/
FilterAddPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.data = p.readVarBytes();
return this;
};
@ -1877,7 +1894,7 @@ function MerkleBlockPacket(block) {
Packet.call(this);
this.block = block || new bcoin.merkleblock();
this.block = block || new MerkleBlock();
}
utils.inherits(MerkleBlockPacket, Packet);
@ -1949,7 +1966,7 @@ GetUTXOsPacket.prototype.type = exports.types.GETUTXOS;
*/
GetUTXOsPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var i;
p.writeU8(this.mempool ? 1 : 0);
@ -1971,7 +1988,7 @@ GetUTXOsPacket.prototype.toRaw = function toRaw(writer) {
*/
GetUTXOsPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
var i, count;
this.mempool = p.readU8() === 1;
@ -1979,7 +1996,7 @@ GetUTXOsPacket.prototype.fromRaw = function fromRaw(data) {
count = p.readVarint();
for (i = 0; i < count; i++)
this.prevout.push(bcoin.outpoint.fromRaw(p));
this.prevout.push(Outpoint.fromRaw(p));
return this;
};
@ -2075,7 +2092,7 @@ UTXOsPacket.fromOptions = function fromOptions(options) {
*/
UTXOsPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var map = new Buffer((this.hits.length + 7) / 8 | 0);
var i, bit, oct, coin, height;
@ -2116,7 +2133,7 @@ UTXOsPacket.prototype.toRaw = function toRaw(writer) {
*/
UTXOsPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
var i, bit, oct, coin, output;
var version, height, map, count;
@ -2135,12 +2152,12 @@ UTXOsPacket.prototype.fromRaw = function fromRaw(data) {
for (i = 0; i < count; i++) {
version = p.readU32();
height = p.readU32();
coin = new bcoin.coin();
coin = new Coin();
if (height === 0x7fffffff)
height = -1;
output = bcoin.output.fromRaw(p);
output = Output.fromRaw(p);
coin.version = version;
coin.height = height;
@ -2244,7 +2261,7 @@ FeeFilterPacket.prototype.type = exports.types.FEEFILTER;
*/
FeeFilterPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.write64(this.rate);
@ -2261,7 +2278,7 @@ FeeFilterPacket.prototype.toRaw = function toRaw(writer) {
*/
FeeFilterPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.rate = p.read64N();
return this;
};
@ -2310,7 +2327,7 @@ SendCmpctPacket.prototype.type = exports.types.SENDCMPCT;
*/
SendCmpctPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.writeU8(this.mode);
p.writeU64(this.version);
@ -2328,7 +2345,7 @@ SendCmpctPacket.prototype.toRaw = function toRaw(writer) {
*/
SendCmpctPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.mode = p.readU8();
this.version = p.readU53();
return this;
@ -2363,7 +2380,7 @@ function CmpctBlockPacket(block, witness) {
Packet.call(this);
this.block = block || new bcoin.bip152.CompactBlock();
this.block = block || new bip152.CompactBlock();
this.witness = witness || false;
}
@ -2421,7 +2438,7 @@ function GetBlockTxnPacket(request) {
Packet.call(this);
this.request = request || new bcoin.bip152.TXRequest();
this.request = request || new bip152.TXRequest();
}
utils.inherits(GetBlockTxnPacket, Packet);
@ -2478,7 +2495,7 @@ function BlockTxnPacket(response, witness) {
Packet.call(this);
this.response = response || new bcoin.bip152.TXResponse();
this.response = response || new bip152.TXResponse();
this.witness = witness || false;
}
@ -2553,7 +2570,7 @@ EncinitPacket.prototype.type = exports.types.ENCINIT;
*/
EncinitPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.writeBytes(this.publicKey);
p.writeU8(this.cipher);
@ -2571,7 +2588,7 @@ EncinitPacket.prototype.toRaw = function toRaw(writer) {
*/
EncinitPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.publicKey = p.readBytes(33);
this.cipher = p.readU8();
return this;
@ -2618,7 +2635,7 @@ EncackPacket.prototype.type = exports.types.ENCACK;
*/
EncackPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.writeBytes(this.publicKey);
@ -2635,7 +2652,7 @@ EncackPacket.prototype.toRaw = function toRaw(writer) {
*/
EncackPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.publicKey = p.readBytes(33);
return this;
};
@ -2681,7 +2698,7 @@ AuthChallengePacket.prototype.type = exports.types.AUTHCHALLENGE;
*/
AuthChallengePacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.writeBytes(this.hash);
@ -2698,7 +2715,7 @@ AuthChallengePacket.prototype.toRaw = function toRaw(writer) {
*/
AuthChallengePacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.hash = p.readHash();
return this;
};
@ -2744,7 +2761,7 @@ AuthReplyPacket.prototype.type = exports.types.AUTHREPLY;
*/
AuthReplyPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.writeBytes(this.signature);
@ -2761,7 +2778,7 @@ AuthReplyPacket.prototype.toRaw = function toRaw(writer) {
*/
AuthReplyPacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.signature = p.readBytes(64);
return this;
};
@ -2807,7 +2824,7 @@ AuthProposePacket.prototype.type = exports.types.AUTHPROPOSE;
*/
AuthProposePacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.writeBytes(this.hash);
@ -2824,7 +2841,7 @@ AuthProposePacket.prototype.toRaw = function toRaw(writer) {
*/
AuthProposePacket.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.hash = p.readHash();
return this;
};
@ -2872,7 +2889,7 @@ UnknownPacket.prototype.type = exports.types.UNKNOWN;
*/
UnknownPacket.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.writeBytes(this.data);

View file

@ -7,11 +7,11 @@
'use strict';
var bcoin = require('../env');
var Network = require('../protocol/network');
var EventEmitter = require('events').EventEmitter;
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var assert = utils.assert;
var assert = require('assert');
var constants = require('../protocol/constants');
var packets = require('./packets');
@ -33,7 +33,7 @@ function Parser(options) {
EventEmitter.call(this);
this.network = bcoin.network.get(options.network);
this.network = Network.get(options.network);
this.bip151 = options.bip151;
this.pending = [];

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,10 +1,9 @@
'use strict';
var bcoin = require('../env');
var utils = bcoin.utils;
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var BufferWriter = require('../utils/writer');
var assert = utils.assert;
var assert = require('assert');
var EventEmitter = require('events').EventEmitter;
var IOClient = require('socket.io-client');
@ -18,6 +17,8 @@ function ProxySocket(uri) {
this.socket = new IOClient(uri, { reconnection: false });
this.sendBuffer = [];
this.recvBuffer = [];
this.paused = false;
this.snonce = null;
this.bytesWritten = 0;
this.bytesRead = 0;
@ -60,6 +61,10 @@ ProxySocket.prototype._init = function _init() {
this.socket.on('tcp data', function(data) {
data = new Buffer(data, 'hex');
if (self.paused) {
self.recvBuffer.push(data);
return;
}
self.bytesRead += data.length;
self.emit('data', data);
});
@ -129,9 +134,13 @@ ProxySocket.prototype.connect = function connect(port, host) {
this.sendBuffer.length = 0;
};
ProxySocket.prototype.write = function write(data) {
ProxySocket.prototype.write = function write(data, callback) {
if (!this.info) {
this.sendBuffer.push(data);
if (callback)
callback();
return true;
}
@ -139,9 +148,33 @@ ProxySocket.prototype.write = function write(data) {
this.socket.emit('tcp data', data.toString('hex'));
if (callback)
callback();
return true;
};
ProxySocket.prototype.pause = function pause() {
this.paused = true;
this.socket.emit('tcp pause');
};
ProxySocket.prototype.resume = function resume() {
var recv = this.recvBuffer;
var i, data;
this.paused = false;
this.recvBuffer = [];
for (i = 0; i < recv.length; i++) {
data = recv[i];
this.bytesRead += data.length;
this.emit('data', data);
}
this.socket.emit('tcp resume');
};
ProxySocket.prototype.destroy = function destroy() {
if (this.closed)
return;

View file

@ -112,4 +112,4 @@ function compare(a, b) {
* Expose
*/
module.exports = TimeData;
module.exports = new TimeData();

View file

@ -8,7 +8,7 @@
var Network = require('../protocol/network');
var utils = require('../utils/utils');
var assert = utils.assert;
var assert = require('assert');
var fs;
if (!utils.isBrowser)

View file

@ -7,10 +7,23 @@
'use strict';
var bcoin = require('../env');
var constants = bcoin.constants;
var constants = require('../protocol/constants');
var utils = require('../utils/utils');
var Node = bcoin.node;
var co = require('../utils/co');
var Node = require('./node');
var Chain = require('../chain/chain');
var Fees = require('../mempool/fees');
var Mempool = require('../mempool/mempool');
var Pool = require('../net/pool');
var Miner = require('../miner/miner');
var WalletDB = require('../wallet/walletdb');
var HTTPServer;
try {
HTTPServer = require('../http/server');
} catch (e) {
;
}
/**
* Create a fullnode complete with a chain,
@ -53,7 +66,7 @@ function Fullnode(options) {
Node.call(this, options);
// Instantiate blockchain.
this.chain = new bcoin.chain({
this.chain = new Chain({
network: this.network,
logger: this.logger,
db: this.options.db,
@ -70,13 +83,13 @@ function Fullnode(options) {
});
// Fee estimation.
this.fees = new bcoin.fees(
this.fees = new Fees(
constants.tx.MIN_RELAY,
this.network,
this.logger);
// Mempool needs access to the chain.
this.mempool = new bcoin.mempool({
this.mempool = new Mempool({
network: this.network,
logger: this.logger,
chain: this.chain,
@ -90,7 +103,7 @@ function Fullnode(options) {
});
// Pool needs access to the chain and mempool.
this.pool = new bcoin.pool({
this.pool = new Pool({
network: this.network,
logger: this.logger,
chain: this.chain,
@ -115,19 +128,18 @@ function Fullnode(options) {
});
// Miner needs access to the chain and mempool.
this.miner = new bcoin.miner({
this.miner = new Miner({
network: this.network,
logger: this.logger,
chain: this.chain,
mempool: this.mempool,
fees: this.fees,
address: this.options.payoutAddress,
coinbaseFlags: this.options.coinbaseFlags,
parallel: this.options.parallel
coinbaseFlags: this.options.coinbaseFlags
});
// Wallet database needs access to fees.
this.walletdb = new bcoin.walletdb({
this.walletdb = new WalletDB({
network: this.network,
logger: this.logger,
fees: this.fees,
@ -141,7 +153,7 @@ function Fullnode(options) {
// HTTP needs access to the node.
if (!utils.isBrowser) {
this.http = new bcoin.http.server({
this.http = new HTTPServer({
network: this.network,
logger: this.logger,
node: this,
@ -185,7 +197,7 @@ Fullnode.prototype._init = function _init() {
this.mempool.on('tx', function(tx) {
self.emit('tx', tx);
self.walletdb.addTX(tx, onError);
self.walletdb.addTX(tx).catch(onError);
});
this.chain.on('block', function(block) {
@ -193,17 +205,17 @@ Fullnode.prototype._init = function _init() {
});
this.chain.on('connect', function(entry, block) {
self.walletdb.addBlock(entry, block.txs, onError);
self.walletdb.addBlock(entry, block.txs).catch(onError);
if (self.chain.synced)
self.mempool.addBlock(block, onError);
self.mempool.addBlock(block).catch(onError);
});
this.chain.on('disconnect', function(entry, block) {
self.walletdb.removeBlock(entry, onError);
self.walletdb.removeBlock(entry).catch(onError);
if (self.chain.synced)
self.mempool.removeBlock(block, onError);
self.mempool.removeBlock(block).catch(onError);
});
this.miner.on('block', function(block) {
@ -211,7 +223,7 @@ Fullnode.prototype._init = function _init() {
});
this.walletdb.on('send', function(tx) {
self.sendTX(tx, onError);
self.sendTX(tx).catch(onError);
});
};
@ -219,82 +231,70 @@ Fullnode.prototype._init = function _init() {
* Open the node and all its child objects,
* wait for the database to load.
* @alias Fullnode#open
* @param {Function} callback
* @returns {Promise}
*/
Fullnode.prototype._open = function open(callback) {
var self = this;
Fullnode.prototype._open = co(function* open() {
yield this.chain.open();
yield this.mempool.open();
yield this.miner.open();
yield this.pool.open();
yield this.walletdb.open();
utils.serial([
this.chain.open.bind(this.chain),
this.mempool.open.bind(this.mempool),
this.miner.open.bind(this.miner),
this.pool.open.bind(this.pool),
this.walletdb.open.bind(this.walletdb),
// Ensure primary wallet.
this.openWallet.bind(this),
// Rescan for any missed transactions.
this.rescan.bind(this),
// Rebroadcast pending transactions.
this.resend.bind(this),
function(next) {
if (!self.http)
return next();
self.http.open(next);
}
], function(err) {
if (err)
return callback(err);
// Ensure primary wallet.
yield this.openWallet();
self.logger.info('Node is loaded.');
// Rescan for any missed transactions.
yield this.rescan();
callback();
});
};
// Rebroadcast pending transactions.
yield this.resend();
if (this.http)
yield this.http.open();
this.logger.info('Node is loaded.');
});
/**
* Close the node, wait for the database to close.
* @alias Fullnode#close
* @param {Function} callback
* @returns {Promise}
*/
Fullnode.prototype._close = function close(callback) {
var self = this;
Fullnode.prototype._close = co(function* close() {
if (this.http)
yield this.http.close();
yield this.wallet.destroy();
this.wallet = null;
utils.serial([
function(next) {
if (!self.http)
return next();
self.http.close(next);
},
this.walletdb.close.bind(this.walletdb),
this.pool.close.bind(this.pool),
this.miner.close.bind(this.miner),
this.mempool.close.bind(this.mempool),
this.chain.close.bind(this.chain)
], callback);
};
yield this.walletdb.close();
yield this.pool.close();
yield this.miner.close();
yield this.mempool.close();
yield this.chain.close();
this.logger.info('Node is closed.');
});
/**
* Rescan for any missed transactions.
* @param {Function} callback
* @returns {Promise}
*/
Fullnode.prototype.rescan = function rescan(callback) {
Fullnode.prototype.rescan = function rescan() {
if (this.options.noScan) {
this.walletdb.setTip(
return this.walletdb.setTip(
this.chain.tip.hash,
this.chain.height,
callback);
return;
this.chain.height);
}
// Always rescan to make sure we didn't
// miss anything: there is no atomicity
// between the chaindb and walletdb.
this.walletdb.rescan(this.chain.db, callback);
return this.walletdb.rescan(this.chain.db);
};
/**
@ -302,7 +302,7 @@ Fullnode.prototype.rescan = function rescan(callback) {
* by the mempool - use with care, lest you get banned from
* bitcoind nodes).
* @param {TX|Block} item
* @param {Function} callback
* @returns {Promise}
*/
Fullnode.prototype.broadcast = function broadcast(item, callback) {
@ -316,53 +316,35 @@ Fullnode.prototype.broadcast = function broadcast(item, callback) {
* node.sendTX(tx, callback);
* node.sendTX(tx, true, callback);
* @param {TX} tx
* @param {Boolean?} wait - Wait to execute callback until a node
* requests our TX, rejects it, or the broadcast itself times out.
* @param {Function} callback - Returns [{@link VerifyError}|Error].
*/
Fullnode.prototype.sendTX = function sendTX(tx, wait, callback) {
var self = this;
if (!callback) {
callback = wait;
wait = null;
Fullnode.prototype.sendTX = co(function* sendTX(tx) {
try {
yield this.mempool.addTX(tx);
} catch (err) {
if (err.type === 'VerifyError') {
this._error(err);
this.logger.warning('Verification failed for tx: %s.', tx.rhash);
this.logger.warning('Attempting to broadcast anyway...');
yield this.pool.broadcast(tx);
return;
}
throw err;
}
this.mempool.addTX(tx, function(err) {
if (err) {
if (err.type === 'VerifyError') {
self._error(err);
self.logger.warning('Verification failed for tx: %s.', tx.rhash);
self.logger.warning('Attempting to broadcast anyway...');
if (!wait) {
self.pool.broadcast(tx);
return callback();
}
return self.pool.broadcast(tx, callback);
}
return callback(err);
}
if (!this.options.selfish)
tx = tx.toInv();
if (!self.options.selfish)
tx = tx.toInv();
if (!wait) {
self.pool.broadcast(tx);
return callback();
}
self.pool.broadcast(tx, callback);
});
};
yield this.pool.broadcast(tx);
});
/**
* Listen on a server socket on
* the p2p network (accepts leech peers).
*/
Fullnode.prototype.listen = function listen(callback) {
this.pool.listen(callback);
Fullnode.prototype.listen = function listen() {
return this.pool.listen();
};
/**
@ -392,21 +374,21 @@ Fullnode.prototype.stopSync = function stopSync() {
/**
* Retrieve a block from the chain database.
* @param {Hash} hash
* @param {Function} callback - Returns [Error, {@link Block}].
* @returns {Promise} - Returns {@link Block}.
*/
Fullnode.prototype.getBlock = function getBlock(hash, callback) {
this.chain.db.getBlock(hash, callback);
Fullnode.prototype.getBlock = function getBlock(hash) {
return this.chain.db.getBlock(hash);
};
/**
* Retrieve a block from the chain database, filled with coins.
* @param {Hash} hash
* @param {Function} callback - Returns [Error, {@link Block}].
* @returns {Promise} - Returns {@link Block}.
*/
Fullnode.prototype.getFullBlock = function getFullBlock(hash, callback) {
this.chain.db.getFullBlock(hash, callback);
Fullnode.prototype.getFullBlock = function getFullBlock(hash) {
return this.chain.db.getFullBlock(hash);
};
/**
@ -414,139 +396,130 @@ Fullnode.prototype.getFullBlock = function getFullBlock(hash, callback) {
* Takes into account spent coins in the mempool.
* @param {Hash} hash
* @param {Number} index
* @param {Function} callback - Returns [Error, {@link Coin}].
* @returns {Promise} - Returns {@link Coin}.
*/
Fullnode.prototype.getCoin = function getCoin(hash, index, callback) {
Fullnode.prototype.getCoin = function getCoin(hash, index) {
var coin = this.mempool.getCoin(hash, index);
if (coin)
return callback(null, coin);
return Promise.resolve(coin);
if (this.mempool.isSpent(hash, index))
return callback();
return Promise.resolve(null);
this.chain.db.getCoin(hash, index, callback);
return this.chain.db.getCoin(hash, index);
};
/**
* Get coins that pertain to an address from the mempool or chain database.
* Takes into account spent coins in the mempool.
* @param {Address} addresses
* @param {Function} callback - Returns [Error, {@link Coin}[]].
* @returns {Promise} - Returns {@link Coin}[].
*/
Fullnode.prototype.getCoinsByAddress = function getCoinsByAddress(addresses, callback) {
var self = this;
Fullnode.prototype.getCoinsByAddress = co(function* getCoinsByAddress(addresses) {
var coins = this.mempool.getCoinsByAddress(addresses);
var i, coin, spent;
var i, blockCoins, coin, spent;
this.chain.db.getCoinsByAddress(addresses, function(err, blockCoins) {
if (err)
return callback(err);
blockCoins = yield this.chain.db.getCoinsByAddress(addresses);
for (i = 0; i < blockCoins.length; i++) {
coin = blockCoins[i];
spent = self.mempool.isSpent(coin.hash, coin.index);
for (i = 0; i < blockCoins.length; i++) {
coin = blockCoins[i];
spent = this.mempool.isSpent(coin.hash, coin.index);
if (!spent)
coins.push(coin);
}
if (!spent)
coins.push(coin);
}
callback(null, coins);
});
};
return coins;
});
/**
* Retrieve transactions pertaining to an
* address from the mempool or chain database.
* @param {Address} addresses
* @param {Function} callback - Returns [Error, {@link TX}[]].
* @returns {Promise} - Returns {@link TX}[].
*/
Fullnode.prototype.getTXByAddress = function getTXByAddress(addresses, callback) {
Fullnode.prototype.getTXByAddress = co(function* getTXByAddress(addresses) {
var mempool = this.mempool.getTXByAddress(addresses);
this.chain.db.getTXByAddress(addresses, function(err, txs) {
if (err)
return callback(err);
callback(null, mempool.concat(txs));
});
};
var txs = yield this.chain.db.getTXByAddress(addresses);
return mempool.concat(txs);
});
/**
* Retrieve a transaction from the mempool or chain database.
* @param {Hash} hash
* @param {Function} callback - Returns [Error, {@link TX}].
* @returns {Promise} - Returns {@link TX}.
*/
Fullnode.prototype.getTX = function getTX(hash, callback) {
Fullnode.prototype.getTX = function getTX(hash) {
var tx = this.mempool.getTX(hash);
if (tx)
return callback(null, tx);
return Promise.resolve(tx);
this.chain.db.getTX(hash, callback);
return this.chain.db.getTX(hash);
};
/**
* Test whether the mempool or chain contains a transaction.
* @param {Hash} hash
* @param {Function} callback - Returns [Error, Boolean].
* @returns {Promise} - Returns Boolean.
*/
Fullnode.prototype.hasTX = function hasTX(hash, callback) {
Fullnode.prototype.hasTX = function hasTX(hash) {
if (this.mempool.hasTX(hash))
return callback(null, true);
return Promise.resolve(true);
this.chain.db.hasTX(hash, callback);
return this.chain.db.hasTX(hash);
};
/**
* Check whether a coin has been spent.
* @param {Hash} hash
* @param {Number} index
* @param {Function} callback - Returns [Error, Boolean].
* @returns {Promise} - Returns Boolean.
*/
Fullnode.prototype.isSpent = function isSpent(hash, index, callback) {
Fullnode.prototype.isSpent = function isSpent(hash, index) {
if (this.mempool.isSpent(hash, index))
return callback(null, true);
return Promise.resolve(true);
this.chain.db.isSpent(hash, index, callback);
return this.chain.db.isSpent(hash, index);
};
/**
* Fill a transaction with coins from the mempool
* and chain database (unspent only).
* @param {TX} tx
* @param {Function} callback - Returns [Error, {@link TX}].
* @returns {Promise} - Returns {@link TX}.
*/
Fullnode.prototype.fillCoins = function fillCoins(tx, callback) {
this.mempool.fillAllCoins(tx, callback);
Fullnode.prototype.fillCoins = function fillCoins(tx) {
return this.mempool.fillAllCoins(tx);
};
/**
* Fill a transaction with all historical coins
* from the mempool and chain database.
* @param {TX} tx
* @param {Function} callback - Returns [Error, {@link TX}].
* @returns {Promise} - Returns {@link TX}.
*/
Fullnode.prototype.fillHistory = function fillHistory(tx, callback) {
this.mempool.fillAllHistory(tx, callback);
Fullnode.prototype.fillHistory = function fillHistory(tx) {
return this.mempool.fillAllHistory(tx);
};
/**
* Return bitcoinj-style confidence for a transaction.
* @param {Hash|TX} tx
* @param {Function} callback - Returns [Error, {@link Confidence}].
* @returns {Promise} - Returns {@link Confidence}.
*/
Fullnode.prototype.getConfidence = function getConfidence(tx, callback) {
this.mempool.getConfidence(tx, callback);
Fullnode.prototype.getConfidence = function getConfidence(tx) {
return this.mempool.getConfidence(tx);
};
/*

7
lib/node/index.js Normal file
View file

@ -0,0 +1,7 @@
'use strict';
exports.config = require('./config');
exports.Fullnode = require('./fullnode');
exports.Logger = require('./logger');
exports.Node = require('./node');
exports.SPVNode = require('./spvnode');

View file

@ -349,6 +349,12 @@ Logger.prototype.memory = function memory() {
utils.mb(mem.rss - mem.heapTotal));
};
/*
* Default
*/
Logger.global = new Logger('none');
/*
* Expose
*/

View file

@ -7,10 +7,14 @@
'use strict';
var bcoin = require('../env');
var AsyncObject = require('../utils/async');
var utils = require('../utils/utils');
var assert = utils.assert;
var co = require('../utils/co');
var assert = require('assert');
var Network = require('../protocol/network');
var Logger = require('./logger');
var time = require('../net/timedata');
var workers = require('../workers/workers');
/**
* Base class from which every other
@ -33,7 +37,7 @@ function Node(options) {
this.parseOptions(options);
this.options = options;
this.network = bcoin.network.get(options.network);
this.network = Network.get(options.network);
this.prefix = options.prefix;
this.logger = options.logger;
@ -62,7 +66,7 @@ Node.prototype.__init = function __init() {
var self = this;
if (!this.logger) {
this.logger = new bcoin.logger({
this.logger = new Logger({
level: this.options.logLevel || 'none',
console: this.options.logConsole,
file: this.options.logFile
@ -87,28 +91,28 @@ Node.prototype._onOpen = function _onOpen() {
this.logger.open();
this._bind(bcoin.time, 'offset', function(offset) {
this._bind(time, 'offset', function(offset) {
self.logger.info('Time offset: %d (%d minutes).', offset, offset / 60 | 0);
});
this._bind(bcoin.time, 'sample', function(sample, total) {
this._bind(time, 'sample', function(sample, total) {
self.logger.debug('Added time data: samples=%d, offset=%d (%d minutes).',
total, sample, sample / 60 | 0);
});
this._bind(bcoin.time, 'mismatch', function() {
this._bind(time, 'mismatch', function() {
self.logger.warning('Please make sure your system clock is correct!');
});
this._bind(bcoin.workerPool, 'spawn', function(child) {
this._bind(workers.pool, 'spawn', function(child) {
self.logger.info('Spawning worker process: %d.', child.id);
});
this._bind(bcoin.workerPool, 'exit', function(code, child) {
this._bind(workers.pool, 'exit', function(code, child) {
self.logger.warning('Worker %d exited: %s.', child.id, code);
});
this._bind(bcoin.workerPool, 'error', function(err, child) {
this._bind(workers.pool, 'error', function(err, child) {
if (child) {
self.logger.error('Worker %d error: %s', child.id, err.message);
return;
@ -179,7 +183,7 @@ Node.prototype._error = function _error(err) {
*/
Node.prototype.parseOptions = function parseOptions(options) {
options.network = bcoin.network.get(options.network);
options.network = Network.get(options.network);
if (!options.prefix)
options.prefix = utils.HOME + '/.bcoin';
@ -229,12 +233,11 @@ Node.prototype.location = function location(name) {
/**
* Open and ensure primary wallet.
* @param {Function} callback
* @returns {Promise}
*/
Node.prototype.openWallet = function openWallet(callback) {
var self = this;
var options;
Node.prototype.openWallet = co(function* openWallet() {
var options, wallet;
assert(!this.wallet);
@ -243,34 +246,29 @@ Node.prototype.openWallet = function openWallet(callback) {
passphrase: this.options.passphrase
};
this.walletdb.ensure(options, function(err, wallet) {
if (err)
return callback(err);
wallet = yield this.walletdb.ensure(options);
self.logger.info(
'Loaded wallet with id=%s wid=%d address=%s',
wallet.id, wallet.wid, wallet.getAddress());
this.logger.info(
'Loaded wallet with id=%s wid=%d address=%s',
wallet.id, wallet.wid, wallet.getAddress());
// Set the miner payout address if the
// programmer didn't pass one in.
if (self.miner) {
if (!self.options.payoutAddress)
self.miner.address = wallet.getAddress();
}
// Set the miner payout address if the
// programmer didn't pass one in.
if (this.miner) {
if (!this.options.payoutAddress)
this.miner.address = wallet.getAddress();
}
self.wallet = wallet;
callback();
});
};
this.wallet = wallet;
});
/**
* Resend all pending transactions.
* @param {Function} callback
* @returns {Promise}
*/
Node.prototype.resend = function resend(callback) {
this.walletdb.resend(callback);
Node.prototype.resend = function resend() {
return this.walletdb.resend();
};
/*

View file

@ -7,9 +7,19 @@
'use strict';
var bcoin = require('../env');
var utils = require('../utils/utils');
var Node = bcoin.node;
var co = require('../utils/co');
var Node = require('./node');
var Chain = require('../chain/chain');
var Pool = require('../net/pool');
var WalletDB = require('../wallet/walletdb');
var HTTPServer;
try {
HTTPServer = require('../http/server');
} catch (e) {
;
}
/**
* Create an spv node which only maintains
@ -40,7 +50,7 @@ function SPVNode(options) {
Node.call(this, options);
this.chain = new bcoin.chain({
this.chain = new Chain({
network: this.network,
logger: this.logger,
db: this.options.db,
@ -51,7 +61,7 @@ function SPVNode(options) {
spv: true
});
this.pool = new bcoin.pool({
this.pool = new Pool({
network: this.network,
logger: this.logger,
chain: this.chain,
@ -69,7 +79,7 @@ function SPVNode(options) {
spv: true
});
this.walletdb = new bcoin.walletdb({
this.walletdb = new WalletDB({
network: this.network,
logger: this.logger,
db: this.options.db,
@ -80,7 +90,7 @@ function SPVNode(options) {
});
if (!utils.isBrowser) {
this.http = new bcoin.http.server({
this.http = new HTTPServer({
network: this.network,
logger: this.logger,
node: this,
@ -122,20 +132,20 @@ SPVNode.prototype._init = function _init() {
this.pool.on('tx', function(tx) {
self.emit('tx', tx);
self.walletdb.addTX(tx, onError);
self.walletdb.addTX(tx).catch(onError);
});
this.chain.on('block', function(block, entry) {
self.emit('block', block);
self.walletdb.addBlock(entry, block.txs, onError);
self.walletdb.addBlock(entry, block.txs).catch(onError);
});
this.walletdb.on('save address', function(address, path) {
self.pool.watch(address.getHash());
this.walletdb.on('path', function(path) {
self.pool.watch(path.hash, 'hex');
});
this.walletdb.on('send', function(tx) {
self.sendTX(tx, onError);
self.sendTX(tx).catch(onError);
});
};
@ -143,108 +153,88 @@ SPVNode.prototype._init = function _init() {
* Open the node and all its child objects,
* wait for the database to load.
* @alias SPVNode#open
* @param {Function} callback
* @returns {Promise}
*/
SPVNode.prototype._open = function open(callback) {
var self = this;
SPVNode.prototype._open = co(function* open(callback) {
yield this.chain.open();
yield this.pool.open();
yield this.walletdb.open();
utils.serial([
this.chain.open.bind(this.chain),
this.pool.open.bind(this.pool),
this.walletdb.open.bind(this.walletdb),
// Ensure primary wallet.
this.openWallet.bind(this),
// Load bloom filter.
this.openFilter.bind(this),
// Rescan for any missed transactions.
this.rescan.bind(this),
// Rebroadcast pending transactions.
this.resend.bind(this),
function(next) {
if (!self.http)
return next();
self.http.open(next);
}
], function(err) {
if (err)
return callback(err);
// Ensure primary wallet.
yield this.openWallet();
self.logger.info('Node is loaded.');
// Load bloom filter.
yield this.openFilter();
callback();
});
};
// Rescan for any missed transactions.
yield this.rescan();
// Rebroadcast pending transactions.
yield this.resend();
if (this.http)
yield this.http.open();
this.logger.info('Node is loaded.');
});
/**
* Close the node, wait for the database to close.
* @alias SPVNode#close
* @param {Function} callback
* @returns {Promise}
*/
SPVNode.prototype._close = function close(callback) {
var self = this;
SPVNode.prototype._close = co(function* close() {
if (this.http)
yield this.http.close();
yield this.wallet.destroy();
this.wallet = null;
utils.parallel([
function(next) {
if (!self.http)
return next();
self.http.close(next);
},
this.walletdb.close.bind(this.walletdb),
this.pool.close.bind(this.pool),
this.chain.close.bind(this.chain)
], callback);
};
yield this.walletdb.close();
yield this.pool.close();
yield this.chain.close();
});
/**
* Initialize p2p bloom filter for address watching.
* @param {Function} callback
* @returns {Promise}
*/
SPVNode.prototype.openFilter = function openFilter(callback) {
var self = this;
SPVNode.prototype.openFilter = co(function* openFilter() {
var hashes = yield this.walletdb.getAddressHashes();
var i;
this.walletdb.getAddressHashes(function(err, hashes) {
if (err)
return callback(err);
if (hashes.length > 0)
this.logger.info('Adding %d addresses to filter.', hashes.length);
if (hashes.length > 0)
self.logger.info('Adding %d addresses to filter.', hashes.length);
for (i = 0; i < hashes.length; i++)
self.pool.watch(hashes[i], 'hex');
callback();
});
};
for (i = 0; i < hashes.length; i++)
this.pool.watch(hashes[i], 'hex');
});
/**
* Rescan for any missed transactions.
* Note that this will replay the blockchain sync.
* @param {Function} callback
* @returns {Promise}
*/
SPVNode.prototype.rescan = function rescan(callback) {
SPVNode.prototype.rescan = function rescan() {
if (this.options.noScan) {
this.walletdb.setTip(
return this.walletdb.setTip(
this.chain.tip.hash,
this.chain.height,
callback);
return;
this.chain.height);
}
if (this.walletdb.height === 0)
return callback();
return Promise.resolve(null);
// Always replay the last block to make
// sure we didn't miss anything: there
// is no atomicity between the chaindb
// and walletdb.
this.chain.reset(this.walletdb.height - 1, callback);
return this.chain.reset(this.walletdb.height - 1);
};
/**
@ -252,11 +242,11 @@ SPVNode.prototype.rescan = function rescan(callback) {
* by the mempool - use with care, lest you get banned from
* bitcoind nodes).
* @param {TX|Block} item
* @param {Function} callback
* @returns {Promise}
*/
SPVNode.prototype.broadcast = function broadcast(item, callback) {
return this.pool.broadcast(item, callback);
SPVNode.prototype.broadcast = function broadcast(item) {
return this.pool.broadcast(item);
};
/**
@ -264,21 +254,11 @@ SPVNode.prototype.broadcast = function broadcast(item, callback) {
* by the mempool - use with care, lest you get banned from
* bitcoind nodes).
* @param {TX} tx
* @param {Function} callback
* @returns {Promise}
*/
SPVNode.prototype.sendTX = function sendTX(tx, wait, callback) {
if (!callback) {
callback = wait;
wait = null;
}
if (!wait) {
this.pool.broadcast(tx);
return utils.nextTick(callback);
}
this.pool.broadcast(tx, callback);
SPVNode.prototype.sendTX = function sendTX(tx) {
return this.pool.broadcast(tx);
};
/**

View file

@ -7,12 +7,17 @@
'use strict';
var bcoin = require('../env');
var constants = bcoin.constants;
var utils = bcoin.utils;
module.exports = AbstractBlock;
var constants = require('../protocol/constants');
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var assert = utils.assert;
var assert = require('assert');
var VerifyResult = utils.VerifyResult;
var BufferWriter = require('../utils/writer');
var time = require('../net/timedata');
var InvItem = require('./invitem');
var Headers = require('./headers');
/**
* The class which all block-like objects inherit from.
@ -151,9 +156,9 @@ AbstractBlock.prototype.hash = function hash(enc) {
*/
AbstractBlock.prototype.abbr = function abbr(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.write32(this.version);
p.writeU32(this.version);
p.writeHash(this.prevBlock);
p.writeHash(this.merkleRoot);
p.writeU32(this.ts);
@ -205,7 +210,7 @@ AbstractBlock.prototype.verifyHeaders = function verifyHeaders(ret) {
}
// Check timestamp against now + 2 hours
if (this.ts > bcoin.now() + 2 * 60 * 60) {
if (this.ts > time.now() + 2 * 60 * 60) {
ret.reason = 'time-too-new';
ret.score = 0;
return false;
@ -242,7 +247,7 @@ AbstractBlock.prototype.__defineGetter__('rhash', function() {
*/
AbstractBlock.prototype.toInv = function toInv() {
return new bcoin.invitem(constants.inv.BLOCK, this.hash('hex'));
return new InvItem(constants.inv.BLOCK, this.hash('hex'));
};
/**
@ -251,7 +256,7 @@ AbstractBlock.prototype.toInv = function toInv() {
*/
AbstractBlock.prototype.toHeaders = function toHeaders() {
var headers = new bcoin.headers(this);
var headers = new Headers(this);
headers._hash = this._hash;
headers._valid = true;
return headers;

View file

@ -7,16 +7,17 @@
'use strict';
var bcoin = require('../env');
var networks = bcoin.networks;
var constants = bcoin.constants;
module.exports = Address;
var Network = require('../protocol/network');
var networks = require('../protocol/networks');
var constants = require('../protocol/constants');
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var assert = utils.assert;
var assert = require('assert');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
var Script = bcoin.script;
var scriptTypes = constants.scriptTypes;
var Script = require('../script/script');
/**
* Represents an address.
@ -39,9 +40,9 @@ function Address(options) {
return new Address(options);
this.hash = constants.ZERO_HASH160;
this.type = scriptTypes.PUBKEYHASH;
this.type = Script.types.PUBKEYHASH;
this.version = -1;
this.network = bcoin.network.get();
this.network = Network.primary;
if (options)
this.fromOptions(options);
@ -113,7 +114,7 @@ Address.prototype.toRaw = function toRaw(network) {
if (!network)
network = this.network;
network = bcoin.network.get(network);
network = Network.get(network);
prefix = Address.getPrefix(this.type, network);
assert(prefix !== -1, 'Not a valid address prefix.');
@ -258,42 +259,42 @@ Address.fromBase58 = function fromBase58(address) {
Address.prototype.fromScript = function fromScript(script) {
if (script.isPubkey()) {
this.hash = crypto.hash160(script.get(0));
this.type = scriptTypes.PUBKEYHASH;
this.type = Script.types.PUBKEYHASH;
this.version = -1;
return this;
}
if (script.isPubkeyhash()) {
this.hash = script.get(2);
this.type = scriptTypes.PUBKEYHASH;
this.type = Script.types.PUBKEYHASH;
this.version = -1;
return this;
}
if (script.isScripthash()) {
this.hash = script.get(1);
this.type = scriptTypes.SCRIPTHASH;
this.type = Script.types.SCRIPTHASH;
this.version = -1;
return this;
}
if (script.isWitnessPubkeyhash()) {
this.hash = script.get(1);
this.type = scriptTypes.WITNESSPUBKEYHASH;
this.type = Script.types.WITNESSPUBKEYHASH;
this.version = 0;
return this;
}
if (script.isWitnessScripthash()) {
this.hash = script.get(1);
this.type = scriptTypes.WITNESSSCRIPTHASH;
this.type = Script.types.WITNESSSCRIPTHASH;
this.version = 0;
return this;
}
if (script.isWitnessMasthash()) {
this.hash = script.get(1);
this.type = scriptTypes.WITNESSSCRIPTHASH;
this.type = Script.types.WITNESSSCRIPTHASH;
this.version = 1;
return this;
}
@ -301,7 +302,7 @@ Address.prototype.fromScript = function fromScript(script) {
// Put this last: it's the slowest to check.
if (script.isMultisig()) {
this.hash = script.hash160();
this.type = scriptTypes.SCRIPTHASH;
this.type = Script.types.SCRIPTHASH;
this.version = -1;
return this;
}
@ -318,14 +319,14 @@ Address.prototype.fromWitness = function fromWitness(witness) {
// since we can't get the version.
if (witness.isPubkeyhashInput()) {
this.hash = crypto.hash160(witness.get(1));
this.type = scriptTypes.WITNESSPUBKEYHASH;
this.type = Script.types.WITNESSPUBKEYHASH;
this.version = 0;
return this;
}
if (witness.isScripthashInput()) {
this.hash = crypto.sha256(witness.get(witness.length - 1));
this.type = scriptTypes.WITNESSSCRIPTHASH;
this.type = Script.types.WITNESSSCRIPTHASH;
this.version = 0;
return this;
}
@ -340,14 +341,14 @@ Address.prototype.fromWitness = function fromWitness(witness) {
Address.prototype.fromInputScript = function fromInputScript(script) {
if (script.isPubkeyhashInput()) {
this.hash = crypto.hash160(script.get(1));
this.type = scriptTypes.PUBKEYHASH;
this.type = Script.types.PUBKEYHASH;
this.version = -1;
return this;
}
if (script.isScripthashInput()) {
this.hash = crypto.hash160(script.get(script.length - 1));
this.type = scriptTypes.SCRIPTHASH;
this.type = Script.types.SCRIPTHASH;
this.version = -1;
return this;
}
@ -405,15 +406,15 @@ Address.prototype.fromHash = function fromHash(hash, type, version, network) {
hash = new Buffer(hash, 'hex');
if (typeof type === 'string')
type = scriptTypes[type.toUpperCase()];
type = Script.types[type.toUpperCase()];
if (type == null)
type = scriptTypes.PUBKEYHASH;
type = Script.types.PUBKEYHASH;
if (version == null)
version = -1;
network = bcoin.network.get(network);
network = Network.get(network);
assert(Buffer.isBuffer(hash));
assert(utils.isNumber(type));
@ -427,11 +428,11 @@ Address.prototype.fromHash = function fromHash(hash, type, version, network) {
} else {
assert(Address.isWitness(type), 'Wrong version (non-witness).');
assert(version >= 0 && version <= 16, 'Bad program version.');
if (version === 0 && type === scriptTypes.WITNESSPUBKEYHASH)
if (version === 0 && type === Script.types.WITNESSPUBKEYHASH)
assert(hash.length === 20, 'Hash is the wrong size.');
else if (version === 0 && type === scriptTypes.WITNESSSCRIPTHASH)
else if (version === 0 && type === Script.types.WITNESSSCRIPTHASH)
assert(hash.length === 32, 'Hash is the wrong size.');
else if (version === 1 && type === scriptTypes.WITNESSSCRIPTHASH)
else if (version === 1 && type === Script.types.WITNESSSCRIPTHASH)
assert(hash.length === 32, 'Hash is the wrong size.');
}
@ -468,9 +469,9 @@ Address.fromHash = function fromHash(hash, type, version, network) {
Address.prototype.fromData = function fromData(data, type, version, network) {
if (typeof type === 'string')
type = scriptTypes[type.toUpperCase()];
type = Script.types[type.toUpperCase()];
if (type === scriptTypes.WITNESSSCRIPTHASH) {
if (type === Script.types.WITNESSSCRIPTHASH) {
if (version === 0) {
assert(Buffer.isBuffer(data));
data = crypto.sha256(data);
@ -480,7 +481,7 @@ Address.prototype.fromData = function fromData(data, type, version, network) {
} else {
throw new Error('Cannot create from version=' + version);
}
} else if (type === scriptTypes.WITNESSPUBKEYHASH) {
} else if (type === Script.types.WITNESSPUBKEYHASH) {
if (version !== 0)
throw new Error('Cannot create from version=' + version);
assert(Buffer.isBuffer(data));
@ -529,7 +530,7 @@ Address.validate = function validate(address, type) {
}
if (typeof type === 'string')
type = scriptTypes[type.toUpperCase()];
type = Script.types[type.toUpperCase()];
if (type && address.type !== type)
return false;
@ -579,13 +580,13 @@ Address.getHash = function getHash(data, enc) {
Address.getPrefix = function getPrefix(type, network) {
var prefixes = network.addressPrefix;
switch (type) {
case scriptTypes.PUBKEYHASH:
case Script.types.PUBKEYHASH:
return prefixes.pubkeyhash;
case scriptTypes.SCRIPTHASH:
case Script.types.SCRIPTHASH:
return prefixes.scripthash;
case scriptTypes.WITNESSPUBKEYHASH:
case Script.types.WITNESSPUBKEYHASH:
return prefixes.witnesspubkeyhash;
case scriptTypes.WITNESSSCRIPTHASH:
case Script.types.WITNESSSCRIPTHASH:
return prefixes.witnessscripthash;
default:
return -1;
@ -603,13 +604,13 @@ Address.getType = function getType(prefix, network) {
var prefixes = network.addressPrefix;
switch (prefix) {
case prefixes.pubkeyhash:
return scriptTypes.PUBKEYHASH;
return Script.types.PUBKEYHASH;
case prefixes.scripthash:
return scriptTypes.SCRIPTHASH;
return Script.types.SCRIPTHASH;
case prefixes.witnesspubkeyhash:
return scriptTypes.WITNESSPUBKEYHASH;
return Script.types.WITNESSPUBKEYHASH;
case prefixes.witnessscripthash:
return scriptTypes.WITNESSSCRIPTHASH;
return Script.types.WITNESSSCRIPTHASH;
default:
return -1;
}
@ -623,9 +624,9 @@ Address.getType = function getType(prefix, network) {
Address.isWitness = function isWitness(type) {
switch (type) {
case scriptTypes.WITNESSPUBKEYHASH:
case Script.types.WITNESSPUBKEYHASH:
return true;
case scriptTypes.WITNESSSCRIPTHASH:
case Script.types.WITNESSSCRIPTHASH:
return true;
default:
return false;

View file

@ -7,13 +7,19 @@
'use strict';
var bcoin = require('../env');
module.exports = Block;
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var assert = utils.assert;
var constants = bcoin.constants;
var AbstractBlock = bcoin.abstractblock;
var assert = require('assert');
var constants = require('../protocol/constants');
var AbstractBlock = require('./abstractblock');
var VerifyResult = utils.VerifyResult;
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
var TX = require('./tx');
var MerkleBlock = require('./merkleblock');
var Network = require('../protocol/network');
/**
* Represents a full block.
@ -162,7 +168,7 @@ Block.prototype.getSizes = function getSizes() {
};
}
writer = new bcoin.writer();
writer = new BufferWriter();
this.toRaw(writer);
return {
@ -262,7 +268,7 @@ Block.prototype.hasTX = function hasTX(hash) {
Block.prototype.indexOf = function indexOf(hash) {
var i;
if (hash instanceof bcoin.tx)
if (hash instanceof TX)
hash = hash.hash('hex');
for (i = 0; i < this.txs.length; i++) {
@ -534,7 +540,7 @@ Block.reward = function reward(height, network) {
assert(height >= 0, 'Bad height for reward.');
network = bcoin.network.get(network);
network = Network.get(network);
halvings = height / network.halvingInterval | 0;
// BIP 42 (well, our own version of it,
@ -647,7 +653,7 @@ Block.prototype.fromJSON = function fromJSON(json) {
this.parseJSON(json);
for (i = 0; i < json.txs.length; i++)
this.txs.push(bcoin.tx.fromJSON(json.txs[i]));
this.txs.push(TX.fromJSON(json.txs[i]));
return this;
};
@ -669,7 +675,7 @@ Block.fromJSON = function fromJSON(json) {
*/
Block.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
var i, tx, witnessSize;
p.start();
@ -685,7 +691,7 @@ Block.prototype.fromRaw = function fromRaw(data) {
witnessSize = 0;
for (i = 0; i < this.totalTX; i++) {
tx = bcoin.tx.fromRaw(p);
tx = TX.fromRaw(p);
witnessSize += tx._witnessSize;
this.addTX(tx);
}
@ -721,7 +727,7 @@ Block.fromRaw = function fromRaw(data, enc) {
*/
Block.prototype.toMerkle = function toMerkle(filter) {
return bcoin.merkleblock.fromBlock(this, filter);
return MerkleBlock.fromBlock(this, filter);
};
/**
@ -733,11 +739,11 @@ Block.prototype.toMerkle = function toMerkle(filter) {
*/
Block.prototype.frame = function frame(witness, writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var witnessSize = 0;
var i, tx;
p.write32(this.version);
p.writeU32(this.version);
p.writeHash(this.prevBlock);
p.writeHash(this.merkleRoot);
p.writeU32(this.ts);

View file

@ -7,11 +7,20 @@
'use strict';
var bcoin = require('../env');
module.exports = Coin;
var utils = require('../utils/utils');
var constants = bcoin.constants;
var assert = utils.assert;
var Output = bcoin.output;
var constants = require('../protocol/constants');
var Network = require('../protocol/network');
var assert = require('assert');
var Output = require('./output');
var Script = require('../script/script');
var Network = require('../protocol/network');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
var compressor = require('../chain/compress');
var compress = compressor.compress;
var decompress = compressor.decompress;
/**
* Represents an unspent output.
@ -36,7 +45,7 @@ function Coin(options) {
this.version = 1;
this.height = -1;
this.value = 0;
this.script = new bcoin.script();
this.script = new Script();
this.coinbase = true;
this.hash = constants.NULL_HASH;
this.index = 0;
@ -95,7 +104,7 @@ Coin.fromOptions = function fromOptions(options) {
Coin.prototype.getConfirmations = function getConfirmations(height) {
if (height == null)
height = bcoin.network.get().height;
height = Network.primary.height;
if (this.height === -1)
return 0;
@ -210,7 +219,7 @@ Coin.prototype.fromJSON = function fromJSON(json) {
*/
Coin.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var height = this.height;
if (height === -1)
@ -235,7 +244,7 @@ Coin.prototype.toRaw = function toRaw(writer) {
*/
Coin.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.version = p.readU32();
this.height = p.readU32();
@ -269,8 +278,7 @@ Coin.fromRaw = function fromRaw(data, enc) {
*/
Coin.prototype.toCompressed = function toCompressed(writer) {
var compress = bcoin.coins.compress;
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var height = this.height;
var bits;
@ -303,8 +311,7 @@ Coin.prototype.toCompressed = function toCompressed(writer) {
*/
Coin.prototype.fromCompressed = function fromCompressed(data) {
var decompress = bcoin.coins.decompress;
var p = bcoin.reader(data);
var p = BufferReader(data);
var bits;
this.version = p.readVarint();
@ -341,7 +348,7 @@ Coin.fromCompressed = function fromCompressed(data, enc) {
*/
Coin.prototype.toExtended = function toExtended(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
this.toRaw(p);
p.writeHash(this.hash);
@ -360,7 +367,7 @@ Coin.prototype.toExtended = function toExtended(writer) {
*/
Coin.prototype.fromExtended = function fromExtended(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.fromRaw(p);
this.hash = p.readHash('hex');
this.index = p.readU32();

View file

@ -7,9 +7,12 @@
'use strict';
var bcoin = require('../env');
module.exports = Headers;
var utils = require('../utils/utils');
var AbstractBlock = bcoin.abstractblock;
var AbstractBlock = require('./abstractblock');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
/**
* Represents block headers obtained from the network via `headers`.
@ -46,7 +49,7 @@ Headers.prototype._verify = function _verify(ret) {
*/
Headers.prototype.getSize = function getSize() {
var writer = new bcoin.writer();
var writer = new BufferWriter();
this.toRaw(writer);
return writer.written;
};
@ -80,9 +83,9 @@ Headers.prototype.inspect = function inspect() {
*/
Headers.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.write32(this.version);
p.writeU32(this.version);
p.writeHash(this.prevBlock);
p.writeHash(this.merkleRoot);
p.writeU32(this.ts);
@ -103,7 +106,7 @@ Headers.prototype.toRaw = function toRaw(writer) {
*/
Headers.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.version = p.readU32(); // Technically signed
this.prevBlock = p.readHash('hex');
@ -136,7 +139,7 @@ Headers.fromRaw = function fromRaw(data, enc) {
*/
Headers.prototype.fromAbbr = function fromAbbr(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.version = p.readU32(); // Technically signed
this.prevBlock = p.readHash('hex');

17
lib/primitives/index.js Normal file
View file

@ -0,0 +1,17 @@
'use strict';
exports.AbstractBlock = require('./abstractblock');
exports.Address = require('./address');
exports.Block = require('./block');
exports.Coin = require('./coin');
exports.Headers = require('./headers');
exports.Input = require('./input');
exports.InvItem = require('./invitem');
exports.KeyRing = require('./keyring');
exports.MemBlock = require('./memblock');
exports.MerkleBlock = require('./merkleblock');
exports.MTX = require('./mtx');
exports.NetworkAddress = require('./netaddress');
exports.Outpoint = require('./outpoint');
exports.Output = require('./output');
exports.TX = require('./tx');

View file

@ -7,11 +7,17 @@
'use strict';
var bcoin = require('../env');
module.exports = Input;
var utils = require('../utils/utils');
var assert = utils.assert;
var constants = bcoin.constants;
var assert = require('assert');
var constants = require('../protocol/constants');
var Script = require('../script/script');
var Witness = require('../script/witness');
var Outpoint = require('./outpoint');
var Coin = require('./coin');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
/**
* Represents a transaction input.
@ -30,9 +36,9 @@ function Input(options) {
return new Input(options);
this.prevout = new Outpoint();
this.script = new bcoin.script();
this.script = new Script();
this.sequence = 0xffffffff;
this.witness = new bcoin.witness();
this.witness = new Witness();
this.coin = null;
this.mutable = false;
this._address = null;
@ -65,7 +71,7 @@ Input.prototype.fromOptions = function fromOptions(options) {
this.witness.fromOptions(options.witness);
if (options.coin)
this.coin = bcoin.coin(options.coin);
this.coin = Coin(options.coin);
return this;
};
@ -277,7 +283,7 @@ Input.prototype.fromJSON = function fromJSON(json) {
assert(json, 'Input data is required.');
assert(utils.isNumber(json.sequence));
this.prevout.fromJSON(json.prevout);
this.coin = json.coin ? bcoin.coin.fromJSON(json.coin) : null;
this.coin = json.coin ? Coin.fromJSON(json.coin) : null;
this.script.fromJSON(json.script);
this.witness.fromJSON(json.witness);
this.sequence = json.sequence;
@ -301,7 +307,7 @@ Input.fromJSON = function fromJSON(json) {
*/
Input.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
this.prevout.toRaw(p);
p.writeVarBytes(this.script.toRaw());
@ -319,7 +325,7 @@ Input.prototype.toRaw = function toRaw(writer) {
*/
Input.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.prevout.fromRaw(p);
this.script.fromRaw(p.readVarBytes());
@ -349,7 +355,7 @@ Input.fromRaw = function fromRaw(data, enc) {
*/
Input.prototype.toExtended = function toExtended(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
this.toRaw(p);
this.witness.toRaw(p);
@ -367,7 +373,7 @@ Input.prototype.toExtended = function toExtended(writer) {
*/
Input.prototype.fromExtended = function fromExtended(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.fromRaw(p);
this.witness.fromRaw(p);
return this;
@ -420,7 +426,7 @@ Input.fromCoin = function fromCoin(coin) {
*/
Input.prototype.fromTX = function fromTX(tx, index) {
var coin = bcoin.coin.fromTX(tx, index);
var coin = Coin.fromTX(tx, index);
return this.fromCoin(coin);
};

View file

@ -7,8 +7,11 @@
'use strict';
var bcoin = require('../env');
module.exports = InvItem;
var constants = require('../protocol/constants');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
/**
* Inv Item
@ -32,7 +35,7 @@ function InvItem(type, hash) {
*/
InvItem.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.writeU32(this.type);
p.writeHash(this.hash);
@ -49,7 +52,7 @@ InvItem.prototype.toRaw = function toRaw(writer) {
*/
InvItem.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.type = p.readU32();
this.hash = p.readHash('hex');
return this;

View file

@ -7,44 +7,46 @@
'use strict';
var bcoin = require('../env');
var constants = bcoin.constants;
var utils = bcoin.utils;
module.exports = KeyRing;
var constants = require('../protocol/constants');
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var assert = utils.assert;
var networks = bcoin.networks;
var assert = require('assert');
var networks = require('../protocol/networks');
var Network = require('../protocol/network');
var BufferReader = require('../utils/reader');
var BufferWriter = require('../utils/writer');
var scriptTypes = constants.scriptTypes;
var Script = require('../script/script');
var Address = require('./address');
var Input = require('./input');
var Output = require('./output');
var ec = require('../crypto/ec');
/**
* Represents a key ring which amounts to an address.
* @exports KeyRing
* @constructor
* @param {Object} options
* @param {HDPrivateKey|HDPublicKey|Buffer} options.key
* @param {Buffer[]} options.keys - Shared multisig keys.
* @param {Number?} options.m - Multisig `m` value.
* @param {Number?} options.n - Multisig `n` value.
* @param {Boolean?} options.witness - Whether witness programs are enabled.
* @param {Network} network
*/
function KeyRing(options, network) {
if (!(this instanceof KeyRing))
return new KeyRing(options, network);
this.network = bcoin.network.get();
this.network = Network.primary;
this.witness = false;
this.nested = false;
this.publicKey = constants.ZERO_KEY;
this.privateKey = null;
this.script = null;
this.path = null;
this._keyHash = null;
this._keyAddress = null;
this._program = null;
this._programHash = null;
this._programAddress = null;
this._nestedHash = null;
this._nestedAddress = null;
this._scriptHash160 = null;
this._scriptHash256 = null;
this._scriptAddress = null;
@ -61,6 +63,11 @@ function KeyRing(options, network) {
KeyRing.prototype.fromOptions = function fromOptions(options, network) {
var key = toKey(options);
var script = options.script;
var compressed = options.compressed;
if (!network)
network = options.network;
if (Buffer.isBuffer(key))
return this.fromKey(key, network);
@ -73,18 +80,20 @@ KeyRing.prototype.fromOptions = function fromOptions(options, network) {
if (options.privateKey)
key = toKey(options.privateKey);
if (options.network)
this.network = bcoin.network.get(options.network);
if (options.witness != null) {
assert(typeof options.witness === 'boolean');
this.witness = options.witness;
}
if (options.script)
return this.fromScript(key, options.script, this.network);
if (options.nested != null) {
assert(typeof options.nested === 'boolean');
this.nested = options.nested;
}
this.fromKey(key, this.network);
if (script)
return this.fromScript(key, script, compressed, network);
this.fromKey(key, compressed, network);
};
/**
@ -100,59 +109,82 @@ KeyRing.fromOptions = function fromOptions(options) {
/**
* Inject data from private key.
* @private
* @param {Buffer} privateKey
* @param {Buffer} key
* @param {Boolean?} compressed
* @param {(NetworkType|Network}) network
*/
KeyRing.prototype.fromPrivate = function fromPrivate(privateKey, network) {
assert(Buffer.isBuffer(privateKey), 'Private key must be a buffer.');
assert(bcoin.ec.privateKeyVerify(privateKey), 'Not a valid private key.');
this.network = bcoin.network.get(network);
this.privateKey = privateKey;
this.publicKey = bcoin.ec.publicKeyCreate(this.privateKey, true);
KeyRing.prototype.fromPrivate = function fromPrivate(key, compressed, network) {
assert(Buffer.isBuffer(key), 'Private key must be a buffer.');
assert(ec.privateKeyVerify(key), 'Not a valid private key.');
if (typeof compressed !== 'boolean') {
network = compressed;
compressed = null;
}
this.network = Network.get(network);
this.privateKey = key;
this.publicKey = ec.publicKeyCreate(key, compressed !== false);
return this;
};
/**
* Instantiate keyring from a private key.
* @param {Buffer} privateKey
* @param {Buffer} key
* @param {Boolean?} compressed
* @param {(NetworkType|Network}) network
* @returns {KeyRing}
*/
KeyRing.fromPrivate = function fromPrivate(privateKey, network) {
return new KeyRing().fromPrivate(privateKey, network);
KeyRing.fromPrivate = function fromPrivate(key, compressed, network) {
return new KeyRing().fromPrivate(key, compressed, network);
};
/**
* Inject data from public key.
* @private
* @param {Buffer} privateKey
* @param {Buffer} key
* @param {(NetworkType|Network}) network
*/
KeyRing.prototype.fromPublic = function fromPublic(publicKey, network) {
assert(Buffer.isBuffer(publicKey), 'Public key must be a buffer.');
assert(bcoin.ec.publicKeyVerify(publicKey), 'Not a valid public key.');
this.network = bcoin.network.get(network);
this.publicKey = publicKey;
KeyRing.prototype.fromPublic = function fromPublic(key, network) {
assert(Buffer.isBuffer(key), 'Public key must be a buffer.');
assert(ec.publicKeyVerify(key), 'Not a valid public key.');
this.network = Network.get(network);
this.publicKey = key;
return this;
};
/**
* Generate a keyring.
* @private
* @param {(Network|NetworkType)?} network
* @returns {KeyRing}
*/
KeyRing.prototype.generate = function(compressed, network) {
var key;
if (typeof compressed !== 'boolean') {
network = compressed;
compressed = null;
}
key = ec.generatePrivateKey();
return this.fromKey(key, compressed, network);
};
/**
* Generate a keyring.
* @param {(Network|NetworkType)?} network
* @returns {KeyRing}
*/
KeyRing.generate = function(network) {
var key = new KeyRing();
key.network = bcoin.network.get(network);
key.privateKey = bcoin.ec.generatePrivateKey();
key.publicKey = bcoin.ec.publicKeyCreate(key.privateKey, true);
return key;
KeyRing.generate = function(compressed, network) {
return new KeyRing().generate(compressed, network);
};
/**
@ -162,8 +194,8 @@ KeyRing.generate = function(network) {
* @returns {KeyRing}
*/
KeyRing.fromPublic = function fromPublic(publicKey, network) {
return new KeyRing().fromPublic(publicKey, network);
KeyRing.fromPublic = function fromPublic(key, network) {
return new KeyRing().fromPublic(key, network);
};
/**
@ -173,14 +205,18 @@ KeyRing.fromPublic = function fromPublic(publicKey, network) {
* @param {(NetworkType|Network}) network
*/
KeyRing.prototype.fromKey = function fromKey(key, network) {
KeyRing.prototype.fromKey = function fromKey(key, compressed, network) {
assert(Buffer.isBuffer(key), 'Key must be a buffer.');
assert(key.length === 32 || key.length === 33, 'Not a key.');
if (key.length === 33)
return this.fromPublic(key, network);
if (typeof compressed !== 'boolean') {
network = compressed;
compressed = null;
}
return this.fromPrivate(key, network);
if (key.length === 32)
return this.fromPrivate(key, compressed !== false, network);
return this.fromPublic(key, network);
};
/**
@ -190,8 +226,8 @@ KeyRing.prototype.fromKey = function fromKey(key, network) {
* @returns {KeyRing}
*/
KeyRing.fromKey = function fromKey(key, network) {
return new KeyRing().fromKey(key, network);
KeyRing.fromKey = function fromKey(key, compressed, network) {
return new KeyRing().fromKey(key, compressed, network);
};
/**
@ -202,10 +238,17 @@ KeyRing.fromKey = function fromKey(key, network) {
* @param {(NetworkType|Network}) network
*/
KeyRing.prototype.fromScript = function fromScript(key, script, network) {
assert(script instanceof bcoin.script, 'Non-script passed into KeyRing.');
this.fromKey(key, network);
KeyRing.prototype.fromScript = function fromScript(key, script, compressed, network) {
assert(script instanceof Script, 'Non-script passed into KeyRing.');
if (typeof compressed !== 'boolean') {
network = compressed;
compressed = null;
}
this.fromKey(key, compressed, network);
this.script = script;
return this;
};
@ -217,8 +260,8 @@ KeyRing.prototype.fromScript = function fromScript(key, script, network) {
* @returns {KeyRing}
*/
KeyRing.fromScript = function fromScript(key, script, network) {
return new KeyRing().fromScript(key, script, network);
KeyRing.fromScript = function fromScript(key, script, compressed, network) {
return new KeyRing().fromScript(key, script, compressed, network);
};
/**
@ -235,7 +278,8 @@ KeyRing.prototype.toSecret = function toSecret() {
p.writeU8(this.network.keyPrefix.privkey);
p.writeBytes(this.privateKey);
p.writeU8(1);
if (this.publicKey.length === 33)
p.writeU8(1);
p.writeChecksum();
@ -274,9 +318,7 @@ KeyRing.prototype.fromSecret = function fromSecret(data) {
p.verifyChecksum();
assert(compressed === false, 'Cannot handle uncompressed.');
return this.fromPrivate(key, type);
return this.fromPrivate(key, compressed, type);
};
/**
@ -347,10 +389,10 @@ KeyRing.prototype.getProgram = function getProgram() {
if (!this._program) {
if (!this.script) {
hash = crypto.hash160(this.publicKey);
program = bcoin.script.fromProgram(0, hash);
program = Script.fromProgram(0, hash);
} else {
hash = this.script.sha256();
program = bcoin.script.fromProgram(0, hash);
program = Script.fromProgram(0, hash);
}
this._program = program;
}
@ -365,16 +407,16 @@ KeyRing.prototype.getProgram = function getProgram() {
* @returns {Buffer}
*/
KeyRing.prototype.getProgramHash = function getProgramHash(enc) {
KeyRing.prototype.getNestedHash = function getNestedHash(enc) {
if (!this.witness)
return;
if (!this._programHash)
this._programHash = this.getProgram().hash160();
if (!this._nestedHash)
this._nestedHash = this.getProgram().hash160();
return enc === 'hex'
? this._programHash.toString('hex')
: this._programHash;
? this._nestedHash.toString('hex')
: this._nestedHash;
};
/**
@ -383,22 +425,22 @@ KeyRing.prototype.getProgramHash = function getProgramHash(enc) {
* @returns {Address|Base58Address}
*/
KeyRing.prototype.getProgramAddress = function getProgramAddress(enc) {
KeyRing.prototype.getNestedAddress = function getNestedAddress(enc) {
var hash, address;
if (!this.witness)
return;
if (!this._programAddress) {
hash = this.getProgramHash();
address = this.compile(hash, scriptTypes.SCRIPTHASH);
this._programAddress = address;
if (!this._nestedAddress) {
hash = this.getNestedHash();
address = this.compile(hash, Script.types.SCRIPTHASH);
this._nestedAddress = address;
}
if (enc === 'base58')
return this._programAddress.toBase58();
return this._nestedAddress.toBase58();
return this._programAddress;
return this._nestedAddress;
};
/**
@ -464,10 +506,10 @@ KeyRing.prototype.getScriptAddress = function getScriptAddress(enc) {
if (!this._scriptAddress) {
if (this.witness) {
hash = this.getScriptHash256();
address = this.compile(hash, scriptTypes.WITNESSSCRIPTHASH, 0);
address = this.compile(hash, Script.types.WITNESSSCRIPTHASH, 0);
} else {
hash = this.getScriptHash160();
address = this.compile(hash, scriptTypes.SCRIPTHASH);
address = this.compile(hash, Script.types.SCRIPTHASH);
}
this._scriptAddress = address;
}
@ -505,9 +547,9 @@ KeyRing.prototype.getKeyAddress = function getKeyAddress(enc) {
if (!this._keyAddress) {
hash = this.getKeyHash();
if (this.witness)
address = this.compile(hash, scriptTypes.WITNESSPUBKEYHASH, 0);
address = this.compile(hash, Script.types.WITNESSPUBKEYHASH, 0);
else
address = this.compile(hash, scriptTypes.PUBKEYHASH);
address = this.compile(hash, Script.types.PUBKEYHASH);
this._keyAddress = address;
}
@ -528,7 +570,7 @@ KeyRing.prototype.getKeyAddress = function getKeyAddress(enc) {
*/
KeyRing.prototype.compile = function compile(hash, type, version) {
return bcoin.address.fromHash(hash, type, version, this.network);
return Address.fromHash(hash, type, version, this.network);
};
/**
@ -538,6 +580,8 @@ KeyRing.prototype.compile = function compile(hash, type, version) {
*/
KeyRing.prototype.getHash = function getHash(enc) {
if (this.nested)
return this.getNestedHash(enc);
if (this.script)
return this.getScriptHash(enc);
return this.getKeyHash(enc);
@ -550,6 +594,8 @@ KeyRing.prototype.getHash = function getHash(enc) {
*/
KeyRing.prototype.getAddress = function getAddress(enc) {
if (this.nested)
return this.getNestedAddress(enc);
if (this.script)
return this.getScriptAddress(enc);
return this.getKeyAddress(enc);
@ -572,7 +618,7 @@ KeyRing.prototype.ownHash = function ownHash(hash) {
return true;
if (this.witness) {
if (utils.equal(hash, this.programHash))
if (utils.equal(hash, this.nestedHash))
return true;
}
@ -589,7 +635,7 @@ KeyRing.prototype.ownHash = function ownHash(hash) {
KeyRing.prototype.ownInput = function ownInput(tx, index) {
var input;
if (tx instanceof bcoin.input) {
if (tx instanceof Input) {
input = tx;
} else {
input = tx.inputs[index];
@ -609,7 +655,7 @@ KeyRing.prototype.ownInput = function ownInput(tx, index) {
KeyRing.prototype.ownOutput = function ownOutput(tx, index) {
var output;
if (tx instanceof bcoin.output) {
if (tx instanceof Output) {
output = tx;
} else {
output = tx.outputs[index];
@ -628,7 +674,7 @@ KeyRing.prototype.ownOutput = function ownOutput(tx, index) {
KeyRing.prototype.getRedeem = function(hash) {
if (this.program) {
if (utils.equal(hash, this.programHash))
if (utils.equal(hash, this.nestedHash))
return this.program;
}
@ -651,7 +697,7 @@ KeyRing.prototype.getRedeem = function(hash) {
KeyRing.prototype.sign = function sign(msg) {
assert(this.privateKey, 'Cannot sign without private key.');
return bcoin.ec.sign(msg, this.privateKey);
return ec.sign(msg, this.privateKey);
};
/**
@ -662,7 +708,7 @@ KeyRing.prototype.sign = function sign(msg) {
*/
KeyRing.prototype.verify = function verify(msg, sig) {
return bcoin.ec.verify(msg, sig, this.publicKey);
return ec.verify(msg, sig, this.publicKey);
};
/**
@ -670,14 +716,35 @@ KeyRing.prototype.verify = function verify(msg, sig) {
* @returns {ScriptType}
*/
KeyRing.prototype.getVersion = function getVersion() {
if (!this.witness)
return -1;
if (this.nested)
return -1;
return 0;
};
/**
* Get address type.
* @returns {ScriptType}
*/
KeyRing.prototype.getType = function getType() {
if (this.program)
return this.program.getType();
if (this.nested)
return Script.types.SCRIPTHASH;
if (this.witness) {
if (this.script)
return Script.types.WITNESSSCRIPTHASH;
return Script.types.WITNESSPUBKEYHASH;
}
if (this.script)
return this.script.getType();
return Script.types.SCRIPTHASH;
return scriptTypes.PUBKEYHASH;
return Script.types.PUBKEYHASH;
};
/*
@ -688,6 +755,10 @@ KeyRing.prototype.__defineGetter__('type', function() {
return this.getType();
});
KeyRing.prototype.__defineGetter__('version', function() {
return this.getVersion();
});
KeyRing.prototype.__defineGetter__('scriptHash', function() {
return this.getScriptHash();
});
@ -708,12 +779,12 @@ KeyRing.prototype.__defineGetter__('program', function() {
return this.getProgram();
});
KeyRing.prototype.__defineGetter__('programHash', function() {
return this.getProgramHash();
KeyRing.prototype.__defineGetter__('nestedHash', function() {
return this.getNestedHash();
});
KeyRing.prototype.__defineGetter__('programAddress', function() {
return this.getProgramAddress();
KeyRing.prototype.__defineGetter__('nestedAddress', function() {
return this.getNestedAddress();
});
KeyRing.prototype.__defineGetter__('keyHash', function() {
@ -750,17 +821,12 @@ KeyRing.prototype.toJSON = function toJSON() {
return {
network: this.network.type,
witness: this.witness,
nested: this.nested,
publicKey: this.publicKey.toString('hex'),
script: this.script ? this.script.toRaw().toString('hex') : null,
program: this.program ? this.program.toRaw().toString('hex') : null,
type: constants.scriptTypesByVal[this.type].toLowerCase(),
wid: this.path ? this.path.wid : undefined,
id: this.path ? this.path.id : undefined,
name: this.path ? this.path.name : undefined,
account: this.path ? this.path.account : undefined,
change: this.path ? this.path.change : undefined,
index: this.path ? this.path.index : undefined,
address: this.getAddress('base58'),
programAddress: this.getProgramAddress('base58')
address: this.getAddress('base58')
};
};
@ -774,11 +840,13 @@ KeyRing.prototype.fromJSON = function fromJSON(json) {
assert(json);
assert(typeof json.network === 'string');
assert(typeof json.witness === 'boolean');
assert(typeof json.nested === 'boolean');
assert(typeof json.publicKey === 'string');
assert(!json.script || typeof json.script === 'string');
this.nework = bcoin.network.get(json.network);
this.nework = Network.get(json.network);
this.witness = json.witness;
this.nested = json.nested;
this.publicKey = new Buffer(json.publicKey, 'hex');
if (json.script)
@ -804,13 +872,22 @@ KeyRing.fromJSON = function fromJSON(json) {
KeyRing.prototype.toRaw = function toRaw(writer) {
var p = new BufferWriter(writer);
var field = 0;
p.writeU8(this.witness ? 1 : 0);
if (this.witness)
field |= 1;
if (this.privateKey)
if (this.nested)
field |= 2;
p.writeU8(field);
if (this.privateKey) {
p.writeVarBytes(this.privateKey);
else
p.writeU8(this.publicKey.length === 33);
} else {
p.writeVarBytes(this.publicKey);
}
if (this.script)
p.writeVarBytes(this.script.toRaw());
@ -831,24 +908,30 @@ KeyRing.prototype.toRaw = function toRaw(writer) {
KeyRing.prototype.fromRaw = function fromRaw(data, network) {
var p = new BufferReader(data);
var key, script;
var field, compressed, key, script;
this.network = bcoin.network.get(network);
this.witness = p.readU8() === 1;
this.network = Network.get(network);
field = p.readU8();
this.witness = (field & 1) !== 0;
this.nested = (field & 2) !== 0;
key = p.readVarBytes();
if (key.length === 32) {
compressed = p.readU8() === 1;
this.privateKey = key;
this.publicKey = bcoin.ec.publicKeyCreate(key, true);
this.publicKey = ec.publicKeyCreate(key, compressed);
} else {
this.publicKey = key;
assert(ec.publicKeyVerify(key), 'Invalid public key.');
}
script = p.readVarBytes();
if (script.length > 0)
this.script = bcoin.script.fromRaw(script);
this.script = Script.fromRaw(script);
return this;
};

View file

@ -7,9 +7,13 @@
'use strict';
var bcoin = require('../env');
module.exports = MemBlock;
var utils = require('../utils/utils');
var AbstractBlock = bcoin.abstractblock;
var AbstractBlock = require('./abstractblock');
var Block = require('./block');
var Script = require('../script/script');
var BufferReader = require('../utils/reader');
/**
* A block object which is essentially a "placeholder"
@ -113,7 +117,7 @@ MemBlock.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
*/
MemBlock.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data, true);
var p = BufferReader(data, true);
var height = -1;
var inCount, input;
@ -137,7 +141,7 @@ MemBlock.prototype.fromRaw = function fromRaw(data) {
if (inCount > 0) {
p.seek(36);
input = p.readVarBytes();
height = bcoin.script.getCoinbaseHeight(input);
height = Script.getCoinbaseHeight(input);
}
}
@ -183,7 +187,7 @@ MemBlock.prototype.toNormal = function toNormal() {
*/
MemBlock.prototype.toBlock = function toBlock() {
var block = bcoin.block.fromRaw(this.raw);
var block = Block.fromRaw(this.raw);
block._hash = this._hash;
block._cbHeight = this.coinbaseHeight;
this.raw = null;

View file

@ -7,14 +7,18 @@
'use strict';
var bcoin = require('../env');
module.exports = MerkleBlock;
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var assert = utils.assert;
var constants = bcoin.constants;
var assert = require('assert');
var constants = require('../protocol/constants');
var DUMMY = new Buffer([0]);
var AbstractBlock = bcoin.abstractblock;
var AbstractBlock = require('./abstractblock');
var VerifyResult = utils.VerifyResult;
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
var TX = require('./tx');
/**
* Represents a merkle (filtered) block.
@ -91,7 +95,7 @@ MerkleBlock.fromOptions = function fromOptions(data) {
*/
MerkleBlock.prototype.getSize = function getSize() {
var writer = new bcoin.writer();
var writer = new BufferWriter();
this.toRaw(writer);
return writer.written;
};
@ -131,7 +135,7 @@ MerkleBlock.prototype.hasTX = function hasTX(hash) {
MerkleBlock.prototype.indexOf = function indexOf(hash) {
var index;
if (hash instanceof bcoin.tx)
if (hash instanceof TX)
hash = hash.hash('hex');
this.verifyPartial();
@ -341,7 +345,7 @@ MerkleBlock.prototype.inspect = function inspect() {
*/
MerkleBlock.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var i;
p.writeU32(this.version);
@ -372,7 +376,7 @@ MerkleBlock.prototype.toRaw = function toRaw(writer) {
*/
MerkleBlock.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
var i, hashCount;
this.version = p.readU32();

View file

@ -7,15 +7,24 @@
'use strict';
var bcoin = require('../env');
module.exports = MTX;
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var assert = utils.assert;
var constants = bcoin.constants;
var Script = bcoin.script;
var opcodes = constants.opcodes;
var FundingError = bcoin.errors.FundingError;
var TX = bcoin.tx;
var assert = require('assert');
var constants = require('../protocol/constants');
var Network = require('../protocol/network');
var Script = require('../script/script');
var opcodes = Script.opcodes;
var FundingError = require('../utils/errors').FundingError;
var TX = require('./tx');
var Input = require('./input');
var Output = require('./output');
var Coin = require('./coin');
var KeyRing = require('./keyring');
var Address = require('./address');
var ec = require('../crypto/ec');
var workers = require('../workers/workers');
/**
* A mutable transaction object.
@ -150,12 +159,12 @@ MTX.prototype.clone = function clone() {
*/
MTX.prototype.addInput = function addInput(options, index) {
var input = new bcoin.input();
var input = new Input();
input.mutable = true;
if (options instanceof TX)
input.fromTX(options, index);
else if (options instanceof bcoin.coin)
else if (options instanceof Coin)
input.fromCoin(options);
else
input.fromOptions(options);
@ -179,18 +188,16 @@ MTX.prototype.addInput = function addInput(options, index) {
MTX.prototype.addOutput = function addOutput(options, value) {
var output;
if ((options instanceof bcoin.wallet)
|| (options instanceof bcoin.keyring)) {
if (options instanceof KeyRing)
options = options.getAddress();
}
if (typeof options === 'string')
options = bcoin.address.fromBase58(options);
options = Address.fromBase58(options);
if (options instanceof bcoin.address)
if (options instanceof Address)
options = Script.fromAddress(options);
output = new bcoin.output();
output = new Output();
output.mutable = true;
if (options instanceof Script) {
@ -385,6 +392,19 @@ MTX.prototype.scriptVector = function scriptVector(prev, vector, ring) {
return false;
};
/**
* Sign a transaction input on the worker pool
* (if workers are enabled).
* @param {Number} index
* @param {Buffer} key
* @param {SighashType?} type
* @returns {Promise}
*/
MTX.prototype.signInputAsync = function signInputAsync(index, key, type) {
return workers.pool.signInput(this, index, key, type);
};
/**
* Sign an input.
* @param {Number} index - Index of input being signed.
@ -462,7 +482,7 @@ MTX.prototype.signInput = function signInput(index, key, type) {
*/
MTX.prototype.signVector = function signVector(prev, vector, sig, key) {
var pub = bcoin.ec.publicKeyCreate(key, true);
var pub = ec.publicKeyCreate(key, true);
var i, m, n, keys, keyIndex, total;
// P2PK
@ -820,6 +840,12 @@ MTX.prototype.template = function template(ring) {
var total = 0;
var i;
if (Array.isArray(ring)) {
for (i = 0; i < ring.length; i++)
total += this.template(ring[i]);
return total;
}
for (i = 0; i < this.inputs.length; i++) {
if (!ring.ownInput(this, i))
continue;
@ -879,29 +905,12 @@ MTX.prototype.sign = function sign(ring, type) {
* (if workers are enabled).
* @param {KeyRing} ring
* @param {SighashType?} type
* @param {Function} callback
* @returns {Promise}
* @returns {Boolean} Whether the inputs are valid.
*/
MTX.prototype.signAsync = function signAsync(ring, type, callback) {
var result;
if (typeof type === 'function') {
callback = type;
type = null;
}
if (!bcoin.useWorkers) {
callback = utils.asyncify(callback);
try {
result = this.sign(ring, type);
} catch (e) {
return callback(e);
}
return callback(null, result);
}
bcoin.workerPool.sign(this, ring, type, callback);
MTX.prototype.signAsync = function signAsync(ring, type) {
return workers.pool.sign(this, ring, type);
};
/**
@ -1002,7 +1011,7 @@ MTX.prototype.maxSize = function maxSize(options) {
if (redeem) {
prev = redeem;
sz = prev.getSize();
size += bcoin.script.sizePush(sz);
size += Script.sizePush(sz);
size += sz;
}
}
@ -1124,8 +1133,8 @@ MTX.prototype._guessRedeem = function guessRedeem(options, hash) {
case 20:
if (options.witness) {
if (options.n > 1)
return bcoin.script.fromProgram(0, constants.ZERO_HASH);
return bcoin.script.fromProgram(0, constants.ZERO_HASH160);
return Script.fromProgram(0, constants.ZERO_HASH);
return Script.fromProgram(0, constants.ZERO_HASH160);
}
return options.script;
case 32:
@ -1175,7 +1184,7 @@ MTX.prototype.subtractFee = function subtractFee(fee, index) {
if (Array.isArray(index)) {
addrs = [];
for (i = 0; i < index.length; i++) {
hash = bcoin.address.getHash(index[i]);
hash = Address.getHash(index[i]);
if (hash)
addrs.push(hash);
}
@ -1308,7 +1317,7 @@ MTX.prototype.sortMembers = function sortMembers() {
MTX.prototype.avoidFeeSniping = function avoidFeeSniping(height) {
if (height == null)
height = bcoin.network.get().height;
height = Network.primary.height;
if (height === -1)
height = 0;
@ -1533,9 +1542,9 @@ CoinSelector.prototype.fromOptions = function fromOptions(options) {
if (options.changeAddress) {
addr = options.changeAddress;
if (typeof addr === 'string') {
this.changeAddress = bcoin.address.fromBase58(addr);
this.changeAddress = Address.fromBase58(addr);
} else {
assert(addr instanceof bcoin.address);
assert(addr instanceof Address);
this.changeAddress = addr;
}
}
@ -1558,7 +1567,7 @@ CoinSelector.prototype.fromOptions = function fromOptions(options) {
}
if (options.script) {
assert(options.script instanceof bcoin.script);
assert(options.script instanceof Script);
this.script = options.script;
}
@ -1660,9 +1669,9 @@ CoinSelector.prototype.getFee = function getFee(size) {
var fee;
if (this.round)
fee = bcoin.tx.getRoundFee(size, this.rate);
fee = TX.getRoundFee(size, this.rate);
else
fee = bcoin.tx.getMinFee(size, this.rate);
fee = TX.getMinFee(size, this.rate);
if (fee > constants.tx.MAX_FEE)
fee = constants.tx.MAX_FEE;

View file

@ -6,11 +6,16 @@
'use strict';
var bcoin = require('../env');
module.exports = NetworkAddress;
var constants = require('../protocol/constants');
var Network = require('../protocol/network');
var time = require('../net/timedata');
var utils = require('../utils/utils');
var IP = require('../utils/ip');
var assert = utils.assert;
var assert = require('assert');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
/**
* Represents a network address.
@ -183,14 +188,14 @@ NetworkAddress.prototype.inspect = function inspect() {
NetworkAddress.prototype.fromHostname = function fromHostname(hostname, network) {
var address = IP.parseHost(hostname);
network = bcoin.network.get(network);
network = Network.get(network);
this.host = address.host;
this.port = address.port || network.port;
this.services = constants.services.NETWORK
| constants.services.BLOOM
| constants.services.WITNESS;
this.ts = bcoin.now();
this.ts = time.now();
this.hostname = IP.hostname(this.host, this.port);
@ -224,7 +229,7 @@ NetworkAddress.prototype.fromSocket = function fromSocket(socket) {
this.services = constants.services.NETWORK
| constants.services.BLOOM
| constants.services.WITNESS;
this.ts = bcoin.now();
this.ts = time.now();
this.hostname = IP.hostname(this.host, this.port);
@ -250,8 +255,8 @@ NetworkAddress.fromSocket = function fromSocket(hostname) {
*/
NetworkAddress.prototype.fromRaw = function fromRaw(data, full) {
var p = bcoin.reader(data);
var now = bcoin.now();
var p = BufferReader(data);
var now = time.now();
// only version >= 31402
this.ts = full ? p.readU32() : 0;
@ -285,7 +290,7 @@ NetworkAddress.fromRaw = function fromRaw(data, full) {
*/
NetworkAddress.prototype.toRaw = function toRaw(full, writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
if (full)
p.writeU32(this.ts);

View file

@ -6,10 +6,13 @@
'use strict';
var bcoin = require('../env');
module.exports = Outpoint;
var utils = require('../utils/utils');
var assert = utils.assert;
var constants = bcoin.constants;
var assert = require('assert');
var constants = require('../protocol/constants');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
/**
* Represents a COutPoint.
@ -69,7 +72,7 @@ Outpoint.prototype.isNull = function isNull() {
*/
Outpoint.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.writeHash(this.hash);
p.writeU32(this.index);
@ -87,7 +90,7 @@ Outpoint.prototype.toRaw = function toRaw(writer) {
*/
Outpoint.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.hash = p.readHash('hex');
this.index = p.readU32();
return this;

View file

@ -7,10 +7,15 @@
'use strict';
var bcoin = require('../env');
module.exports = Output;
var utils = require('../utils/utils');
var constants = bcoin.constants;
var assert = utils.assert;
var constants = require('../protocol/constants');
var Script = require('../script/script');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
var assert = require('assert');
var TX = require('./tx');
/**
* Represents a transaction output.
@ -26,7 +31,7 @@ function Output(options) {
return new Output(options);
this.value = 0;
this.script = new bcoin.script();
this.script = new Script();
this.mutable = false;
this._address = null;
@ -165,7 +170,7 @@ Output.prototype.getDustThreshold = function getDustThreshold(rate) {
size += 32 + 4 + 1 + 107 + 4;
}
return 3 * bcoin.tx.getMinFee(size, rate);
return 3 * TX.getMinFee(size, rate);
};
/**
@ -174,7 +179,7 @@ Output.prototype.getDustThreshold = function getDustThreshold(rate) {
*/
Output.prototype.getSize = function getSize() {
return this.toRaw(bcoin.writer()).written;
return this.toRaw(BufferWriter()).written;
};
/**
@ -217,7 +222,7 @@ Output.fromJSON = function fromJSON(json) {
*/
Output.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
p.write64(this.value);
p.writeVarBytes(this.script.toRaw());
@ -235,7 +240,7 @@ Output.prototype.toRaw = function toRaw(writer) {
*/
Output.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
this.value = p.read64N();
this.script.fromRaw(p.readVarBytes());

View file

@ -7,15 +7,25 @@
'use strict';
var bcoin = require('../env');
module.exports = TX;
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var assert = utils.assert;
var constants = bcoin.constants;
var Script = bcoin.script;
var Stack = bcoin.stack;
var assert = require('assert');
var constants = require('../protocol/constants');
var Network = require('../protocol/network');
var Script = require('../script/script');
var Stack = require('../script/stack');
var BufferWriter = require('../utils/writer');
var VerifyResult = utils.VerifyResult;
var Input = require('./input');
var Output = require('./output');
var Outpoint = require('./outpoint');
var Coin = require('./coin');
var InvItem = require('./invitem');
var workers = require('../workers/workers');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
/*
* Constants
@ -117,13 +127,13 @@ TX.prototype.fromOptions = function fromOptions(options) {
if (options.inputs) {
assert(Array.isArray(options.inputs));
for (i = 0; i < options.inputs.length; i++)
this.inputs.push(new bcoin.input(options.inputs[i]));
this.inputs.push(new Input(options.inputs[i]));
}
if (options.outputs) {
assert(Array.isArray(options.outputs));
for (i = 0; i < options.outputs.length; i++)
this.outputs.push(new bcoin.output(options.outputs[i]));
this.outputs.push(new Output(options.outputs[i]));
}
if (options.locktime != null) {
@ -474,7 +484,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
// Remove all code separators.
prev = prev.removeSeparators();
p.write32(this.version);
p.writeU32(this.version);
if (type & constants.hashType.ANYONECANPAY) {
p.writeVarint(1);
@ -628,7 +638,7 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, type) {
hashOutputs = utils.copy(constants.ZERO_HASH);
}
p.write32(this.version);
p.writeU32(this.version);
p.writeBytes(hashPrevouts);
p.writeBytes(hashSequence);
p.writeHash(this.inputs[index].prevout.hash);
@ -709,39 +719,39 @@ TX.prototype.verifyInput = function verifyInput(index, flags) {
* Verify the transaction inputs on the worker pool
* (if workers are enabled).
* @param {VerifyFlags?} [flags=STANDARD_VERIFY_FLAGS]
* @param {Function} callback
* @returns {Promise}
* @returns {Boolean} Whether the inputs are valid.
*/
TX.prototype.verifyAsync = function verifyAsync(flags, callback) {
var result;
TX.prototype.verifyAsync = function verifyAsync(flags) {
if (this.inputs.length === 0)
return Promise.resolve(false);
if (typeof flags === 'function') {
callback = flags;
flags = null;
}
if (this.isCoinbase())
return Promise.resolve(true);
if (!bcoin.useWorkers) {
callback = utils.asyncify(callback);
try {
result = this.verify(flags);
} catch (e) {
return callback(e);
}
return callback(null, result);
}
return workers.pool.verify(this, flags);
};
if (this.inputs.length === 0) {
callback = utils.asyncify(callback);
return callback(null, false);
}
/**
* Verify a transaction input asynchronously.
* @param {Number} index - Index of output being
* verified.
* @param {VerifyFlags} [flags=STANDARD_VERIFY_FLAGS]
* @returns {Boolean} Whether the input is valid.
*/
if (this.isCoinbase()) {
callback = utils.asyncify(callback);
return callback(null, true);
}
TX.prototype.verifyInputAsync = function verifyInputAsync(index, flags) {
var input;
bcoin.workerPool.verify(this, flags, callback);
if (typeof index === 'object')
index = this.inputs.indexOf(index);
input = this.inputs[index];
assert(input, 'Input does not exist.');
return workers.pool.verifyInput(this, index, flags);
};
/**
@ -968,7 +978,7 @@ TX.prototype.fillCoins = function fillCoins(coins) {
var result = true;
var i, input, hash, index, map, coin;
if ((coins instanceof bcoin.coin)
if ((coins instanceof Coin)
|| (coins instanceof TX)) {
coins = [coins];
}
@ -979,7 +989,7 @@ TX.prototype.fillCoins = function fillCoins(coins) {
coin = coins[i];
if (coin instanceof TX) {
map[coin.hash('hex')] = coin;
} else if (coin instanceof bcoin.coin) {
} else if (coin instanceof Coin) {
assert(typeof coin.hash === 'string');
assert(typeof coin.index === 'number');
map[coin.hash + coin.index] = coin;
@ -1001,7 +1011,7 @@ TX.prototype.fillCoins = function fillCoins(coins) {
coin = coins[hash];
if (coin) {
input.coin = bcoin.coin.fromTX(coin, index);
input.coin = Coin.fromTX(coin, index);
continue;
}
@ -1486,7 +1496,7 @@ TX.prototype.getWitnessStandard = function getWitnessStandard() {
ret = BAD_NONSTD_P2WSH;
}
redeem = new bcoin.script(redeem);
redeem = new Script(redeem);
if (redeem.isPubkey()) {
if (input.witness.length - 1 !== 1)
@ -1662,7 +1672,7 @@ TX.prototype.getPriority = function getPriority(height, size) {
if (height == null) {
height = this.height;
if (height === -1)
height = bcoin.network.get().height;
height = Network.primary.height;
}
if (size == null)
@ -1791,7 +1801,7 @@ TX.prototype.getRate = function getRate(size) {
TX.prototype.getConfirmations = function getConfirmations(height) {
if (height == null)
height = bcoin.network.get().height;
height = Network.primary.height;
if (this.height === -1)
return 0;
@ -1851,11 +1861,11 @@ TX.prototype.isWatched = function isWatched(filter) {
// Test the output script
if (output.script.test(filter)) {
if (filter.update === constants.filterFlags.ALL) {
outpoint = bcoin.outpoint.fromTX(this, i);
outpoint = Outpoint.fromTX(this, i);
filter.add(outpoint.toRaw());
} else if (filter.update === constants.filterFlags.PUBKEY_ONLY) {
if (output.script.isPubkey() || output.script.isMultisig()) {
outpoint = bcoin.outpoint.fromTX(this, i);
outpoint = Outpoint.fromTX(this, i);
filter.add(outpoint.toRaw());
}
}
@ -1917,7 +1927,7 @@ TX.prototype.__defineGetter__('wtxid', function() {
*/
TX.prototype.toInv = function toInv() {
return new bcoin.invitem(constants.inv.TX, this.hash('hex'));
return new InvItem(constants.inv.TX, this.hash('hex'));
};
/**
@ -2074,12 +2084,12 @@ TX.prototype.fromJSON = function fromJSON(json) {
for (i = 0; i < json.inputs.length; i++) {
input = json.inputs[i];
this.inputs.push(bcoin.input.fromJSON(input));
this.inputs.push(Input.fromJSON(input));
}
for (i = 0; i < json.outputs.length; i++) {
output = json.outputs[i];
this.outputs.push(bcoin.output.fromJSON(output));
this.outputs.push(Output.fromJSON(output));
}
this.locktime = json.locktime;
@ -2118,25 +2128,25 @@ TX.fromRaw = function fromRaw(data, enc) {
*/
TX.prototype.fromRaw = function fromRaw(data) {
var p, i, inCount, outCount;
var p, i, count;
if (TX.isWitness(data))
return this.fromWitness(data);
p = bcoin.reader(data);
p = BufferReader(data);
p.start();
this.version = p.readU32(); // Technically signed
inCount = p.readVarint();
count = p.readVarint();
for (i = 0; i < inCount; i++)
this.inputs.push(bcoin.input.fromRaw(p));
for (i = 0; i < count; i++)
this.inputs.push(Input.fromRaw(p));
outCount = p.readVarint();
count = p.readVarint();
for (i = 0; i < outCount; i++)
this.outputs.push(bcoin.output.fromRaw(p));
for (i = 0; i < count; i++)
this.outputs.push(Output.fromRaw(p));
this.locktime = p.readU32();
@ -2159,49 +2169,61 @@ TX.prototype.fromRaw = function fromRaw(data) {
*/
TX.prototype.fromWitness = function fromWitness(data) {
var p = bcoin.reader(data);
var i, marker, inCount, outCount, input, hasWitness, witnessSize;
var p = BufferReader(data);
var flag = 0;
var witnessSize = 0;
var hasWitness = false;
var i, count, input;
p.start();
this.version = p.readU32(); // Technically signed
marker = p.readU8();
this.flag = p.readU8();
assert(p.readU8() === 0, 'Non-zero marker.');
if (marker !== 0)
throw new Error('Invalid witness tx (marker != 0)');
flag = p.readU8();
if (this.flag === 0)
throw new Error('Invalid witness tx (flag == 0)');
assert(flag !== 0, 'Flag byte is zero.');
inCount = p.readVarint();
this.flag = flag;
for (i = 0; i < inCount; i++)
this.inputs.push(bcoin.input.fromRaw(p));
count = p.readVarint();
outCount = p.readVarint();
for (i = 0; i < count; i++)
this.inputs.push(Input.fromRaw(p));
for (i = 0; i < outCount; i++)
this.outputs.push(bcoin.output.fromRaw(p));
count = p.readVarint();
p.start();
for (i = 0; i < count; i++)
this.outputs.push(Output.fromRaw(p));
for (i = 0; i < inCount; i++) {
input = this.inputs[i];
input.witness.fromRaw(p);
if (input.witness.items.length > 0)
hasWitness = true;
if (flag & 1) {
flag ^= 1;
p.start();
for (i = 0; i < this.inputs.length; i++) {
input = this.inputs[i];
input.witness.fromRaw(p);
if (input.witness.items.length > 0)
hasWitness = true;
}
witnessSize = p.end() + 2;
}
if (!hasWitness)
throw new Error('Witness tx has an empty witness.');
if (flag !== 0)
throw new Error('Unknown witness flag.');
witnessSize = p.end() + 2;
// We'll never be able to reserialize
// this to get the regular txid, and
// there's no way it's valid anyway.
if (this.inputs.length === 0 && this.outputs.length !== 0)
throw new Error('Zero input witness tx.');
this.locktime = p.readU32();
if (!this.mutable) {
if (!this.mutable && hasWitness) {
this._raw = p.endData();
this._size = this._raw.length;
this._witnessSize = witnessSize;
@ -2212,27 +2234,6 @@ TX.prototype.fromWitness = function fromWitness(data) {
return this;
};
/**
* Test whether data is a witness transaction.
* @param {Buffer|BufferReader} data
* @returns {Boolean}
*/
TX.isWitness = function isWitness(data) {
if (Buffer.isBuffer(data)) {
if (data.length < 12)
return false;
return data[4] === 0 && data[5] !== 0;
}
if (data.left() < 12)
return false;
return data.data[data.offset + 4] === 0
&& data.data[data.offset + 5] !== 0;
};
/**
* Serialize transaction without witness.
* @private
@ -2241,13 +2242,13 @@ TX.isWitness = function isWitness(data) {
*/
TX.prototype.frameNormal = function frameNormal(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var i;
if (this.inputs.length === 0 && this.outputs.length === 1)
if (this.inputs.length === 0 && this.outputs.length !== 0)
throw new Error('Cannot serialize zero-input tx.');
p.write32(this.version);
p.writeU32(this.version);
p.writeVarint(this.inputs.length);
@ -2278,11 +2279,14 @@ TX.prototype.frameNormal = function frameNormal(writer) {
*/
TX.prototype.frameWitness = function frameWitness(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var witnessSize = 0;
var i, start;
p.write32(this.version);
if (this.inputs.length === 0 && this.outputs.length !== 0)
throw new Error('Cannot serialize zero-input tx.');
p.writeU32(this.version);
p.writeU8(0);
p.writeU8(this.flag);
@ -2316,6 +2320,27 @@ TX.prototype.frameWitness = function frameWitness(writer) {
return p;
};
/**
* Test whether data is a witness transaction.
* @param {Buffer|BufferReader} data
* @returns {Boolean}
*/
TX.isWitness = function isWitness(data) {
if (Buffer.isBuffer(data)) {
if (data.length < 6)
return false;
return data[4] === 0 && data[5] !== 0;
}
if (data.left() < 6)
return false;
return data.data[data.offset + 4] === 0
&& data.data[data.offset + 5] !== 0;
};
/**
* Serialize a transaction to BCoin "extended format".
* This is the serialization format BCoin uses internally
@ -2331,7 +2356,7 @@ TX.prototype.frameWitness = function frameWitness(writer) {
TX.prototype.toExtended = function toExtended(saveCoins, writer) {
var height = this.height;
var index = this.index;
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var i, input;
if (height === -1)
@ -2377,7 +2402,7 @@ TX.prototype.toExtended = function toExtended(saveCoins, writer) {
*/
TX.prototype.fromExtended = function fromExtended(data, saveCoins) {
var p = bcoin.reader(data);
var p = BufferReader(data);
var i, coinCount, coin;
this.fromRaw(p);
@ -2403,7 +2428,7 @@ TX.prototype.fromExtended = function fromExtended(data, saveCoins) {
coin = p.readVarBytes();
if (coin.length === 0)
continue;
coin = bcoin.coin.fromRaw(coin);
coin = Coin.fromRaw(coin);
coin.hash = this.inputs[i].prevout.hash;
coin.index = this.inputs[i].prevout.index;
this.inputs[i].coin = coin;

View file

@ -775,8 +775,9 @@ exports.flags = {
VERIFY_CHECKSEQUENCEVERIFY: (1 << 10),
VERIFY_WITNESS: (1 << 11),
VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM: (1 << 12),
VERIFY_MAST: (1 << 13),
VERIFY_MINIMALIF: (1 << 13),
VERIFY_NULLFAIL: (1 << 14),
VERIFY_MAST: (1 << 15), // should be 1 << 13
VERIFY_SEQUENCE: (1 << 0),
MEDIAN_TIME_PAST: (1 << 1)
};

5
lib/protocol/index.js Normal file
View file

@ -0,0 +1,5 @@
'use strict';
exports.constants = require('./constants');
exports.network = require('./network');
exports.networks = require('./networks');

View file

@ -7,8 +7,7 @@
'use strict';
var utils = require('../utils/utils');
var assert = utils.assert;
var assert = require('assert');
var networks = require('./networks');
/**
@ -16,10 +15,6 @@ var networks = require('./networks');
* @exports Network
* @constructor
* @param {Object|NetworkType} options - See {@link module:network}.
* @property {Number} height
* @property {Rate} feeRate
* @property {Rate} minRelay
* @property {PolicyEstimator} fees
*/
function Network(options) {
@ -51,8 +46,6 @@ function Network(options) {
this.rpcPort = options.rpcPort;
this.minRelay = options.minRelay;
this.feeRate = options.feeRate;
this.minRate = options.minRate;
this.maxRate = options.maxRate;
this.selfConnect = options.selfConnect;
this.requestMempool = options.requestMempool;
this.batchSize = options.batchSize;
@ -60,11 +53,18 @@ function Network(options) {
/**
* Default network.
* @type {String}
* @type {Network}
*/
Network.primary = null;
/**
* Default network type.
* @type {String}
*/
Network.type = null;
/*
* Networks (to avoid hash table mode).
*/
@ -85,50 +85,6 @@ Network.prototype.updateHeight = function updateHeight(height) {
this.height = height;
};
/**
* Update the estimated fee rate of the network.
* @param {Rate} rate
*/
Network.prototype.updateRate = function updateRate(rate) {
this.feeRate = rate;
};
/**
* Update the minimum relay rate (reject rate) of the network.
* @param {Rate} rate
*/
Network.prototype.updateMinRelay = function updateMinRelay(rate) {
this.minRelay = rate;
};
/**
* Calculate the minimum relay rate. If the network is
* inactive (height=-1), return the default minimum relay.
* @return {Rate} Rate
*/
Network.prototype.getMinRelay = function getMinRelay() {
if (this.height === -1)
return this.minRate;
return Math.min(this.minRelay, this.maxRate);
};
/**
* Calculate the normal relay rate. If the network is
* inactive (height=-1), return the default rate.
* @return {Rate} Rate
*/
Network.prototype.getRate = function getRate() {
if (this.height === -1)
return this.maxRate;
return Math.min(this.feeRate, this.maxRate);
};
/**
* Determine how many blocks to request
* based on current height of the chain.
@ -187,6 +143,7 @@ Network.create = function create(options) {
Network.set = function set(type) {
assert(typeof type === 'string', 'Bad network.');
Network.primary = Network.get(type);
Network.type = type;
return Network.primary;
};
@ -261,6 +218,12 @@ Network.isNetwork = function isNetwork(obj) {
&& typeof obj.pow === 'object';
};
/*
* Set initial network.
*/
Network.set(process.env.BCOIN_NETWORK || 'main');
/*
* Expose
*/

View file

@ -399,7 +399,7 @@ main.requireStandard = true;
main.rpcPort = 8332;
/**
* Default min relay rate (the rate for mempoolRejectFee).
* Default min relay rate.
* @const {Rate}
* @default
*/
@ -414,22 +414,6 @@ main.minRelay = 10000;
main.feeRate = 50000;
/**
* Default min rate.
* @const {Rate}
* @default
*/
main.minRate = 10000;
/**
* Default max rate.
* @const {Rate}
* @default
*/
main.maxRate = 50000;
/**
* Whether to allow self-connection.
* @const {Boolean}
@ -597,10 +581,6 @@ testnet.minRelay = 10000;
testnet.feeRate = 20000;
testnet.minRate = 10000;
testnet.maxRate = 40000;
testnet.selfConnect = false;
testnet.requestMempool = false;
@ -743,10 +723,6 @@ regtest.minRelay = 10000;
regtest.feeRate = 20000;
regtest.minRate = 10000;
regtest.maxRate = 40000;
regtest.selfConnect = true;
regtest.requestMempool = true;
@ -863,10 +839,6 @@ segnet3.minRelay = 10000;
segnet3.feeRate = 20000;
segnet3.minRate = 10000;
segnet3.maxRate = 40000;
segnet3.selfConnect = false;
segnet3.requestMempool = true;
@ -1002,10 +974,6 @@ segnet4.minRelay = 10000;
segnet4.feeRate = 20000;
segnet4.minRate = 10000;
segnet4.maxRate = 40000;
segnet4.selfConnect = false;
segnet4.requestMempool = true;
@ -1149,10 +1117,6 @@ simnet.minRelay = 10000;
simnet.feeRate = 20000;
simnet.minRate = 10000;
simnet.maxRate = 40000;
simnet.selfConnect = true;
simnet.requestMempool = false;

8
lib/script/index.js Normal file
View file

@ -0,0 +1,8 @@
'use strict';
exports.Opcode = require('./opcode');
exports.Program = require('./program');
exports.Script = require('./script');
exports.SigCache = require('./sigcache');
exports.Stack = require('./stack');
exports.Witness = require('./witness');

View file

@ -7,11 +7,13 @@
'use strict';
var bcoin = require('../env');
module.exports = Opcode;
var bn = require('bn.js');
var constants = bcoin.constants;
var constants = require('../protocol/constants');
var utils = require('../utils/utils');
var assert = utils.assert;
var Script = require('./script');
var assert = require('assert');
var opcodes = constants.opcodes;
/**
@ -39,7 +41,7 @@ function Opcode(value, data) {
*/
Opcode.prototype.toRaw = function toRaw(writer) {
return bcoin.script.encode([this], writer);
return Script.encode([this], writer);
};
/**
@ -105,7 +107,7 @@ Opcode.fromPush = function fromPush(data) {
*/
Opcode.fromNumber = function fromNumber(num) {
return Opcode.fromData(bcoin.script.array(num));
return Opcode.fromData(Script.array(num));
};
/**

View file

@ -7,10 +7,11 @@
'use strict';
var bcoin = require('../env');
var constants = bcoin.constants;
module.exports = Program;
var constants = require('../protocol/constants');
var utils = require('../utils/utils');
var assert = utils.assert;
var assert = require('assert');
var scriptTypes = constants.scriptTypes;
/**

File diff suppressed because it is too large Load diff

View file

@ -6,9 +6,9 @@
'use strict';
var bcoin = require('../env');
var utils = bcoin.utils;
var assert = utils.assert;
var utils = require('../utils/utils');
var ec = require('../crypto/ec');
var assert = require('assert');
/**
* Signature cache.
@ -106,14 +106,14 @@ SigCache.prototype.verify = function verify(msg, sig, key, historical, high) {
var hash, result;
if (historical || this.size === 0)
return bcoin.ec.verify(msg, sig, key, historical, high);
return ec.verify(msg, sig, key, historical, high);
hash = msg.toString('hex');
if (this.has(hash, sig, key))
return true;
result = bcoin.ec.verify(msg, sig, key, historical, high);
result = ec.verify(msg, sig, key, historical, high);
if (!result)
return false;
@ -152,4 +152,4 @@ SigCacheEntry.prototype.equal = function equal(sig, key) {
* Expose
*/
module.exports = SigCache;
module.exports = new SigCache(+process.env.BCOIN_SIGCACHE_SIZE || 0);

View file

@ -7,10 +7,10 @@
'use strict';
var bcoin = require('../env');
var constants = bcoin.constants;
var opcodes = constants.opcodes;
var ScriptError = bcoin.errors.ScriptError;
module.exports = Stack;
var Script = require('./script');
var Witness = require('./witness');
/**
* Represents the stack of a Script during execution.
@ -51,7 +51,7 @@ Stack.prototype.inspect = function inspect() {
*/
Stack.prototype.toString = function toString() {
return bcoin.witness.format(this.items);
return Witness.format(this.items);
};
/**
@ -61,7 +61,7 @@ Stack.prototype.toString = function toString() {
*/
Stack.prototype.toASM = function toASM(decode) {
return bcoin.script.formatASM(this.items, decode);
return Script.formatASM(this.items, decode);
};
/**
@ -73,7 +73,7 @@ Stack.prototype.getRedeem = function getRedeem() {
var redeem = this.items[this.items.length - 1];
if (!redeem)
return;
return new bcoin.script(redeem);
return new Script(redeem);
};
/**
@ -85,16 +85,6 @@ Stack.prototype.clone = function clone() {
return new Stack(this.items.slice());
};
/**
* Get total size of the stack, including the alt stack.
* @param {Array} alt - Alt stack.
* @returns {Number}
*/
Stack.prototype.getSize = function getSize(alt) {
return this.items.length + alt.length;
};
/**
* Push item onto stack.
* @see Array#push
@ -122,11 +112,12 @@ Stack.prototype.unshift = function unshift(item) {
* @param {Number} start
* @param {Number} end
* @see Array#slice
* @returns {Buffer[]}
* @returns {Stack}
*/
Stack.prototype.slice = function slice(start, end) {
return this.items.slice(start, end);
this.items = this.items.slice(start, end);
return this;
};
/**
@ -139,11 +130,62 @@ Stack.prototype.slice = function slice(start, end) {
*/
Stack.prototype.splice = function splice(i, remove, insert) {
if (i < 0)
i = this.items.length + i;
if (insert === undefined)
return this.items.splice(i, remove);
return this.items.splice(i, remove, insert);
};
/**
* Erase stack items.
* @param {Number} start
* @param {Number} end
* @returns {Buffer[]}
*/
Stack.prototype.erase = function erase(start, end) {
if (start < 0)
start = this.items.length + start;
if (end < 0)
end = this.items.length + end;
this.items.splice(start, end - start);
};
/**
* Insert an item.
* @param {Number} index
* @param {Buffer} item
* @returns {Buffer}
*/
Stack.prototype.insert = function insert(i, item) {
if (i < 0)
i = this.items.length + i;
this.items.splice(i, 0, item);
};
/**
* Remove an item.
* @param {Number} index
* @returns {Buffer}
*/
Stack.prototype.remove = function remove(i) {
if (i < 0)
i = this.items.length + i;
if (i >= this.items.length)
return;
return this.items.splice(i, 1)[0];
};
/**
* Pop a stack item.
* @see Array#pop
@ -203,21 +245,26 @@ Stack.prototype.clear = function clear() {
*/
Stack.prototype.set = function set(i, value) {
if (i < 0)
i = this.items.length + i;
return this.items[i] = value;
};
/**
* Swap stack values.
* @private
* @param {Number} i1 - Index 1.
* @param {Number} i2 - Index 2.
*/
Stack.prototype._swap = function _swap(i1, i2) {
Stack.prototype.swap = function swap(i1, i2) {
var v1, v2;
i1 = this.items.length + i1;
i2 = this.items.length + i2;
if (i1 < 0)
i1 = this.items.length + i1;
if (i2 < 0)
i2 = this.items.length + i2;
v1 = this.items[i1];
v2 = this.items[i2];
@ -226,300 +273,6 @@ Stack.prototype._swap = function _swap(i1, i2) {
this.items[i2] = v1;
};
/**
* Perform the OP_TOALTSTACK operation.
* @param {Array} alt - Alt stack.
* @throws {ScriptError}
*/
Stack.prototype.toalt = function toalt(alt) {
if (this.length === 0)
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_TOALTSTACK);
alt.push(this.pop());
};
/**
* Perform the OP_FROMALTSTACK operation.
* @param {Array} alt - Alt stack.
* @throws {ScriptError}
*/
Stack.prototype.fromalt = function fromalt(alt) {
if (alt.length === 0)
throw new ScriptError('INVALID_ALTSTACK_OPERATION', opcodes.OP_FROMALTSTACK);
this.push(alt.pop());
};
/**
* Perform the OP_IFDUP operation.
* @throws {ScriptError}
*/
Stack.prototype.ifdup = function ifdup() {
if (this.length === 0)
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_IFDUP);
if (bcoin.script.bool(this.top(-1)))
this.push(this.top(-1));
};
/**
* Perform the OP_DEPTH operation.
* @throws {ScriptError}
*/
Stack.prototype.depth = function depth() {
this.push(bcoin.script.array(this.length));
};
/**
* Perform the OP_DROP operation.
* @throws {ScriptError}
*/
Stack.prototype.drop = function drop() {
if (this.length === 0)
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_DROP);
this.pop();
};
/**
* Perform the OP_DUP operation.
* @throws {ScriptError}
*/
Stack.prototype.dup = function dup() {
if (this.length === 0)
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_DUP);
this.push(this.top(-1));
};
/**
* Perform the OP_NIP operation.
* @throws {ScriptError}
*/
Stack.prototype.nip = function nip() {
if (this.length < 2)
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_NIP);
this.splice(this.length - 2, 1);
};
/**
* Perform the OP_OVER operation.
* @throws {ScriptError}
*/
Stack.prototype.over = function over() {
if (this.length < 2)
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_OVER);
this.push(this.top(-2));
};
/**
* Perform the OP_PICK operation.
* @param {VerifyFlags} flags
* @throws {ScriptError}
*/
Stack.prototype.pick = function pick(flags) {
return this._pickroll(opcodes.OP_PICK, flags);
};
/**
* Perform the OP_ROLL operation.
* @param {VerifyFlags} flags
* @throws {ScriptError}
*/
Stack.prototype.roll = function roll(flags) {
return this._pickroll(opcodes.OP_ROLL, flags);
};
/**
* Perform a pick or roll.
* @private
* @param {Number} op
* @param {VerifyFlags} flags
* @throws {ScriptError}
*/
Stack.prototype._pickroll = function pickroll(op, flags) {
var val, n;
if (this.length < 2)
throw new ScriptError('INVALID_STACK_OPERATION', op);
val = this.pop();
n = bcoin.script.num(val, flags).toNumber();
if (n < 0 || n >= this.length)
throw new ScriptError('INVALID_STACK_OPERATION', op);
val = this.top(-n - 1);
if (op === opcodes.OP_ROLL)
this.splice(this.length - n - 1, 1);
this.push(val);
};
/**
* Perform the OP_ROT operation.
* @throws {ScriptError}
*/
Stack.prototype.rot = function rot() {
if (this.length < 3)
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_ROT);
this._swap(-3, -2);
this._swap(-2, -1);
};
/**
* Perform the OP_SWAP operation.
* @throws {ScriptError}
*/
Stack.prototype.swap = function swap() {
if (this.length < 2)
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_SWAP);
this._swap(-2, -1);
};
/**
* Perform the OP_TUCK operation.
* @throws {ScriptError}
*/
Stack.prototype.tuck = function tuck() {
if (this.length < 2)
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_TUCK);
this.splice(this.length - 2, 0, this.top(-1));
};
/**
* Perform the OP_2DROP operation.
* @throws {ScriptError}
*/
Stack.prototype.drop2 = function drop2() {
if (this.length < 2)
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_2DROP);
this.pop();
this.pop();
};
/**
* Perform the OP_2DUP operation.
* @throws {ScriptError}
*/
Stack.prototype.dup2 = function dup2() {
var v1, v2;
if (this.length < 2)
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_2DUP);
v1 = this.top(-2);
v2 = this.top(-1);
this.push(v1);
this.push(v2);
};
/**
* Perform the OP_3DUP operation.
* @throws {ScriptError}
*/
Stack.prototype.dup3 = function dup3() {
var v1, v2, v3;
if (this.length < 3)
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_3DUP);
v1 = this.top(-3);
v2 = this.top(-2);
v3 = this.top(-1);
this.push(v1);
this.push(v2);
this.push(v3);
};
/**
* Perform the OP_2OVER operation.
* @throws {ScriptError}
*/
Stack.prototype.over2 = function over2() {
var v1, v2;
if (this.length < 4)
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_2OVER);
v1 = this.top(-4);
v2 = this.top(-3);
this.push(v1);
this.push(v2);
};
/**
* Perform the OP_2ROT operation.
* @throws {ScriptError}
*/
Stack.prototype.rot2 = function rot2() {
var v1, v2;
if (this.length < 6)
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_2ROT);
v1 = this.top(-6);
v2 = this.top(-5);
this.splice(this.length - 6, 2);
this.push(v1);
this.push(v2);
};
/**
* Perform the OP_2SWAP operation.
* @throws {ScriptError}
*/
Stack.prototype.swap2 = function swap2() {
if (this.length < 4)
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_2SWAP);
this._swap(-4, -2);
this._swap(-3, -1);
};
/**
* Perform the OP_SIZE operation.
* @throws {ScriptError}
*/
Stack.prototype.size = function size() {
if (this.length < 1)
throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_SIZE);
this.push(bcoin.script.array(this.top(-1).length));
};
/**
* Test an object to see if it is a Stack.
* @param {Object} obj
@ -527,7 +280,7 @@ Stack.prototype.size = function size() {
*/
Stack.isStack = function isStack(obj) {
return obj && Array.isArray(obj.items) && typeof obj.swap2 === 'function';
return obj && Array.isArray(obj.items) && typeof obj.swap === 'function';
};
/*

View file

@ -7,17 +7,22 @@
'use strict';
var bcoin = require('../env');
module.exports = Witness;
var bn = require('bn.js');
var constants = bcoin.constants;
var constants = require('../protocol/constants');
var utils = require('../utils/utils');
var assert = utils.assert;
var assert = require('assert');
var opcodes = constants.opcodes;
var STACK_FALSE = new Buffer([]);
var STACK_FALSE = new Buffer(0);
var STACK_NEGATE = new Buffer([0x81]);
var scriptTypes = constants.scriptTypes;
var Script = require('./script');
var Opcode = require('./opcode');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
var Address = require('../primitives/address');
var Stack = require('./stack');
/**
* Refers to the witness field of segregated witness transactions.
@ -159,7 +164,7 @@ Witness.prototype.clone = function clone() {
*/
Witness.prototype.toStack = function toStack() {
return new bcoin.stack(this.items.slice());
return new Stack(this.items.slice());
};
/**
@ -185,7 +190,7 @@ Witness.prototype.getInputType = function getInputType() {
*/
Witness.prototype.getInputAddress = function getInputAddress() {
return bcoin.address.fromWitness(this);
return Address.fromWitness(this);
};
/**
@ -301,7 +306,7 @@ Witness.prototype.indexOf = function indexOf(data) {
*/
Witness.prototype.toRaw = function toRaw(writer) {
var p = bcoin.writer(writer);
var p = BufferWriter(writer);
var i;
p.writeVarint(this.items.length);
@ -515,7 +520,7 @@ Witness.encodeItem = function encodeItem(data) {
*/
Witness.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
var p = BufferReader(data);
var chunkCount = p.readVarint();
var i;

Some files were not shown because too many files have changed in this diff Show more