refactor: use const as much as possible.
This commit is contained in:
parent
9cc5c393b4
commit
6f3988e861
@ -3,24 +3,25 @@
|
||||
const Address = require('../lib/primitives/address');
|
||||
const random = require('../lib/crypto/random');
|
||||
const bench = require('./bench');
|
||||
|
||||
let i, end, addr;
|
||||
|
||||
const addrs = [];
|
||||
|
||||
end = bench('serialize');
|
||||
for (i = 0; i < 100000; i++) {
|
||||
addr = Address.fromProgram(0, random.randomBytes(20));
|
||||
addrs.push(addr.toBech32());
|
||||
{
|
||||
const end = bench('serialize');
|
||||
for (let i = 0; i < 100000; i++) {
|
||||
const addr = Address.fromProgram(0, random.randomBytes(20));
|
||||
addrs.push(addr.toBech32());
|
||||
}
|
||||
end(100000);
|
||||
}
|
||||
end(i);
|
||||
|
||||
end = bench('parse');
|
||||
for (i = 0; i < 100000; i++) {
|
||||
addr = addrs[i];
|
||||
addr = Address.fromBech32(addr);
|
||||
addrs[i] = addr;
|
||||
{
|
||||
const end = bench('parse');
|
||||
for (let i = 0; i < 100000; i++) {
|
||||
const b32 = addrs[i];
|
||||
const addr = Address.fromBech32(b32);
|
||||
addrs[i] = addr;
|
||||
}
|
||||
end(100000);
|
||||
}
|
||||
end(i);
|
||||
|
||||
console.error(addrs);
|
||||
console.error(addrs[0][0]);
|
||||
|
||||
@ -6,26 +6,27 @@ const BufferWriter = require('../lib/utils/writer');
|
||||
const StaticWriter = require('../lib/utils/staticwriter');
|
||||
const bench = require('./bench');
|
||||
|
||||
let wtx = fs.readFileSync(`${__dirname}/../test/data/wtx.hex`, 'utf8');
|
||||
let i, tx, end;
|
||||
const hex = fs.readFileSync(`${__dirname}/../test/data/wtx.hex`, 'utf8');
|
||||
const raw = Buffer.from(hex.trim(), 'hex');
|
||||
const tx = TX.fromRaw(raw);
|
||||
|
||||
wtx = Buffer.from(wtx.trim(), 'hex');
|
||||
tx = TX.fromRaw(wtx);
|
||||
|
||||
end = bench('serialize (static-writer)');
|
||||
for (i = 0; i < 10000; i++) {
|
||||
tx._raw = null;
|
||||
tx._size = -1;
|
||||
tx._witness = -1;
|
||||
tx.writeWitness(new StaticWriter(tx.getWitnessSizes().total)).render();
|
||||
{
|
||||
const end = bench('serialize (static-writer)');
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
tx.refresh();
|
||||
const {size} = tx.getWitnessSizes();
|
||||
const bw = new StaticWriter(size);
|
||||
tx.toWitnessWriter(bw).render();
|
||||
}
|
||||
end(10000);
|
||||
}
|
||||
end(i);
|
||||
|
||||
end = bench('serialize (buffer-writer)');
|
||||
for (i = 0; i < 10000; i++) {
|
||||
tx._raw = null;
|
||||
tx._size = -1;
|
||||
tx._witness = -1;
|
||||
tx.writeWitness(new BufferWriter()).render();
|
||||
{
|
||||
const end = bench('serialize (buffer-writer)');
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
tx.refresh();
|
||||
const bw = new BufferWriter();
|
||||
tx.toWitnessWriter(bw).render();
|
||||
}
|
||||
end(10000);
|
||||
}
|
||||
end(i);
|
||||
|
||||
@ -4,47 +4,53 @@ const ChaCha20 = require('../lib/crypto/chacha20');
|
||||
const Poly1305 = require('../lib/crypto/poly1305');
|
||||
const digest = require('../lib/crypto/digest');
|
||||
const bench = require('./bench');
|
||||
let i, chacha, iv, poly, key, data, end;
|
||||
|
||||
console.log('note: rate measured in kb/s');
|
||||
|
||||
chacha = new ChaCha20();
|
||||
key = Buffer.allocUnsafe(32);
|
||||
key.fill(2);
|
||||
iv = Buffer.from('0102030405060708', 'hex');
|
||||
chacha.init(key, iv, 0);
|
||||
data = Buffer.allocUnsafe(32);
|
||||
for (i = 0; i < 32; i++)
|
||||
data[i] = i;
|
||||
end = bench('encrypt');
|
||||
for (i = 0; i < 1000000; i++)
|
||||
chacha.encrypt(data);
|
||||
end(i * 32 / 1024);
|
||||
const chacha = new ChaCha20();
|
||||
const poly = new Poly1305();
|
||||
const key = Buffer.alloc(32, 0x02);
|
||||
const iv = Buffer.from('0102030405060708', 'hex');
|
||||
const chunk = Buffer.allocUnsafe(32);
|
||||
const data = Buffer.allocUnsafe(32);
|
||||
|
||||
poly = new Poly1305();
|
||||
key = Buffer.allocUnsafe(32);
|
||||
key.fill(2);
|
||||
poly.init(key);
|
||||
for (let i = 0; i < 32; i++)
|
||||
chunk[i] = i;
|
||||
|
||||
data = Buffer.allocUnsafe(32);
|
||||
for (i = 0; i < 32; i++)
|
||||
for (let i = 0; i < 32; i++)
|
||||
data[i] = i & 0xff;
|
||||
|
||||
end = bench('update');
|
||||
for (i = 0; i < 1000000; i++)
|
||||
poly.update(data);
|
||||
end(i * 32 / 1024);
|
||||
chacha.init(key, iv, 0);
|
||||
poly.init(key);
|
||||
|
||||
end = bench('finish');
|
||||
for (i = 0; i < 1000000; i++) {
|
||||
poly.init(key);
|
||||
poly.update(data);
|
||||
poly.finish();
|
||||
{
|
||||
const end = bench('encrypt');
|
||||
for (let i = 0; i < 1000000; i++)
|
||||
chacha.encrypt(chunk);
|
||||
end(1000000 * 32 / 1024);
|
||||
}
|
||||
|
||||
{
|
||||
const end = bench('update');
|
||||
for (let i = 0; i < 1000000; i++)
|
||||
poly.update(data);
|
||||
end(1000000 * 32 / 1024);
|
||||
}
|
||||
|
||||
{
|
||||
const end = bench('finish');
|
||||
for (let i = 0; i < 1000000; i++) {
|
||||
poly.init(key);
|
||||
poly.update(data);
|
||||
poly.finish();
|
||||
}
|
||||
end(1000000 * 32 / 1024);
|
||||
}
|
||||
end(i * 32 / 1024);
|
||||
|
||||
// For reference:
|
||||
end = bench('sha256');
|
||||
for (i = 0; i < 1000000; i++)
|
||||
digest.hash256(data);
|
||||
end(i * 32 / 1024);
|
||||
{
|
||||
const end = bench('sha256');
|
||||
for (let i = 0; i < 1000000; i++)
|
||||
digest.hash256(data);
|
||||
end(1000000 * 32 / 1024);
|
||||
}
|
||||
|
||||
@ -1,39 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const bench = require('./bench');
|
||||
const Coins = require('../migrate/coins-old');
|
||||
const TX = require('../lib/primitives/tx');
|
||||
|
||||
let wtx = fs.readFileSync(`${__dirname}/../test/data/wtx.hex`, 'utf8');
|
||||
wtx = TX.fromRaw(wtx.trim(), 'hex');
|
||||
|
||||
let coins = Coins.fromTX(wtx);
|
||||
let i, j, end, raw, hash;
|
||||
|
||||
//raw = coins.toRaw();
|
||||
//console.log(Coins.fromRaw(raw));
|
||||
|
||||
end = bench('serialize');
|
||||
for (i = 0; i < 10000; i++)
|
||||
raw = coins.toRaw();
|
||||
end(i);
|
||||
|
||||
end = bench('parse');
|
||||
for (i = 0; i < 10000; i++)
|
||||
Coins.fromRaw(raw);
|
||||
end(i);
|
||||
|
||||
end = bench('parse-single');
|
||||
hash = wtx.hash('hex');
|
||||
for (i = 0; i < 10000; i++)
|
||||
Coins.parseCoin(raw, hash, 5);
|
||||
end(i);
|
||||
|
||||
coins = Coins.fromRaw(raw);
|
||||
end = bench('get');
|
||||
|
||||
for (i = 0; i < 10000; i++)
|
||||
for (j = 0; j < coins.outputs.length; j++)
|
||||
coins.get(j);
|
||||
end(i * coins.outputs.length);
|
||||
@ -5,31 +5,32 @@ const Coins = require('../lib/coins/coins');
|
||||
const TX = require('../lib/primitives/tx');
|
||||
const bench = require('./bench');
|
||||
|
||||
let raw = fs.readFileSync(`${__dirname}/../test/data/wtx.hex`, 'utf8');
|
||||
const wtx = TX.fromRaw(raw.trim(), 'hex');
|
||||
let coins = Coins.fromTX(wtx, 1);
|
||||
let i, j, end, hash;
|
||||
const hex = fs.readFileSync(`${__dirname}/../test/data/wtx.hex`, 'utf8');
|
||||
const wtx = TX.fromRaw(hex.trim(), 'hex');
|
||||
const coins = Coins.fromTX(wtx, 1);
|
||||
const raw = coins.toRaw();
|
||||
|
||||
end = bench('serialize');
|
||||
for (i = 0; i < 10000; i++)
|
||||
raw = coins.toRaw();
|
||||
end(i);
|
||||
|
||||
end = bench('parse');
|
||||
for (i = 0; i < 10000; i++)
|
||||
Coins.fromRaw(raw);
|
||||
end(i);
|
||||
|
||||
end = bench('parse-single');
|
||||
hash = wtx.hash('hex');
|
||||
for (i = 0; i < 10000; i++)
|
||||
Coins.parseCoin(raw, hash, 5);
|
||||
end(i);
|
||||
|
||||
coins = Coins.fromRaw(raw);
|
||||
end = bench('get');
|
||||
for (i = 0; i < 10000; i++) {
|
||||
for (j = 0; j < coins.outputs.length; j++)
|
||||
coins.get(j);
|
||||
{
|
||||
const end = bench('serialize');
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
coins.toRaw();
|
||||
}
|
||||
end(10000);
|
||||
}
|
||||
|
||||
{
|
||||
const end = bench('parse');
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
Coins.fromRaw(raw);
|
||||
}
|
||||
end(10000);
|
||||
}
|
||||
|
||||
{
|
||||
const end = bench('get');
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
for (let j = 0; j < coins.outputs.length; j++)
|
||||
coins.get(j);
|
||||
}
|
||||
end(10000 * coins.outputs.length);
|
||||
}
|
||||
end(i * coins.outputs.length);
|
||||
|
||||
@ -12,11 +12,10 @@ for (let i = 0; i < 3000; i++)
|
||||
|
||||
{
|
||||
const end = bench('tree');
|
||||
let i;
|
||||
for (i = 0; i < 1000; i++) {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
const [n, m] = merkle.createTree(leaves.slice());
|
||||
assert(n);
|
||||
assert(!m);
|
||||
}
|
||||
end(i);
|
||||
end(1000);
|
||||
}
|
||||
|
||||
@ -9,11 +9,12 @@ const mnemonic = new Mnemonic();
|
||||
HD.fromMnemonic(mnemonic);
|
||||
|
||||
const phrase = mnemonic.getPhrase();
|
||||
let i, end;
|
||||
|
||||
assert.equal(Mnemonic.fromPhrase(phrase).getPhrase(), phrase);
|
||||
|
||||
end = bench('fromPhrase');
|
||||
for (i = 0; i < 10000; i++)
|
||||
Mnemonic.fromPhrase(phrase);
|
||||
end(i);
|
||||
{
|
||||
const end = bench('fromPhrase');
|
||||
for (let i = 0; i < 10000; i++)
|
||||
Mnemonic.fromPhrase(phrase);
|
||||
end(10000);
|
||||
}
|
||||
|
||||
@ -1,37 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
const random = require('../lib/crypto/random');
|
||||
const Script = require('../lib/script/script');
|
||||
const bench = require('./bench');
|
||||
const opcodes = Script.opcodes;
|
||||
let i, hashes, end;
|
||||
|
||||
Script.prototype.fromPubkeyhashOld = function fromScripthash(hash) {
|
||||
assert(Buffer.isBuffer(hash) && hash.length === 20);
|
||||
this.push(opcodes.OP_DUP);
|
||||
this.push(opcodes.OP_HASH160);
|
||||
this.push(hash);
|
||||
this.push(opcodes.OP_EQUALVERIFY);
|
||||
this.push(opcodes.OP_CHECKSIG);
|
||||
this.compile();
|
||||
return this;
|
||||
};
|
||||
const hashes = [];
|
||||
|
||||
Script.fromPubkeyhashOld = function fromScripthash(hash) {
|
||||
return new Script().fromPubkeyhashOld(hash);
|
||||
};
|
||||
|
||||
hashes = [];
|
||||
for (i = 0; i < 100000; i++)
|
||||
for (let i = 0; i < 100000; i++)
|
||||
hashes.push(random.randomBytes(20));
|
||||
|
||||
end = bench('old');
|
||||
for (i = 0; i < hashes.length; i++)
|
||||
Script.fromPubkeyhashOld(hashes[i]);
|
||||
end(i);
|
||||
|
||||
end = bench('hash');
|
||||
for (i = 0; i < hashes.length; i++)
|
||||
Script.fromPubkeyhash(hashes[i]);
|
||||
end(i);
|
||||
{
|
||||
const end = bench('hash');
|
||||
for (let i = 0; i < hashes.length; i++)
|
||||
Script.fromPubkeyhash(hashes[i]);
|
||||
end(100000);
|
||||
}
|
||||
|
||||
195
bench/tx.js
195
bench/tx.js
@ -17,106 +17,127 @@ const block = Block.fromJSON(json);
|
||||
const btx = { tx: block.txs[397], view: new CoinView() };
|
||||
|
||||
const tx3 = parseTX('../test/data/tx3.hex');
|
||||
let wtx = fs.readFileSync(`${__dirname}/../test/data/wtx.hex`, 'utf8');
|
||||
let i, tx, end, flags, input;
|
||||
const hex = fs.readFileSync(`${__dirname}/../test/data/wtx.hex`, 'utf8');
|
||||
const raw = Buffer.from(hex.trim(), 'hex');
|
||||
|
||||
wtx = Buffer.from(wtx.trim(), 'hex');
|
||||
|
||||
tx = json.txs[397];
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
btx.view.addCoin(Coin.fromJSON(input.coin));
|
||||
{
|
||||
const tx = json.txs[397];
|
||||
for (const input of tx.inputs)
|
||||
btx.view.addCoin(Coin.fromJSON(input.coin));
|
||||
}
|
||||
|
||||
function parseTX(file) {
|
||||
const data = fs.readFileSync(`${__dirname}/${file}`, 'utf8');
|
||||
const parts = data.trim().split(/\n+/);
|
||||
let raw = parts[0];
|
||||
const raw = parts[0];
|
||||
const tx = TX.fromRaw(raw.trim(), 'hex');
|
||||
const view = new CoinView();
|
||||
let i, prev;
|
||||
|
||||
for (i = 1; i < parts.length; i++) {
|
||||
raw = parts[i];
|
||||
prev = TX.fromRaw(raw.trim(), 'hex');
|
||||
for (let i = 1; i < parts.length; i++) {
|
||||
const raw = parts[i];
|
||||
const prev = TX.fromRaw(raw.trim(), 'hex');
|
||||
view.addTX(prev, -1);
|
||||
}
|
||||
|
||||
return { tx: tx, view: view };
|
||||
}
|
||||
|
||||
end = bench('parse');
|
||||
for (i = 0; i < 1000; i++)
|
||||
tx = TX.fromRaw(wtx);
|
||||
end(i);
|
||||
|
||||
end = bench('serialize');
|
||||
for (i = 0; i < 1000; i++) {
|
||||
tx._raw = null;
|
||||
tx.toRaw();
|
||||
{
|
||||
const end = bench('parse');
|
||||
for (let i = 0; i < 1000; i++)
|
||||
TX.fromRaw(raw);
|
||||
end(1000);
|
||||
}
|
||||
end(i);
|
||||
|
||||
end = bench('hash');
|
||||
for (i = 0; i < 3000; i++) {
|
||||
tx3.tx.hash();
|
||||
tx3.tx._hash = null;
|
||||
{
|
||||
const end = bench('serialize');
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
tx._raw = null;
|
||||
tx.toRaw();
|
||||
}
|
||||
end(1000);
|
||||
}
|
||||
end(i);
|
||||
|
||||
end = bench('witness hash');
|
||||
for (i = 0; i < 3000; i++) {
|
||||
tx.witnessHash();
|
||||
tx._whash = null;
|
||||
{
|
||||
const end = bench('hash');
|
||||
for (let i = 0; i < 3000; i++) {
|
||||
tx3.tx.hash();
|
||||
tx3.tx._hash = null;
|
||||
}
|
||||
end(3000);
|
||||
}
|
||||
end(i);
|
||||
|
||||
end = bench('sanity');
|
||||
for (i = 0; i < 1000; i++)
|
||||
tx.isSane();
|
||||
end(i);
|
||||
{
|
||||
const end = bench('witness hash');
|
||||
for (let i = 0; i < 3000; i++) {
|
||||
tx.witnessHash();
|
||||
tx._whash = null;
|
||||
}
|
||||
end(3000);
|
||||
}
|
||||
|
||||
end = bench('input hashes');
|
||||
for (i = 0; i < 1000; i++)
|
||||
tx.getInputHashes(null, 'hex');
|
||||
end(i);
|
||||
{
|
||||
const end = bench('sanity');
|
||||
for (let i = 0; i < 1000; i++)
|
||||
tx.isSane();
|
||||
end(1000);
|
||||
}
|
||||
|
||||
end = bench('output hashes');
|
||||
for (i = 0; i < 1000; i++)
|
||||
tx.getOutputHashes('hex');
|
||||
end(i);
|
||||
{
|
||||
const end = bench('input hashes');
|
||||
for (let i = 0; i < 1000; i++)
|
||||
tx.getInputHashes(null, 'hex');
|
||||
end(1000);
|
||||
}
|
||||
|
||||
end = bench('all hashes');
|
||||
for (i = 0; i < 1000; i++)
|
||||
tx.getHashes(null, 'hex');
|
||||
end(i);
|
||||
{
|
||||
const end = bench('output hashes');
|
||||
for (let i = 0; i < 1000; i++)
|
||||
tx.getOutputHashes('hex');
|
||||
end(1000);
|
||||
}
|
||||
|
||||
end = bench('verify');
|
||||
for (i = 0; i < 3000; i++)
|
||||
tx3.tx.verify(tx3.view, Script.flags.VERIFY_P2SH);
|
||||
end(i * tx3.tx.inputs.length);
|
||||
{
|
||||
const end = bench('all hashes');
|
||||
for (let i = 0; i < 1000; i++)
|
||||
tx.getHashes(null, 'hex');
|
||||
end(1000);
|
||||
}
|
||||
|
||||
end = bench('verify2');
|
||||
const script = tx3.view.getOutputFor(tx3.tx.inputs[0]).script;
|
||||
for (i = 0; i < 100000; i++)
|
||||
tx3.tx.signatureHashV0(0, script, Script.hashType.ALL);
|
||||
end(i);
|
||||
{
|
||||
const end = bench('verify');
|
||||
for (let i = 0; i < 3000; i++)
|
||||
tx3.tx.verify(tx3.view, Script.flags.VERIFY_P2SH);
|
||||
end(3000 * tx3.tx.inputs.length);
|
||||
}
|
||||
|
||||
end = bench('fee');
|
||||
for (i = 0; i < 1000; i++)
|
||||
tx3.tx.getFee(tx3.view);
|
||||
end(i);
|
||||
{
|
||||
const end = bench('verify2');
|
||||
const script = tx3.view.getOutputFor(tx3.tx.inputs[0]).script;
|
||||
for (let i = 0; i < 100000; i++)
|
||||
tx3.tx.signatureHashV0(0, script, Script.hashType.ALL);
|
||||
end(100000);
|
||||
}
|
||||
|
||||
flags = Script.flags.VERIFY_P2SH | Script.flags.VERIFY_DERSIG;
|
||||
end = bench('verify multisig');
|
||||
for (i = 0; i < 3000; i++)
|
||||
btx.tx.verify(btx.view, flags);
|
||||
end(i * btx.tx.inputs.length);
|
||||
{
|
||||
const end = bench('fee');
|
||||
for (let i = 0; i < 1000; i++)
|
||||
tx3.tx.getFee(tx3.view);
|
||||
end(1000);
|
||||
}
|
||||
|
||||
tx = new MTX();
|
||||
{
|
||||
const flags = Script.flags.VERIFY_P2SH | Script.flags.VERIFY_DERSIG;
|
||||
const end = bench('verify multisig');
|
||||
for (let i = 0; i < 3000; i++)
|
||||
btx.tx.verify(btx.view, flags);
|
||||
end(3000 * btx.tx.inputs.length);
|
||||
}
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
tx.addInput({
|
||||
const mtx = new MTX();
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
mtx.addInput({
|
||||
prevout: {
|
||||
hash: encoding.NULL_HASH,
|
||||
index: 0
|
||||
@ -126,25 +147,31 @@ for (i = 0; i < 100; i++) {
|
||||
random.randomBytes(33)
|
||||
]
|
||||
});
|
||||
tx.addOutput({
|
||||
mtx.addOutput({
|
||||
address: Address.fromHash(random.randomBytes(20)),
|
||||
value: 0
|
||||
});
|
||||
}
|
||||
|
||||
tx = tx.toTX();
|
||||
const tx = mtx.toTX();
|
||||
|
||||
end = bench('input hashes');
|
||||
for (i = 0; i < 1000; i++)
|
||||
tx.getInputHashes(null, 'hex');
|
||||
end(i);
|
||||
{
|
||||
const end = bench('input hashes');
|
||||
for (let i = 0; i < 1000; i++)
|
||||
tx.getInputHashes(null, 'hex');
|
||||
end(1000);
|
||||
}
|
||||
|
||||
end = bench('output hashes');
|
||||
for (i = 0; i < 1000; i++)
|
||||
tx.getOutputHashes('hex');
|
||||
end(i);
|
||||
{
|
||||
const end = bench('output hashes');
|
||||
for (let i = 0; i < 1000; i++)
|
||||
tx.getOutputHashes('hex');
|
||||
end(1000);
|
||||
}
|
||||
|
||||
end = bench('all hashes');
|
||||
for (i = 0; i < 1000; i++)
|
||||
tx.getHashes(null, 'hex');
|
||||
end(i);
|
||||
{
|
||||
const end = bench('all hashes');
|
||||
for (let i = 0; i < 1000; i++)
|
||||
tx.getHashes(null, 'hex');
|
||||
end(1000);
|
||||
}
|
||||
|
||||
@ -5,115 +5,127 @@ const random = require('../lib/crypto/random');
|
||||
const WalletDB = require('../lib/wallet/walletdb');
|
||||
const MTX = require('../lib/primitives/mtx');
|
||||
const Outpoint = require('../lib/primitives/outpoint');
|
||||
let walletdb;
|
||||
|
||||
function dummy() {
|
||||
const hash = random.randomBytes(32).toString('hex');
|
||||
return new Outpoint(hash, 0);
|
||||
}
|
||||
|
||||
walletdb = new WalletDB({
|
||||
const walletdb = new WalletDB({
|
||||
name: 'wallet-test',
|
||||
db: 'memory',
|
||||
resolution: false,
|
||||
verify: false
|
||||
});
|
||||
|
||||
async function runBench() {
|
||||
let i, j, wallet, addrs, jobs, end;
|
||||
let result, tx, mtx, options;
|
||||
|
||||
(async () => {
|
||||
// Open and Create
|
||||
await walletdb.open();
|
||||
wallet = await walletdb.create();
|
||||
addrs = [];
|
||||
|
||||
const wallet = await walletdb.create();
|
||||
const addrs = [];
|
||||
|
||||
// Accounts
|
||||
jobs = [];
|
||||
for (i = 0; i < 1000; i++)
|
||||
jobs.push(wallet.createAccount({}));
|
||||
{
|
||||
const jobs = [];
|
||||
for (let i = 0; i < 1000; i++)
|
||||
jobs.push(wallet.createAccount({}));
|
||||
|
||||
end = bench('accounts');
|
||||
result = await Promise.all(jobs);
|
||||
end(1000);
|
||||
const end = bench('accounts');
|
||||
const result = await Promise.all(jobs);
|
||||
end(1000);
|
||||
|
||||
for (i = 0; i < result.length; i++)
|
||||
addrs.push(result[i].receive.getAddress());
|
||||
for (const addr of result)
|
||||
addrs.push(addr.receive.getAddress());
|
||||
}
|
||||
|
||||
// Keys
|
||||
jobs = [];
|
||||
for (i = 0; i < 1000; i++) {
|
||||
for (j = 0; j < 10; j++)
|
||||
jobs.push(wallet.createReceive(i));
|
||||
{
|
||||
const jobs = [];
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
for (let j = 0; j < 10; j++)
|
||||
jobs.push(wallet.createReceive(i));
|
||||
}
|
||||
|
||||
const end = bench('keys');
|
||||
const result = await Promise.all(jobs);
|
||||
end(1000 * 10);
|
||||
|
||||
for (const addr of result)
|
||||
addrs.push(addr.getAddress());
|
||||
}
|
||||
|
||||
end = bench('keys');
|
||||
result = await Promise.all(jobs);
|
||||
end(1000 * 10);
|
||||
|
||||
for (i = 0; i < result.length; i++)
|
||||
addrs.push(result[i].getAddress());
|
||||
|
||||
// TX deposit
|
||||
jobs = [];
|
||||
for (i = 0; i < 10000; i++) {
|
||||
mtx = new MTX();
|
||||
mtx.addOutpoint(dummy());
|
||||
mtx.addOutput(addrs[(i + 0) % addrs.length], 50460);
|
||||
mtx.addOutput(addrs[(i + 1) % addrs.length], 50460);
|
||||
mtx.addOutput(addrs[(i + 2) % addrs.length], 50460);
|
||||
mtx.addOutput(addrs[(i + 3) % addrs.length], 50460);
|
||||
tx = mtx.toTX();
|
||||
{
|
||||
const jobs = [];
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
const mtx = new MTX();
|
||||
mtx.addOutpoint(dummy());
|
||||
mtx.addOutput(addrs[(i + 0) % addrs.length], 50460);
|
||||
mtx.addOutput(addrs[(i + 1) % addrs.length], 50460);
|
||||
mtx.addOutput(addrs[(i + 2) % addrs.length], 50460);
|
||||
mtx.addOutput(addrs[(i + 3) % addrs.length], 50460);
|
||||
const tx = mtx.toTX();
|
||||
|
||||
jobs.push(walletdb.addTX(tx));
|
||||
jobs.push(walletdb.addTX(tx));
|
||||
}
|
||||
|
||||
const end = bench('deposit');
|
||||
await Promise.all(jobs);
|
||||
end(10000);
|
||||
}
|
||||
|
||||
end = bench('deposit');
|
||||
result = await Promise.all(jobs);
|
||||
end(10000);
|
||||
|
||||
// TX redemption
|
||||
jobs = [];
|
||||
for (i = 0; i < 10000; i++) {
|
||||
mtx = new MTX();
|
||||
mtx.addTX(tx, 0);
|
||||
mtx.addTX(tx, 1);
|
||||
mtx.addTX(tx, 2);
|
||||
mtx.addTX(tx, 3);
|
||||
mtx.addOutput(addrs[(i + 0) % addrs.length], 50460);
|
||||
mtx.addOutput(addrs[(i + 1) % addrs.length], 50460);
|
||||
mtx.addOutput(addrs[(i + 2) % addrs.length], 50460);
|
||||
mtx.addOutput(addrs[(i + 3) % addrs.length], 50460);
|
||||
tx = mtx.toTX();
|
||||
{
|
||||
const jobs = [];
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
const mtx = new MTX();
|
||||
mtx.addTX(tx, 0);
|
||||
mtx.addTX(tx, 1);
|
||||
mtx.addTX(tx, 2);
|
||||
mtx.addTX(tx, 3);
|
||||
mtx.addOutput(addrs[(i + 0) % addrs.length], 50460);
|
||||
mtx.addOutput(addrs[(i + 1) % addrs.length], 50460);
|
||||
mtx.addOutput(addrs[(i + 2) % addrs.length], 50460);
|
||||
mtx.addOutput(addrs[(i + 3) % addrs.length], 50460);
|
||||
const tx = mtx.toTX();
|
||||
|
||||
jobs.push(walletdb.addTX(tx));
|
||||
jobs.push(walletdb.addTX(tx));
|
||||
}
|
||||
|
||||
const end = bench('redemption');
|
||||
await Promise.all(jobs);
|
||||
end(10000);
|
||||
}
|
||||
|
||||
end = bench('redemption');
|
||||
result = await Promise.all(jobs);
|
||||
end(10000);
|
||||
|
||||
// Balance
|
||||
end = bench('balance');
|
||||
result = await wallet.getBalance();
|
||||
end(1);
|
||||
{
|
||||
const end = bench('balance');
|
||||
await wallet.getBalance();
|
||||
end(1);
|
||||
}
|
||||
|
||||
// Coins
|
||||
end = bench('coins');
|
||||
result = await wallet.getCoins();
|
||||
end(1);
|
||||
{
|
||||
const end = bench('coins');
|
||||
await wallet.getCoins();
|
||||
end(1);
|
||||
}
|
||||
|
||||
// Create
|
||||
end = bench('create');
|
||||
options = {
|
||||
rate: 10000,
|
||||
outputs: [{
|
||||
value: 50460,
|
||||
address: addrs[0]
|
||||
}]
|
||||
};
|
||||
await wallet.createTX(options);
|
||||
end(1);
|
||||
}
|
||||
|
||||
runBench().then(process.exit);
|
||||
{
|
||||
const end = bench('create');
|
||||
const options = {
|
||||
rate: 10000,
|
||||
outputs: [{
|
||||
value: 50460,
|
||||
address: addrs[0]
|
||||
}]
|
||||
};
|
||||
await wallet.createTX(options);
|
||||
end(1);
|
||||
}
|
||||
})().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
38
bin/cli
38
bin/cli
@ -39,9 +39,7 @@ CLI.prototype.getWallets = async function getWallets() {
|
||||
};
|
||||
|
||||
CLI.prototype.createWallet = async function createWallet() {
|
||||
let options, wallet;
|
||||
|
||||
options = {
|
||||
const options = {
|
||||
id: this.config.str([0, 'id']),
|
||||
type: this.config.str('type'),
|
||||
master: this.config.str('master'),
|
||||
@ -59,7 +57,7 @@ CLI.prototype.createWallet = async function createWallet() {
|
||||
options.accountKey = this.config.str('watch');
|
||||
}
|
||||
|
||||
wallet = await this.client.createWallet(options);
|
||||
const wallet = await this.client.createWallet(options);
|
||||
|
||||
this.log(wallet);
|
||||
};
|
||||
@ -110,9 +108,8 @@ CLI.prototype.getAccount = async function getAccount() {
|
||||
|
||||
CLI.prototype.createAccount = async function createAccount() {
|
||||
const name = this.config.str([0, 'name']);
|
||||
let options, account;
|
||||
|
||||
options = {
|
||||
const options = {
|
||||
type: this.config.str('type'),
|
||||
m: this.config.num('m'),
|
||||
n: this.config.num('n'),
|
||||
@ -120,7 +117,7 @@ CLI.prototype.createAccount = async function createAccount() {
|
||||
accountKey: this.config.str('watch')
|
||||
};
|
||||
|
||||
account = await this.wallet.createAccount(name, options);
|
||||
const account = await this.wallet.createAccount(name, options);
|
||||
|
||||
this.log(account);
|
||||
};
|
||||
@ -155,15 +152,14 @@ CLI.prototype.getWallet = async function getWallet() {
|
||||
|
||||
CLI.prototype.getTX = async function getTX() {
|
||||
const hash = this.config.str(0);
|
||||
let txs, tx;
|
||||
|
||||
if (util.isBase58(hash)) {
|
||||
txs = await this.client.getTXByAddress(hash);
|
||||
const txs = await this.client.getTXByAddress(hash);
|
||||
this.log(txs);
|
||||
return;
|
||||
}
|
||||
|
||||
tx = await this.client.getTX(hash);
|
||||
const tx = await this.client.getTX(hash);
|
||||
|
||||
if (!tx) {
|
||||
this.log('TX not found.');
|
||||
@ -175,12 +171,11 @@ CLI.prototype.getTX = async function getTX() {
|
||||
|
||||
CLI.prototype.getBlock = async function getBlock() {
|
||||
let hash = this.config.str(0);
|
||||
let block;
|
||||
|
||||
if (hash.length !== 64)
|
||||
hash = +hash;
|
||||
|
||||
block = await this.client.getBlock(hash);
|
||||
const block = await this.client.getBlock(hash);
|
||||
|
||||
if (!block) {
|
||||
this.log('Block not found.');
|
||||
@ -193,15 +188,14 @@ CLI.prototype.getBlock = async function getBlock() {
|
||||
CLI.prototype.getCoin = async function getCoin() {
|
||||
const hash = this.config.str(0);
|
||||
const index = this.config.num(1);
|
||||
let coins, coin;
|
||||
|
||||
if (util.isBase58(hash)) {
|
||||
coins = await this.client.getCoinsByAddress(hash);
|
||||
const coins = await this.client.getCoinsByAddress(hash);
|
||||
this.log(coins);
|
||||
return;
|
||||
}
|
||||
|
||||
coin = await this.client.getCoin(hash, index);
|
||||
const coin = await this.client.getCoin(hash, index);
|
||||
|
||||
if (!coin) {
|
||||
this.log('Coin not found.');
|
||||
@ -277,7 +271,7 @@ CLI.prototype.getMempool = async function getMempool() {
|
||||
};
|
||||
|
||||
CLI.prototype.sendTX = async function sendTX() {
|
||||
let output, options, tx;
|
||||
let output;
|
||||
|
||||
if (this.config.has('script')) {
|
||||
output = {
|
||||
@ -291,7 +285,7 @@ CLI.prototype.sendTX = async function sendTX() {
|
||||
};
|
||||
}
|
||||
|
||||
options = {
|
||||
const options = {
|
||||
account: this.config.str('account'),
|
||||
passphrase: this.config.str('passphrase'),
|
||||
outputs: [output],
|
||||
@ -300,13 +294,13 @@ CLI.prototype.sendTX = async function sendTX() {
|
||||
subtractFee: this.config.bool('subtract-fee')
|
||||
};
|
||||
|
||||
tx = await this.wallet.send(options);
|
||||
const tx = await this.wallet.send(options);
|
||||
|
||||
this.log(tx);
|
||||
};
|
||||
|
||||
CLI.prototype.createTX = async function createTX() {
|
||||
let output, options, tx;
|
||||
let output;
|
||||
|
||||
if (this.config.has('script')) {
|
||||
output = {
|
||||
@ -320,7 +314,7 @@ CLI.prototype.createTX = async function createTX() {
|
||||
};
|
||||
}
|
||||
|
||||
options = {
|
||||
const options = {
|
||||
account: this.config.str('account'),
|
||||
passphrase: this.config.str('passphrase'),
|
||||
outputs: [output],
|
||||
@ -328,7 +322,7 @@ CLI.prototype.createTX = async function createTX() {
|
||||
rate: this.config.amt('rate')
|
||||
};
|
||||
|
||||
tx = await this.wallet.createTX(options);
|
||||
const tx = await this.wallet.createTX(options);
|
||||
|
||||
this.log(tx);
|
||||
};
|
||||
@ -461,7 +455,6 @@ CLI.prototype.unlock = async function unlock() {
|
||||
CLI.prototype.rpc = async function rpc() {
|
||||
const method = this.argv.shift();
|
||||
const params = [];
|
||||
let result;
|
||||
|
||||
for (const arg of this.argv) {
|
||||
let param;
|
||||
@ -473,6 +466,7 @@ CLI.prototype.rpc = async function rpc() {
|
||||
params.push(param);
|
||||
}
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = await this.client.rpc.execute(method, params);
|
||||
} catch (e) {
|
||||
|
||||
@ -7,11 +7,9 @@ const chain = new Chain({
|
||||
});
|
||||
|
||||
(async () => {
|
||||
let entry;
|
||||
|
||||
await chain.open();
|
||||
|
||||
entry = await chain.getEntry(0);
|
||||
const entry = await chain.getEntry(0);
|
||||
|
||||
console.log(entry);
|
||||
})();
|
||||
|
||||
@ -7,9 +7,8 @@ const MTX = require('bcoin/lib/primitives/mtx');
|
||||
const HTTP = require('bcoin/lib/http');
|
||||
const FullNode = require('bcoin/lib/node/fullnode');
|
||||
const plugin = require('bcoin/lib/wallet/plugin');
|
||||
let node, wallet;
|
||||
|
||||
node = new FullNode({
|
||||
const node = new FullNode({
|
||||
network: 'regtest',
|
||||
apiKey: 'foo',
|
||||
walletAuth: true,
|
||||
@ -18,22 +17,21 @@ node = new FullNode({
|
||||
|
||||
node.use(plugin);
|
||||
|
||||
wallet = new HTTP.Wallet({
|
||||
const wallet = new HTTP.Wallet({
|
||||
network: 'regtest',
|
||||
apiKey: 'foo'
|
||||
});
|
||||
|
||||
async function fundWallet(wdb, addr) {
|
||||
let tx;
|
||||
|
||||
// Coinbase
|
||||
tx = new MTX();
|
||||
tx.addOutpoint(new Outpoint(encoding.NULL_HASH, 0));
|
||||
tx.addOutput(addr, 50460);
|
||||
tx.addOutput(addr, 50460);
|
||||
tx.addOutput(addr, 50460);
|
||||
tx.addOutput(addr, 50460);
|
||||
tx = tx.toTX();
|
||||
const mtx = new MTX();
|
||||
mtx.addOutpoint(new Outpoint(encoding.NULL_HASH, 0));
|
||||
mtx.addOutput(addr, 50460);
|
||||
mtx.addOutput(addr, 50460);
|
||||
mtx.addOutput(addr, 50460);
|
||||
mtx.addOutput(addr, 50460);
|
||||
|
||||
const tx = mtx.toTX();
|
||||
|
||||
wallet.once('balance', (balance) => {
|
||||
console.log('New Balance:');
|
||||
@ -55,9 +53,7 @@ async function fundWallet(wdb, addr) {
|
||||
}
|
||||
|
||||
async function sendTX(addr, value) {
|
||||
let options, tx;
|
||||
|
||||
options = {
|
||||
const options = {
|
||||
rate: 10000,
|
||||
outputs: [{
|
||||
value: value,
|
||||
@ -65,19 +61,18 @@ async function sendTX(addr, value) {
|
||||
}]
|
||||
};
|
||||
|
||||
tx = await wallet.send(options);
|
||||
const tx = await wallet.send(options);
|
||||
|
||||
return tx.hash;
|
||||
}
|
||||
|
||||
async function callNodeApi() {
|
||||
const info = await wallet.client.getInfo();
|
||||
let json;
|
||||
|
||||
console.log('Server Info:');
|
||||
console.log(info);
|
||||
|
||||
json = await wallet.client.rpc.execute('getblocktemplate', []);
|
||||
const json = await wallet.client.rpc.execute('getblocktemplate', []);
|
||||
|
||||
console.log('Block Template (RPC):');
|
||||
console.log(json);
|
||||
@ -85,11 +80,10 @@ async function callNodeApi() {
|
||||
|
||||
(async () => {
|
||||
const wdb = node.require('walletdb');
|
||||
let w, acct, hash, balance, tx;
|
||||
|
||||
await node.open();
|
||||
|
||||
w = await wallet.create({ id: 'test' });
|
||||
const w = await wallet.create({ id: 'test' });
|
||||
|
||||
console.log('Wallet:');
|
||||
console.log(w);
|
||||
@ -97,23 +91,23 @@ async function callNodeApi() {
|
||||
// Fund default account.
|
||||
await fundWallet(wdb, w.account.receiveAddress);
|
||||
|
||||
balance = await wallet.getBalance();
|
||||
const balance = await wallet.getBalance();
|
||||
|
||||
console.log('Balance:');
|
||||
console.log(balance);
|
||||
|
||||
acct = await wallet.createAccount('foo');
|
||||
const acct = await wallet.createAccount('foo');
|
||||
|
||||
console.log('Account:');
|
||||
console.log(acct);
|
||||
|
||||
// Send to our new account.
|
||||
hash = await sendTX(acct.receiveAddress, 10000);
|
||||
const hash = await sendTX(acct.receiveAddress, 10000);
|
||||
|
||||
console.log('Sent TX:');
|
||||
console.log(hash);
|
||||
|
||||
tx = await wallet.getTX(hash);
|
||||
const tx = await wallet.getTX(hash);
|
||||
|
||||
console.log('Sent TX details:');
|
||||
console.log(tx);
|
||||
|
||||
@ -24,17 +24,15 @@ const miner = new Miner({
|
||||
});
|
||||
|
||||
(async () => {
|
||||
let tmpl, job, block;
|
||||
|
||||
await miner.open();
|
||||
|
||||
tmpl = await miner.createBlock();
|
||||
const tmpl = await miner.createBlock();
|
||||
|
||||
console.log('Block template:');
|
||||
console.log(tmpl);
|
||||
|
||||
job = await miner.cpu.createJob();
|
||||
block = await job.mineAsync();
|
||||
const job = await miner.cpu.createJob();
|
||||
const block = await job.mineAsync();
|
||||
|
||||
console.log('Mined block:');
|
||||
console.log(block);
|
||||
|
||||
@ -6,9 +6,8 @@ const Peer = require('bcoin/lib/net/peer');
|
||||
const NetAddress = require('bcoin/lib/primitives/netaddress');
|
||||
const Network = require('bcoin/lib/protocol/network');
|
||||
const network = Network.get('testnet');
|
||||
let peer, addr;
|
||||
|
||||
peer = Peer.fromOptions({
|
||||
const peer = Peer.fromOptions({
|
||||
network: 'testnet',
|
||||
agent: 'my-subversion',
|
||||
hasWitness: () => {
|
||||
@ -16,7 +15,7 @@ peer = Peer.fromOptions({
|
||||
}
|
||||
});
|
||||
|
||||
addr = NetAddress.fromHostname(process.argv[2], 'testnet');
|
||||
const addr = NetAddress.fromHostname(process.argv[2], 'testnet');
|
||||
|
||||
peer.connect(addr);
|
||||
peer.tryOpen();
|
||||
|
||||
@ -16,30 +16,29 @@ const walletdb = new WalletDB({
|
||||
});
|
||||
|
||||
(async () => {
|
||||
let wallet, acct, mtx, tx, wtx;
|
||||
|
||||
await walletdb.open();
|
||||
|
||||
wallet = await walletdb.create();
|
||||
const wallet = await walletdb.create();
|
||||
|
||||
console.log('Created wallet');
|
||||
console.log(wallet);
|
||||
|
||||
acct = await wallet.createAccount({
|
||||
const acct = await wallet.createAccount({
|
||||
name: 'foo'
|
||||
});
|
||||
|
||||
console.log('Created account');
|
||||
console.log(acct);
|
||||
|
||||
mtx = new MTX();
|
||||
const mtx = new MTX();
|
||||
mtx.addOutpoint(dummy());
|
||||
mtx.addOutput(acct.getReceive(), 50460);
|
||||
tx = mtx.toTX();
|
||||
|
||||
const tx = mtx.toTX();
|
||||
|
||||
await walletdb.addTX(tx);
|
||||
|
||||
wtx = await wallet.getTX(tx.hash('hex'));
|
||||
const wtx = await wallet.getTX(tx.hash('hex'));
|
||||
|
||||
console.log('Added transaction');
|
||||
console.log(wtx);
|
||||
|
||||
@ -150,12 +150,10 @@ PaymentRequest.prototype.toRaw = function toRaw() {
|
||||
*/
|
||||
|
||||
PaymentRequest.prototype.getAlgorithm = function getAlgorithm() {
|
||||
let parts;
|
||||
|
||||
if (!this.pkiType)
|
||||
throw new Error('No PKI type available.');
|
||||
|
||||
parts = this.pkiType.split('+');
|
||||
const parts = this.pkiType.split('+');
|
||||
|
||||
if (parts.length !== 2)
|
||||
throw new Error('Could not parse PKI algorithm.');
|
||||
@ -176,11 +174,10 @@ PaymentRequest.prototype.getAlgorithm = function getAlgorithm() {
|
||||
|
||||
PaymentRequest.prototype.signatureData = function signatureData() {
|
||||
const signature = this.signature;
|
||||
let data;
|
||||
|
||||
this.signature = Buffer.alloc(0);
|
||||
|
||||
data = this.toRaw();
|
||||
const data = this.toRaw();
|
||||
|
||||
this.signature = signature;
|
||||
|
||||
@ -227,12 +224,11 @@ PaymentRequest.prototype.setChain = function setChain(chain) {
|
||||
|
||||
PaymentRequest.prototype.getChain = function getChain() {
|
||||
const chain = [];
|
||||
let br;
|
||||
|
||||
if (!this.pkiData)
|
||||
return chain;
|
||||
|
||||
br = new ProtoReader(this.pkiData);
|
||||
const br = new ProtoReader(this.pkiData);
|
||||
|
||||
while (br.nextTag() === 1)
|
||||
chain.push(br.readFieldBytes(1));
|
||||
@ -243,21 +239,19 @@ PaymentRequest.prototype.getChain = function getChain() {
|
||||
/**
|
||||
* Sign payment request (chain must be set).
|
||||
* @param {Buffer} key
|
||||
* @param {Buffer[]?} chain
|
||||
* @param {Buffer[]?} certs
|
||||
*/
|
||||
|
||||
PaymentRequest.prototype.sign = function sign(key, chain) {
|
||||
let alg, msg;
|
||||
|
||||
if (chain)
|
||||
this.setChain(chain);
|
||||
PaymentRequest.prototype.sign = function sign(key, certs) {
|
||||
if (certs)
|
||||
this.setChain(certs);
|
||||
|
||||
if (!this.pkiType)
|
||||
this.pkiType = 'x509+sha256';
|
||||
|
||||
alg = this.getAlgorithm();
|
||||
msg = this.signatureData();
|
||||
chain = this.getChain();
|
||||
const alg = this.getAlgorithm();
|
||||
const msg = this.signatureData();
|
||||
const chain = this.getChain();
|
||||
|
||||
this.signature = x509.signSubject(alg.hash, msg, key, chain);
|
||||
};
|
||||
@ -268,23 +262,22 @@ PaymentRequest.prototype.sign = function sign(key, chain) {
|
||||
*/
|
||||
|
||||
PaymentRequest.prototype.verify = function verify() {
|
||||
let alg, msg, sig, chain;
|
||||
|
||||
if (!this.pkiType || this.pkiType === 'none')
|
||||
return false;
|
||||
|
||||
if (!this.signature)
|
||||
return false;
|
||||
|
||||
let alg;
|
||||
try {
|
||||
alg = this.getAlgorithm();
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
msg = this.signatureData();
|
||||
sig = this.signature;
|
||||
chain = this.getChain();
|
||||
const msg = this.signatureData();
|
||||
const sig = this.signature;
|
||||
const chain = this.getChain();
|
||||
|
||||
try {
|
||||
return x509.verifySubject(alg.hash, msg, sig, chain);
|
||||
@ -315,17 +308,15 @@ PaymentRequest.prototype.verifyChain = function verifyChain() {
|
||||
*/
|
||||
|
||||
PaymentRequest.prototype.getCA = function getCA() {
|
||||
let chain, root;
|
||||
|
||||
if (!this.pkiType || this.pkiType === 'none')
|
||||
throw new Error('No CA found (pkiType).');
|
||||
|
||||
chain = this.getChain();
|
||||
const chain = this.getChain();
|
||||
|
||||
if (chain.length === 0)
|
||||
throw new Error('No CA found (chain).');
|
||||
|
||||
root = x509.parse(chain[chain.length - 1]);
|
||||
const root = x509.parse(chain[chain.length - 1]);
|
||||
|
||||
return new CA(root);
|
||||
};
|
||||
|
||||
@ -139,8 +139,6 @@ x509.setTrust = function setTrust(certs) {
|
||||
assert(Array.isArray(certs), 'Certs must be an array.');
|
||||
|
||||
for (let cert of certs) {
|
||||
let hash;
|
||||
|
||||
if (typeof cert === 'string') {
|
||||
const pem = PEM.decode(cert);
|
||||
assert(pem.type === 'certificate', 'Must add certificates to trust.');
|
||||
@ -151,10 +149,10 @@ x509.setTrust = function setTrust(certs) {
|
||||
|
||||
cert = x509.parse(cert);
|
||||
|
||||
hash = digest.sha256(cert.raw);
|
||||
hash = hash.toString('hex');
|
||||
const hash = digest.sha256(cert.raw);
|
||||
const fingerprint = hash.toString('hex');
|
||||
|
||||
x509.trusted.add(hash);
|
||||
x509.trusted.add(fingerprint);
|
||||
}
|
||||
};
|
||||
|
||||
@ -217,7 +215,7 @@ x509.getSigAlgorithm = function getSigAlgorithm(cert) {
|
||||
*/
|
||||
|
||||
x509.getCurve = function getCurve(params) {
|
||||
let oid, curve;
|
||||
let oid;
|
||||
|
||||
try {
|
||||
oid = ASN1.parseOID(params);
|
||||
@ -225,7 +223,7 @@ x509.getCurve = function getCurve(params) {
|
||||
throw new Error('Could not parse curve OID.');
|
||||
}
|
||||
|
||||
curve = x509.curves[oid];
|
||||
const curve = x509.curves[oid];
|
||||
|
||||
if (!curve)
|
||||
throw new Error(`Unknown ECDSA curve: ${oid}.`);
|
||||
@ -257,7 +255,7 @@ x509.getPublicKey = function getPublicKey(cert) {
|
||||
const alg = x509.getKeyAlgorithm(cert);
|
||||
const key = cert.tbs.pubkey.pubkey;
|
||||
const params = cert.tbs.pubkey.alg.params;
|
||||
let curve;
|
||||
let curve = null;
|
||||
|
||||
if (alg.key === 'ecdsa') {
|
||||
if (!params)
|
||||
@ -297,7 +295,7 @@ x509.getSigningKey = function getSigningKey(key, chain) {
|
||||
assert(chain.length !== 0, 'No chain available.');
|
||||
|
||||
if (typeof key === 'string') {
|
||||
let curve;
|
||||
let curve = null;
|
||||
|
||||
key = PEM.decode(key);
|
||||
|
||||
@ -350,15 +348,12 @@ x509.signSubject = function signSubject(hash, msg, key, chain) {
|
||||
*/
|
||||
|
||||
x509.getVerifyKey = function getVerifyKey(chain) {
|
||||
let cert, key;
|
||||
|
||||
if (chain.length === 0)
|
||||
throw new Error('No verify key available (cert chain).');
|
||||
|
||||
cert = x509.parse(chain[0]);
|
||||
key = x509.getPublicKey(cert);
|
||||
const cert = x509.parse(chain[0]);
|
||||
|
||||
return key;
|
||||
return x509.getPublicKey(cert);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -97,8 +97,6 @@ util.inherits(Chain, AsyncObject);
|
||||
*/
|
||||
|
||||
Chain.prototype._open = async function open() {
|
||||
let tip, state;
|
||||
|
||||
this.logger.info('Chain is loading.');
|
||||
|
||||
if (this.options.checkpoints)
|
||||
@ -115,7 +113,7 @@ Chain.prototype._open = async function open() {
|
||||
|
||||
await this.db.open();
|
||||
|
||||
tip = await this.db.getTip();
|
||||
const tip = await this.db.getTip();
|
||||
|
||||
assert(tip);
|
||||
|
||||
@ -126,7 +124,7 @@ Chain.prototype._open = async function open() {
|
||||
|
||||
this.logger.memory();
|
||||
|
||||
state = await this.getDeploymentState();
|
||||
const state = await this.getDeploymentState();
|
||||
|
||||
this.setDeploymentState(state);
|
||||
|
||||
@ -158,16 +156,14 @@ Chain.prototype._close = function close() {
|
||||
*/
|
||||
|
||||
Chain.prototype.verifyContext = async function verifyContext(block, prev, flags) {
|
||||
let state, view;
|
||||
|
||||
// Initial non-contextual verification.
|
||||
state = await this.verify(block, prev, flags);
|
||||
const state = await this.verify(block, prev, flags);
|
||||
|
||||
// BIP30 - Verify there are no duplicate txids.
|
||||
await this.verifyDuplicates(block, prev, state);
|
||||
|
||||
// Verify scripts, spend and add coins.
|
||||
view = await this.verifyInputs(block, prev, state);
|
||||
const view = await this.verifyInputs(block, prev, state);
|
||||
|
||||
return [view, state];
|
||||
};
|
||||
@ -230,7 +226,6 @@ Chain.prototype.verify = async function verify(block, prev, flags) {
|
||||
const hash = block.hash('hex');
|
||||
const now = this.network.now();
|
||||
const height = prev.height + 1;
|
||||
let time, mtp, commit, state, bits;
|
||||
|
||||
assert(typeof flags === 'number');
|
||||
|
||||
@ -275,7 +270,7 @@ Chain.prototype.verify = async function verify(block, prev, flags) {
|
||||
return this.state;
|
||||
|
||||
// Ensure the POW is what we expect.
|
||||
bits = await this.getTarget(block.time, prev);
|
||||
const bits = await this.getTarget(block.time, prev);
|
||||
|
||||
if (block.bits !== bits) {
|
||||
throw new VerifyError(block,
|
||||
@ -285,7 +280,7 @@ Chain.prototype.verify = async function verify(block, prev, flags) {
|
||||
}
|
||||
|
||||
// Ensure the timestamp is correct.
|
||||
mtp = await prev.getMedianTime();
|
||||
const mtp = await prev.getMedianTime();
|
||||
|
||||
if (block.time <= mtp) {
|
||||
throw new VerifyError(block,
|
||||
@ -321,7 +316,7 @@ Chain.prototype.verify = async function verify(block, prev, flags) {
|
||||
throw new VerifyError(block, 'obsolete', 'bad-version', 0);
|
||||
|
||||
// Get the new deployment state.
|
||||
state = await this.getDeployments(block.time, prev);
|
||||
const state = await this.getDeployments(block.time, prev);
|
||||
|
||||
// Enforce BIP91/BIP148.
|
||||
if (state.hasBIP91() || state.hasBIP148()) {
|
||||
@ -330,7 +325,7 @@ Chain.prototype.verify = async function verify(block, prev, flags) {
|
||||
}
|
||||
|
||||
// Get timestamp for tx.isFinal().
|
||||
time = state.hasMTP() ? mtp : block.time;
|
||||
const time = state.hasMTP() ? mtp : block.time;
|
||||
|
||||
// Transactions must be finalized with
|
||||
// regards to nSequence and nLockTime.
|
||||
@ -355,6 +350,7 @@ Chain.prototype.verify = async function verify(block, prev, flags) {
|
||||
}
|
||||
|
||||
// Check the commitment hash for segwit.
|
||||
let commit = null;
|
||||
if (state.hasWitness()) {
|
||||
commit = block.getCommitmentHash();
|
||||
if (commit) {
|
||||
@ -418,7 +414,6 @@ Chain.prototype.getDeployments = async function getDeployments(time, prev) {
|
||||
const deployments = this.network.deployments;
|
||||
const height = prev.height + 1;
|
||||
const state = new DeploymentState();
|
||||
let witness;
|
||||
|
||||
// For some reason bitcoind has p2sh in the
|
||||
// mandatory flags by default, when in reality
|
||||
@ -452,7 +447,7 @@ Chain.prototype.getDeployments = async function getDeployments(time, prev) {
|
||||
}
|
||||
|
||||
// Check the state of the segwit deployment.
|
||||
witness = await this.getState(prev, deployments.segwit);
|
||||
const witness = await this.getState(prev, deployments.segwit);
|
||||
|
||||
// Segregrated witness (bip141) is now usable
|
||||
// along with SCRIPT_VERIFY_NULLDUMMY (bip147).
|
||||
@ -586,17 +581,18 @@ Chain.prototype.verifyDuplicates = async function verifyDuplicates(block, prev,
|
||||
*/
|
||||
|
||||
Chain.prototype.verifyInputs = async function verifyInputs(block, prev, state) {
|
||||
if (this.options.spv)
|
||||
return view;
|
||||
|
||||
const interval = this.network.halvingInterval;
|
||||
const view = new CoinView();
|
||||
const height = prev.height + 1;
|
||||
const historical = prev.isHistorical();
|
||||
const jobs = [];
|
||||
|
||||
let sigops = 0;
|
||||
let reward = 0;
|
||||
|
||||
if (this.options.spv)
|
||||
return view;
|
||||
|
||||
// Check all transactions
|
||||
for (let i = 0; i < block.txs.length; i++) {
|
||||
const tx = block.txs[i];
|
||||
@ -755,14 +751,12 @@ Chain.prototype.findFork = async function findFork(fork, longer) {
|
||||
Chain.prototype.reorganize = async function reorganize(competitor) {
|
||||
const tip = this.tip;
|
||||
const fork = await this.findFork(tip, competitor);
|
||||
const disconnect = [];
|
||||
const connect = [];
|
||||
let entry;
|
||||
|
||||
assert(fork, 'No free space or data corruption.');
|
||||
|
||||
// Blocks to disconnect.
|
||||
entry = tip;
|
||||
const disconnect = [];
|
||||
let entry = tip;
|
||||
while (entry.hash !== fork.hash) {
|
||||
disconnect.push(entry);
|
||||
entry = await entry.getPrevious();
|
||||
@ -770,6 +764,7 @@ Chain.prototype.reorganize = async function reorganize(competitor) {
|
||||
}
|
||||
|
||||
// Blocks to connect.
|
||||
const connect = [];
|
||||
entry = competitor;
|
||||
while (entry.hash !== fork.hash) {
|
||||
connect.push(entry);
|
||||
@ -814,12 +809,12 @@ Chain.prototype.reorganize = async function reorganize(competitor) {
|
||||
Chain.prototype.reorganizeSPV = async function reorganizeSPV(competitor) {
|
||||
const tip = this.tip;
|
||||
const fork = await this.findFork(tip, competitor);
|
||||
const disconnect = [];
|
||||
let entry = tip;
|
||||
|
||||
assert(fork, 'No free space or data corruption.');
|
||||
|
||||
// Buffer disconnected blocks.
|
||||
const disconnect = [];
|
||||
let entry = tip;
|
||||
while (entry.hash !== fork.hash) {
|
||||
disconnect.push(entry);
|
||||
entry = await entry.getPrevious();
|
||||
@ -864,7 +859,6 @@ Chain.prototype.reorganizeSPV = async function reorganizeSPV(competitor) {
|
||||
|
||||
Chain.prototype.disconnect = async function disconnect(entry) {
|
||||
let block = await this.db.getBlock(entry.hash);
|
||||
let prev, view;
|
||||
|
||||
if (!block) {
|
||||
if (!this.options.spv)
|
||||
@ -872,8 +866,8 @@ Chain.prototype.disconnect = async function disconnect(entry) {
|
||||
block = entry.toHeaders();
|
||||
}
|
||||
|
||||
prev = await entry.getPrevious();
|
||||
view = await this.db.disconnect(entry, block);
|
||||
const prev = await entry.getPrevious();
|
||||
const view = await this.db.disconnect(entry, block);
|
||||
|
||||
assert(prev);
|
||||
|
||||
@ -898,8 +892,8 @@ Chain.prototype.disconnect = async function disconnect(entry) {
|
||||
|
||||
Chain.prototype.reconnect = async function reconnect(entry) {
|
||||
const flags = common.flags.VERIFY_NONE;
|
||||
|
||||
let block = await this.db.getBlock(entry.hash);
|
||||
let prev, view, state;
|
||||
|
||||
if (!block) {
|
||||
if (!this.options.spv)
|
||||
@ -907,9 +901,10 @@ Chain.prototype.reconnect = async function reconnect(entry) {
|
||||
block = entry.toHeaders();
|
||||
}
|
||||
|
||||
prev = await entry.getPrevious();
|
||||
const prev = await entry.getPrevious();
|
||||
assert(prev);
|
||||
|
||||
let view, state;
|
||||
try {
|
||||
[view, state] = await this.verifyContext(block, prev, flags);
|
||||
} catch (err) {
|
||||
@ -950,8 +945,6 @@ Chain.prototype.reconnect = async function reconnect(entry) {
|
||||
*/
|
||||
|
||||
Chain.prototype.setBestChain = async function setBestChain(entry, block, prev, flags) {
|
||||
let view, state;
|
||||
|
||||
// A higher fork has arrived.
|
||||
// Time to reorganize the chain.
|
||||
if (entry.prevBlock !== this.tip.hash) {
|
||||
@ -976,6 +969,7 @@ Chain.prototype.setBestChain = async function setBestChain(entry, block, prev, f
|
||||
// Do "contextual" verification on our block
|
||||
// now that we're certain its previous
|
||||
// block is in the chain.
|
||||
let view, state;
|
||||
try {
|
||||
[view, state] = await this.verifyContext(block, prev, flags);
|
||||
} catch (err) {
|
||||
@ -1085,14 +1079,13 @@ Chain.prototype.reset = async function reset(block) {
|
||||
|
||||
Chain.prototype._reset = async function reset(block, silent) {
|
||||
const tip = await this.db.reset(block);
|
||||
let state;
|
||||
|
||||
// Reset state.
|
||||
this.tip = tip;
|
||||
this.height = tip.height;
|
||||
this.synced = false;
|
||||
|
||||
state = await this.getDeploymentState();
|
||||
const state = await this.getDeploymentState();
|
||||
|
||||
this.setDeploymentState(state);
|
||||
|
||||
@ -1242,7 +1235,6 @@ Chain.prototype.add = async function add(block, flags, id) {
|
||||
|
||||
Chain.prototype._add = async function add(block, flags, id) {
|
||||
const hash = block.hash('hex');
|
||||
let entry, prev;
|
||||
|
||||
if (flags == null)
|
||||
flags = common.flags.DEFAULT_FLAGS;
|
||||
@ -1288,7 +1280,7 @@ Chain.prototype._add = async function add(block, flags, id) {
|
||||
}
|
||||
|
||||
// Find the previous block entry.
|
||||
prev = await this.db.getEntry(block.prevBlock);
|
||||
const prev = await this.db.getEntry(block.prevBlock);
|
||||
|
||||
// If previous block wasn't ever seen,
|
||||
// add it current to orphans and return.
|
||||
@ -1298,7 +1290,7 @@ Chain.prototype._add = async function add(block, flags, id) {
|
||||
}
|
||||
|
||||
// Connect the block.
|
||||
entry = await this.connect(prev, block, flags);
|
||||
const entry = await this.connect(prev, block, flags);
|
||||
|
||||
// Handle any orphans.
|
||||
if (this.hasNextOrphan(hash))
|
||||
@ -1319,7 +1311,6 @@ Chain.prototype._add = async function add(block, flags, id) {
|
||||
|
||||
Chain.prototype.connect = async function connect(prev, block, flags) {
|
||||
const start = util.hrtime();
|
||||
let entry;
|
||||
|
||||
// Sanity check.
|
||||
assert(block.prevBlock === prev.hash);
|
||||
@ -1348,7 +1339,7 @@ Chain.prototype.connect = async function connect(prev, block, flags) {
|
||||
}
|
||||
|
||||
// Create a new chain entry.
|
||||
entry = ChainEntry.fromBlock(this, block, prev);
|
||||
const entry = ChainEntry.fromBlock(this, block, prev);
|
||||
|
||||
// The block is on a alternate chain if the
|
||||
// chainwork is less than or equal to
|
||||
@ -1442,15 +1433,13 @@ Chain.prototype.isSlow = function isSlow() {
|
||||
*/
|
||||
|
||||
Chain.prototype.logStatus = function logStatus(start, block, entry) {
|
||||
let elapsed;
|
||||
|
||||
if (!this.isSlow())
|
||||
return;
|
||||
|
||||
// Report memory for debugging.
|
||||
this.logger.memory();
|
||||
|
||||
elapsed = util.hrtime(start);
|
||||
const elapsed = util.hrtime(start);
|
||||
|
||||
this.logger.info(
|
||||
'Block %s (%d) added to chain (size=%d txs=%d time=%d).',
|
||||
@ -1475,13 +1464,11 @@ Chain.prototype.logStatus = function logStatus(start, block, entry) {
|
||||
*/
|
||||
|
||||
Chain.prototype.verifyCheckpoint = function verifyCheckpoint(prev, hash) {
|
||||
let height, checkpoint;
|
||||
|
||||
if (!this.checkpoints)
|
||||
return true;
|
||||
|
||||
height = prev.height + 1;
|
||||
checkpoint = this.network.checkpointMap[height];
|
||||
const height = prev.height + 1;
|
||||
const checkpoint = this.network.checkpointMap[height];
|
||||
|
||||
if (!checkpoint)
|
||||
return true;
|
||||
@ -1639,7 +1626,7 @@ Chain.prototype.purgeOrphans = function purgeOrphans() {
|
||||
|
||||
Chain.prototype.limitOrphans = function limitOrphans() {
|
||||
const now = util.now();
|
||||
let oldest;
|
||||
let oldest = null;
|
||||
|
||||
for (const orphan of this.orphanMap.values()) {
|
||||
if (now < orphan.time + 60 * 60) {
|
||||
@ -1874,25 +1861,23 @@ Chain.prototype.getLocator = async function getLocator(start) {
|
||||
*/
|
||||
|
||||
Chain.prototype._getLocator = async function getLocator(start) {
|
||||
const hashes = [];
|
||||
let step = 1;
|
||||
let height, entry, main, hash;
|
||||
|
||||
if (start == null)
|
||||
start = this.tip.hash;
|
||||
|
||||
assert(typeof start === 'string');
|
||||
|
||||
entry = await this.db.getEntry(start);
|
||||
let entry = await this.db.getEntry(start);
|
||||
const hashes = [];
|
||||
|
||||
if (!entry) {
|
||||
entry = this.tip;
|
||||
hashes.push(start);
|
||||
}
|
||||
|
||||
hash = entry.hash;
|
||||
height = entry.height;
|
||||
main = await entry.isMainChain();
|
||||
let hash = entry.hash;
|
||||
let height = entry.height;
|
||||
const main = await entry.isMainChain();
|
||||
let step = 1;
|
||||
|
||||
hashes.push(hash);
|
||||
|
||||
@ -1929,7 +1914,7 @@ Chain.prototype._getLocator = async function getLocator(start) {
|
||||
*/
|
||||
|
||||
Chain.prototype.getOrphanRoot = function getOrphanRoot(hash) {
|
||||
let root;
|
||||
let root = null;
|
||||
|
||||
assert(hash);
|
||||
|
||||
@ -1997,7 +1982,6 @@ Chain.prototype.getCurrentTarget = async function getCurrentTarget() {
|
||||
|
||||
Chain.prototype.getTarget = async function getTarget(time, prev) {
|
||||
const pow = this.network.pow;
|
||||
let first, height;
|
||||
|
||||
// Genesis
|
||||
if (!prev) {
|
||||
@ -2030,10 +2014,10 @@ Chain.prototype.getTarget = async function getTarget(time, prev) {
|
||||
}
|
||||
|
||||
// Back 2 weeks
|
||||
height = prev.height - (pow.retargetInterval - 1);
|
||||
const height = prev.height - (pow.retargetInterval - 1);
|
||||
assert(height >= 0);
|
||||
|
||||
first = await prev.getAncestor(height);
|
||||
const first = await prev.getAncestor(height);
|
||||
assert(first);
|
||||
|
||||
return this.retarget(prev, first);
|
||||
@ -2050,13 +2034,13 @@ Chain.prototype.getTarget = async function getTarget(time, prev) {
|
||||
Chain.prototype.retarget = function retarget(prev, first) {
|
||||
const pow = this.network.pow;
|
||||
const targetTimespan = pow.targetTimespan;
|
||||
let actualTimespan, target;
|
||||
|
||||
if (pow.noRetargeting)
|
||||
return prev.bits;
|
||||
|
||||
actualTimespan = prev.time - first.time;
|
||||
target = consensus.fromCompact(prev.bits);
|
||||
const target = consensus.fromCompact(prev.bits);
|
||||
|
||||
let actualTimespan = prev.time - first.time;
|
||||
|
||||
if (actualTimespan < targetTimespan / 4 | 0)
|
||||
actualTimespan = targetTimespan / 4 | 0;
|
||||
@ -2121,8 +2105,6 @@ Chain.prototype.getState = async function getState(prev, deployment) {
|
||||
let window = this.network.minerWindow;
|
||||
let threshold = this.network.activationThreshold;
|
||||
const bit = deployment.bit;
|
||||
const compute = [];
|
||||
let entry, state;
|
||||
|
||||
if (deployment.threshold !== -1)
|
||||
threshold = deployment.threshold;
|
||||
@ -2141,19 +2123,19 @@ Chain.prototype.getState = async function getState(prev, deployment) {
|
||||
assert(((prev.height + 1) % window) === 0);
|
||||
}
|
||||
|
||||
entry = prev;
|
||||
state = thresholdStates.DEFINED;
|
||||
let entry = prev;
|
||||
let state = thresholdStates.DEFINED;
|
||||
const compute = [];
|
||||
|
||||
while (entry) {
|
||||
const cached = this.db.stateCache.get(bit, entry);
|
||||
let time, height;
|
||||
|
||||
if (cached !== -1) {
|
||||
state = cached;
|
||||
break;
|
||||
}
|
||||
|
||||
time = await entry.getMedianTime();
|
||||
const time = await entry.getMedianTime();
|
||||
|
||||
if (time < deployment.startTime) {
|
||||
state = thresholdStates.DEFINED;
|
||||
@ -2163,7 +2145,7 @@ Chain.prototype.getState = async function getState(prev, deployment) {
|
||||
|
||||
compute.push(entry);
|
||||
|
||||
height = entry.height - window;
|
||||
const height = entry.height - window;
|
||||
entry = await entry.getAncestor(height);
|
||||
}
|
||||
|
||||
@ -2326,12 +2308,10 @@ Chain.prototype.getLocks = async function getLocks(prev, tx, view, flags) {
|
||||
return [minHeight, minTime];
|
||||
|
||||
for (const {prevout, sequence} of tx.inputs) {
|
||||
let height, time, entry;
|
||||
|
||||
if (sequence & disableFlag)
|
||||
continue;
|
||||
|
||||
height = view.getHeight(prevout);
|
||||
let height = view.getHeight(prevout);
|
||||
|
||||
if (height === -1)
|
||||
height = this.height + 1;
|
||||
@ -2343,10 +2323,11 @@ Chain.prototype.getLocks = async function getLocks(prev, tx, view, flags) {
|
||||
}
|
||||
|
||||
height = Math.max(height - 1, 0);
|
||||
entry = await prev.getAncestor(height);
|
||||
|
||||
const entry = await prev.getAncestor(height);
|
||||
assert(entry, 'Database is corrupt.');
|
||||
|
||||
time = await entry.getMedianTime();
|
||||
let time = await entry.getMedianTime();
|
||||
time += ((sequence & mask) << granularity) - 1;
|
||||
minTime = Math.max(minTime, time);
|
||||
}
|
||||
@ -2366,7 +2347,6 @@ Chain.prototype.getLocks = async function getLocks(prev, tx, view, flags) {
|
||||
|
||||
Chain.prototype.verifyLocks = async function verifyLocks(prev, tx, view, flags) {
|
||||
const [height, time] = await this.getLocks(prev, tx, view, flags);
|
||||
let mtp;
|
||||
|
||||
// Also catches case where
|
||||
// height is `-1`. Fall through.
|
||||
@ -2376,7 +2356,7 @@ Chain.prototype.verifyLocks = async function verifyLocks(prev, tx, view, flags)
|
||||
if (time === -1)
|
||||
return true;
|
||||
|
||||
mtp = await prev.getMedianTime();
|
||||
const mtp = await prev.getMedianTime();
|
||||
|
||||
if (time >= mtp)
|
||||
return false;
|
||||
|
||||
@ -79,14 +79,12 @@ ChainDB.layout = layout;
|
||||
*/
|
||||
|
||||
ChainDB.prototype.open = async function open() {
|
||||
let state;
|
||||
|
||||
this.logger.info('Opening ChainDB...');
|
||||
|
||||
await this.db.open();
|
||||
await this.db.checkVersion('V', 3);
|
||||
|
||||
state = await this.getState();
|
||||
const state = await this.getState();
|
||||
|
||||
if (state) {
|
||||
// Verify options have not changed.
|
||||
@ -275,8 +273,6 @@ ChainDB.prototype.getCache = function getCache(block) {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.getHeight = async function getHeight(hash) {
|
||||
let entry, height;
|
||||
|
||||
if (typeof hash === 'number')
|
||||
return hash;
|
||||
|
||||
@ -285,12 +281,12 @@ ChainDB.prototype.getHeight = async function getHeight(hash) {
|
||||
if (hash === encoding.NULL_HASH)
|
||||
return -1;
|
||||
|
||||
entry = this.cacheHash.get(hash);
|
||||
const entry = this.cacheHash.get(hash);
|
||||
|
||||
if (entry)
|
||||
return entry.height;
|
||||
|
||||
height = await this.db.get(layout.h(hash));
|
||||
const height = await this.db.get(layout.h(hash));
|
||||
|
||||
if (!height)
|
||||
return -1;
|
||||
@ -307,8 +303,6 @@ ChainDB.prototype.getHeight = async function getHeight(hash) {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.getHash = async function getHash(height) {
|
||||
let entry, hash;
|
||||
|
||||
if (typeof height === 'string')
|
||||
return height;
|
||||
|
||||
@ -317,12 +311,12 @@ ChainDB.prototype.getHash = async function getHash(height) {
|
||||
if (height < 0)
|
||||
return;
|
||||
|
||||
entry = this.cacheHeight.get(height);
|
||||
const entry = this.cacheHeight.get(height);
|
||||
|
||||
if (entry)
|
||||
return entry.hash;
|
||||
|
||||
hash = await this.db.get(layout.H(height));
|
||||
const hash = await this.db.get(layout.H(height));
|
||||
|
||||
if (!hash)
|
||||
return;
|
||||
@ -338,27 +332,26 @@ ChainDB.prototype.getHash = async function getHash(height) {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.getEntryByHeight = async function getEntryByHeight(height) {
|
||||
let state, entry, hash;
|
||||
|
||||
assert(typeof height === 'number');
|
||||
|
||||
if (height < 0)
|
||||
return;
|
||||
|
||||
entry = this.cacheHeight.get(height);
|
||||
const cache = this.cacheHeight.get(height);
|
||||
|
||||
if (entry)
|
||||
return entry;
|
||||
if (cache)
|
||||
return cache;
|
||||
|
||||
hash = await this.db.get(layout.H(height));
|
||||
let hash = await this.db.get(layout.H(height));
|
||||
|
||||
if (!hash)
|
||||
return;
|
||||
|
||||
hash = hash.toString('hex');
|
||||
state = this.chain.state;
|
||||
|
||||
entry = await this.getEntryByHash(hash);
|
||||
const state = this.chain.state;
|
||||
|
||||
const entry = await this.getEntryByHash(hash);
|
||||
|
||||
if (!entry)
|
||||
return;
|
||||
@ -380,24 +373,22 @@ ChainDB.prototype.getEntryByHeight = async function getEntryByHeight(height) {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.getEntryByHash = async function getEntryByHash(hash) {
|
||||
let entry, raw;
|
||||
|
||||
assert(typeof hash === 'string');
|
||||
|
||||
if (hash === encoding.NULL_HASH)
|
||||
return;
|
||||
|
||||
entry = this.cacheHash.get(hash);
|
||||
const cache = this.cacheHash.get(hash);
|
||||
|
||||
if (entry)
|
||||
return entry;
|
||||
if (cache)
|
||||
return cache;
|
||||
|
||||
raw = await this.db.get(layout.e(hash));
|
||||
const raw = await this.db.get(layout.e(hash));
|
||||
|
||||
if (!raw)
|
||||
return;
|
||||
|
||||
entry = ChainEntry.fromRaw(this.chain, raw);
|
||||
const entry = ChainEntry.fromRaw(this.chain, raw);
|
||||
|
||||
// There's no efficient way to check whether
|
||||
// this is in the main chain or not, so
|
||||
@ -626,13 +617,12 @@ ChainDB.prototype.writeDeployments = function writeDeployments(batch) {
|
||||
|
||||
ChainDB.prototype.checkDeployments = async function checkDeployments() {
|
||||
const raw = await this.db.get(layout.V);
|
||||
const invalid = [];
|
||||
let br, count;
|
||||
|
||||
assert(raw, 'No deployment table found.');
|
||||
|
||||
br = new BufferReader(raw);
|
||||
count = br.readU8();
|
||||
const br = new BufferReader(raw);
|
||||
const count = br.readU8();
|
||||
const invalid = [];
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const bit = br.readU8();
|
||||
@ -663,7 +653,7 @@ ChainDB.prototype.checkDeployments = async function checkDeployments() {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.verifyDeployments = async function verifyDeployments() {
|
||||
let invalid, batch;
|
||||
let invalid;
|
||||
|
||||
try {
|
||||
invalid = await this.checkDeployments();
|
||||
@ -678,7 +668,7 @@ ChainDB.prototype.verifyDeployments = async function verifyDeployments() {
|
||||
if (invalid.length === 0)
|
||||
return true;
|
||||
|
||||
batch = this.db.batch();
|
||||
const batch = this.db.batch();
|
||||
|
||||
for (const bit of invalid) {
|
||||
this.logger.warning('Versionbit deployment params modified.');
|
||||
@ -721,9 +711,8 @@ ChainDB.prototype.prune = async function prune(tip) {
|
||||
const options = this.options;
|
||||
const keepBlocks = this.network.block.keepBlocks;
|
||||
const pruneAfter = this.network.block.pruneAfterHeight;
|
||||
let flags = await this.getFlags();
|
||||
const height = await this.getHeight(tip);
|
||||
let start, end, batch;
|
||||
|
||||
const flags = await this.getFlags();
|
||||
|
||||
if (flags.prune)
|
||||
throw new Error('Chain is already pruned.');
|
||||
@ -731,9 +720,10 @@ ChainDB.prototype.prune = async function prune(tip) {
|
||||
if (height <= pruneAfter + keepBlocks)
|
||||
return false;
|
||||
|
||||
start = pruneAfter + 1;
|
||||
end = height - keepBlocks;
|
||||
batch = this.db.batch();
|
||||
const height = await this.getHeight(tip);
|
||||
const start = pruneAfter + 1;
|
||||
const end = height - keepBlocks;
|
||||
const batch = this.db.batch();
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
const hash = await this.getHash(i);
|
||||
@ -748,7 +738,7 @@ ChainDB.prototype.prune = async function prune(tip) {
|
||||
try {
|
||||
options.prune = true;
|
||||
|
||||
flags = ChainFlags.fromOptions(options);
|
||||
const flags = ChainFlags.fromOptions(options);
|
||||
assert(flags.prune);
|
||||
|
||||
batch.put(layout.O, flags.toRaw());
|
||||
@ -788,8 +778,6 @@ ChainDB.prototype.getNextHash = async function getNextHash(hash) {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.isMainChain = async function isMainChain(hash) {
|
||||
let entry;
|
||||
|
||||
assert(typeof hash === 'string');
|
||||
|
||||
if (hash === this.chain.tip.hash
|
||||
@ -800,7 +788,7 @@ ChainDB.prototype.isMainChain = async function isMainChain(hash) {
|
||||
if (hash === encoding.NULL_HASH)
|
||||
return false;
|
||||
|
||||
entry = this.cacheHash.get(hash);
|
||||
let entry = this.cacheHash.get(hash);
|
||||
|
||||
if (entry) {
|
||||
entry = this.cacheHeight.get(entry.height);
|
||||
@ -849,20 +837,19 @@ ChainDB.prototype.getTips = function getTips() {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.readCoin = async function readCoin(prevout) {
|
||||
const {hash, index} = prevout;
|
||||
const key = prevout.toKey();
|
||||
const state = this.state;
|
||||
let raw;
|
||||
|
||||
if (this.options.spv)
|
||||
return;
|
||||
|
||||
raw = this.coinCache.get(key);
|
||||
const {hash, index} = prevout;
|
||||
const key = prevout.toKey();
|
||||
const state = this.state;
|
||||
|
||||
if (raw)
|
||||
return CoinEntry.fromRaw(raw);
|
||||
const cache = this.coinCache.get(key);
|
||||
|
||||
raw = await this.db.get(layout.c(hash, index));
|
||||
if (cache)
|
||||
return CoinEntry.fromRaw(cache);
|
||||
|
||||
const raw = await this.db.get(layout.c(hash, index));
|
||||
|
||||
if (!raw)
|
||||
return;
|
||||
@ -943,12 +930,10 @@ ChainDB.prototype.getSpentView = async function getSpentView(tx) {
|
||||
const view = await this.getCoinView(tx);
|
||||
|
||||
for (const [hash, coins] of view.map) {
|
||||
let meta;
|
||||
|
||||
if (!coins.isEmpty())
|
||||
continue;
|
||||
|
||||
meta = await this.getMeta(hash);
|
||||
const meta = await this.getMeta(hash);
|
||||
|
||||
if (!meta)
|
||||
continue;
|
||||
@ -968,8 +953,10 @@ ChainDB.prototype.getSpentView = async function getSpentView(tx) {
|
||||
|
||||
ChainDB.prototype.getUndoCoins = async function getUndoCoins(hash) {
|
||||
const data = await this.db.get(layout.u(hash));
|
||||
|
||||
if (!data)
|
||||
return new UndoCoins();
|
||||
|
||||
return UndoCoins.fromRaw(data);
|
||||
};
|
||||
|
||||
@ -997,12 +984,10 @@ ChainDB.prototype.getBlock = async function getBlock(hash) {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.getRawBlock = async function getRawBlock(block) {
|
||||
let hash;
|
||||
|
||||
if (this.options.spv)
|
||||
return;
|
||||
|
||||
hash = await this.getHash(block);
|
||||
const hash = await this.getHash(block);
|
||||
|
||||
if (!hash)
|
||||
return;
|
||||
@ -1047,12 +1032,10 @@ ChainDB.prototype.getBlockView = async function getBlockView(block) {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.getMeta = async function getMeta(hash) {
|
||||
let data;
|
||||
|
||||
if (!this.options.indexTX)
|
||||
return;
|
||||
|
||||
data = await this.db.get(layout.t(hash));
|
||||
const data = await this.db.get(layout.t(hash));
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
@ -1176,7 +1159,6 @@ ChainDB.prototype.getTXByAddress = async function getTXByAddress(addrs) {
|
||||
|
||||
ChainDB.prototype.getMetaByAddress = async function getTXByAddress(addrs) {
|
||||
const txs = [];
|
||||
let hashes;
|
||||
|
||||
if (!this.options.indexTX || !this.options.indexAddress)
|
||||
return txs;
|
||||
@ -1184,7 +1166,7 @@ ChainDB.prototype.getMetaByAddress = async function getTXByAddress(addrs) {
|
||||
if (!Array.isArray(addrs))
|
||||
addrs = [addrs];
|
||||
|
||||
hashes = await this.getHashesByAddress(addrs);
|
||||
const hashes = await this.getHashesByAddress(addrs);
|
||||
|
||||
for (const hash of hashes) {
|
||||
const tx = await this.getMeta(hash);
|
||||
@ -1205,9 +1187,6 @@ ChainDB.prototype.getMetaByAddress = async function getTXByAddress(addrs) {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.scan = async function scan(start, filter, iter) {
|
||||
let total = 0;
|
||||
let entry;
|
||||
|
||||
if (start == null)
|
||||
start = this.network.genesis.hash;
|
||||
|
||||
@ -1216,7 +1195,7 @@ ChainDB.prototype.scan = async function scan(start, filter, iter) {
|
||||
else
|
||||
this.logger.info('Scanning from block %s.', util.revHex(start));
|
||||
|
||||
entry = await this.getEntry(start);
|
||||
let entry = await this.getEntry(start);
|
||||
|
||||
if (!entry)
|
||||
return;
|
||||
@ -1224,6 +1203,8 @@ ChainDB.prototype.scan = async function scan(start, filter, iter) {
|
||||
if (!(await entry.isMainChain()))
|
||||
throw new Error('Cannot rescan an alternate chain.');
|
||||
|
||||
let total = 0;
|
||||
|
||||
while (entry) {
|
||||
const block = await this.getBlock(entry.hash);
|
||||
const txs = [];
|
||||
@ -1419,10 +1400,9 @@ ChainDB.prototype._reconnect = async function reconnect(entry, block, view) {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.disconnect = async function disconnect(entry, block) {
|
||||
let view;
|
||||
|
||||
this.start();
|
||||
|
||||
let view;
|
||||
try {
|
||||
view = await this._disconnect(entry, block);
|
||||
} catch (e) {
|
||||
@ -1445,8 +1425,6 @@ ChainDB.prototype.disconnect = async function disconnect(entry, block) {
|
||||
*/
|
||||
|
||||
ChainDB.prototype._disconnect = async function disconnect(entry, block) {
|
||||
let view;
|
||||
|
||||
// Remove hash->next-block index.
|
||||
this.del(layout.n(entry.prevBlock));
|
||||
|
||||
@ -1458,7 +1436,7 @@ ChainDB.prototype._disconnect = async function disconnect(entry, block) {
|
||||
this.saveUpdates();
|
||||
|
||||
// Disconnect inputs.
|
||||
view = await this.disconnectBlock(entry, block);
|
||||
const view = await this.disconnectBlock(entry, block);
|
||||
|
||||
// Revert chain state to previous tip.
|
||||
this.put(layout.R, this.pending.commit(entry.prevBlock));
|
||||
@ -1495,7 +1473,6 @@ ChainDB.prototype.saveUpdates = function saveUpdates() {
|
||||
|
||||
ChainDB.prototype.reset = async function reset(block) {
|
||||
const entry = await this.getEntry(block);
|
||||
let tip;
|
||||
|
||||
if (!entry)
|
||||
throw new Error('Block not found.');
|
||||
@ -1512,7 +1489,7 @@ ChainDB.prototype.reset = async function reset(block) {
|
||||
// the chain.
|
||||
await this.removeChains();
|
||||
|
||||
tip = await this.getTip();
|
||||
let tip = await this.getTip();
|
||||
assert(tip);
|
||||
|
||||
this.logger.debug('Resetting main chain to: %s', entry.rhash());
|
||||
@ -1660,12 +1637,10 @@ ChainDB.prototype.saveBlock = async function saveBlock(entry, block, view) {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.removeBlock = async function removeBlock(entry) {
|
||||
let block;
|
||||
|
||||
if (this.options.spv)
|
||||
return;
|
||||
|
||||
block = await this.getBlock(entry.hash);
|
||||
const block = await this.getBlock(entry.hash);
|
||||
|
||||
if (!block)
|
||||
throw new Error('Block not found.');
|
||||
@ -1684,15 +1659,13 @@ ChainDB.prototype.removeBlock = async function removeBlock(entry) {
|
||||
ChainDB.prototype.saveView = function saveView(view) {
|
||||
for (const [hash, coins] of view.map) {
|
||||
for (const [index, coin] of coins.outputs) {
|
||||
let raw;
|
||||
|
||||
if (coin.spent) {
|
||||
this.del(layout.c(hash, index));
|
||||
this.coinCache.unpush(hash + index);
|
||||
continue;
|
||||
}
|
||||
|
||||
raw = coin.toRaw();
|
||||
const raw = coin.toRaw();
|
||||
|
||||
this.put(layout.c(hash, index), raw);
|
||||
this.coinCache.push(hash + index, raw);
|
||||
@ -1710,11 +1683,11 @@ ChainDB.prototype.saveView = function saveView(view) {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.connectBlock = async function connectBlock(entry, block, view) {
|
||||
const hash = block.hash();
|
||||
|
||||
if (this.options.spv)
|
||||
return;
|
||||
|
||||
const hash = block.hash();
|
||||
|
||||
this.pending.connect(block);
|
||||
|
||||
// Genesis block's coinbase is unspendable.
|
||||
@ -1761,14 +1734,12 @@ ChainDB.prototype.connectBlock = async function connectBlock(entry, block, view)
|
||||
*/
|
||||
|
||||
ChainDB.prototype.disconnectBlock = async function disconnectBlock(entry, block) {
|
||||
const view = new CoinView();
|
||||
const hash = block.hash();
|
||||
let undo;
|
||||
|
||||
if (this.options.spv)
|
||||
return view;
|
||||
|
||||
undo = await this.getUndoCoins(hash);
|
||||
const view = new CoinView();
|
||||
const hash = block.hash();
|
||||
const undo = await this.getUndoCoins(hash);
|
||||
|
||||
this.pending.disconnect(block);
|
||||
|
||||
@ -1822,20 +1793,18 @@ ChainDB.prototype.disconnectBlock = async function disconnectBlock(entry, block)
|
||||
*/
|
||||
|
||||
ChainDB.prototype.pruneBlock = async function pruneBlock(entry) {
|
||||
let height, hash;
|
||||
|
||||
if (this.options.spv)
|
||||
return;
|
||||
|
||||
if (!this.options.prune)
|
||||
return;
|
||||
|
||||
height = entry.height - this.network.block.keepBlocks;
|
||||
const height = entry.height - this.network.block.keepBlocks;
|
||||
|
||||
if (height <= this.network.block.pruneAfterHeight)
|
||||
return;
|
||||
|
||||
hash = await this.getHash(height);
|
||||
const hash = await this.getHash(height);
|
||||
|
||||
if (!hash)
|
||||
return;
|
||||
@ -2044,11 +2013,10 @@ ChainFlags.prototype.toRaw = function toRaw() {
|
||||
|
||||
ChainFlags.prototype.fromRaw = function fromRaw(data) {
|
||||
const br = new BufferReader(data);
|
||||
let flags;
|
||||
|
||||
this.network = Network.fromMagic(br.readU32());
|
||||
|
||||
flags = br.readU32();
|
||||
const flags = br.readU32();
|
||||
|
||||
this.spv = (flags & 1) !== 0;
|
||||
this.witness = (flags & 2) !== 0;
|
||||
@ -2177,11 +2145,10 @@ StateCache.prototype.set = function set(bit, entry, state) {
|
||||
|
||||
StateCache.prototype.get = function get(bit, entry) {
|
||||
const cache = this.bits[bit];
|
||||
let state;
|
||||
|
||||
assert(cache);
|
||||
|
||||
state = cache.get(entry.hash);
|
||||
const state = cache.get(entry.hash);
|
||||
|
||||
if (state == null)
|
||||
return -1;
|
||||
|
||||
@ -166,14 +166,12 @@ ChainEntry.prototype.isGenesis = function isGenesis() {
|
||||
*/
|
||||
|
||||
ChainEntry.prototype.isMainChain = async function isMainChain() {
|
||||
let entry;
|
||||
|
||||
if (this.hash === this.chain.tip.hash
|
||||
|| this.hash === this.chain.network.genesis.hash) {
|
||||
return true;
|
||||
}
|
||||
|
||||
entry = this.chain.db.getCache(this.height);
|
||||
const entry = this.chain.db.getCache(this.height);
|
||||
|
||||
if (entry) {
|
||||
if (entry.hash === this.hash)
|
||||
@ -195,8 +193,6 @@ ChainEntry.prototype.isMainChain = async function isMainChain() {
|
||||
*/
|
||||
|
||||
ChainEntry.prototype.getAncestor = async function getAncestor(height) {
|
||||
let entry = this;
|
||||
|
||||
if (height < 0)
|
||||
return;
|
||||
|
||||
@ -206,6 +202,7 @@ ChainEntry.prototype.getAncestor = async function getAncestor(height) {
|
||||
if (await this.isMainChain())
|
||||
return await this.chain.db.getEntry(height);
|
||||
|
||||
let entry = this;
|
||||
while (entry.height !== height) {
|
||||
entry = await entry.getPrevious();
|
||||
assert(entry);
|
||||
@ -273,7 +270,6 @@ ChainEntry.prototype.getNextEntry = async function getNextEntry() {
|
||||
|
||||
ChainEntry.prototype.getMedianTime = async function getMedianTime(time) {
|
||||
let timespan = ChainEntry.MEDIAN_TIMESPAN;
|
||||
let entry = this;
|
||||
const median = [];
|
||||
|
||||
// In case we ever want to check
|
||||
@ -284,12 +280,11 @@ ChainEntry.prototype.getMedianTime = async function getMedianTime(time) {
|
||||
timespan -= 1;
|
||||
}
|
||||
|
||||
let entry = this;
|
||||
for (let i = 0; i < timespan && entry; i++) {
|
||||
let cache;
|
||||
|
||||
median.push(entry.time);
|
||||
|
||||
cache = entry.getPrevCache();
|
||||
const cache = entry.getPrevCache();
|
||||
|
||||
if (cache) {
|
||||
entry = cache;
|
||||
|
||||
@ -335,11 +335,10 @@ Amount.btc = function btc(value, num) {
|
||||
*/
|
||||
|
||||
Amount.serialize = function serialize(value, exp, num) {
|
||||
let negative = false;
|
||||
let hi, lo, result;
|
||||
|
||||
assert(util.isInt(value), 'Non-satoshi value for conversion.');
|
||||
|
||||
let negative = false;
|
||||
|
||||
if (value < 0) {
|
||||
value = -value;
|
||||
negative = true;
|
||||
@ -352,15 +351,15 @@ Amount.serialize = function serialize(value, exp, num) {
|
||||
while (value.length < exp + 1)
|
||||
value = '0' + value;
|
||||
|
||||
hi = value.slice(0, -exp);
|
||||
lo = value.slice(-exp);
|
||||
const hi = value.slice(0, -exp);
|
||||
let lo = value.slice(-exp);
|
||||
|
||||
lo = lo.replace(/0+$/, '');
|
||||
|
||||
if (lo.length === 0)
|
||||
lo += '0';
|
||||
|
||||
result = `${hi}.${lo}`;
|
||||
let result = `${hi}.${lo}`;
|
||||
|
||||
if (negative)
|
||||
result = '-' + result;
|
||||
@ -425,12 +424,6 @@ Amount.value = function _value(value, num) {
|
||||
*/
|
||||
|
||||
Amount.parse = function parse(value, exp, num) {
|
||||
let negative = false;
|
||||
const mult = pow10(exp);
|
||||
const maxLo = modSafe(mult);
|
||||
const maxHi = divSafe(mult);
|
||||
let parts, hi, lo, result;
|
||||
|
||||
if (num && typeof value === 'number') {
|
||||
assert(util.isNumber(value), 'Non-BTC value for conversion.');
|
||||
value = value.toString(10);
|
||||
@ -438,17 +431,22 @@ Amount.parse = function parse(value, exp, num) {
|
||||
|
||||
assert(util.isFloat(value), 'Non-BTC value for conversion.');
|
||||
|
||||
const mult = pow10(exp);
|
||||
const maxLo = modSafe(mult);
|
||||
const maxHi = divSafe(mult);
|
||||
let negative = false;
|
||||
|
||||
if (value[0] === '-') {
|
||||
negative = true;
|
||||
value = value.substring(1);
|
||||
}
|
||||
|
||||
parts = value.split('.');
|
||||
const parts = value.split('.');
|
||||
|
||||
assert(parts.length <= 2, 'Bad decimal point.');
|
||||
|
||||
hi = parts[0] || '0';
|
||||
lo = parts[1] || '0';
|
||||
let hi = parts[0] || '0';
|
||||
let lo = parts[1] || '0';
|
||||
|
||||
hi = hi.replace(/^0+/, '');
|
||||
lo = lo.replace(/0+$/, '');
|
||||
@ -468,7 +466,7 @@ Amount.parse = function parse(value, exp, num) {
|
||||
assert(hi < maxHi || (hi === maxHi && lo <= maxLo),
|
||||
'Number exceeds 2^53-1.');
|
||||
|
||||
result = hi * mult + lo;
|
||||
let result = hi * mult + lo;
|
||||
|
||||
if (negative)
|
||||
result = -result;
|
||||
|
||||
@ -93,32 +93,31 @@ URI.fromOptions = function fromOptions(options) {
|
||||
*/
|
||||
|
||||
URI.prototype.fromString = function fromString(str, network) {
|
||||
let prefix, index, query, address;
|
||||
|
||||
assert(typeof str === 'string');
|
||||
assert(str.length > 8, 'Not a bitcoin URI.');
|
||||
|
||||
prefix = str.substring(0, 8);
|
||||
const prefix = str.substring(0, 8);
|
||||
|
||||
assert(prefix === 'bitcoin:', 'Not a bitcoin URI.');
|
||||
|
||||
str = str.substring(8);
|
||||
|
||||
index = str.indexOf('?');
|
||||
const index = str.indexOf('?');
|
||||
|
||||
let addr, qs;
|
||||
if (index === -1) {
|
||||
address = str;
|
||||
addr = str;
|
||||
} else {
|
||||
address = str.substring(0, index);
|
||||
query = str.substring(index + 1);
|
||||
addr = str.substring(0, index);
|
||||
qs = str.substring(index + 1);
|
||||
}
|
||||
|
||||
this.address.fromString(address, network);
|
||||
this.address.fromString(addr, network);
|
||||
|
||||
if (!query)
|
||||
if (!qs)
|
||||
return this;
|
||||
|
||||
query = parsePairs(query);
|
||||
const query = parsePairs(qs);
|
||||
|
||||
if (query.amount) {
|
||||
assert(query.amount.length > 0, 'Value is empty.');
|
||||
@ -156,10 +155,11 @@ URI.fromString = function fromString(str, network) {
|
||||
|
||||
URI.prototype.toString = function toString() {
|
||||
let str = 'bitcoin:';
|
||||
const query = [];
|
||||
|
||||
str += this.address.toString();
|
||||
|
||||
const query = [];
|
||||
|
||||
if (this.amount !== -1)
|
||||
query.push(`amount=${Amount.btc(this.amount)}`);
|
||||
|
||||
|
||||
@ -148,12 +148,10 @@ CoinEntry.fromTX = function fromTX(tx, index, height) {
|
||||
*/
|
||||
|
||||
CoinEntry.prototype.getSize = function getSize() {
|
||||
let size;
|
||||
|
||||
if (this.raw)
|
||||
return this.raw.length;
|
||||
|
||||
size = 0;
|
||||
let size = 0;
|
||||
size += encoding.sizeVarint(this.version);
|
||||
size += 4;
|
||||
size += compress.size(this.output);
|
||||
@ -167,15 +165,14 @@ CoinEntry.prototype.getSize = function getSize() {
|
||||
*/
|
||||
|
||||
CoinEntry.prototype.toWriter = function toWriter(bw) {
|
||||
let flags = 0;
|
||||
let height = this.height;
|
||||
let field;
|
||||
|
||||
if (this.raw) {
|
||||
bw.writeBytes(this.raw);
|
||||
return bw;
|
||||
}
|
||||
|
||||
let height = this.height;
|
||||
let flags = 0;
|
||||
|
||||
// We save 29 bits for the height.
|
||||
// This should be good for the next 4000 years.
|
||||
if (height === -1)
|
||||
@ -184,7 +181,7 @@ CoinEntry.prototype.toWriter = function toWriter(bw) {
|
||||
if (this.coinbase)
|
||||
flags |= 1;
|
||||
|
||||
field = (height * 8) | flags;
|
||||
const field = (height * 8) | flags;
|
||||
|
||||
bw.writeVarint(this.version);
|
||||
bw.writeU32(field);
|
||||
@ -199,13 +196,11 @@ CoinEntry.prototype.toWriter = function toWriter(bw) {
|
||||
*/
|
||||
|
||||
CoinEntry.prototype.toRaw = function toRaw() {
|
||||
let size, bw;
|
||||
|
||||
if (this.raw)
|
||||
return this.raw;
|
||||
|
||||
size = this.getSize();
|
||||
bw = new StaticWriter(size);
|
||||
const size = this.getSize();
|
||||
const bw = new StaticWriter(size);
|
||||
|
||||
this.toWriter(bw);
|
||||
|
||||
@ -221,18 +216,16 @@ CoinEntry.prototype.toRaw = function toRaw() {
|
||||
*/
|
||||
|
||||
CoinEntry.prototype.fromReader = function fromReader(br) {
|
||||
let field, flags, height;
|
||||
const version = br.readVarint();
|
||||
const field = br.readU32();
|
||||
|
||||
this.version = br.readVarint();
|
||||
|
||||
field = br.readU32();
|
||||
|
||||
height = field / 8 | 0;
|
||||
flags = field & 0x07;
|
||||
const flags = field & 0x07;
|
||||
let height = field / 8 | 0;
|
||||
|
||||
if (height === 0x1fffffff)
|
||||
height = -1;
|
||||
|
||||
this.version = version;
|
||||
this.coinbase = (flags & 1) !== 0;
|
||||
this.height = height;
|
||||
|
||||
|
||||
@ -189,12 +189,11 @@ CoinView.prototype.addOutput = function addOutput(prevout, output) {
|
||||
CoinView.prototype.spendEntry = function spendEntry(prevout) {
|
||||
const {hash, index} = prevout;
|
||||
const coins = this.get(hash);
|
||||
let coin;
|
||||
|
||||
if (!coins)
|
||||
return null;
|
||||
|
||||
coin = coins.spend(index);
|
||||
const coin = coins.spend(index);
|
||||
|
||||
if (!coin)
|
||||
return null;
|
||||
@ -408,12 +407,12 @@ CoinView.prototype.isCoinbaseFor = function isCoinbaseFor(input) {
|
||||
*/
|
||||
|
||||
CoinView.prototype.readCoin = async function readCoin(db, prevout) {
|
||||
let coin = this.getEntry(prevout);
|
||||
const cache = this.getEntry(prevout);
|
||||
|
||||
if (coin)
|
||||
return coin;
|
||||
if (cache)
|
||||
return cache;
|
||||
|
||||
coin = await db.readCoin(prevout);
|
||||
const coin = await db.readCoin(prevout);
|
||||
|
||||
if (!coin)
|
||||
return null;
|
||||
@ -451,12 +450,11 @@ CoinView.prototype.readInputs = async function readInputs(db, tx) {
|
||||
CoinView.prototype.spendInputs = async function spendInputs(db, tx) {
|
||||
if (tx.inputs.length < 4) {
|
||||
const jobs = [];
|
||||
let coins;
|
||||
|
||||
for (const {prevout} of tx.inputs)
|
||||
jobs.push(this.readCoin(db, prevout));
|
||||
|
||||
coins = await Promise.all(jobs);
|
||||
const coins = await Promise.all(jobs);
|
||||
|
||||
for (const coin of coins) {
|
||||
if (!coin || coin.spent)
|
||||
@ -537,12 +535,10 @@ CoinView.prototype.toWriter = function toWriter(bw, tx) {
|
||||
|
||||
CoinView.prototype.fromReader = function fromReader(br, tx) {
|
||||
for (const {prevout} of tx.inputs) {
|
||||
let coin;
|
||||
|
||||
if (br.readU8() === 0)
|
||||
continue;
|
||||
|
||||
coin = CoinEntry.fromReader(br);
|
||||
const coin = CoinEntry.fromReader(br);
|
||||
|
||||
this.addEntry(prevout, coin);
|
||||
}
|
||||
|
||||
@ -58,9 +58,9 @@ function compressScript(script, bw) {
|
||||
// Only works if the key is valid.
|
||||
// Saves up to 35 bytes.
|
||||
if (script.isPubkey(true)) {
|
||||
let key = script.code[0].data;
|
||||
if (publicKeyVerify(key)) {
|
||||
key = compressKey(key);
|
||||
const data = script.code[0].data;
|
||||
if (publicKeyVerify(data)) {
|
||||
const key = compressKey(data);
|
||||
bw.writeBytes(key);
|
||||
return bw;
|
||||
}
|
||||
@ -80,42 +80,44 @@ function compressScript(script, bw) {
|
||||
*/
|
||||
|
||||
function decompressScript(script, br) {
|
||||
let size, data;
|
||||
|
||||
// Decompress the script.
|
||||
switch (br.readU8()) {
|
||||
case 0:
|
||||
data = br.readBytes(20, true);
|
||||
script.fromPubkeyhash(data);
|
||||
case 0: {
|
||||
const hash = br.readBytes(20, true);
|
||||
script.fromPubkeyhash(hash);
|
||||
break;
|
||||
case 1:
|
||||
data = br.readBytes(20, true);
|
||||
script.fromScripthash(data);
|
||||
}
|
||||
case 1: {
|
||||
const hash = br.readBytes(20, true);
|
||||
script.fromScripthash(hash);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 5: {
|
||||
br.offset -= 1;
|
||||
data = br.readBytes(33, true);
|
||||
const data = br.readBytes(33, true);
|
||||
// Decompress the key. If this fails,
|
||||
// we have database corruption!
|
||||
data = decompressKey(data);
|
||||
script.fromPubkey(data);
|
||||
const key = decompressKey(data);
|
||||
script.fromPubkey(key);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
br.offset -= 1;
|
||||
size = br.readVarint() - COMPRESS_TYPES;
|
||||
const size = br.readVarint() - COMPRESS_TYPES;
|
||||
if (size > consensus.MAX_SCRIPT_SIZE) {
|
||||
// This violates consensus rules.
|
||||
// We don't need to read it.
|
||||
script.fromNulldata(EMPTY_BUFFER);
|
||||
br.seek(size);
|
||||
} else {
|
||||
data = br.readBytes(size);
|
||||
const data = br.readBytes(size);
|
||||
script.fromRaw(data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return script;
|
||||
@ -127,8 +129,6 @@ function decompressScript(script, br) {
|
||||
*/
|
||||
|
||||
function sizeScript(script) {
|
||||
let size;
|
||||
|
||||
if (script.isPubkeyhash(true))
|
||||
return 21;
|
||||
|
||||
@ -141,7 +141,7 @@ function sizeScript(script) {
|
||||
return 33;
|
||||
}
|
||||
|
||||
size = 0;
|
||||
let size = 0;
|
||||
size += encoding.sizeVarint(script.raw.length + COMPRESS_TYPES);
|
||||
size += script.raw.length;
|
||||
|
||||
@ -193,19 +193,17 @@ function sizeOutput(output) {
|
||||
*/
|
||||
|
||||
function compressValue(value) {
|
||||
let exp, last;
|
||||
|
||||
if (value === 0)
|
||||
return 0;
|
||||
|
||||
exp = 0;
|
||||
let exp = 0;
|
||||
while (value % 10 === 0 && exp < 9) {
|
||||
value /= 10;
|
||||
exp++;
|
||||
}
|
||||
|
||||
if (exp < 9) {
|
||||
last = value % 10;
|
||||
const last = value % 10;
|
||||
value = (value - last) / 10;
|
||||
return 1 + 10 * (9 * value + last - 1) + exp;
|
||||
}
|
||||
@ -220,18 +218,18 @@ function compressValue(value) {
|
||||
*/
|
||||
|
||||
function decompressValue(value) {
|
||||
let exp, n, last;
|
||||
|
||||
if (value === 0)
|
||||
return 0;
|
||||
|
||||
value--;
|
||||
|
||||
exp = value % 10;
|
||||
let exp = value % 10;
|
||||
|
||||
value = (value - exp) / 10;
|
||||
|
||||
let n;
|
||||
if (exp < 9) {
|
||||
last = value % 9;
|
||||
const last = value % 9;
|
||||
value = (value - last) / 9;
|
||||
n = value * 10 + last + 1;
|
||||
} else {
|
||||
@ -309,7 +307,6 @@ function compressKey(key) {
|
||||
|
||||
function decompressKey(key) {
|
||||
const format = key[0];
|
||||
let out;
|
||||
|
||||
assert(key.length === 33);
|
||||
|
||||
@ -328,7 +325,7 @@ function decompressKey(key) {
|
||||
}
|
||||
|
||||
// Decompress the key.
|
||||
out = secp256k1.publicKeyConvert(key, false);
|
||||
const out = secp256k1.publicKeyConvert(key, false);
|
||||
|
||||
// Reset the first byte so as not to
|
||||
// mutate the original buffer.
|
||||
|
||||
@ -123,7 +123,8 @@ AEAD.prototype.auth = function auth(data) {
|
||||
|
||||
AEAD.prototype.finish = function finish() {
|
||||
const len = Buffer.allocUnsafe(16);
|
||||
let lo, hi;
|
||||
let lo = 0;
|
||||
let hi = 0;
|
||||
|
||||
// The RFC says these are supposed to be
|
||||
// uint32le, but their own fucking test
|
||||
@ -154,14 +155,12 @@ AEAD.prototype.finish = function finish() {
|
||||
*/
|
||||
|
||||
AEAD.prototype.pad16 = function pad16(size) {
|
||||
let pad;
|
||||
|
||||
size %= 16;
|
||||
|
||||
if (size === 0)
|
||||
return;
|
||||
|
||||
pad = Buffer.allocUnsafe(16 - size);
|
||||
const pad = Buffer.allocUnsafe(16 - size);
|
||||
pad.fill(0);
|
||||
|
||||
this.poly1305.update(pad);
|
||||
|
||||
@ -86,16 +86,14 @@ AESKey.prototype.destroy = function destroy() {
|
||||
*/
|
||||
|
||||
AESKey.prototype.getEncryptKey = function getEncryptKey() {
|
||||
let i = 0;
|
||||
let key, kp;
|
||||
|
||||
assert(this.userKey, 'Cannot use key once it is destroyed.');
|
||||
|
||||
if (this.encryptKey)
|
||||
return this.encryptKey;
|
||||
|
||||
key = new Uint32Array(60);
|
||||
kp = 0;
|
||||
const key = new Uint32Array(60);
|
||||
let kp = 0;
|
||||
let i = 0;
|
||||
|
||||
key[kp + 0] = readU32(this.userKey, 0);
|
||||
key[kp + 1] = readU32(this.userKey, 4);
|
||||
@ -195,17 +193,15 @@ AESKey.prototype.getEncryptKey = function getEncryptKey() {
|
||||
*/
|
||||
|
||||
AESKey.prototype.getDecryptKey = function getDecryptKey() {
|
||||
let kp, enc, key;
|
||||
|
||||
assert(this.userKey, 'Cannot use key once it is destroyed.');
|
||||
|
||||
if (this.decryptKey)
|
||||
return this.decryptKey;
|
||||
|
||||
// First, start with an encryption schedule.
|
||||
enc = this.getEncryptKey();
|
||||
key = new Uint32Array(60);
|
||||
kp = 0;
|
||||
const enc = this.getEncryptKey();
|
||||
const key = new Uint32Array(60);
|
||||
let kp = 0;
|
||||
|
||||
for (let i = 0; i < enc.length; i++)
|
||||
key[i] = enc[i];
|
||||
@ -264,22 +260,21 @@ AESKey.prototype.getDecryptKey = function getDecryptKey() {
|
||||
*/
|
||||
|
||||
AESKey.prototype.encryptBlock = function encryptBlock(input) {
|
||||
let output, kp, key, r, s0, s1, s2, s3, t0, t1, t2, t3;
|
||||
|
||||
assert(this.userKey, 'Cannot use key once it is destroyed.');
|
||||
|
||||
key = this.getEncryptKey();
|
||||
kp = 0;
|
||||
const key = this.getEncryptKey();
|
||||
let kp = 0;
|
||||
|
||||
// Map byte array block to cipher
|
||||
// state and add initial round key.
|
||||
s0 = readU32(input, 0) ^ key[0];
|
||||
s1 = readU32(input, 4) ^ key[1];
|
||||
s2 = readU32(input, 8) ^ key[2];
|
||||
s3 = readU32(input, 12) ^ key[3];
|
||||
let s0 = readU32(input, 0) ^ key[0];
|
||||
let s1 = readU32(input, 4) ^ key[1];
|
||||
let s2 = readU32(input, 8) ^ key[2];
|
||||
let s3 = readU32(input, 12) ^ key[3];
|
||||
|
||||
// Nr - 1 full rounds
|
||||
r = this.rounds >>> 1;
|
||||
let r = this.rounds >>> 1;
|
||||
let t0, t1, t2, t3;
|
||||
|
||||
for (;;) {
|
||||
t0 = TE0[(s0 >>> 24) & 0xff]
|
||||
@ -353,7 +348,7 @@ AESKey.prototype.encryptBlock = function encryptBlock(input) {
|
||||
^ (TE1[(t2 >>> 0) & 0xff] & 0x000000ff)
|
||||
^ key[kp + 3];
|
||||
|
||||
output = Buffer.allocUnsafe(16);
|
||||
const output = Buffer.allocUnsafe(16);
|
||||
writeU32(output, s0, 0);
|
||||
writeU32(output, s1, 4);
|
||||
writeU32(output, s2, 8);
|
||||
@ -369,22 +364,21 @@ AESKey.prototype.encryptBlock = function encryptBlock(input) {
|
||||
*/
|
||||
|
||||
AESKey.prototype.decryptBlock = function decryptBlock(input) {
|
||||
let output, kp, key, r, s0, s1, s2, s3, t0, t1, t2, t3;
|
||||
|
||||
assert(this.userKey, 'Cannot use AESKey once it is destroyed.');
|
||||
|
||||
key = this.getDecryptKey();
|
||||
kp = 0;
|
||||
const key = this.getDecryptKey();
|
||||
let kp = 0;
|
||||
|
||||
// Map byte array block to cipher
|
||||
// state and add initial round key.
|
||||
s0 = readU32(input, 0) ^ key[kp + 0];
|
||||
s1 = readU32(input, 4) ^ key[kp + 1];
|
||||
s2 = readU32(input, 8) ^ key[kp + 2];
|
||||
s3 = readU32(input, 12) ^ key[kp + 3];
|
||||
let s0 = readU32(input, 0) ^ key[kp + 0];
|
||||
let s1 = readU32(input, 4) ^ key[kp + 1];
|
||||
let s2 = readU32(input, 8) ^ key[kp + 2];
|
||||
let s3 = readU32(input, 12) ^ key[kp + 3];
|
||||
|
||||
// Nr - 1 full rounds
|
||||
r = this.rounds >>> 1;
|
||||
let r = this.rounds >>> 1;
|
||||
let t0, t1, t2, t3;
|
||||
|
||||
for (;;) {
|
||||
t0 = TD0[(s0 >>> 24) & 0xff]
|
||||
@ -458,7 +452,7 @@ AESKey.prototype.decryptBlock = function decryptBlock(input) {
|
||||
^ (TD4[(t0 >>> 0) & 0xff] << 0)
|
||||
^ key[kp + 3];
|
||||
|
||||
output = Buffer.allocUnsafe(16);
|
||||
const output = Buffer.allocUnsafe(16);
|
||||
writeU32(output, s0, 0);
|
||||
writeU32(output, s1, 4);
|
||||
writeU32(output, s2, 8);
|
||||
@ -497,15 +491,14 @@ function AESCipher(key, iv, bits, mode) {
|
||||
|
||||
AESCipher.prototype.update = function update(data) {
|
||||
const blocks = [];
|
||||
let trailing, len;
|
||||
|
||||
if (this.waiting) {
|
||||
data = concat(this.waiting, data);
|
||||
this.waiting = null;
|
||||
}
|
||||
|
||||
trailing = data.length % 16;
|
||||
len = data.length - trailing;
|
||||
const trailing = data.length % 16;
|
||||
const len = data.length - trailing;
|
||||
|
||||
// Encrypt all blocks except for the last.
|
||||
for (let i = 0; i < len; i += 16) {
|
||||
@ -583,24 +576,22 @@ function AESDecipher(key, iv, bits, mode) {
|
||||
|
||||
AESDecipher.prototype.update = function update(data) {
|
||||
const blocks = [];
|
||||
let trailing, len;
|
||||
|
||||
if (this.waiting) {
|
||||
data = concat(this.waiting, data);
|
||||
this.waiting = null;
|
||||
}
|
||||
|
||||
trailing = data.length % 16;
|
||||
len = data.length - trailing;
|
||||
const trailing = data.length % 16;
|
||||
const len = data.length - trailing;
|
||||
|
||||
// Decrypt all blocks.
|
||||
for (let i = 0; i < len; i += 16) {
|
||||
const chunk = this.prev;
|
||||
let block;
|
||||
|
||||
this.prev = data.slice(i, i + 16);
|
||||
|
||||
block = this.key.decryptBlock(this.prev);
|
||||
let block = this.key.decryptBlock(this.prev);
|
||||
|
||||
if (this.mode === 'cbc')
|
||||
block = xor(block, chunk);
|
||||
@ -629,17 +620,15 @@ AESDecipher.prototype.update = function update(data) {
|
||||
*/
|
||||
|
||||
AESDecipher.prototype.final = function final() {
|
||||
let b, n, block;
|
||||
|
||||
this.key.destroy();
|
||||
|
||||
assert(!this.waiting, 'Bad decrypt (trailing bytes).');
|
||||
assert(this.lastBlock, 'Bad decrypt (no data).');
|
||||
|
||||
// Check padding on the last block.
|
||||
block = this.lastBlock;
|
||||
b = 16;
|
||||
n = block[b - 1];
|
||||
let block = this.lastBlock;
|
||||
let b = 16;
|
||||
const n = block[b - 1];
|
||||
|
||||
if (n === 0 || n > b)
|
||||
throw new Error('Bad decrypt (padding).');
|
||||
|
||||
@ -19,8 +19,6 @@
|
||||
*/
|
||||
|
||||
module.exports = function ccmp(a, b) {
|
||||
let res;
|
||||
|
||||
if (!Buffer.isBuffer(a))
|
||||
return false;
|
||||
|
||||
@ -30,7 +28,7 @@ module.exports = function ccmp(a, b) {
|
||||
if (b.length === 0)
|
||||
return a.length === 0;
|
||||
|
||||
res = a.length ^ b.length;
|
||||
let res = a.length ^ b.length;
|
||||
|
||||
for (let i = 0; i < a.length; i++)
|
||||
res |= a[i] ^ b[i % b.length];
|
||||
|
||||
@ -148,13 +148,11 @@ ChaCha20.prototype.encrypt = function encrypt(data) {
|
||||
*/
|
||||
|
||||
ChaCha20.prototype.setCounter = function setCounter(counter) {
|
||||
let lo, hi;
|
||||
|
||||
if (!counter)
|
||||
counter = 0;
|
||||
|
||||
lo = counter % 0x100000000;
|
||||
hi = (counter - lo) / 0x100000000;
|
||||
const lo = counter % 0x100000000;
|
||||
const hi = (counter - lo) / 0x100000000;
|
||||
|
||||
this.state[12] = lo;
|
||||
|
||||
|
||||
@ -24,12 +24,10 @@ const POOL64 = Buffer.allocUnsafe(64);
|
||||
*/
|
||||
|
||||
exports.hash = function _hash(alg, data) {
|
||||
let hash;
|
||||
|
||||
if (alg === 'sha256')
|
||||
return sha256.digest(data);
|
||||
|
||||
hash = hashjs[alg];
|
||||
const hash = hashjs[alg];
|
||||
|
||||
assert(hash != null, 'Unknown algorithm.');
|
||||
|
||||
@ -115,11 +113,10 @@ exports.root256 = function root256(left, right) {
|
||||
|
||||
exports.hmac = function _hmac(alg, data, key) {
|
||||
const hash = hashjs[alg];
|
||||
let hmac;
|
||||
|
||||
assert(hash != null, 'Unknown algorithm.');
|
||||
|
||||
hmac = hashjs.hmac(hash, key);
|
||||
const hmac = hashjs.hmac(hash, key);
|
||||
|
||||
return Buffer.from(hmac.update(data).digest());
|
||||
};
|
||||
|
||||
@ -25,16 +25,14 @@ const digest = require('./digest');
|
||||
*/
|
||||
|
||||
exports.verify = function verify(curve, alg, msg, sig, key) {
|
||||
let ec, hash;
|
||||
|
||||
assert(typeof curve === 'string', 'No curve selected.');
|
||||
assert(typeof alg === 'string', 'No algorithm selected.');
|
||||
assert(Buffer.isBuffer(msg));
|
||||
assert(Buffer.isBuffer(sig));
|
||||
assert(Buffer.isBuffer(key));
|
||||
|
||||
ec = elliptic.ec(curve);
|
||||
hash = digest.hash(alg, msg);
|
||||
const ec = elliptic.ec(curve);
|
||||
const hash = digest.hash(alg, msg);
|
||||
|
||||
try {
|
||||
return ec.verify(hash, sig, key);
|
||||
@ -54,17 +52,14 @@ exports.verify = function verify(curve, alg, msg, sig, key) {
|
||||
*/
|
||||
|
||||
exports.sign = function sign(curve, alg, msg, key) {
|
||||
let ec, hash, sig;
|
||||
|
||||
assert(typeof curve === 'string', 'No curve selected.');
|
||||
assert(typeof alg === 'string', 'No algorithm selected.');
|
||||
assert(Buffer.isBuffer(msg));
|
||||
assert(Buffer.isBuffer(key));
|
||||
|
||||
ec = elliptic.ec(curve);
|
||||
hash = digest.hash(alg, msg);
|
||||
|
||||
sig = ec.sign(hash, key, { canonical: true });
|
||||
const ec = elliptic.ec(curve);
|
||||
const hash = digest.hash(alg, msg);
|
||||
const sig = ec.sign(hash, key, { canonical: true });
|
||||
|
||||
return Buffer.from(sig.toDER());
|
||||
};
|
||||
|
||||
@ -36,22 +36,22 @@ exports.extract = function extract(ikm, key, alg) {
|
||||
exports.expand = function expand(prk, info, len, alg) {
|
||||
const size = digest.hash(alg, Buffer.alloc(0)).length;
|
||||
const blocks = Math.ceil(len / size);
|
||||
let okm, buf, out;
|
||||
|
||||
if (blocks > 255)
|
||||
throw new Error('Too many blocks.');
|
||||
|
||||
okm = Buffer.allocUnsafe(len);
|
||||
const okm = Buffer.allocUnsafe(len);
|
||||
|
||||
if (blocks === 0)
|
||||
return okm;
|
||||
|
||||
buf = Buffer.allocUnsafe(size + info.length + 1);
|
||||
const buf = Buffer.allocUnsafe(size + info.length + 1);
|
||||
|
||||
// First round:
|
||||
info.copy(buf, size);
|
||||
buf[buf.length - 1] = 1;
|
||||
out = digest.hmac(alg, buf.slice(size), prk);
|
||||
|
||||
let out = digest.hmac(alg, buf.slice(size), prk);
|
||||
out.copy(okm, 0);
|
||||
|
||||
for (let i = 1; i < blocks; i++) {
|
||||
|
||||
@ -36,14 +36,13 @@ exports.createTree = function createTree(leaves) {
|
||||
const k = Math.min(j + 1, size - 1);
|
||||
const left = nodes[i + j];
|
||||
const right = nodes[i + k];
|
||||
let hash;
|
||||
|
||||
if (k === j + 1 && k + 1 === size
|
||||
&& left.equals(right)) {
|
||||
malleated = true;
|
||||
}
|
||||
|
||||
hash = digest.root256(left, right);
|
||||
const hash = digest.root256(left, right);
|
||||
|
||||
nodes.push(hash);
|
||||
}
|
||||
|
||||
@ -36,9 +36,8 @@ exports.derive = function derive(key, salt, iter, len, alg) {
|
||||
salt.copy(buf, 0);
|
||||
|
||||
for (let i = 0; i < blocks; i++) {
|
||||
let mac;
|
||||
buf.writeUInt32BE(i + 1, salt.length, true);
|
||||
mac = digest.hmac(alg, buf, key);
|
||||
let mac = digest.hmac(alg, buf, key);
|
||||
mac.copy(block, 0);
|
||||
for (let j = 1; j < iter; j++) {
|
||||
mac = digest.hmac(alg, mac, key);
|
||||
@ -65,20 +64,19 @@ exports.derive = function derive(key, salt, iter, len, alg) {
|
||||
exports.deriveAsync = async function deriveAsync(key, salt, iter, len, alg) {
|
||||
const algo = { name: 'PBKDF2' };
|
||||
const use = ['deriveBits'];
|
||||
let options, imported, data;
|
||||
|
||||
if (!subtle.importKey || !subtle.deriveBits)
|
||||
return exports.derive(key, salt, iter, len, alg);
|
||||
|
||||
options = {
|
||||
const options = {
|
||||
name: 'PBKDF2',
|
||||
salt: salt,
|
||||
iterations: iter,
|
||||
hash: getHash(alg)
|
||||
};
|
||||
|
||||
imported = await subtle.importKey('raw', key, algo, false, use);
|
||||
data = await subtle.deriveBits(options, imported, len * 8);
|
||||
const imported = await subtle.importKey('raw', key, algo, false, use);
|
||||
const data = await subtle.deriveBits(options, imported, len * 8);
|
||||
|
||||
return Buffer.from(data);
|
||||
};
|
||||
|
||||
@ -10,7 +10,7 @@ const native = require('../native').binding;
|
||||
|
||||
/**
|
||||
* Poly1305 (used for bip151)
|
||||
* @alias module:crypto.Poly1305
|
||||
* @alias module:crypto/chachapoly.Poly1305
|
||||
* @constructor
|
||||
* @see https://github.com/floodyberry/poly1305-donna
|
||||
* @see https://tools.ietf.org/html/rfc7539#section-2.5
|
||||
@ -88,7 +88,6 @@ Poly1305.prototype.blocks = function blocks(data, bytes, m) {
|
||||
const t5 = data.readUInt16LE(m + 10, true);
|
||||
const t6 = data.readUInt16LE(m + 12, true);
|
||||
const t7 = data.readUInt16LE(m + 14, true);
|
||||
let c = 0;
|
||||
|
||||
this.h[0] += t0 & 0x1fff;
|
||||
this.h[1] += ((t0 >>> 13) | (t1 << 3)) & 0x1fff;
|
||||
@ -102,14 +101,19 @@ Poly1305.prototype.blocks = function blocks(data, bytes, m) {
|
||||
this.h[9] += ((t7 >>> 5)) | hibit;
|
||||
|
||||
// h *= r, (partial) h %= p
|
||||
let c = 0;
|
||||
for (let i = 0; i < 10; i++) {
|
||||
d[i] = c;
|
||||
|
||||
for (let j = 0; j < 10; j++) {
|
||||
let a = this.h[j];
|
||||
|
||||
if (j <= i)
|
||||
d[i] += this.r[i - j];
|
||||
a *= this.r[i - j];
|
||||
else
|
||||
d[i] += 5 * this.r[i + 10 - j];
|
||||
a *= 5 * this.r[i + 10 - j];
|
||||
|
||||
d[i] += a;
|
||||
|
||||
// Sum(h[i] * r[i] * 5) will overflow slightly
|
||||
// above 6 products with an unclamped r, so
|
||||
@ -151,21 +155,15 @@ Poly1305.prototype.update = function update(data) {
|
||||
// handle leftover
|
||||
if (this.leftover) {
|
||||
let want = 16 - this.leftover;
|
||||
|
||||
if (want > bytes)
|
||||
want = bytes;
|
||||
|
||||
for (let i = 0; i < want; i++)
|
||||
this.buffer[this.leftover + i] = data[m + i];
|
||||
|
||||
bytes -= want;
|
||||
m += want;
|
||||
|
||||
this.leftover += want;
|
||||
|
||||
if (this.leftover < 16)
|
||||
return;
|
||||
|
||||
this.blocks(this.buffer, 16, 0);
|
||||
this.leftover = 0;
|
||||
}
|
||||
@ -194,7 +192,6 @@ Poly1305.prototype.update = function update(data) {
|
||||
Poly1305.prototype.finish = function finish() {
|
||||
const mac = Buffer.allocUnsafe(16);
|
||||
const g = new Uint16Array(10);
|
||||
let c, mask, f;
|
||||
|
||||
// process the remaining block
|
||||
if (this.leftover) {
|
||||
@ -207,7 +204,7 @@ Poly1305.prototype.finish = function finish() {
|
||||
}
|
||||
|
||||
// fully carry h
|
||||
c = this.h[1] >>> 13;
|
||||
let c = this.h[1] >>> 13;
|
||||
this.h[1] &= 0x1fff;
|
||||
for (let i = 2; i < 10; i++) {
|
||||
this.h[i] += c;
|
||||
@ -233,7 +230,7 @@ Poly1305.prototype.finish = function finish() {
|
||||
}
|
||||
|
||||
// select h if h < p, or h + -p if h >= p
|
||||
mask = (c ^ 1) - 1;
|
||||
let mask = (c ^ 1) - 1;
|
||||
for (let i = 0; i < 10; i++)
|
||||
g[i] &= mask;
|
||||
mask = ~mask;
|
||||
@ -252,7 +249,7 @@ Poly1305.prototype.finish = function finish() {
|
||||
this.h[7] = ((this.h[8] >>> 8) | (this.h[9] << 5)) & 0xffff;
|
||||
|
||||
// mac = (h + pad) % (2^128)
|
||||
f = this.h[0] + this.pad[0];
|
||||
let f = this.h[0] + this.pad[0];
|
||||
this.h[0] = f;
|
||||
for (let i = 1; i < 8; i++) {
|
||||
f = this.h[i] + this.pad[i] + (f >>> 16);
|
||||
@ -265,10 +262,8 @@ Poly1305.prototype.finish = function finish() {
|
||||
// zero out the state
|
||||
for (let i = 0; i < 10; i++)
|
||||
this.h[i] = 0;
|
||||
|
||||
for (let i = 0; i < 10; i++)
|
||||
this.r[i] = 0;
|
||||
|
||||
for (let i = 0; i < 8; i++)
|
||||
this.pad[i] = 0;
|
||||
|
||||
|
||||
@ -44,33 +44,31 @@ rsa.prefixes = {
|
||||
*/
|
||||
|
||||
rsa.verify = function verify(alg, msg, sig, key) {
|
||||
const prefix = rsa.prefixes[alg];
|
||||
let hash, len, pub;
|
||||
let N, e, k, m, em, ok;
|
||||
|
||||
assert(typeof alg === 'string', 'No algorithm selected.');
|
||||
assert(Buffer.isBuffer(msg));
|
||||
assert(Buffer.isBuffer(sig));
|
||||
assert(Buffer.isBuffer(key));
|
||||
|
||||
const prefix = rsa.prefixes[alg];
|
||||
|
||||
if (!prefix)
|
||||
throw new Error('Unknown PKCS prefix.');
|
||||
|
||||
hash = digest.hash(alg, msg);
|
||||
len = prefix.length + hash.length;
|
||||
pub = ASN1.parseRSAPublic(key);
|
||||
const hash = digest.hash(alg, msg);
|
||||
const len = prefix.length + hash.length;
|
||||
const pub = ASN1.parseRSAPublic(key);
|
||||
|
||||
N = new BN(pub.modulus);
|
||||
e = new BN(pub.publicExponent);
|
||||
k = Math.ceil(N.bitLength() / 8);
|
||||
const N = new BN(pub.modulus);
|
||||
const e = new BN(pub.publicExponent);
|
||||
const k = Math.ceil(N.bitLength() / 8);
|
||||
|
||||
if (k < len + 11)
|
||||
throw new Error('Message too long.');
|
||||
|
||||
m = rsa.encrypt(N, e, sig);
|
||||
em = leftpad(m, k);
|
||||
const m = rsa.encrypt(N, e, sig);
|
||||
const em = leftpad(m, k);
|
||||
|
||||
ok = ceq(em[0], 0x00);
|
||||
let ok = ceq(em[0], 0x00);
|
||||
ok &= ceq(em[1], 0x01);
|
||||
ok &= ccmp(em.slice(k - hash.length, k), hash);
|
||||
ok &= ccmp(em.slice(k - len, k - hash.length), prefix);
|
||||
@ -91,29 +89,27 @@ rsa.verify = function verify(alg, msg, sig, key) {
|
||||
*/
|
||||
|
||||
rsa.sign = function sign(alg, msg, key) {
|
||||
const prefix = rsa.prefixes[alg];
|
||||
let hash, len, priv;
|
||||
let N, D, k, em;
|
||||
|
||||
assert(typeof alg === 'string', 'No algorithm selected.');
|
||||
assert(Buffer.isBuffer(msg));
|
||||
assert(Buffer.isBuffer(key));
|
||||
|
||||
const prefix = rsa.prefixes[alg];
|
||||
|
||||
if (!prefix)
|
||||
throw new Error('Unknown PKCS prefix.');
|
||||
|
||||
hash = digest.hash(alg, msg);
|
||||
len = prefix.length + hash.length;
|
||||
priv = ASN1.parseRSAPrivate(key);
|
||||
const hash = digest.hash(alg, msg);
|
||||
const len = prefix.length + hash.length;
|
||||
const priv = ASN1.parseRSAPrivate(key);
|
||||
|
||||
N = new BN(priv.modulus);
|
||||
D = new BN(priv.privateExponent);
|
||||
k = Math.ceil(N.bitLength() / 8);
|
||||
const N = new BN(priv.modulus);
|
||||
const D = new BN(priv.privateExponent);
|
||||
const k = Math.ceil(N.bitLength() / 8);
|
||||
|
||||
if (k < len + 11)
|
||||
throw new Error('Message too long.');
|
||||
|
||||
em = Buffer.allocUnsafe(k);
|
||||
const em = Buffer.allocUnsafe(k);
|
||||
em.fill(0);
|
||||
|
||||
em[1] = 0x01;
|
||||
@ -169,12 +165,11 @@ rsa.encrypt = function encrypt(N, e, m) {
|
||||
|
||||
function leftpad(input, size) {
|
||||
let n = input.length;
|
||||
let out;
|
||||
|
||||
if (n > size)
|
||||
n = size;
|
||||
|
||||
out = Buffer.allocUnsafe(size);
|
||||
const out = Buffer.allocUnsafe(size);
|
||||
out.fill(0);
|
||||
|
||||
input.copy(out, out.length - n);
|
||||
|
||||
@ -24,17 +24,14 @@ const PEM = require('../utils/pem');
|
||||
*/
|
||||
|
||||
exports.verify = function verify(alg, msg, sig, key) {
|
||||
let pem, name, ctx;
|
||||
|
||||
assert(typeof alg === 'string', 'No algorithm selected.');
|
||||
assert(Buffer.isBuffer(msg));
|
||||
assert(Buffer.isBuffer(sig));
|
||||
assert(Buffer.isBuffer(key));
|
||||
|
||||
name = normalizeAlg('rsa', alg);
|
||||
pem = PEM.encode(key, 'rsa', 'public key');
|
||||
|
||||
ctx = crypto.createVerify(name);
|
||||
const name = normalizeAlg('rsa', alg);
|
||||
const pem = PEM.encode(key, 'rsa', 'public key');
|
||||
const ctx = crypto.createVerify(name);
|
||||
|
||||
try {
|
||||
ctx.update(msg);
|
||||
@ -53,16 +50,14 @@ exports.verify = function verify(alg, msg, sig, key) {
|
||||
*/
|
||||
|
||||
exports.sign = function sign(alg, msg, key) {
|
||||
let pem, name, ctx;
|
||||
|
||||
assert(typeof alg === 'string', 'No algorithm selected.');
|
||||
assert(Buffer.isBuffer(msg));
|
||||
assert(Buffer.isBuffer(key));
|
||||
|
||||
name = normalizeAlg('rsa', alg);
|
||||
pem = PEM.encode(key, 'rsa', 'private key');
|
||||
const name = normalizeAlg('rsa', alg);
|
||||
const pem = PEM.encode(key, 'rsa', 'private key');
|
||||
const ctx = crypto.createSign(name);
|
||||
|
||||
ctx = crypto.createSign(name);
|
||||
ctx.update(msg);
|
||||
|
||||
return ctx.sign(pem);
|
||||
|
||||
@ -49,8 +49,6 @@ schnorr.hash = function _hash(msg, r) {
|
||||
*/
|
||||
|
||||
schnorr.trySign = function trySign(msg, prv, k, pn) {
|
||||
let r, h, s;
|
||||
|
||||
if (prv.cmpn(0) === 0)
|
||||
throw new Error('Bad private key.');
|
||||
|
||||
@ -63,7 +61,7 @@ schnorr.trySign = function trySign(msg, prv, k, pn) {
|
||||
if (k.cmp(curve.n) >= 0)
|
||||
return null;
|
||||
|
||||
r = curve.g.mul(k);
|
||||
let r = curve.g.mul(k);
|
||||
|
||||
if (pn)
|
||||
r = r.add(pn);
|
||||
@ -73,7 +71,7 @@ schnorr.trySign = function trySign(msg, prv, k, pn) {
|
||||
k = curve.n.sub(k);
|
||||
}
|
||||
|
||||
h = schnorr.hash(msg, r.getX());
|
||||
const h = schnorr.hash(msg, r.getX());
|
||||
|
||||
if (h.cmpn(0) === 0)
|
||||
return null;
|
||||
@ -81,7 +79,7 @@ schnorr.trySign = function trySign(msg, prv, k, pn) {
|
||||
if (h.cmp(curve.n) >= 0)
|
||||
return null;
|
||||
|
||||
s = h.imul(prv);
|
||||
let s = h.imul(prv);
|
||||
s = k.isub(s);
|
||||
s = s.umod(curve.n);
|
||||
|
||||
@ -103,13 +101,14 @@ schnorr.sign = function sign(msg, key, pubNonce) {
|
||||
const prv = new BN(key);
|
||||
const drbg = schnorr.drbg(msg, key, pubNonce);
|
||||
const len = curve.n.byteLength();
|
||||
let k, pn, sig;
|
||||
let pn = null;
|
||||
let sig = null;
|
||||
|
||||
if (pubNonce)
|
||||
pn = curve.decodePoint(pubNonce);
|
||||
|
||||
while (!sig) {
|
||||
k = new BN(drbg.generate(len));
|
||||
const k = new BN(drbg.generate(len));
|
||||
sig = schnorr.trySign(msg, prv, k, pn);
|
||||
}
|
||||
|
||||
@ -127,7 +126,6 @@ schnorr.sign = function sign(msg, key, pubNonce) {
|
||||
schnorr.verify = function verify(msg, signature, key) {
|
||||
const sig = new Signature(signature);
|
||||
const h = schnorr.hash(msg, sig.r);
|
||||
let k, l, r, rl;
|
||||
|
||||
if (h.cmp(curve.n) >= 0)
|
||||
throw new Error('Invalid hash.');
|
||||
@ -141,10 +139,10 @@ schnorr.verify = function verify(msg, signature, key) {
|
||||
if (sig.r.cmp(curve.p) > 0)
|
||||
throw new Error('Invalid R value.');
|
||||
|
||||
k = curve.decodePoint(key);
|
||||
l = k.mul(h);
|
||||
r = curve.g.mul(sig.s);
|
||||
rl = l.add(r);
|
||||
const k = curve.decodePoint(key);
|
||||
const l = k.mul(h);
|
||||
const r = curve.g.mul(sig.s);
|
||||
const rl = l.add(r);
|
||||
|
||||
if (rl.y.isOdd())
|
||||
throw new Error('Odd R value.');
|
||||
@ -162,7 +160,6 @@ schnorr.verify = function verify(msg, signature, key) {
|
||||
schnorr.recover = function recover(signature, msg) {
|
||||
const sig = new Signature(signature);
|
||||
const h = schnorr.hash(msg, sig.r);
|
||||
let hinv, s, R, l, r, k, rl;
|
||||
|
||||
if (h.cmp(curve.n) >= 0)
|
||||
throw new Error('Invalid hash.');
|
||||
@ -176,24 +173,25 @@ schnorr.recover = function recover(signature, msg) {
|
||||
if (sig.r.cmp(curve.p) > 0)
|
||||
throw new Error('Invalid R value.');
|
||||
|
||||
hinv = h.invm(curve.n);
|
||||
let hinv = h.invm(curve.n);
|
||||
hinv = hinv.umod(curve.n);
|
||||
|
||||
s = sig.s;
|
||||
let s = sig.s;
|
||||
s = curve.n.sub(s);
|
||||
s = s.umod(curve.n);
|
||||
|
||||
s = s.imul(hinv);
|
||||
s = s.umod(curve.n);
|
||||
|
||||
R = curve.pointFromX(sig.r, false);
|
||||
l = R.mul(hinv);
|
||||
r = curve.g.mul(s);
|
||||
k = l.add(r);
|
||||
const R = curve.pointFromX(sig.r, false);
|
||||
let l = R.mul(hinv);
|
||||
let r = curve.g.mul(s);
|
||||
const k = l.add(r);
|
||||
|
||||
l = k.mul(h);
|
||||
r = curve.g.mul(sig.s);
|
||||
rl = l.add(r);
|
||||
|
||||
const rl = l.add(r);
|
||||
|
||||
if (rl.y.isOdd())
|
||||
throw new Error('Odd R value.');
|
||||
@ -212,7 +210,8 @@ schnorr.recover = function recover(signature, msg) {
|
||||
|
||||
schnorr.combineSigs = function combineSigs(sigs) {
|
||||
let s = new BN(0);
|
||||
let r, last;
|
||||
let r = null;
|
||||
let last = null;
|
||||
|
||||
for (let i = 0; i < sigs.length; i++) {
|
||||
const sig = new Signature(sigs[i]);
|
||||
@ -248,18 +247,16 @@ schnorr.combineSigs = function combineSigs(sigs) {
|
||||
*/
|
||||
|
||||
schnorr.combineKeys = function combineKeys(keys) {
|
||||
let i, key, point;
|
||||
|
||||
if (keys.length === 0)
|
||||
throw new Error();
|
||||
|
||||
if (keys.length === 1)
|
||||
return keys[0];
|
||||
|
||||
point = curve.decodePoint(keys[0]);
|
||||
let point = curve.decodePoint(keys[0]);
|
||||
|
||||
for (i = 1; i < keys.length; i++) {
|
||||
key = curve.decodePoint(keys[i]);
|
||||
for (let i = 1; i < keys.length; i++) {
|
||||
const key = curve.decodePoint(keys[i]);
|
||||
point = point.add(key);
|
||||
}
|
||||
|
||||
|
||||
@ -56,8 +56,6 @@ const native = require('../native').binding;
|
||||
*/
|
||||
|
||||
function derive(passwd, salt, N, r, p, len) {
|
||||
let B, V, XY;
|
||||
|
||||
if (r * p >= (1 << 30))
|
||||
throw new Error('EFBIG');
|
||||
|
||||
@ -67,10 +65,10 @@ function derive(passwd, salt, N, r, p, len) {
|
||||
if (N > 0xffffffff)
|
||||
throw new Error('EINVAL');
|
||||
|
||||
XY = Buffer.allocUnsafe(256 * r);
|
||||
V = Buffer.allocUnsafe(128 * r * N);
|
||||
const XY = Buffer.allocUnsafe(256 * r);
|
||||
const V = Buffer.allocUnsafe(128 * r * N);
|
||||
|
||||
B = pbkdf2.derive(passwd, salt, 1, p * 128 * r, 'sha256');
|
||||
const B = pbkdf2.derive(passwd, salt, 1, p * 128 * r, 'sha256');
|
||||
|
||||
for (let i = 0; i < p; i++)
|
||||
smix(B, i * 128 * r, r, N, V, XY);
|
||||
@ -95,8 +93,6 @@ if (native)
|
||||
*/
|
||||
|
||||
async function deriveAsync(passwd, salt, N, r, p, len) {
|
||||
let B, V, XY;
|
||||
|
||||
if (r * p >= (1 << 30))
|
||||
throw new Error('EFBIG');
|
||||
|
||||
@ -106,10 +102,10 @@ async function deriveAsync(passwd, salt, N, r, p, len) {
|
||||
if (N > 0xffffffff)
|
||||
throw new Error('EINVAL');
|
||||
|
||||
XY = Buffer.allocUnsafe(256 * r);
|
||||
V = Buffer.allocUnsafe(128 * r * N);
|
||||
const XY = Buffer.allocUnsafe(256 * r);
|
||||
const V = Buffer.allocUnsafe(128 * r * N);
|
||||
|
||||
B = await pbkdf2.deriveAsync(passwd, salt, 1, p * 128 * r, 'sha256');
|
||||
const B = await pbkdf2.deriveAsync(passwd, salt, 1, p * 128 * r, 'sha256');
|
||||
|
||||
for (let i = 0; i < p; i++)
|
||||
await smixAsync(B, i * 128 * r, r, N, V, XY);
|
||||
|
||||
@ -46,14 +46,12 @@ ec.generatePrivateKey = function generatePrivateKey() {
|
||||
*/
|
||||
|
||||
ec.publicKeyCreate = function publicKeyCreate(priv, compress) {
|
||||
let key;
|
||||
|
||||
assert(Buffer.isBuffer(priv));
|
||||
|
||||
if (compress == null)
|
||||
compress = true;
|
||||
|
||||
key = secp256k1.keyPair({ priv: priv });
|
||||
const key = secp256k1.keyPair({ priv: priv });
|
||||
|
||||
return Buffer.from(key.getPublic(compress, 'array'));
|
||||
};
|
||||
@ -103,12 +101,11 @@ ec.privateKeyTweakAdd = function privateKeyTweakAdd(privateKey, tweak) {
|
||||
ec.publicKeyTweakAdd = function publicKeyTweakAdd(publicKey, tweak, compress) {
|
||||
const key = curve.decodePoint(publicKey);
|
||||
const point = curve.g.mul(new BN(tweak)).add(key);
|
||||
let pub;
|
||||
|
||||
if (compress == null)
|
||||
compress = true;
|
||||
|
||||
pub = Buffer.from(point.encode('array', compress));
|
||||
const pub = Buffer.from(point.encode('array', compress));
|
||||
|
||||
if (!ec.publicKeyVerify(pub))
|
||||
throw new Error('Public key is invalid.');
|
||||
@ -139,14 +136,13 @@ ec.ecdh = function ecdh(pub, priv) {
|
||||
*/
|
||||
|
||||
ec.recover = function recover(msg, sig, j, compress) {
|
||||
let point;
|
||||
|
||||
if (!j)
|
||||
j = 0;
|
||||
|
||||
if (compress == null)
|
||||
compress = true;
|
||||
|
||||
let point;
|
||||
try {
|
||||
point = secp256k1.recoverPubKey(msg, sig, j);
|
||||
} catch (e) {
|
||||
@ -224,13 +220,11 @@ ec.privateKeyVerify = function privateKeyVerify(key) {
|
||||
*/
|
||||
|
||||
ec.sign = function sign(msg, key) {
|
||||
let sig;
|
||||
|
||||
assert(Buffer.isBuffer(msg));
|
||||
assert(Buffer.isBuffer(key));
|
||||
|
||||
// Sign message and ensure low S value
|
||||
sig = secp256k1.sign(msg, key, { canonical: true });
|
||||
const sig = secp256k1.sign(msg, key, { canonical: true });
|
||||
|
||||
// Convert to DER
|
||||
return Buffer.from(sig.toDER());
|
||||
@ -238,17 +232,15 @@ ec.sign = function sign(msg, key) {
|
||||
|
||||
/**
|
||||
* Convert DER signature to R/S.
|
||||
* @param {Buffer} sig
|
||||
* @param {Buffer} raw
|
||||
* @returns {Buffer} R/S-formatted signature.
|
||||
*/
|
||||
|
||||
ec.fromDER = function fromDER(sig) {
|
||||
let out;
|
||||
ec.fromDER = function fromDER(raw) {
|
||||
assert(Buffer.isBuffer(raw));
|
||||
|
||||
assert(Buffer.isBuffer(sig));
|
||||
|
||||
sig = new Signature(sig);
|
||||
out = Buffer.allocUnsafe(64);
|
||||
const sig = new Signature(raw);
|
||||
const out = Buffer.allocUnsafe(64);
|
||||
|
||||
sig.r.toBuffer('be', 32).copy(out, 0);
|
||||
sig.s.toBuffer('be', 32).copy(out, 32);
|
||||
@ -262,17 +254,15 @@ ec.fromDER = function fromDER(sig) {
|
||||
* @returns {Buffer} DER-formatted signature.
|
||||
*/
|
||||
|
||||
ec.toDER = function toDER(sig) {
|
||||
let out;
|
||||
ec.toDER = function toDER(raw) {
|
||||
assert(Buffer.isBuffer(raw));
|
||||
|
||||
assert(Buffer.isBuffer(sig));
|
||||
|
||||
out = new Signature({
|
||||
r: new BN(sig.slice(0, 32), 'be'),
|
||||
s: new BN(sig.slice(32, 64), 'be')
|
||||
const sig = new Signature({
|
||||
r: new BN(raw.slice(0, 32), 'be'),
|
||||
s: new BN(raw.slice(32, 64), 'be')
|
||||
});
|
||||
|
||||
return Buffer.from(out.toDER());
|
||||
return Buffer.from(sig.toDER());
|
||||
};
|
||||
|
||||
/**
|
||||
@ -281,9 +271,10 @@ ec.toDER = function toDER(sig) {
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
ec.isLowS = function isLowS(sig) {
|
||||
ec.isLowS = function isLowS(raw) {
|
||||
let sig;
|
||||
try {
|
||||
sig = new Signature(sig);
|
||||
sig = new Signature(raw);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
@ -306,12 +297,11 @@ ec.isLowS = function isLowS(sig) {
|
||||
function normalizeLength(sig) {
|
||||
let data = sig;
|
||||
const p = { place: 0 };
|
||||
let len, rlen, slen;
|
||||
|
||||
if (data[p.place++] !== 0x30)
|
||||
return sig;
|
||||
|
||||
len = getLength(data, p);
|
||||
const len = getLength(data, p);
|
||||
|
||||
if (data.length > len + p.place)
|
||||
data = data.slice(0, len + p.place);
|
||||
@ -319,13 +309,13 @@ function normalizeLength(sig) {
|
||||
if (data[p.place++] !== 0x02)
|
||||
return sig;
|
||||
|
||||
rlen = getLength(data, p);
|
||||
const rlen = getLength(data, p);
|
||||
p.place += rlen;
|
||||
|
||||
if (data[p.place++] !== 0x02)
|
||||
return sig;
|
||||
|
||||
slen = getLength(data, p);
|
||||
const slen = getLength(data, p);
|
||||
if (data.length > slen + p.place)
|
||||
data = data.slice(0, slen + p.place);
|
||||
|
||||
|
||||
@ -34,13 +34,12 @@ function siphash24(data, key, shift) {
|
||||
const k0 = U64.fromRaw(key, 0);
|
||||
const k1 = U64.fromRaw(key, 8);
|
||||
let p = 0;
|
||||
let v0, v1, v2, v3;
|
||||
|
||||
// Init
|
||||
v0 = c0.ixor(k0);
|
||||
v1 = c1.ixor(k1);
|
||||
v2 = c2.ixor(k0);
|
||||
v3 = c3.ixor(k1);
|
||||
const v0 = c0.ixor(k0);
|
||||
const v1 = c1.ixor(k1);
|
||||
const v2 = c2.ixor(k0);
|
||||
const v3 = c3.ixor(k1);
|
||||
|
||||
// Blocks
|
||||
for (let i = 0; i < blocks; i++) {
|
||||
@ -153,18 +152,17 @@ function U64(hi, lo) {
|
||||
|
||||
U64.prototype.iadd = function iadd(b) {
|
||||
const a = this;
|
||||
let hi, lo, as, bs, s, c;
|
||||
|
||||
// Credit to @indutny for this method.
|
||||
lo = (a.lo + b.lo) | 0;
|
||||
const lo = (a.lo + b.lo) | 0;
|
||||
|
||||
s = lo >> 31;
|
||||
as = a.lo >> 31;
|
||||
bs = b.lo >> 31;
|
||||
const s = lo >> 31;
|
||||
const as = a.lo >> 31;
|
||||
const bs = b.lo >> 31;
|
||||
|
||||
c = ((as & bs) | (~s & (as ^ bs))) & 1;
|
||||
const c = ((as & bs) | (~s & (as ^ bs))) & 1;
|
||||
|
||||
hi = ((a.hi + b.hi) | 0) + c;
|
||||
const hi = ((a.hi + b.hi) | 0) + c;
|
||||
|
||||
a.hi = hi | 0;
|
||||
a.lo = lo;
|
||||
|
||||
@ -493,12 +493,11 @@ LowlevelUp.prototype.keys = async function _keys(options) {
|
||||
|
||||
for (;;) {
|
||||
const item = await iter.next();
|
||||
let key;
|
||||
|
||||
if (!item)
|
||||
break;
|
||||
|
||||
key = item.key;
|
||||
let key = item.key;
|
||||
|
||||
if (parse) {
|
||||
try {
|
||||
@ -536,12 +535,11 @@ LowlevelUp.prototype.values = async function _values(options) {
|
||||
|
||||
for (;;) {
|
||||
const item = await iter.next();
|
||||
let value;
|
||||
|
||||
if (!item)
|
||||
break;
|
||||
|
||||
value = item.value;
|
||||
let value = item.value;
|
||||
|
||||
if (parse) {
|
||||
try {
|
||||
@ -613,24 +611,23 @@ LowlevelUp.prototype.checkVersion = async function checkVersion(key, version) {
|
||||
*/
|
||||
|
||||
LowlevelUp.prototype.clone = async function clone(path) {
|
||||
const options = new LLUOptions(this.options);
|
||||
const hwm = 256 << 20;
|
||||
let total = 0;
|
||||
let tmp, batch, iter;
|
||||
|
||||
if (!this.loaded)
|
||||
throw new Error('Database is closed.');
|
||||
|
||||
const options = new LLUOptions(this.options);
|
||||
const hwm = 256 << 20;
|
||||
|
||||
options.createIfMissing = true;
|
||||
options.errorIfExists = true;
|
||||
|
||||
tmp = new LowlevelUp(this.backend, path, options);
|
||||
const tmp = new LowlevelUp(this.backend, path, options);
|
||||
|
||||
await tmp.open();
|
||||
|
||||
batch = tmp.batch();
|
||||
let batch = tmp.batch();
|
||||
let total = 0;
|
||||
|
||||
iter = this.iterator({
|
||||
const iter = this.iterator({
|
||||
keys: true,
|
||||
values: true
|
||||
});
|
||||
|
||||
@ -37,14 +37,12 @@ function MemDB(location) {
|
||||
*/
|
||||
|
||||
MemDB.prototype.search = function search(key) {
|
||||
let node;
|
||||
|
||||
if (typeof key === 'string')
|
||||
key = Buffer.from(key, 'utf8');
|
||||
|
||||
assert(Buffer.isBuffer(key), 'Key must be a Buffer.');
|
||||
|
||||
node = this.tree.search(key);
|
||||
const node = this.tree.search(key);
|
||||
|
||||
if (!node)
|
||||
return;
|
||||
@ -149,8 +147,6 @@ MemDB.prototype.close = function close(callback) {
|
||||
*/
|
||||
|
||||
MemDB.prototype.get = function get(key, options, callback) {
|
||||
let value;
|
||||
|
||||
if (!callback) {
|
||||
callback = options;
|
||||
options = null;
|
||||
@ -159,7 +155,7 @@ MemDB.prototype.get = function get(key, options, callback) {
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
value = this.search(key);
|
||||
let value = this.search(key);
|
||||
|
||||
if (!value) {
|
||||
const err = new Error('MEMDB_NOTFOUND: Key not found.');
|
||||
@ -221,14 +217,12 @@ MemDB.prototype.del = function del(key, options, callback) {
|
||||
*/
|
||||
|
||||
MemDB.prototype.batch = function _batch(ops, options, callback) {
|
||||
let batch;
|
||||
|
||||
if (!callback) {
|
||||
callback = options;
|
||||
options = null;
|
||||
}
|
||||
|
||||
batch = new Batch(this, options);
|
||||
const batch = new Batch(this, options);
|
||||
|
||||
if (ops) {
|
||||
batch.ops = ops;
|
||||
|
||||
@ -140,15 +140,13 @@ Mnemonic.prototype.destroy = function destroy() {
|
||||
*/
|
||||
|
||||
Mnemonic.prototype.toSeed = function toSeed(passphrase) {
|
||||
let phrase, passwd;
|
||||
|
||||
if (!passphrase)
|
||||
passphrase = this.passphrase;
|
||||
|
||||
this.passphrase = passphrase;
|
||||
|
||||
phrase = nfkd(this.getPhrase());
|
||||
passwd = nfkd('mnemonic' + passphrase);
|
||||
const phrase = nfkd(this.getPhrase());
|
||||
const passwd = nfkd('mnemonic' + passphrase);
|
||||
|
||||
return pbkdf2.derive(
|
||||
Buffer.from(phrase, 'utf8'),
|
||||
@ -176,25 +174,22 @@ Mnemonic.prototype.getEntropy = function getEntropy() {
|
||||
*/
|
||||
|
||||
Mnemonic.prototype.getPhrase = function getPhrase() {
|
||||
let phrase, wordlist, bits, ent, entropy;
|
||||
|
||||
if (this.phrase)
|
||||
return this.phrase;
|
||||
|
||||
phrase = [];
|
||||
wordlist = Mnemonic.getWordlist(this.language);
|
||||
let phrase = [];
|
||||
const wordlist = Mnemonic.getWordlist(this.language);
|
||||
|
||||
ent = this.getEntropy();
|
||||
bits = this.bits;
|
||||
const ent = this.getEntropy();
|
||||
|
||||
// Include the first `ENT / 32` bits
|
||||
// of the hash (the checksum).
|
||||
bits += bits / 32;
|
||||
const bits = this.bits + (this.bits / 32);
|
||||
|
||||
// Append the hash to the entropy to
|
||||
// make things easy when grabbing
|
||||
// the checksum bits.
|
||||
entropy = Buffer.allocUnsafe(Math.ceil(bits / 8));
|
||||
const entropy = Buffer.allocUnsafe(Math.ceil(bits / 8));
|
||||
ent.copy(entropy, 0);
|
||||
digest.sha256(ent).copy(entropy, ent.length);
|
||||
|
||||
@ -234,9 +229,6 @@ Mnemonic.prototype.fromPhrase = function fromPhrase(phrase) {
|
||||
let bits = words.length * 11;
|
||||
const cbits = bits % 32;
|
||||
const cbytes = Math.ceil(cbits / 8);
|
||||
const lang = Mnemonic.getLanguage(words[0]);
|
||||
const wordlist = Mnemonic.getWordlist(lang);
|
||||
let ent, entropy, chk;
|
||||
|
||||
bits -= cbits;
|
||||
|
||||
@ -245,9 +237,12 @@ Mnemonic.prototype.fromPhrase = function fromPhrase(phrase) {
|
||||
assert(bits % 32 === 0);
|
||||
assert(cbits !== 0, 'Invalid checksum.');
|
||||
|
||||
ent = Buffer.allocUnsafe(Math.ceil((bits + cbits) / 8));
|
||||
const ent = Buffer.allocUnsafe(Math.ceil((bits + cbits) / 8));
|
||||
ent.fill(0);
|
||||
|
||||
const lang = Mnemonic.getLanguage(words[0]);
|
||||
const wordlist = Mnemonic.getWordlist(lang);
|
||||
|
||||
// Rebuild entropy bytes.
|
||||
for (let i = 0; i < words.length; i++) {
|
||||
const word = words[i];
|
||||
@ -265,16 +260,16 @@ Mnemonic.prototype.fromPhrase = function fromPhrase(phrase) {
|
||||
}
|
||||
}
|
||||
|
||||
entropy = ent.slice(0, ent.length - cbytes);
|
||||
ent = ent.slice(ent.length - cbytes);
|
||||
chk = digest.sha256(entropy);
|
||||
const entropy = ent.slice(0, ent.length - cbytes);
|
||||
const chk1 = ent.slice(ent.length - cbytes);
|
||||
const chk2 = digest.sha256(entropy);
|
||||
|
||||
// Verify checksum.
|
||||
for (let i = 0; i < cbits; i++) {
|
||||
const bit = i % 8;
|
||||
const oct = (i - bit) / 8;
|
||||
const a = (ent[oct] >>> (7 - bit)) & 1;
|
||||
const b = (chk[oct] >>> (7 - bit)) & 1;
|
||||
const a = (chk1[oct] >>> (7 - bit)) & 1;
|
||||
const b = (chk2[oct] >>> (7 - bit)) & 1;
|
||||
if (a !== b)
|
||||
throw new Error('Invalid checksum.');
|
||||
}
|
||||
@ -342,10 +337,8 @@ Mnemonic.fromEntropy = function fromEntropy(entropy, lang) {
|
||||
*/
|
||||
|
||||
Mnemonic.getLanguage = function getLanguage(word) {
|
||||
let lang, wordlist;
|
||||
|
||||
for (lang of Mnemonic.languages) {
|
||||
wordlist = Mnemonic.getWordlist(lang);
|
||||
for (const lang of Mnemonic.languages) {
|
||||
const wordlist = Mnemonic.getWordlist(lang);
|
||||
if (util.binarySearch(wordlist, word, util.strcmp) !== -1)
|
||||
return lang;
|
||||
}
|
||||
|
||||
@ -178,8 +178,6 @@ HDPrivateKey.prototype.destroy = function destroy(pub) {
|
||||
*/
|
||||
|
||||
HDPrivateKey.prototype.derive = function derive(index, hardened) {
|
||||
let bw, id, data, hash, left, right, key, child;
|
||||
|
||||
assert(typeof index === 'number');
|
||||
|
||||
if (hardened && index < common.HARDENED)
|
||||
@ -191,13 +189,13 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
|
||||
if (this.depth >= 0xff)
|
||||
throw new Error('Depth too high.');
|
||||
|
||||
id = this.getID(index);
|
||||
child = common.cache.get(id);
|
||||
const id = this.getID(index);
|
||||
const cache = common.cache.get(id);
|
||||
|
||||
if (child)
|
||||
return child;
|
||||
if (cache)
|
||||
return cache;
|
||||
|
||||
bw = new StaticWriter(37);
|
||||
const bw = new StaticWriter(37);
|
||||
|
||||
if (index >= common.HARDENED) {
|
||||
bw.writeU8(0);
|
||||
@ -208,12 +206,13 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
|
||||
bw.writeU32BE(index);
|
||||
}
|
||||
|
||||
data = bw.render();
|
||||
const data = bw.render();
|
||||
|
||||
hash = digest.hmac('sha512', data, this.chainCode);
|
||||
left = hash.slice(0, 32);
|
||||
right = hash.slice(32, 64);
|
||||
const hash = digest.hmac('sha512', data, this.chainCode);
|
||||
const left = hash.slice(0, 32);
|
||||
const right = hash.slice(32, 64);
|
||||
|
||||
let key;
|
||||
try {
|
||||
key = secp256k1.privateKeyTweakAdd(this.privateKey, left);
|
||||
} catch (e) {
|
||||
@ -223,7 +222,7 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
|
||||
if (!this.fingerPrint)
|
||||
this.fingerPrint = digest.hash160(this.publicKey).slice(0, 4);
|
||||
|
||||
child = new HDPrivateKey();
|
||||
const child = new HDPrivateKey();
|
||||
child.network = this.network;
|
||||
child.depth = this.depth + 1;
|
||||
child.parentFingerPrint = this.fingerPrint;
|
||||
@ -313,15 +312,13 @@ HDPrivateKey.prototype.isBIP45 = function isBIP45() {
|
||||
*/
|
||||
|
||||
HDPrivateKey.isBase58 = function isBase58(data, network) {
|
||||
let prefix;
|
||||
|
||||
if (typeof data !== 'string')
|
||||
return false;
|
||||
|
||||
if (data.length < 4)
|
||||
return false;
|
||||
|
||||
prefix = data.substring(0, 4);
|
||||
const prefix = data.substring(0, 4);
|
||||
|
||||
try {
|
||||
Network.fromPrivate58(prefix, network);
|
||||
@ -339,15 +336,13 @@ HDPrivateKey.isBase58 = function isBase58(data, network) {
|
||||
*/
|
||||
|
||||
HDPrivateKey.isRaw = function isRaw(data, network) {
|
||||
let version;
|
||||
|
||||
if (!Buffer.isBuffer(data))
|
||||
return false;
|
||||
|
||||
if (data.length < 4)
|
||||
return false;
|
||||
|
||||
version = data.readUInt32BE(0, true);
|
||||
const version = data.readUInt32BE(0, true);
|
||||
|
||||
try {
|
||||
Network.fromPrivate(version, network);
|
||||
@ -458,8 +453,6 @@ HDPrivateKey.prototype.compare = function compare(key) {
|
||||
*/
|
||||
|
||||
HDPrivateKey.prototype.fromSeed = function fromSeed(seed, network) {
|
||||
let hash, left, right;
|
||||
|
||||
assert(Buffer.isBuffer(seed));
|
||||
|
||||
if (!(seed.length * 8 >= common.MIN_ENTROPY
|
||||
@ -467,9 +460,9 @@ HDPrivateKey.prototype.fromSeed = function fromSeed(seed, network) {
|
||||
throw new Error('Entropy not in range.');
|
||||
}
|
||||
|
||||
hash = digest.hmac('sha512', seed, common.SEED_SALT);
|
||||
left = hash.slice(0, 32);
|
||||
right = hash.slice(32, 64);
|
||||
const hash = digest.hmac('sha512', seed, common.SEED_SALT);
|
||||
const left = hash.slice(0, 32);
|
||||
const right = hash.slice(32, 64);
|
||||
|
||||
// Only a 1 in 2^127 chance of happening.
|
||||
if (!secp256k1.privateKeyVerify(left))
|
||||
|
||||
@ -152,8 +152,6 @@ HDPublicKey.prototype.destroy = function destroy() {
|
||||
*/
|
||||
|
||||
HDPublicKey.prototype.derive = function derive(index, hardened) {
|
||||
let bw, id, data, hash, left, right, key, child;
|
||||
|
||||
assert(typeof index === 'number');
|
||||
|
||||
if (index >= common.HARDENED || hardened)
|
||||
@ -165,21 +163,24 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
|
||||
if (this.depth >= 0xff)
|
||||
throw new Error('Depth too high.');
|
||||
|
||||
id = this.getID(index);
|
||||
child = common.cache.get(id);
|
||||
const id = this.getID(index);
|
||||
const cache = common.cache.get(id);
|
||||
|
||||
if (child)
|
||||
return child;
|
||||
if (cache)
|
||||
return cache;
|
||||
|
||||
const bw = new StaticWriter(37);
|
||||
|
||||
bw = new StaticWriter(37);
|
||||
bw.writeBytes(this.publicKey);
|
||||
bw.writeU32BE(index);
|
||||
data = bw.render();
|
||||
|
||||
hash = digest.hmac('sha512', data, this.chainCode);
|
||||
left = hash.slice(0, 32);
|
||||
right = hash.slice(32, 64);
|
||||
const data = bw.render();
|
||||
|
||||
const hash = digest.hmac('sha512', data, this.chainCode);
|
||||
const left = hash.slice(0, 32);
|
||||
const right = hash.slice(32, 64);
|
||||
|
||||
let key;
|
||||
try {
|
||||
key = secp256k1.publicKeyTweakAdd(this.publicKey, left, true);
|
||||
} catch (e) {
|
||||
@ -189,7 +190,7 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
|
||||
if (!this.fingerPrint)
|
||||
this.fingerPrint = digest.hash160(this.publicKey).slice(0, 4);
|
||||
|
||||
child = new HDPublicKey();
|
||||
const child = new HDPublicKey();
|
||||
child.network = this.network;
|
||||
child.depth = this.depth + 1;
|
||||
child.parentFingerPrint = this.fingerPrint;
|
||||
@ -409,15 +410,13 @@ HDPublicKey.fromJSON = function fromJSON(json, network) {
|
||||
*/
|
||||
|
||||
HDPublicKey.isBase58 = function isBase58(data, network) {
|
||||
let prefix;
|
||||
|
||||
if (typeof data !== 'string')
|
||||
return false;
|
||||
|
||||
if (data.length < 4)
|
||||
return false;
|
||||
|
||||
prefix = data.substring(0, 4);
|
||||
const prefix = data.substring(0, 4);
|
||||
|
||||
try {
|
||||
Network.fromPublic58(prefix, network);
|
||||
@ -435,15 +434,13 @@ HDPublicKey.isBase58 = function isBase58(data, network) {
|
||||
*/
|
||||
|
||||
HDPublicKey.isRaw = function isRaw(data, network) {
|
||||
let version;
|
||||
|
||||
if (!Buffer.isBuffer(data))
|
||||
return false;
|
||||
|
||||
if (data.length < 4)
|
||||
return false;
|
||||
|
||||
version = data.readUInt32BE(0, true);
|
||||
const version = data.readUInt32BE(0, true);
|
||||
|
||||
try {
|
||||
Network.fromPublic(version, network);
|
||||
|
||||
@ -121,8 +121,6 @@ HTTPBase.prototype._initRouter = function _initRouter() {
|
||||
*/
|
||||
|
||||
HTTPBase.prototype.handleRequest = async function handleRequest(req, res) {
|
||||
let routes;
|
||||
|
||||
if (await this.handleMounts(req, res))
|
||||
return;
|
||||
|
||||
@ -131,7 +129,7 @@ HTTPBase.prototype.handleRequest = async function handleRequest(req, res) {
|
||||
if (await this.handleStack(req, res))
|
||||
return;
|
||||
|
||||
routes = this.routes.getHandlers(req.method);
|
||||
const routes = this.routes.getHandlers(req.method);
|
||||
|
||||
if (!routes)
|
||||
throw new Error(`No routes found for method: ${req.method}.`);
|
||||
@ -212,13 +210,12 @@ HTTPBase.prototype.basicAuth = function basicAuth(options) {
|
||||
}
|
||||
|
||||
return async (req, res) => {
|
||||
let auth = req.headers['authorization'];
|
||||
let parts, username, password, hash;
|
||||
const hdr = req.headers['authorization'];
|
||||
|
||||
if (!auth)
|
||||
if (!hdr)
|
||||
return fail(res);
|
||||
|
||||
parts = auth.split(' ');
|
||||
const parts = hdr.split(' ');
|
||||
|
||||
if (parts.length !== 2)
|
||||
return fail(res);
|
||||
@ -226,22 +223,22 @@ HTTPBase.prototype.basicAuth = function basicAuth(options) {
|
||||
if (parts[0] !== 'Basic')
|
||||
return fail(res);
|
||||
|
||||
auth = Buffer.from(parts[1], 'base64').toString('utf8');
|
||||
parts = auth.split(':');
|
||||
const auth = Buffer.from(parts[1], 'base64').toString('utf8');
|
||||
const items = auth.split(':');
|
||||
|
||||
username = parts.shift();
|
||||
password = parts.join(':');
|
||||
const username = items.shift();
|
||||
const password = items.join(':');
|
||||
|
||||
if (user) {
|
||||
hash = Buffer.from(username, 'utf8');
|
||||
hash = digest.hash256(hash);
|
||||
const raw = Buffer.from(username, 'utf8');
|
||||
const hash = digest.hash256(raw);
|
||||
|
||||
if (!ccmp(hash, user))
|
||||
return fail(res);
|
||||
}
|
||||
|
||||
hash = Buffer.from(password, 'utf8');
|
||||
hash = digest.hash256(hash);
|
||||
const raw = Buffer.from(password, 'utf8');
|
||||
const hash = digest.hash256(raw);
|
||||
|
||||
if (!ccmp(hash, pass))
|
||||
return fail(res);
|
||||
@ -284,17 +281,17 @@ HTTPBase.prototype.bodyParser = function bodyParser(options) {
|
||||
|
||||
HTTPBase.prototype.parseBody = async function parseBody(req, options) {
|
||||
let body = Object.create(null);
|
||||
let type = req.contentType;
|
||||
let data;
|
||||
|
||||
if (req.method === 'GET')
|
||||
return body;
|
||||
|
||||
data = await this.readBody(req, 'utf8', options);
|
||||
const data = await this.readBody(req, 'utf8', options);
|
||||
|
||||
if (!data)
|
||||
return body;
|
||||
|
||||
let type = req.contentType;
|
||||
|
||||
if (options.contentType)
|
||||
type = options.contentType;
|
||||
|
||||
@ -400,8 +397,6 @@ HTTPBase.prototype._readBody = function _readBody(req, enc, options, resolve, re
|
||||
|
||||
HTTPBase.prototype.jsonRPC = function jsonRPC(rpc) {
|
||||
return async (req, res) => {
|
||||
let json;
|
||||
|
||||
if (req.method !== 'POST')
|
||||
return;
|
||||
|
||||
@ -411,7 +406,7 @@ HTTPBase.prototype.jsonRPC = function jsonRPC(rpc) {
|
||||
if (typeof req.body.method !== 'string')
|
||||
return;
|
||||
|
||||
json = await rpc.call(req.body, req.query);
|
||||
let json = await rpc.call(req.body, req.query);
|
||||
|
||||
json = JSON.stringify(json);
|
||||
json += '\n';
|
||||
@ -1086,18 +1081,16 @@ Route.prototype.compile = function compile() {
|
||||
};
|
||||
|
||||
Route.prototype.match = function _match(pathname) {
|
||||
let match, params;
|
||||
|
||||
this.compile();
|
||||
|
||||
assert(this.regex);
|
||||
|
||||
match = this.regex.exec(pathname);
|
||||
const match = this.regex.exec(pathname);
|
||||
|
||||
if (!match)
|
||||
return;
|
||||
|
||||
params = Object.create(null);
|
||||
const params = Object.create(null);
|
||||
|
||||
for (let i = 1; i < match.length; i++) {
|
||||
const item = match[i];
|
||||
@ -1233,7 +1226,6 @@ Request.prototype.parse = function parse(url) {
|
||||
let pathname = uri.pathname;
|
||||
let query = Object.create(null);
|
||||
let trailing = false;
|
||||
let path, parts;
|
||||
|
||||
if (pathname) {
|
||||
pathname = pathname.replace(/\/{2,}/g, '/');
|
||||
@ -1260,12 +1252,12 @@ Request.prototype.parse = function parse(url) {
|
||||
if (pathname.length > 1)
|
||||
assert(pathname[pathname.length - 1] !== '/');
|
||||
|
||||
path = pathname;
|
||||
let path = pathname;
|
||||
|
||||
if (path[0] === '/')
|
||||
path = path.substring(1);
|
||||
|
||||
parts = path.split('/');
|
||||
let parts = path.split('/');
|
||||
|
||||
if (parts.length === 1) {
|
||||
if (parts[0].length === 0)
|
||||
|
||||
@ -195,7 +195,7 @@ HTTPClient.prototype.onDisconnect = function onDisconnect() {
|
||||
*/
|
||||
|
||||
HTTPClient.prototype._request = async function _request(method, endpoint, json) {
|
||||
let query, network, res;
|
||||
let query;
|
||||
|
||||
if (this.token) {
|
||||
if (!json)
|
||||
@ -208,7 +208,7 @@ HTTPClient.prototype._request = async function _request(method, endpoint, json)
|
||||
json = null;
|
||||
}
|
||||
|
||||
res = await request({
|
||||
const res = await request({
|
||||
method: method,
|
||||
uri: this.uri + endpoint,
|
||||
pool: true,
|
||||
@ -235,7 +235,7 @@ HTTPClient.prototype._request = async function _request(method, endpoint, json)
|
||||
if (!res.body)
|
||||
throw new Error('Bad response (no body).');
|
||||
|
||||
network = res.headers['x-bcoin-network'];
|
||||
const network = res.headers['x-bcoin-network'];
|
||||
|
||||
if (network && network !== this.network.type)
|
||||
throw new Error('Bad response (wrong network).');
|
||||
|
||||
@ -223,12 +223,10 @@ RequestOptions.prototype.getBackend = function getBackend() {
|
||||
};
|
||||
|
||||
RequestOptions.prototype.getHeaders = function getHeaders() {
|
||||
let headers;
|
||||
|
||||
if (this.headers)
|
||||
return this.headers;
|
||||
|
||||
headers = Object.create(null);
|
||||
const headers = Object.create(null);
|
||||
|
||||
headers['User-Agent'] = this.agent;
|
||||
|
||||
|
||||
340
lib/http/rpc.js
340
lib/http/rpc.js
File diff suppressed because it is too large
Load Diff
@ -144,12 +144,11 @@ HTTPServer.prototype.initRouter = function initRouter() {
|
||||
const valid = req.valid();
|
||||
const address = valid.str('address');
|
||||
const result = [];
|
||||
let coins;
|
||||
|
||||
enforce(address, 'Address is required.');
|
||||
enforce(!this.chain.options.spv, 'Cannot get coins in SPV mode.');
|
||||
|
||||
coins = await this.node.getCoinsByAddress(address);
|
||||
const coins = await this.node.getCoinsByAddress(address);
|
||||
|
||||
for (const coin of coins)
|
||||
result.push(coin.getJSON(this.network));
|
||||
@ -162,13 +161,12 @@ HTTPServer.prototype.initRouter = function initRouter() {
|
||||
const valid = req.valid();
|
||||
const hash = valid.hash('hash');
|
||||
const index = valid.u32('index');
|
||||
let coin;
|
||||
|
||||
enforce(hash, 'Hash is required.');
|
||||
enforce(index != null, 'Index is required.');
|
||||
enforce(!this.chain.options.spv, 'Cannot get coins in SPV mode.');
|
||||
|
||||
coin = await this.node.getCoin(hash, index);
|
||||
const coin = await this.node.getCoin(hash, index);
|
||||
|
||||
if (!coin) {
|
||||
res.send(404);
|
||||
@ -183,12 +181,11 @@ HTTPServer.prototype.initRouter = function initRouter() {
|
||||
const valid = req.valid();
|
||||
const address = valid.array('addresses');
|
||||
const result = [];
|
||||
let coins;
|
||||
|
||||
enforce(address, 'Address is required.');
|
||||
enforce(!this.chain.options.spv, 'Cannot get coins in SPV mode.');
|
||||
|
||||
coins = await this.node.getCoinsByAddress(address);
|
||||
const coins = await this.node.getCoinsByAddress(address);
|
||||
|
||||
for (const coin of coins)
|
||||
result.push(coin.getJSON(this.network));
|
||||
@ -200,19 +197,18 @@ HTTPServer.prototype.initRouter = function initRouter() {
|
||||
this.get('/tx/:hash', async (req, res) => {
|
||||
const valid = req.valid();
|
||||
const hash = valid.hash('hash');
|
||||
let meta, view;
|
||||
|
||||
enforce(hash, 'Hash is required.');
|
||||
enforce(!this.chain.options.spv, 'Cannot get TX in SPV mode.');
|
||||
|
||||
meta = await this.node.getMeta(hash);
|
||||
const meta = await this.node.getMeta(hash);
|
||||
|
||||
if (!meta) {
|
||||
res.send(404);
|
||||
return;
|
||||
}
|
||||
|
||||
view = await this.node.getMetaView(meta);
|
||||
const view = await this.node.getMetaView(meta);
|
||||
|
||||
res.send(200, meta.getJSON(this.network, view));
|
||||
});
|
||||
@ -222,12 +218,11 @@ HTTPServer.prototype.initRouter = function initRouter() {
|
||||
const valid = req.valid();
|
||||
const address = valid.str('address');
|
||||
const result = [];
|
||||
let metas;
|
||||
|
||||
enforce(address, 'Address is required.');
|
||||
enforce(!this.chain.options.spv, 'Cannot get TX in SPV mode.');
|
||||
|
||||
metas = await this.node.getMetaByAddress(address);
|
||||
const metas = await this.node.getMetaByAddress(address);
|
||||
|
||||
for (const meta of metas) {
|
||||
const view = await this.node.getMetaView(meta);
|
||||
@ -242,12 +237,11 @@ HTTPServer.prototype.initRouter = function initRouter() {
|
||||
const valid = req.valid();
|
||||
const address = valid.array('address');
|
||||
const result = [];
|
||||
let metas;
|
||||
|
||||
enforce(address, 'Address is required.');
|
||||
enforce(!this.chain.options.spv, 'Cannot get TX in SPV mode.');
|
||||
|
||||
metas = await this.node.getMetaByAddress(address);
|
||||
const metas = await this.node.getMetaByAddress(address);
|
||||
|
||||
for (const meta of metas) {
|
||||
const view = await this.node.getMetaView(meta);
|
||||
@ -261,7 +255,6 @@ HTTPServer.prototype.initRouter = function initRouter() {
|
||||
this.get('/block/:block', async (req, res) => {
|
||||
const valid = req.valid();
|
||||
let hash = valid.get('block');
|
||||
let block, view, height;
|
||||
|
||||
enforce(typeof hash === 'string', 'Hash or height required.');
|
||||
enforce(!this.chain.options.spv, 'Cannot get block in SPV mode.');
|
||||
@ -271,21 +264,21 @@ HTTPServer.prototype.initRouter = function initRouter() {
|
||||
else
|
||||
hash = +hash;
|
||||
|
||||
block = await this.chain.db.getBlock(hash);
|
||||
const block = await this.chain.db.getBlock(hash);
|
||||
|
||||
if (!block) {
|
||||
res.send(404);
|
||||
return;
|
||||
}
|
||||
|
||||
view = await this.chain.db.getBlockView(block);
|
||||
const view = await this.chain.db.getBlockView(block);
|
||||
|
||||
if (!view) {
|
||||
res.send(404);
|
||||
return;
|
||||
}
|
||||
|
||||
height = await this.chain.db.getHeight(hash);
|
||||
const height = await this.chain.db.getHeight(hash);
|
||||
|
||||
res.send(200, block.getJSON(this.network, view, height));
|
||||
});
|
||||
@ -293,11 +286,10 @@ HTTPServer.prototype.initRouter = function initRouter() {
|
||||
// Mempool snapshot
|
||||
this.get('/mempool', async (req, res) => {
|
||||
const result = [];
|
||||
let hashes;
|
||||
|
||||
enforce(this.mempool, 'No mempool available.');
|
||||
|
||||
hashes = this.mempool.getSnapshot();
|
||||
const hashes = this.mempool.getSnapshot();
|
||||
|
||||
for (const hash of hashes)
|
||||
result.push(util.revHex(hash));
|
||||
@ -309,11 +301,10 @@ HTTPServer.prototype.initRouter = function initRouter() {
|
||||
this.post('/broadcast', async (req, res) => {
|
||||
const valid = req.valid();
|
||||
const raw = valid.buf('tx');
|
||||
let tx;
|
||||
|
||||
enforce(raw, 'TX is required.');
|
||||
|
||||
tx = TX.fromRaw(raw);
|
||||
const tx = TX.fromRaw(raw);
|
||||
|
||||
await this.node.sendTX(tx);
|
||||
|
||||
@ -324,14 +315,13 @@ HTTPServer.prototype.initRouter = function initRouter() {
|
||||
this.get('/fee', async (req, res) => {
|
||||
const valid = req.valid();
|
||||
const blocks = valid.u32('blocks');
|
||||
let fee;
|
||||
|
||||
if (!this.fees) {
|
||||
res.send(200, { rate: this.network.feeRate });
|
||||
return;
|
||||
}
|
||||
|
||||
fee = this.fees.estimateFee(blocks);
|
||||
const fee = this.fees.estimateFee(blocks);
|
||||
|
||||
res.send(200, { rate: fee });
|
||||
});
|
||||
@ -443,24 +433,23 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) {
|
||||
socket.hook('get entry', async (args) => {
|
||||
const valid = new Validator([args]);
|
||||
const block = valid.numhash(0);
|
||||
let entry;
|
||||
|
||||
if (block == null)
|
||||
throw new Error('Invalid parameter.');
|
||||
|
||||
entry = await this.chain.db.getEntry(block);
|
||||
|
||||
if (!(await entry.isMainChain()))
|
||||
entry = null;
|
||||
const entry = await this.chain.db.getEntry(block);
|
||||
|
||||
if (!entry)
|
||||
return null;
|
||||
|
||||
if (!(await entry.isMainChain()))
|
||||
return null;
|
||||
|
||||
return entry.toRaw();
|
||||
});
|
||||
|
||||
socket.hook('add filter', (args) => {
|
||||
let valid = new Validator([args]);
|
||||
const valid = new Validator([args]);
|
||||
const chunks = valid.array(0);
|
||||
|
||||
if (!chunks)
|
||||
@ -469,10 +458,10 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) {
|
||||
if (!socket.filter)
|
||||
throw new Error('No filter set.');
|
||||
|
||||
valid = new Validator([chunks]);
|
||||
const items = new Validator([chunks]);
|
||||
|
||||
for (let i = 0; i < chunks.length; i++) {
|
||||
const data = valid.buf(i);
|
||||
const data = items.buf(i);
|
||||
|
||||
if (!data)
|
||||
throw new Error('Bad data chunk.');
|
||||
@ -504,12 +493,11 @@ HTTPServer.prototype.handleAuth = function handleAuth(socket) {
|
||||
socket.hook('send', (args) => {
|
||||
const valid = new Validator([args]);
|
||||
const data = valid.buf(0);
|
||||
let tx;
|
||||
|
||||
if (!data)
|
||||
throw new Error('Invalid parameter.');
|
||||
|
||||
tx = TX.fromRaw(data);
|
||||
const tx = TX.fromRaw(data);
|
||||
|
||||
this.node.send(tx);
|
||||
|
||||
@ -539,12 +527,11 @@ HTTPServer.prototype.bindChain = function bindChain() {
|
||||
|
||||
this.chain.on('connect', (entry, block, view) => {
|
||||
const list = this.channel('chain');
|
||||
let raw;
|
||||
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
raw = entry.toRaw();
|
||||
const raw = entry.toRaw();
|
||||
|
||||
this.to('chain', 'chain connect', raw);
|
||||
|
||||
@ -557,12 +544,11 @@ HTTPServer.prototype.bindChain = function bindChain() {
|
||||
|
||||
this.chain.on('disconnect', (entry, block, view) => {
|
||||
const list = this.channel('chain');
|
||||
let raw;
|
||||
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
raw = entry.toRaw();
|
||||
const raw = entry.toRaw();
|
||||
|
||||
this.to('chain', 'chain disconnect', raw);
|
||||
this.to('chain', 'block disconnect', raw);
|
||||
@ -570,24 +556,22 @@ HTTPServer.prototype.bindChain = function bindChain() {
|
||||
|
||||
this.chain.on('reset', (tip) => {
|
||||
const list = this.channel('chain');
|
||||
let raw;
|
||||
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
raw = tip.toRaw();
|
||||
const raw = tip.toRaw();
|
||||
|
||||
this.to('chain', 'chain reset', raw);
|
||||
});
|
||||
|
||||
pool.on('tx', (tx) => {
|
||||
const list = this.channel('mempool');
|
||||
let raw;
|
||||
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
raw = tx.toRaw();
|
||||
const raw = tx.toRaw();
|
||||
|
||||
for (let item = list.head; item; item = item.next) {
|
||||
const socket = item.value;
|
||||
|
||||
@ -123,12 +123,10 @@ HTTPWallet.prototype.open = async function open(options) {
|
||||
*/
|
||||
|
||||
HTTPWallet.prototype.create = async function create(options) {
|
||||
let wallet;
|
||||
|
||||
await this.client.open();
|
||||
await this.client.sendWalletAuth();
|
||||
|
||||
wallet = await this.client.createWallet(options);
|
||||
const wallet = await this.client.createWallet(options);
|
||||
|
||||
this.id = wallet.id;
|
||||
this.token = wallet.token;
|
||||
|
||||
@ -133,12 +133,10 @@ ConfirmStats.prototype.clearCurrent = function clearCurrent(height) {
|
||||
*/
|
||||
|
||||
ConfirmStats.prototype.record = function record(blocks, val) {
|
||||
let bucketIndex;
|
||||
|
||||
if (blocks < 1)
|
||||
return;
|
||||
|
||||
bucketIndex = this.bucketMap.search(val);
|
||||
const bucketIndex = this.bucketMap.search(val);
|
||||
|
||||
for (let i = blocks; i <= this.curBlockConf.length; i++)
|
||||
this.curBlockConf[i - 1][bucketIndex]++;
|
||||
@ -173,21 +171,20 @@ ConfirmStats.prototype.updateAverages = function updateAverages() {
|
||||
*/
|
||||
|
||||
ConfirmStats.prototype.estimateMedian = function estimateMedian(target, needed, breakpoint, greater, height) {
|
||||
let conf = 0;
|
||||
let total = 0;
|
||||
let extra = 0;
|
||||
const max = this.buckets.length - 1;
|
||||
const start = greater ? max : 0;
|
||||
const step = greater ? -1 : 1;
|
||||
const bins = this.unconfTX.length;
|
||||
let conf = 0;
|
||||
let total = 0;
|
||||
let extra = 0;
|
||||
let near = start;
|
||||
let far = start;
|
||||
let bestNear = start;
|
||||
let bestFar = start;
|
||||
let found = false;
|
||||
const bins = this.unconfTX.length;
|
||||
let median = -1;
|
||||
let sum = 0;
|
||||
let minBucket, maxBucket;
|
||||
|
||||
for (let i = start; i >= 0 && i <= max; i += step) {
|
||||
far = i;
|
||||
@ -218,8 +215,8 @@ ConfirmStats.prototype.estimateMedian = function estimateMedian(target, needed,
|
||||
}
|
||||
}
|
||||
|
||||
minBucket = bestNear < bestFar ? bestNear : bestFar;
|
||||
maxBucket = bestNear > bestFar ? bestNear : bestFar;
|
||||
const minBucket = bestNear < bestFar ? bestNear : bestFar;
|
||||
const maxBucket = bestNear > bestFar ? bestNear : bestFar;
|
||||
|
||||
for (let i = minBucket; i <= maxBucket; i++)
|
||||
sum += this.txAvg[i];
|
||||
@ -540,7 +537,6 @@ PolicyEstimator.prototype.isPriPoint = function isPriPoint(fee, priority) {
|
||||
PolicyEstimator.prototype.processTX = function processTX(entry, current) {
|
||||
const height = entry.height;
|
||||
const hash = entry.hash('hex');
|
||||
let fee, rate, priority, item;
|
||||
|
||||
if (this.map.has(hash)) {
|
||||
this.logger.debug('Mempool tx %s already tracked.', entry.txid());
|
||||
@ -559,28 +555,25 @@ PolicyEstimator.prototype.processTX = function processTX(entry, current) {
|
||||
if (entry.dependencies)
|
||||
return;
|
||||
|
||||
fee = entry.getFee();
|
||||
rate = entry.getRate();
|
||||
priority = entry.getPriority(height);
|
||||
const fee = entry.getFee();
|
||||
const rate = entry.getRate();
|
||||
const priority = entry.getPriority(height);
|
||||
|
||||
this.logger.spam('Processing mempool tx %s.', entry.txid());
|
||||
|
||||
if (fee === 0 || this.isPriPoint(rate, priority)) {
|
||||
item = new StatEntry();
|
||||
const item = new StatEntry();
|
||||
item.blockHeight = height;
|
||||
item.bucketIndex = this.priStats.addTX(height, priority);
|
||||
this.map.set(hash, item);
|
||||
} else if (this.isFeePoint(rate, priority)) {
|
||||
item = new StatEntry();
|
||||
const item = new StatEntry();
|
||||
item.blockHeight = height;
|
||||
item.bucketIndex = this.feeStats.addTX(height, rate);
|
||||
}
|
||||
|
||||
if (!item) {
|
||||
this.map.set(hash, item);
|
||||
} else {
|
||||
this.logger.spam('Not adding tx %s.', entry.txid());
|
||||
return;
|
||||
}
|
||||
|
||||
this.map.set(hash, item);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -590,13 +583,11 @@ PolicyEstimator.prototype.processTX = function processTX(entry, current) {
|
||||
*/
|
||||
|
||||
PolicyEstimator.prototype.processBlockTX = function processBlockTX(height, entry) {
|
||||
let blocks, fee, rate, priority;
|
||||
|
||||
// Requires other mempool txs in order to be confirmed. Ignore.
|
||||
if (entry.dependencies)
|
||||
return;
|
||||
|
||||
blocks = height - entry.height;
|
||||
const blocks = height - entry.height;
|
||||
|
||||
if (blocks <= 0) {
|
||||
this.logger.debug(
|
||||
@ -607,9 +598,9 @@ PolicyEstimator.prototype.processBlockTX = function processBlockTX(height, entry
|
||||
return;
|
||||
}
|
||||
|
||||
fee = entry.getFee();
|
||||
rate = entry.getRate();
|
||||
priority = entry.getPriority(height);
|
||||
const fee = entry.getFee();
|
||||
const rate = entry.getRate();
|
||||
const priority = entry.getPriority(height);
|
||||
|
||||
if (fee === 0 || this.isPriPoint(rate, priority))
|
||||
this.priStats.record(blocks, priority);
|
||||
@ -692,8 +683,6 @@ PolicyEstimator.prototype.processBlock = function processBlock(height, entries,
|
||||
*/
|
||||
|
||||
PolicyEstimator.prototype.estimateFee = function estimateFee(target, smart) {
|
||||
let rate;
|
||||
|
||||
if (!target)
|
||||
target = 1;
|
||||
|
||||
@ -715,7 +704,7 @@ PolicyEstimator.prototype.estimateFee = function estimateFee(target, smart) {
|
||||
return Math.floor(rate);
|
||||
}
|
||||
|
||||
rate = -1;
|
||||
let rate = -1;
|
||||
while (rate < 0 && target <= this.feeStats.maxConfirms) {
|
||||
rate = this.feeStats.estimateMedian(
|
||||
target++, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT,
|
||||
@ -738,8 +727,6 @@ PolicyEstimator.prototype.estimateFee = function estimateFee(target, smart) {
|
||||
*/
|
||||
|
||||
PolicyEstimator.prototype.estimatePriority = function estimatePriority(target, smart) {
|
||||
let priority;
|
||||
|
||||
if (!target)
|
||||
target = 1;
|
||||
|
||||
@ -751,13 +738,13 @@ PolicyEstimator.prototype.estimatePriority = function estimatePriority(target, s
|
||||
'Too many confirmations for estimate.');
|
||||
|
||||
if (!smart) {
|
||||
priority = this.priStats.estimateMedian(
|
||||
const priority = this.priStats.estimateMedian(
|
||||
target, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT,
|
||||
true, this.bestHeight);
|
||||
return Math.floor(priority);
|
||||
}
|
||||
|
||||
priority = -1;
|
||||
let priority = -1;
|
||||
while (priority < 0 && target <= this.priStats.maxConfirms) {
|
||||
priority = this.priStats.estimateMedian(
|
||||
target++, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT,
|
||||
|
||||
@ -185,14 +185,12 @@ Mempool.prototype.addBlock = async function addBlock(block, txs) {
|
||||
*/
|
||||
|
||||
Mempool.prototype._addBlock = async function addBlock(block, txs) {
|
||||
let entries;
|
||||
|
||||
if (this.map.size === 0) {
|
||||
this.tip = block.hash;
|
||||
return;
|
||||
}
|
||||
|
||||
entries = [];
|
||||
const entries = [];
|
||||
|
||||
for (let i = txs.length - 1; i >= 1; i--) {
|
||||
const tx = txs[i];
|
||||
@ -265,13 +263,13 @@ Mempool.prototype.removeBlock = async function removeBlock(block, txs) {
|
||||
*/
|
||||
|
||||
Mempool.prototype._removeBlock = async function removeBlock(block, txs) {
|
||||
let total = 0;
|
||||
|
||||
if (this.map.size === 0) {
|
||||
this.tip = block.prevBlock;
|
||||
return;
|
||||
}
|
||||
|
||||
let total = 0;
|
||||
|
||||
for (let i = 1; i < txs.length; i++) {
|
||||
const tx = txs[i];
|
||||
const hash = tx.hash('hex');
|
||||
@ -365,14 +363,13 @@ Mempool.prototype.limitSize = function limitSize(added) {
|
||||
const maxSize = this.options.maxSize;
|
||||
const threshold = maxSize - (maxSize / 10);
|
||||
const expiryTime = this.options.expiryTime;
|
||||
const now = util.now();
|
||||
let queue, start;
|
||||
|
||||
if (this.size <= maxSize)
|
||||
return false;
|
||||
|
||||
start = util.hrtime();
|
||||
queue = new Heap(cmpRate);
|
||||
const now = util.now();
|
||||
let start = util.hrtime();
|
||||
const queue = new Heap(cmpRate);
|
||||
|
||||
for (const entry of this.map.values()) {
|
||||
if (this.hasDepends(entry.tx))
|
||||
@ -592,12 +589,11 @@ Mempool.prototype.getMetaByAddress = function getMetaByAddress(addrs) {
|
||||
|
||||
Mempool.prototype.getMeta = function getMeta(hash) {
|
||||
const entry = this.getEntry(hash);
|
||||
let meta;
|
||||
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
meta = TXMeta.fromTX(entry.tx);
|
||||
const meta = TXMeta.fromTX(entry.tx);
|
||||
meta.mtime = entry.time;
|
||||
|
||||
return meta;
|
||||
@ -722,17 +718,16 @@ Mempool.prototype._addTX = async function _addTX(tx, id) {
|
||||
*/
|
||||
|
||||
Mempool.prototype.insertTX = async function insertTX(tx, id) {
|
||||
assert(!tx.mutable, 'Cannot add mutable TX to mempool.');
|
||||
|
||||
const lockFlags = common.lockFlags.STANDARD_LOCKTIME_FLAGS;
|
||||
const height = this.chain.height;
|
||||
const hash = tx.hash('hex');
|
||||
let valid, reason, score, entry, view, missing;
|
||||
|
||||
assert(!tx.mutable, 'Cannot add mutable TX to mempool.');
|
||||
|
||||
// Basic sanity checks.
|
||||
// This is important because it ensures
|
||||
// other functions will be overflow safe.
|
||||
[valid, reason, score] = tx.checkSanity();
|
||||
const [valid, reason, score] = tx.checkSanity();
|
||||
|
||||
if (!valid)
|
||||
throw new VerifyError(tx, 'invalid', reason, score);
|
||||
@ -823,10 +818,10 @@ Mempool.prototype.insertTX = async function insertTX(tx, id) {
|
||||
|
||||
// Get coin viewpoint as it
|
||||
// pertains to the mempool.
|
||||
view = await this.getCoinView(tx);
|
||||
const view = await this.getCoinView(tx);
|
||||
|
||||
// Find missing outpoints.
|
||||
missing = this.findMissing(tx, view);
|
||||
const missing = this.findMissing(tx, view);
|
||||
|
||||
// Maybe store as an orphan.
|
||||
if (missing)
|
||||
@ -834,7 +829,7 @@ Mempool.prototype.insertTX = async function insertTX(tx, id) {
|
||||
|
||||
// Create a new mempool entry
|
||||
// at current chain height.
|
||||
entry = MempoolEntry.fromTX(tx, view, height);
|
||||
const entry = MempoolEntry.fromTX(tx, view, height);
|
||||
|
||||
// Contextual verification.
|
||||
await this.verify(entry, view);
|
||||
@ -866,7 +861,6 @@ Mempool.prototype.verify = async function verify(entry, view) {
|
||||
const lockFlags = common.lockFlags.STANDARD_LOCKTIME_FLAGS;
|
||||
let flags = Script.flags.STANDARD_VERIFY_FLAGS;
|
||||
const tx = entry.tx;
|
||||
let fee, reason, score, minFee;
|
||||
|
||||
// Verify sequence locks.
|
||||
if (!(await this.verifyLocks(tx, view, lockFlags))) {
|
||||
@ -904,7 +898,7 @@ Mempool.prototype.verify = async function verify(entry, view) {
|
||||
}
|
||||
|
||||
// Make sure this guy gave a decent fee.
|
||||
minFee = policy.getMinFee(entry.size, this.options.minRelay);
|
||||
const minFee = policy.getMinFee(entry.size, this.options.minRelay);
|
||||
|
||||
if (this.options.relayPriority && entry.fee < minFee) {
|
||||
if (!entry.isFree(height)) {
|
||||
@ -949,7 +943,7 @@ Mempool.prototype.verify = async function verify(entry, view) {
|
||||
}
|
||||
|
||||
// Contextual sanity checks.
|
||||
[fee, reason, score] = tx.checkInputs(view, height);
|
||||
const [fee, reason, score] = tx.checkInputs(view, height);
|
||||
|
||||
if (fee === -1)
|
||||
throw new VerifyError(tx, 'invalid', reason, score);
|
||||
@ -958,28 +952,28 @@ Mempool.prototype.verify = async function verify(entry, view) {
|
||||
try {
|
||||
await this.verifyInputs(tx, view, flags);
|
||||
} catch (err) {
|
||||
let valid;
|
||||
|
||||
if (tx.hasWitness())
|
||||
throw err;
|
||||
|
||||
// Try without segwit and cleanstack.
|
||||
flags &= ~Script.flags.VERIFY_WITNESS;
|
||||
flags &= ~Script.flags.VERIFY_CLEANSTACK;
|
||||
valid = await this.verifyResult(tx, view, flags);
|
||||
|
||||
const valid1 = await this.verifyResult(tx, view, flags);
|
||||
|
||||
// If it failed, the first verification
|
||||
// was the only result we needed.
|
||||
if (!valid)
|
||||
if (!valid1)
|
||||
throw err;
|
||||
|
||||
// If it succeeded, segwit may be causing the
|
||||
// failure. Try with segwit but without cleanstack.
|
||||
flags |= Script.flags.VERIFY_CLEANSTACK;
|
||||
valid = await this.verifyResult(tx, view, flags);
|
||||
|
||||
const valid2 = await this.verifyResult(tx, view, flags);
|
||||
|
||||
// Cleanstack was causing the failure.
|
||||
if (valid)
|
||||
if (valid2)
|
||||
throw err;
|
||||
|
||||
// Do not insert into reject cache.
|
||||
@ -989,9 +983,8 @@ Mempool.prototype.verify = async function verify(entry, view) {
|
||||
|
||||
// Paranoid checks.
|
||||
if (this.options.paranoidChecks) {
|
||||
let valid;
|
||||
flags = Script.flags.MANDATORY_VERIFY_FLAGS;
|
||||
valid = await this.verifyResult(tx, view, flags);
|
||||
const flags = Script.flags.MANDATORY_VERIFY_FLAGS;
|
||||
const valid = await this.verifyResult(tx, view, flags);
|
||||
assert(valid, 'BUG: Verify failed for mandatory but not standard.');
|
||||
}
|
||||
};
|
||||
@ -1225,12 +1218,11 @@ Mempool.prototype._countDescendants = function countDescendants(entry, set) {
|
||||
|
||||
for (let i = 0; i < tx.outputs.length; i++) {
|
||||
const child = this.getSpent(hash, i);
|
||||
let next;
|
||||
|
||||
if (!child)
|
||||
continue;
|
||||
|
||||
next = child.hash('hex');
|
||||
const next = child.hash('hex');
|
||||
|
||||
if (set.has(next))
|
||||
continue;
|
||||
@ -1308,12 +1300,11 @@ Mempool.prototype._getDescendants = function getDescendants(entry, entries, set)
|
||||
|
||||
for (let i = 0; i < tx.outputs.length; i++) {
|
||||
const child = this.getSpent(hash, i);
|
||||
let next;
|
||||
|
||||
if (!child)
|
||||
continue;
|
||||
|
||||
next = child.hash('hex');
|
||||
const next = child.hash('hex');
|
||||
|
||||
if (set.has(next))
|
||||
continue;
|
||||
@ -1592,12 +1583,11 @@ Mempool.prototype.removeOrphan = function removeOrphan(hash) {
|
||||
*/
|
||||
|
||||
Mempool.prototype.limitOrphans = function limitOrphans() {
|
||||
let index, hash;
|
||||
|
||||
if (this.orphans.size < this.options.maxOrphans)
|
||||
return false;
|
||||
|
||||
index = random.randomRange(0, this.orphans.size);
|
||||
let index = random.randomRange(0, this.orphans.size);
|
||||
let hash = null;
|
||||
|
||||
for (hash of this.orphans.keys()) {
|
||||
if (index === 0)
|
||||
@ -1605,6 +1595,8 @@ Mempool.prototype.limitOrphans = function limitOrphans() {
|
||||
index--;
|
||||
}
|
||||
|
||||
assert(hash);
|
||||
|
||||
this.logger.debug('Removing orphan %s from mempool.', util.revHex(hash));
|
||||
|
||||
this.removeOrphan(hash);
|
||||
@ -1660,14 +1652,13 @@ Mempool.prototype.getCoinView = async function getCoinView(tx) {
|
||||
|
||||
for (const {prevout} of tx.inputs) {
|
||||
const entry = this.getEntry(prevout.hash);
|
||||
let coin;
|
||||
|
||||
if (entry) {
|
||||
view.addTX(entry.tx, -1);
|
||||
continue;
|
||||
}
|
||||
|
||||
coin = await this.chain.db.readCoin(prevout);
|
||||
const coin = await this.chain.db.readCoin(prevout);
|
||||
|
||||
if (!coin) {
|
||||
const coins = new Coins();
|
||||
@ -2231,19 +2222,18 @@ CoinIndex.prototype.insert = function insert(tx, index) {
|
||||
const output = tx.outputs[index];
|
||||
const hash = tx.hash('hex');
|
||||
const addr = output.getHash('hex');
|
||||
let items, key;
|
||||
|
||||
if (!addr)
|
||||
return;
|
||||
|
||||
items = this.index.get(addr);
|
||||
let items = this.index.get(addr);
|
||||
|
||||
if (!items) {
|
||||
items = new Map();
|
||||
this.index.set(addr, items);
|
||||
}
|
||||
|
||||
key = Outpoint.toKey(hash, index);
|
||||
const key = Outpoint.toKey(hash, index);
|
||||
|
||||
assert(!items.has(key));
|
||||
items.set(key, new IndexedCoin(tx, index));
|
||||
@ -2254,12 +2244,11 @@ CoinIndex.prototype.insert = function insert(tx, index) {
|
||||
CoinIndex.prototype.remove = function remove(hash, index) {
|
||||
const key = Outpoint.toKey(hash, index);
|
||||
const addr = this.map.get(key);
|
||||
let items;
|
||||
|
||||
if (!addr)
|
||||
return;
|
||||
|
||||
items = this.index.get(addr);
|
||||
const items = this.index.get(addr);
|
||||
|
||||
assert(items);
|
||||
assert(items.has(key));
|
||||
|
||||
@ -108,16 +108,12 @@ CPUMiner.prototype.start = function start() {
|
||||
*/
|
||||
|
||||
CPUMiner.prototype._start = async function start() {
|
||||
let job;
|
||||
|
||||
assert(!this.running, 'Miner is already running.');
|
||||
|
||||
this.running = true;
|
||||
this.stopping = false;
|
||||
|
||||
for (;;) {
|
||||
let block, entry;
|
||||
|
||||
this.job = null;
|
||||
|
||||
try {
|
||||
@ -132,6 +128,8 @@ CPUMiner.prototype._start = async function start() {
|
||||
if (this.stopping)
|
||||
break;
|
||||
|
||||
let block = null;
|
||||
|
||||
try {
|
||||
block = await this.mineAsync(this.job);
|
||||
} catch (e) {
|
||||
@ -147,6 +145,8 @@ CPUMiner.prototype._start = async function start() {
|
||||
if (!block)
|
||||
continue;
|
||||
|
||||
let entry = null;
|
||||
|
||||
try {
|
||||
entry = await this.chain.add(block);
|
||||
} catch (e) {
|
||||
@ -178,7 +178,7 @@ CPUMiner.prototype._start = async function start() {
|
||||
this.emit('block', block, entry);
|
||||
}
|
||||
|
||||
job = this.stopJob;
|
||||
const job = this.stopJob;
|
||||
|
||||
if (job) {
|
||||
this.stopJob = null;
|
||||
@ -473,12 +473,11 @@ CPUJob.prototype.commit = function commit(nonce) {
|
||||
const n1 = this.nonce1;
|
||||
const n2 = this.nonce2;
|
||||
const time = attempt.time;
|
||||
let proof;
|
||||
|
||||
assert(!this.committed, 'Job already committed.');
|
||||
this.committed = true;
|
||||
|
||||
proof = attempt.getProof(n1, n2, time, nonce);
|
||||
const proof = attempt.getProof(n1, n2, time, nonce);
|
||||
|
||||
return attempt.commit(proof);
|
||||
};
|
||||
|
||||
@ -122,7 +122,6 @@ Miner.prototype.createBlock = async function createBlock(tip, address) {
|
||||
|
||||
Miner.prototype._createBlock = async function createBlock(tip, address) {
|
||||
let version = this.options.version;
|
||||
let time, mtp, locktime, target, attempt, state;
|
||||
|
||||
if (!tip)
|
||||
tip = this.chain.tip;
|
||||
@ -133,18 +132,15 @@ Miner.prototype._createBlock = async function createBlock(tip, address) {
|
||||
if (version === -1)
|
||||
version = await this.chain.computeBlockVersion(tip);
|
||||
|
||||
mtp = await tip.getMedianTime();
|
||||
time = Math.max(this.network.now(), mtp + 1);
|
||||
locktime = time;
|
||||
const mtp = await tip.getMedianTime();
|
||||
const time = Math.max(this.network.now(), mtp + 1);
|
||||
|
||||
state = await this.chain.getDeployments(time, tip);
|
||||
const state = await this.chain.getDeployments(time, tip);
|
||||
const target = await this.chain.getTarget(time, tip);
|
||||
|
||||
if (state.hasMTP())
|
||||
locktime = mtp;
|
||||
const locktime = state.hasMTP() ? mtp : time;
|
||||
|
||||
target = await this.chain.getTarget(time, tip);
|
||||
|
||||
attempt = new BlockTemplate({
|
||||
const attempt = new BlockTemplate({
|
||||
prevBlock: tip.hash,
|
||||
height: tip.height + 1,
|
||||
version: version,
|
||||
@ -302,7 +298,6 @@ Miner.prototype.assemble = function assemble(attempt) {
|
||||
const hash = item.hash;
|
||||
let weight = attempt.weight;
|
||||
let sigops = attempt.sigops;
|
||||
let deps;
|
||||
|
||||
if (!tx.isFinal(attempt.height, attempt.locktime))
|
||||
continue;
|
||||
@ -339,7 +334,7 @@ Miner.prototype.assemble = function assemble(attempt) {
|
||||
attempt.fees += item.fee;
|
||||
attempt.items.push(item);
|
||||
|
||||
deps = depMap.get(hash);
|
||||
const deps = depMap.get(hash);
|
||||
|
||||
if (!deps)
|
||||
continue;
|
||||
|
||||
@ -173,14 +173,13 @@ BlockTemplate.fromOptions = function fromOptions(options) {
|
||||
BlockTemplate.prototype.getWitnessHash = function getWitnessHash() {
|
||||
const nonce = encoding.ZERO_HASH;
|
||||
const leaves = [];
|
||||
let root, malleated;
|
||||
|
||||
leaves.push(encoding.ZERO_HASH);
|
||||
|
||||
for (const item of this.items)
|
||||
leaves.push(item.tx.witnessHash());
|
||||
|
||||
[root, malleated] = merkle.createRoot(leaves);
|
||||
const [root, malleated] = merkle.createRoot(leaves);
|
||||
|
||||
assert(!malleated);
|
||||
|
||||
@ -237,11 +236,9 @@ BlockTemplate.prototype.getReward = function getReward() {
|
||||
BlockTemplate.prototype.createCoinbase = function createCoinbase(hash) {
|
||||
const scale = consensus.WITNESS_SCALE_FACTOR;
|
||||
const cb = new TX();
|
||||
let padding = 0;
|
||||
let input, output, commit;
|
||||
|
||||
// Coinbase input.
|
||||
input = new Input();
|
||||
const input = new Input();
|
||||
|
||||
// Height (required in v2+ blocks)
|
||||
input.script.push(new BN(this.height));
|
||||
@ -267,7 +264,7 @@ BlockTemplate.prototype.createCoinbase = function createCoinbase(hash) {
|
||||
cb.inputs.push(input);
|
||||
|
||||
// Reward output.
|
||||
output = new Output();
|
||||
const output = new Output();
|
||||
output.script.fromPubkeyhash(encoding.ZERO_HASH160);
|
||||
output.value = this.getReward();
|
||||
|
||||
@ -277,13 +274,13 @@ BlockTemplate.prototype.createCoinbase = function createCoinbase(hash) {
|
||||
// need to set up the commitment.
|
||||
if (this.witness) {
|
||||
// Commitment output.
|
||||
commit = new Output();
|
||||
const commit = new Output();
|
||||
commit.script.fromCommitment(hash);
|
||||
cb.outputs.push(commit);
|
||||
}
|
||||
|
||||
// Padding for the CB height (constant size).
|
||||
padding = 5 - input.script.code[0].getSize();
|
||||
const padding = 5 - input.script.code[0].getSize();
|
||||
assert(padding >= 0);
|
||||
|
||||
// Reserved size.
|
||||
@ -332,7 +329,6 @@ BlockTemplate.prototype.refresh = function refresh() {
|
||||
const cb = this.createCoinbase(hash);
|
||||
const raw = cb.toNormal();
|
||||
let size = 0;
|
||||
let left, right;
|
||||
|
||||
size += 4; // version
|
||||
size += 1; // varint inputs length
|
||||
@ -341,11 +337,11 @@ BlockTemplate.prototype.refresh = function refresh() {
|
||||
|
||||
// Cut off right after the nonce
|
||||
// push and before the sequence.
|
||||
left = raw.slice(0, size);
|
||||
const left = raw.slice(0, size);
|
||||
|
||||
// Include the sequence.
|
||||
size += 4 + 4; // nonce1 + nonce2
|
||||
right = raw.slice(size);
|
||||
const right = raw.slice(size);
|
||||
|
||||
this.commitment = hash;
|
||||
this.left = left;
|
||||
@ -362,13 +358,12 @@ BlockTemplate.prototype.refresh = function refresh() {
|
||||
|
||||
BlockTemplate.prototype.getRawCoinbase = function getRawCoinbase(nonce1, nonce2) {
|
||||
let size = 0;
|
||||
let bw;
|
||||
|
||||
size += this.left.length;
|
||||
size += 4 + 4;
|
||||
size += this.right.length;
|
||||
|
||||
bw = new StaticWriter(size);
|
||||
const bw = new StaticWriter(size);
|
||||
bw.writeBytes(this.left);
|
||||
bw.writeU32BE(nonce1);
|
||||
bw.writeU32BE(nonce2);
|
||||
@ -437,10 +432,9 @@ BlockTemplate.prototype.getProof = function getProof(nonce1, nonce2, time, nonce
|
||||
BlockTemplate.prototype.getCoinbase = function getCoinbase(nonce1, nonce2) {
|
||||
const raw = this.getRawCoinbase(nonce1, nonce2);
|
||||
const tx = TX.fromRaw(raw);
|
||||
let input;
|
||||
|
||||
if (this.witness) {
|
||||
input = tx.inputs[0];
|
||||
const input = tx.inputs[0];
|
||||
input.witness.push(encoding.ZERO_HASH);
|
||||
input.witness.compile();
|
||||
tx.refresh();
|
||||
@ -462,7 +456,6 @@ BlockTemplate.prototype.commit = function commit(proof) {
|
||||
const time = proof.time;
|
||||
const nonce = proof.nonce;
|
||||
const block = new Block();
|
||||
let tx;
|
||||
|
||||
block.version = this.version;
|
||||
block.prevBlock = this.prevBlock;
|
||||
@ -471,7 +464,7 @@ BlockTemplate.prototype.commit = function commit(proof) {
|
||||
block.bits = this.bits;
|
||||
block.nonce = nonce;
|
||||
|
||||
tx = this.getCoinbase(n1, n2);
|
||||
const tx = this.getCoinbase(n1, n2);
|
||||
|
||||
block.txs.push(tx);
|
||||
|
||||
@ -529,13 +522,11 @@ BlockTemplate.prototype.setAddress = function setAddress(address) {
|
||||
*/
|
||||
|
||||
BlockTemplate.prototype.addTX = function addTX(tx, view) {
|
||||
let item, weight, sigops;
|
||||
|
||||
assert(!tx.mutable, 'Cannot add mutable TX to block.');
|
||||
|
||||
item = BlockEntry.fromTX(tx, view, this);
|
||||
weight = item.tx.getWeight();
|
||||
sigops = item.sigops;
|
||||
const item = BlockEntry.fromTX(tx, view, this);
|
||||
const weight = item.tx.getWeight();
|
||||
const sigops = item.sigops;
|
||||
|
||||
if (!tx.isFinal(this.height, this.locktime))
|
||||
return false;
|
||||
@ -567,16 +558,14 @@ BlockTemplate.prototype.addTX = function addTX(tx, view) {
|
||||
*/
|
||||
|
||||
BlockTemplate.prototype.pushTX = function pushTX(tx, view) {
|
||||
let item, weight, sigops;
|
||||
|
||||
assert(!tx.mutable, 'Cannot add mutable TX to block.');
|
||||
|
||||
if (!view)
|
||||
view = new CoinView();
|
||||
|
||||
item = BlockEntry.fromTX(tx, view, this);
|
||||
weight = item.tx.getWeight();
|
||||
sigops = item.sigops;
|
||||
const item = BlockEntry.fromTX(tx, view, this);
|
||||
const weight = item.tx.getWeight();
|
||||
const sigops = item.sigops;
|
||||
|
||||
this.weight += weight;
|
||||
this.sigops += sigops;
|
||||
|
||||
@ -122,7 +122,6 @@ BIP150.prototype.isAuthed = function isAuthed() {
|
||||
|
||||
BIP150.prototype.challenge = function challenge(hash) {
|
||||
const type = this.outbound ? 'r' : 'i';
|
||||
let msg, sig;
|
||||
|
||||
assert(this.bip151.handshake, 'No BIP151 handshake before challenge.');
|
||||
assert(!this.challengeReceived, 'Peer challenged twice.');
|
||||
@ -131,7 +130,7 @@ BIP150.prototype.challenge = function challenge(hash) {
|
||||
if (hash.equals(encoding.ZERO_HASH))
|
||||
throw new Error('Auth failure.');
|
||||
|
||||
msg = this.hash(this.input.sid, type, this.publicKey);
|
||||
const msg = this.hash(this.input.sid, type, this.publicKey);
|
||||
|
||||
if (!ccmp(hash, msg))
|
||||
return encoding.ZERO_SIG64;
|
||||
@ -141,7 +140,7 @@ BIP150.prototype.challenge = function challenge(hash) {
|
||||
this.emit('auth');
|
||||
}
|
||||
|
||||
sig = secp256k1.sign(msg, this.privateKey);
|
||||
const sig = secp256k1.sign(msg, this.privateKey);
|
||||
|
||||
// authreply
|
||||
return secp256k1.fromDER(sig);
|
||||
@ -157,7 +156,6 @@ BIP150.prototype.challenge = function challenge(hash) {
|
||||
|
||||
BIP150.prototype.reply = function reply(data) {
|
||||
const type = this.outbound ? 'i' : 'r';
|
||||
let sig, msg, result;
|
||||
|
||||
assert(this.challengeSent, 'Unsolicited reply.');
|
||||
assert(!this.replyReceived, 'Peer replied twice.');
|
||||
@ -169,10 +167,10 @@ BIP150.prototype.reply = function reply(data) {
|
||||
if (!this.peerIdentity)
|
||||
return random.randomBytes(32);
|
||||
|
||||
sig = secp256k1.toDER(data);
|
||||
msg = this.hash(this.output.sid, type, this.peerIdentity);
|
||||
const sig = secp256k1.toDER(data);
|
||||
const msg = this.hash(this.output.sid, type, this.peerIdentity);
|
||||
|
||||
result = secp256k1.verify(msg, sig, this.peerIdentity);
|
||||
const result = secp256k1.verify(msg, sig, this.peerIdentity);
|
||||
|
||||
if (!result)
|
||||
return random.randomBytes(32);
|
||||
@ -197,14 +195,12 @@ BIP150.prototype.reply = function reply(data) {
|
||||
*/
|
||||
|
||||
BIP150.prototype.propose = function propose(hash) {
|
||||
let match;
|
||||
|
||||
assert(!this.outbound, 'Outbound peer tried to propose.');
|
||||
assert(!this.challengeSent, 'Unsolicited propose.');
|
||||
assert(!this.proposeReceived, 'Peer proposed twice.');
|
||||
this.proposeReceived = true;
|
||||
|
||||
match = this.findAuthorized(hash);
|
||||
const match = this.findAuthorized(hash);
|
||||
|
||||
if (!match)
|
||||
return encoding.ZERO_HASH;
|
||||
@ -228,13 +224,11 @@ BIP150.prototype.propose = function propose(hash) {
|
||||
*/
|
||||
|
||||
BIP150.prototype.toChallenge = function toChallenge() {
|
||||
let msg;
|
||||
|
||||
assert(this.bip151.handshake, 'No BIP151 handshake before challenge.');
|
||||
assert(this.outbound, 'Cannot challenge an inbound connection.');
|
||||
assert(this.peerIdentity, 'Cannot challenge without a peer identity.');
|
||||
|
||||
msg = this.hash(this.output.sid, 'i', this.peerIdentity);
|
||||
const msg = this.hash(this.output.sid, 'i', this.peerIdentity);
|
||||
|
||||
assert(!this.challengeSent, 'Cannot initiate challenge twice.');
|
||||
this.challengeSent = true;
|
||||
@ -540,15 +534,13 @@ AuthDB.prototype.close = async function close() {
|
||||
*/
|
||||
|
||||
AuthDB.prototype.addKnown = function addKnown(host, key) {
|
||||
let addr;
|
||||
|
||||
assert(typeof host === 'string',
|
||||
'Known host must be a string.');
|
||||
|
||||
assert(Buffer.isBuffer(key) && key.length === 33,
|
||||
'Invalid public key for known peer.');
|
||||
|
||||
addr = IP.fromHostname(host);
|
||||
const addr = IP.fromHostname(host);
|
||||
|
||||
if (addr.type === IP.types.DNS) {
|
||||
// Defer this for resolution.
|
||||
@ -604,12 +596,11 @@ AuthDB.prototype.setAuthorized = function setAuthorized(keys) {
|
||||
|
||||
AuthDB.prototype.getKnown = function getKnown(hostname) {
|
||||
const known = this.known.get(hostname);
|
||||
let addr;
|
||||
|
||||
if (known)
|
||||
return known;
|
||||
|
||||
addr = IP.fromHostname(hostname);
|
||||
const addr = IP.fromHostname(hostname);
|
||||
|
||||
return this.known.get(addr.host);
|
||||
};
|
||||
@ -667,15 +658,14 @@ AuthDB.prototype.populate = async function populate(addr, key) {
|
||||
*/
|
||||
|
||||
AuthDB.prototype.readKnown = async function readKnown() {
|
||||
let file, text;
|
||||
|
||||
if (fs.unsupported)
|
||||
return;
|
||||
|
||||
if (!this.prefix)
|
||||
return;
|
||||
|
||||
file = path.join(this.prefix, 'known-peers');
|
||||
const file = path.join(this.prefix, 'known-peers');
|
||||
let text;
|
||||
|
||||
try {
|
||||
text = await fs.readFile(file, 'utf8');
|
||||
@ -698,8 +688,6 @@ AuthDB.prototype.parseKnown = function parseKnown(text) {
|
||||
const lines = text.split(/\n+/);
|
||||
|
||||
for (let line of lines) {
|
||||
let parts, hostname, host, ip, key;
|
||||
|
||||
line = line.trim();
|
||||
|
||||
if (line.length === 0)
|
||||
@ -708,12 +696,13 @@ AuthDB.prototype.parseKnown = function parseKnown(text) {
|
||||
if (/^\s*#/.test(line))
|
||||
continue;
|
||||
|
||||
parts = line.split(/\s+/);
|
||||
const parts = line.split(/\s+/);
|
||||
|
||||
if (parts.length < 2)
|
||||
continue;
|
||||
|
||||
hostname = parts[0].trim().split(',');
|
||||
const hostname = parts[0].trim().split(',');
|
||||
let host, ip;
|
||||
|
||||
if (hostname.length >= 2) {
|
||||
host = hostname[0];
|
||||
@ -723,8 +712,8 @@ AuthDB.prototype.parseKnown = function parseKnown(text) {
|
||||
ip = hostname[0];
|
||||
}
|
||||
|
||||
key = parts[1].trim();
|
||||
key = Buffer.from(key, 'hex');
|
||||
const hex = parts[1].trim();
|
||||
const key = Buffer.from(hex, 'hex');
|
||||
|
||||
if (key.length !== 33)
|
||||
throw new Error(`Invalid key: ${parts[1]}.`);
|
||||
@ -746,15 +735,14 @@ AuthDB.prototype.parseKnown = function parseKnown(text) {
|
||||
*/
|
||||
|
||||
AuthDB.prototype.readAuth = async function readAuth() {
|
||||
let file, text;
|
||||
|
||||
if (fs.unsupported)
|
||||
return;
|
||||
|
||||
if (!this.prefix)
|
||||
return;
|
||||
|
||||
file = path.join(this.prefix, 'authorized-peers');
|
||||
const file = path.join(this.prefix, 'authorized-peers');
|
||||
let text;
|
||||
|
||||
try {
|
||||
text = await fs.readFile(file, 'utf8');
|
||||
@ -777,8 +765,6 @@ AuthDB.prototype.parseAuth = function parseAuth(text) {
|
||||
const lines = text.split(/\n+/);
|
||||
|
||||
for (let line of lines) {
|
||||
let key;
|
||||
|
||||
line = line.trim();
|
||||
|
||||
if (line.length === 0)
|
||||
@ -787,7 +773,7 @@ AuthDB.prototype.parseAuth = function parseAuth(text) {
|
||||
if (/^\s*#/.test(line))
|
||||
continue;
|
||||
|
||||
key = Buffer.from(line, 'hex');
|
||||
const key = Buffer.from(line, 'hex');
|
||||
|
||||
if (key.length !== 33)
|
||||
throw new Error(`Invalid key: ${line}.`);
|
||||
|
||||
@ -599,7 +599,6 @@ BIP151.prototype.packet = function _packet(cmd, body) {
|
||||
const size = this.packetSize(cmd, body);
|
||||
const bw = new StaticWriter(size);
|
||||
const payloadSize = size - 20;
|
||||
let packet, payload;
|
||||
|
||||
bw.writeU32(payloadSize);
|
||||
bw.writeVarString(cmd, 'ascii');
|
||||
@ -607,8 +606,8 @@ BIP151.prototype.packet = function _packet(cmd, body) {
|
||||
bw.writeBytes(body);
|
||||
bw.seek(16);
|
||||
|
||||
packet = bw.render();
|
||||
payload = packet.slice(4, 4 + payloadSize);
|
||||
const packet = bw.render();
|
||||
const payload = packet.slice(4, 4 + payloadSize);
|
||||
|
||||
this.maybeRekey(packet);
|
||||
|
||||
@ -645,35 +644,32 @@ BIP151.prototype.feed = function feed(data) {
|
||||
*/
|
||||
|
||||
BIP151.prototype.read = function read(size) {
|
||||
let pending, chunk, off, len;
|
||||
|
||||
assert(this.total >= size, 'Reading too much.');
|
||||
|
||||
if (size === 0)
|
||||
return Buffer.alloc(0);
|
||||
|
||||
pending = this.pending[0];
|
||||
const pending = this.pending[0];
|
||||
|
||||
if (pending.length > size) {
|
||||
chunk = pending.slice(0, size);
|
||||
const chunk = pending.slice(0, size);
|
||||
this.pending[0] = pending.slice(size);
|
||||
this.total -= chunk.length;
|
||||
return chunk;
|
||||
}
|
||||
|
||||
if (pending.length === size) {
|
||||
chunk = this.pending.shift();
|
||||
const chunk = this.pending.shift();
|
||||
this.total -= chunk.length;
|
||||
return chunk;
|
||||
}
|
||||
|
||||
chunk = Buffer.allocUnsafe(size);
|
||||
off = 0;
|
||||
len = 0;
|
||||
const chunk = Buffer.allocUnsafe(size);
|
||||
let off = 0;
|
||||
|
||||
while (off < chunk.length) {
|
||||
pending = this.pending[0];
|
||||
len = pending.copy(chunk, off);
|
||||
const pending = this.pending[0];
|
||||
const len = pending.copy(chunk, off);
|
||||
if (len === pending.length)
|
||||
this.pending.shift();
|
||||
else
|
||||
@ -695,8 +691,6 @@ BIP151.prototype.read = function read(size) {
|
||||
*/
|
||||
|
||||
BIP151.prototype.parse = function parse(data) {
|
||||
let payload, tag, br;
|
||||
|
||||
if (!this.hasSize) {
|
||||
const size = this.input.decryptSize(data);
|
||||
|
||||
@ -720,8 +714,8 @@ BIP151.prototype.parse = function parse(data) {
|
||||
return;
|
||||
}
|
||||
|
||||
payload = data.slice(0, this.waiting - 16);
|
||||
tag = data.slice(this.waiting - 16, this.waiting);
|
||||
const payload = data.slice(0, this.waiting - 16);
|
||||
const tag = data.slice(this.waiting - 16, this.waiting);
|
||||
|
||||
this.hasSize = false;
|
||||
this.waiting = 4;
|
||||
@ -741,7 +735,7 @@ BIP151.prototype.parse = function parse(data) {
|
||||
this.input.decrypt(payload);
|
||||
this.input.sequence();
|
||||
|
||||
br = new BufferReader(payload);
|
||||
const br = new BufferReader(payload);
|
||||
|
||||
while (br.left()) {
|
||||
let cmd, body;
|
||||
|
||||
@ -122,32 +122,30 @@ CompactBlock.prototype.verifyBody = function verifyBody() {
|
||||
|
||||
CompactBlock.prototype.fromRaw = function fromRaw(data) {
|
||||
const br = new BufferReader(data);
|
||||
let count;
|
||||
|
||||
this.readHead(br);
|
||||
|
||||
this.keyNonce = br.readBytes(8);
|
||||
this.sipKey = this.getKey();
|
||||
|
||||
count = br.readVarint();
|
||||
const idCount = br.readVarint();
|
||||
|
||||
this.totalTX += count;
|
||||
this.totalTX += idCount;
|
||||
|
||||
for (let i = 0; i < count; i++)
|
||||
for (let i = 0; i < idCount; i++)
|
||||
this.ids.push(br.readU32() + br.readU16() * 0x100000000);
|
||||
|
||||
count = br.readVarint();
|
||||
const txCount = br.readVarint();
|
||||
|
||||
this.totalTX += count;
|
||||
this.totalTX += txCount;
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
for (let i = 0; i < txCount; i++) {
|
||||
const index = br.readVarint();
|
||||
let tx;
|
||||
|
||||
assert(index <= 0xffff);
|
||||
assert(index < this.totalTX);
|
||||
|
||||
tx = TX.fromReader(br);
|
||||
const tx = TX.fromReader(br);
|
||||
|
||||
this.ptx.push([index, tx]);
|
||||
}
|
||||
@ -299,22 +297,19 @@ CompactBlock.prototype.toRequest = function toRequest() {
|
||||
*/
|
||||
|
||||
CompactBlock.prototype.fillMempool = function fillMempool(witness, mempool) {
|
||||
let have;
|
||||
|
||||
if (this.count === this.totalTX)
|
||||
return true;
|
||||
|
||||
have = new Set();
|
||||
const have = new Set();
|
||||
|
||||
for (const {tx} of mempool.map.values()) {
|
||||
let hash = tx.hash();
|
||||
let id, index;
|
||||
|
||||
if (witness)
|
||||
hash = tx.witnessHash();
|
||||
|
||||
id = this.sid(hash);
|
||||
index = this.idMap.get(id);
|
||||
const id = this.sid(hash);
|
||||
const index = this.idMap.get(id);
|
||||
|
||||
if (index == null)
|
||||
continue;
|
||||
@ -368,12 +363,10 @@ CompactBlock.prototype.fillMissing = function fillMissing(res) {
|
||||
*/
|
||||
|
||||
CompactBlock.prototype.sid = function sid(hash) {
|
||||
let hi, lo;
|
||||
|
||||
if (typeof hash === 'string')
|
||||
hash = Buffer.from(hash, 'hex');
|
||||
|
||||
[hi, lo] = siphash256(hash, this.sipKey);
|
||||
const [hi, lo] = siphash256(hash, this.sipKey);
|
||||
|
||||
return (hi & 0xffff) * 0x100000000 + (lo >>> 0);
|
||||
};
|
||||
@ -406,9 +399,6 @@ CompactBlock.prototype.getKey = function getKey() {
|
||||
*/
|
||||
|
||||
CompactBlock.prototype.init = function init() {
|
||||
let last = -1;
|
||||
let offset = 0;
|
||||
|
||||
if (this.totalTX === 0)
|
||||
throw new Error('Empty vectors.');
|
||||
|
||||
@ -426,6 +416,9 @@ CompactBlock.prototype.init = function init() {
|
||||
for (let i = 0; i < this.totalTX; i++)
|
||||
this.available.push(null);
|
||||
|
||||
let last = -1;
|
||||
let offset = 0;
|
||||
|
||||
for (let i = 0; i < this.ptx.length; i++) {
|
||||
const [index, tx] = this.ptx[i];
|
||||
last += index + 1;
|
||||
@ -506,12 +499,11 @@ CompactBlock.prototype.fromBlock = function fromBlock(block, witness, nonce) {
|
||||
for (let i = 1; i < block.txs.length; i++) {
|
||||
const tx = block.txs[i];
|
||||
let hash = tx.hash();
|
||||
let id;
|
||||
|
||||
if (witness)
|
||||
hash = tx.witnessHash();
|
||||
|
||||
id = this.sid(hash);
|
||||
const id = this.sid(hash);
|
||||
|
||||
this.ids.push(id);
|
||||
}
|
||||
@ -624,12 +616,10 @@ TXRequest.fromCompact = function fromCompact(block) {
|
||||
*/
|
||||
|
||||
TXRequest.prototype.fromReader = function fromReader(br) {
|
||||
let offset = 0;
|
||||
let count;
|
||||
|
||||
this.hash = br.readHash('hex');
|
||||
|
||||
count = br.readVarint();
|
||||
const count = br.readVarint();
|
||||
let offset = 0;
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const index = br.readVarint();
|
||||
@ -788,11 +778,9 @@ TXResponse.fromOptions = function fromOptions(options) {
|
||||
*/
|
||||
|
||||
TXResponse.prototype.fromReader = function fromReader(br) {
|
||||
let count;
|
||||
|
||||
this.hash = br.readHash('hex');
|
||||
|
||||
count = br.readVarint();
|
||||
const count = br.readVarint();
|
||||
|
||||
for (let i = 0; i < count; i++)
|
||||
this.txs.push(TX.fromReader(br));
|
||||
|
||||
@ -22,7 +22,7 @@ const external = exports;
|
||||
*/
|
||||
|
||||
external.getIPv4 = async function getIPv4() {
|
||||
let res, ip;
|
||||
let res = null;
|
||||
|
||||
try {
|
||||
res = await request({
|
||||
@ -35,14 +35,16 @@ external.getIPv4 = async function getIPv4() {
|
||||
return await external.getIPv42();
|
||||
}
|
||||
|
||||
try {
|
||||
ip = res.body.trim();
|
||||
ip = IP.toBuffer(ip);
|
||||
let ip = null;
|
||||
|
||||
if (!IP.isIPv4(ip))
|
||||
try {
|
||||
const str = res.body.trim();
|
||||
const raw = IP.toBuffer(str);
|
||||
|
||||
if (!IP.isIPv4(raw))
|
||||
throw new Error('Could not find IPv4.');
|
||||
|
||||
ip = IP.toString(ip);
|
||||
ip = IP.toString(raw);
|
||||
} catch (e) {
|
||||
return await external.getIPv42();
|
||||
}
|
||||
@ -58,22 +60,20 @@ external.getIPv4 = async function getIPv4() {
|
||||
*/
|
||||
|
||||
external.getIPv42 = async function getIPv42() {
|
||||
let res, match, ip, raw;
|
||||
|
||||
res = await request({
|
||||
const res = await request({
|
||||
method: 'GET',
|
||||
uri: 'http://checkip.dyndns.org',
|
||||
expect: 'html',
|
||||
timeout: 2000
|
||||
});
|
||||
|
||||
match = /IP Address:\s*([0-9a-f.:]+)/i.exec(res.body);
|
||||
const match = /IP Address:\s*([0-9a-f.:]+)/i.exec(res.body);
|
||||
|
||||
if (!match)
|
||||
throw new Error('Could not find IPv4.');
|
||||
|
||||
ip = match[1];
|
||||
raw = IP.toBuffer(ip);
|
||||
const str = match[1];
|
||||
const raw = IP.toBuffer(str);
|
||||
|
||||
if (!IP.isIPv4(raw))
|
||||
throw new Error('Could not find IPv4.');
|
||||
@ -88,20 +88,18 @@ external.getIPv42 = async function getIPv42() {
|
||||
*/
|
||||
|
||||
external.getIPv6 = async function getIPv6() {
|
||||
let res, ip;
|
||||
|
||||
res = await request({
|
||||
const res = await request({
|
||||
method: 'GET',
|
||||
uri: 'http://ipv6.icanhazip.com',
|
||||
expect: 'txt',
|
||||
timeout: 2000
|
||||
});
|
||||
|
||||
ip = res.body.trim();
|
||||
ip = IP.toBuffer(ip);
|
||||
const str = res.body.trim();
|
||||
const raw = IP.toBuffer(str);
|
||||
|
||||
if (!IP.isIPv6(ip))
|
||||
if (!IP.isIPv6(raw))
|
||||
throw new Error('Could not find IPv6.');
|
||||
|
||||
return IP.toString(ip);
|
||||
return IP.toString(raw);
|
||||
};
|
||||
|
||||
@ -33,14 +33,11 @@ function Framer(network) {
|
||||
*/
|
||||
|
||||
Framer.prototype.packet = function _packet(cmd, payload, checksum) {
|
||||
let packet;
|
||||
|
||||
assert(payload, 'No payload.');
|
||||
|
||||
assert(cmd.length < 12);
|
||||
assert(payload.length <= 0xffffffff);
|
||||
|
||||
packet = Buffer.allocUnsafe(24 + payload.length);
|
||||
const packet = Buffer.allocUnsafe(24 + payload.length);
|
||||
|
||||
// Magic value
|
||||
packet.writeUInt32LE(this.network.magic, 0, true);
|
||||
|
||||
@ -253,7 +253,6 @@ HostList.prototype.injectSeeds = function injectSeeds() {
|
||||
|
||||
HostList.prototype.loadFile = async function loadFile() {
|
||||
const filename = this.options.filename;
|
||||
let data, json;
|
||||
|
||||
if (fs.unsupported)
|
||||
return;
|
||||
@ -264,6 +263,7 @@ HostList.prototype.loadFile = async function loadFile() {
|
||||
if (!filename)
|
||||
return;
|
||||
|
||||
let data;
|
||||
try {
|
||||
data = await fs.readFile(filename, 'utf8');
|
||||
} catch (e) {
|
||||
@ -272,7 +272,7 @@ HostList.prototype.loadFile = async function loadFile() {
|
||||
throw e;
|
||||
}
|
||||
|
||||
json = JSON.parse(data);
|
||||
const json = JSON.parse(data);
|
||||
|
||||
this.fromJSON(json);
|
||||
};
|
||||
@ -285,7 +285,6 @@ HostList.prototype.loadFile = async function loadFile() {
|
||||
|
||||
HostList.prototype.flush = async function flush() {
|
||||
const filename = this.options.filename;
|
||||
let json, data;
|
||||
|
||||
if (fs.unsupported)
|
||||
return;
|
||||
@ -303,8 +302,8 @@ HostList.prototype.flush = async function flush() {
|
||||
|
||||
this.logger.debug('Writing hosts to %s.', filename);
|
||||
|
||||
json = this.toJSON();
|
||||
data = JSON.stringify(json);
|
||||
const json = this.toJSON();
|
||||
const data = JSON.stringify(json);
|
||||
|
||||
try {
|
||||
await fs.writeFile(filename, data, 'utf8');
|
||||
@ -422,13 +421,13 @@ HostList.prototype.getHost = function getHost() {
|
||||
for (;;) {
|
||||
let index = util.random(0, buckets.length);
|
||||
const bucket = buckets[index];
|
||||
let entry, num;
|
||||
|
||||
if (bucket.size === 0)
|
||||
continue;
|
||||
|
||||
index = util.random(0, bucket.size);
|
||||
|
||||
let entry;
|
||||
if (buckets === this.used) {
|
||||
entry = bucket.head;
|
||||
while (index--)
|
||||
@ -441,7 +440,7 @@ HostList.prototype.getHost = function getHost() {
|
||||
}
|
||||
}
|
||||
|
||||
num = util.random(0, 1 << 30);
|
||||
const num = util.random(0, 1 << 30);
|
||||
|
||||
if (num < factor * entry.chance(now) * (1 << 30))
|
||||
return entry;
|
||||
@ -488,17 +487,15 @@ HostList.prototype.usedBucket = function usedBucket(entry) {
|
||||
*/
|
||||
|
||||
HostList.prototype.add = function add(addr, src) {
|
||||
const now = this.network.now();
|
||||
let penalty = 2 * 60 * 60;
|
||||
let interval = 24 * 60 * 60;
|
||||
let factor = 1;
|
||||
let entry, bucket;
|
||||
|
||||
assert(addr.port !== 0);
|
||||
|
||||
entry = this.map.get(addr.hostname);
|
||||
let entry = this.map.get(addr.hostname);
|
||||
|
||||
if (entry) {
|
||||
const now = this.network.now();
|
||||
let penalty = 2 * 60 * 60;
|
||||
let interval = 24 * 60 * 60;
|
||||
|
||||
// No source means we're inserting
|
||||
// this ourselves. No penalty.
|
||||
if (!src)
|
||||
@ -539,6 +536,7 @@ HostList.prototype.add = function add(addr, src) {
|
||||
|
||||
// Stochastic test: previous refCount
|
||||
// N: 2^N times harder to increase it.
|
||||
let factor = 1;
|
||||
for (let i = 0; i < entry.refCount; i++)
|
||||
factor *= 2;
|
||||
|
||||
@ -556,7 +554,7 @@ HostList.prototype.add = function add(addr, src) {
|
||||
this.totalFresh++;
|
||||
}
|
||||
|
||||
bucket = this.freshBucket(entry);
|
||||
const bucket = this.freshBucket(entry);
|
||||
|
||||
if (bucket.has(entry.key()))
|
||||
return false;
|
||||
@ -579,7 +577,7 @@ HostList.prototype.add = function add(addr, src) {
|
||||
*/
|
||||
|
||||
HostList.prototype.evictFresh = function evictFresh(bucket) {
|
||||
let old;
|
||||
let old = null;
|
||||
|
||||
for (const entry of bucket.values()) {
|
||||
if (this.isStale(entry)) {
|
||||
@ -730,12 +728,12 @@ HostList.prototype.markSuccess = function markSuccess(hostname) {
|
||||
|
||||
HostList.prototype.markAck = function markAck(hostname, services) {
|
||||
const entry = this.map.get(hostname);
|
||||
const now = this.network.now();
|
||||
let bucket, evicted, old, fresh;
|
||||
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
const now = this.network.now();
|
||||
|
||||
entry.addr.services |= services;
|
||||
entry.addr.services >>>= 0;
|
||||
|
||||
@ -749,6 +747,7 @@ HostList.prototype.markAck = function markAck(hostname, services) {
|
||||
assert(entry.refCount > 0);
|
||||
|
||||
// Remove from fresh.
|
||||
let old;
|
||||
for (const bucket of this.fresh) {
|
||||
if (bucket.delete(entry.key())) {
|
||||
entry.refCount--;
|
||||
@ -761,7 +760,7 @@ HostList.prototype.markAck = function markAck(hostname, services) {
|
||||
this.totalFresh--;
|
||||
|
||||
// Find room in used bucket.
|
||||
bucket = this.usedBucket(entry);
|
||||
const bucket = this.usedBucket(entry);
|
||||
|
||||
if (bucket.size < this.options.maxEntries) {
|
||||
entry.used = true;
|
||||
@ -771,8 +770,8 @@ HostList.prototype.markAck = function markAck(hostname, services) {
|
||||
}
|
||||
|
||||
// No room. Evict.
|
||||
evicted = this.evictUsed(bucket);
|
||||
fresh = this.freshBucket(evicted);
|
||||
const evicted = this.evictUsed(bucket);
|
||||
let fresh = this.freshBucket(evicted);
|
||||
|
||||
// Move to entry's old bucket if no room.
|
||||
if (fresh.size >= this.options.maxEntries)
|
||||
@ -828,15 +827,15 @@ HostList.prototype.toArray = function toArray() {
|
||||
*/
|
||||
|
||||
HostList.prototype.addSeed = function addSeed(host) {
|
||||
let addr = IP.fromHostname(host, this.network.port);
|
||||
const ip = IP.fromHostname(host, this.network.port);
|
||||
|
||||
if (addr.type === IP.types.DNS) {
|
||||
if (ip.type === IP.types.DNS) {
|
||||
// Defer for resolution.
|
||||
this.dnsSeeds.push(addr);
|
||||
this.dnsSeeds.push(ip);
|
||||
return;
|
||||
}
|
||||
|
||||
addr = NetAddress.fromHost(addr.host, addr.port, this.network);
|
||||
const addr = NetAddress.fromHost(ip.host, ip.port, this.network);
|
||||
|
||||
this.add(addr);
|
||||
|
||||
@ -850,15 +849,15 @@ HostList.prototype.addSeed = function addSeed(host) {
|
||||
*/
|
||||
|
||||
HostList.prototype.addNode = function addNode(host) {
|
||||
let addr = IP.fromHostname(host, this.network.port);
|
||||
const ip = IP.fromHostname(host, this.network.port);
|
||||
|
||||
if (addr.type === IP.types.DNS) {
|
||||
if (ip.type === IP.types.DNS) {
|
||||
// Defer for resolution.
|
||||
this.dnsNodes.push(addr);
|
||||
this.dnsNodes.push(ip);
|
||||
return;
|
||||
}
|
||||
|
||||
addr = NetAddress.fromHost(addr.host, addr.port, this.network);
|
||||
const addr = NetAddress.fromHost(ip.host, ip.port, this.network);
|
||||
|
||||
this.nodes.push(addr);
|
||||
this.add(addr);
|
||||
@ -939,15 +938,13 @@ HostList.prototype.addLocal = function addLocal(host, port, score) {
|
||||
*/
|
||||
|
||||
HostList.prototype.pushLocal = function pushLocal(addr, score) {
|
||||
let local;
|
||||
|
||||
if (!addr.isRoutable())
|
||||
return false;
|
||||
|
||||
if (this.local.has(addr.hostname))
|
||||
return false;
|
||||
|
||||
local = new LocalAddress(addr, score);
|
||||
const local = new LocalAddress(addr, score);
|
||||
|
||||
this.local.set(addr.hostname, local);
|
||||
|
||||
@ -1076,12 +1073,12 @@ HostList.prototype.populateSeed = async function populateSeed(seed) {
|
||||
|
||||
HostList.prototype.populate = async function populate(target) {
|
||||
const addrs = [];
|
||||
let hosts;
|
||||
|
||||
assert(target.type === IP.types.DNS, 'Resolved host passed.');
|
||||
|
||||
this.logger.info('Resolving host: %s.', target.host);
|
||||
|
||||
let hosts;
|
||||
try {
|
||||
hosts = await this.resolve(target.host);
|
||||
} catch (e) {
|
||||
|
||||
@ -987,11 +987,9 @@ GetBlocksPacket.prototype.toRaw = function toRaw() {
|
||||
*/
|
||||
|
||||
GetBlocksPacket.prototype.fromReader = function fromReader(br) {
|
||||
let count;
|
||||
|
||||
this.version = br.readU32();
|
||||
|
||||
count = br.readVarint();
|
||||
const count = br.readVarint();
|
||||
|
||||
assert(count <= 50000, 'Too many block hashes.');
|
||||
|
||||
|
||||
@ -63,10 +63,9 @@ Parser.prototype.feed = function feed(data) {
|
||||
while (this.total >= this.waiting) {
|
||||
const chunk = Buffer.allocUnsafe(this.waiting);
|
||||
let off = 0;
|
||||
let len = 0;
|
||||
|
||||
while (off < chunk.length) {
|
||||
len = this.pending[0].copy(chunk, off);
|
||||
const len = this.pending[0].copy(chunk, off);
|
||||
if (len === this.pending[0].length)
|
||||
this.pending.shift();
|
||||
else
|
||||
@ -87,8 +86,6 @@ Parser.prototype.feed = function feed(data) {
|
||||
*/
|
||||
|
||||
Parser.prototype.parse = function parse(data) {
|
||||
let payload, checksum;
|
||||
|
||||
assert(data.length <= common.MAX_MESSAGE);
|
||||
|
||||
if (!this.header) {
|
||||
@ -96,7 +93,7 @@ Parser.prototype.parse = function parse(data) {
|
||||
return;
|
||||
}
|
||||
|
||||
checksum = digest.hash256(data).readUInt32LE(0, true);
|
||||
const checksum = digest.hash256(data).readUInt32LE(0, true);
|
||||
|
||||
if (checksum !== this.header.checksum) {
|
||||
this.waiting = 24;
|
||||
@ -105,6 +102,8 @@ Parser.prototype.parse = function parse(data) {
|
||||
return;
|
||||
}
|
||||
|
||||
let payload = null;
|
||||
|
||||
try {
|
||||
payload = this.parsePayload(this.header.cmd, data);
|
||||
} catch (e) {
|
||||
@ -127,26 +126,25 @@ Parser.prototype.parse = function parse(data) {
|
||||
*/
|
||||
|
||||
Parser.prototype.parseHeader = function parseHeader(data) {
|
||||
let i, magic, cmd, size, checksum;
|
||||
|
||||
magic = data.readUInt32LE(0, true);
|
||||
const magic = data.readUInt32LE(0, true);
|
||||
|
||||
if (magic !== this.network.magic) {
|
||||
this.error('Invalid magic value: %s.', util.hex32(magic));
|
||||
return null;
|
||||
}
|
||||
|
||||
// Count length of the cmd
|
||||
for (i = 0; data[i + 4] !== 0 && i < 12; i++);
|
||||
// Count length of the cmd.
|
||||
let i = 0;
|
||||
for (; data[i + 4] !== 0 && i < 12; i++);
|
||||
|
||||
if (i === 12) {
|
||||
this.error('Non NULL-terminated command.');
|
||||
return null;
|
||||
}
|
||||
|
||||
cmd = data.toString('ascii', 4, 4 + i);
|
||||
const cmd = data.toString('ascii', 4, 4 + i);
|
||||
|
||||
size = data.readUInt32LE(16, true);
|
||||
const size = data.readUInt32LE(16, true);
|
||||
|
||||
if (size > common.MAX_MESSAGE) {
|
||||
this.waiting = 24;
|
||||
@ -156,7 +154,7 @@ Parser.prototype.parseHeader = function parseHeader(data) {
|
||||
|
||||
this.waiting = size;
|
||||
|
||||
checksum = data.readUInt32LE(20, true);
|
||||
const checksum = data.readUInt32LE(20, true);
|
||||
|
||||
return new Header(cmd, size, checksum);
|
||||
};
|
||||
|
||||
@ -341,7 +341,7 @@ Peer.prototype.setCipher = function setCipher(cipher) {
|
||||
});
|
||||
|
||||
this.bip151.on('packet', (cmd, body) => {
|
||||
let payload;
|
||||
let payload = null;
|
||||
try {
|
||||
payload = this.parser.parsePayload(cmd, body);
|
||||
} catch (e) {
|
||||
@ -435,11 +435,9 @@ Peer.prototype.accept = function accept(socket) {
|
||||
*/
|
||||
|
||||
Peer.prototype.connect = function connect(addr) {
|
||||
let socket;
|
||||
|
||||
assert(!this.socket);
|
||||
|
||||
socket = this.options.createSocket(addr.port, addr.host);
|
||||
const socket = this.options.createSocket(addr.port, addr.host);
|
||||
|
||||
this.address = addr;
|
||||
this.outbound = true;
|
||||
@ -525,7 +523,7 @@ Peer.prototype.initConnect = function initConnect() {
|
||||
this.socket.removeListener('error', onError);
|
||||
};
|
||||
|
||||
let onError = (err) => {
|
||||
const onError = (err) => {
|
||||
cleanup();
|
||||
reject(err);
|
||||
};
|
||||
@ -805,8 +803,6 @@ Peer.prototype.announceTX = function announceTX(txs) {
|
||||
*/
|
||||
|
||||
Peer.prototype.queueInv = function queueInv(items) {
|
||||
let hasBlock = false;
|
||||
|
||||
if (!this.handshake)
|
||||
return;
|
||||
|
||||
@ -816,6 +812,8 @@ Peer.prototype.queueInv = function queueInv(items) {
|
||||
if (!Array.isArray(items))
|
||||
items = [items];
|
||||
|
||||
let hasBlock = false;
|
||||
|
||||
for (const item of items) {
|
||||
if (item.type === invTypes.BLOCK)
|
||||
hasBlock = true;
|
||||
@ -1022,7 +1020,6 @@ Peer.prototype.sendFeeRate = function sendFeeRate(rate) {
|
||||
|
||||
Peer.prototype.destroy = function destroy() {
|
||||
const connected = this.connected;
|
||||
let jobs;
|
||||
|
||||
if (this.destroyed)
|
||||
return;
|
||||
@ -1059,7 +1056,7 @@ Peer.prototype.destroy = function destroy() {
|
||||
this.connectTimeout = null;
|
||||
}
|
||||
|
||||
jobs = this.drainQueue;
|
||||
const jobs = this.drainQueue;
|
||||
|
||||
this.drainSize = 0;
|
||||
this.drainQueue = [];
|
||||
@ -1098,13 +1095,12 @@ Peer.prototype.write = function write(data) {
|
||||
*/
|
||||
|
||||
Peer.prototype.send = function send(packet) {
|
||||
let checksum;
|
||||
|
||||
if (this.destroyed)
|
||||
throw new Error('Peer is destroyed (send).');
|
||||
|
||||
// Used cached hashes as the
|
||||
// packet checksum for speed.
|
||||
let checksum = null;
|
||||
if (packet.type === packetTypes.TX) {
|
||||
const tx = packet.tx;
|
||||
if (packet.witness) {
|
||||
@ -1300,8 +1296,6 @@ Peer.prototype.maybeTimeout = function maybeTimeout() {
|
||||
}
|
||||
|
||||
if (now > this.time + 60000) {
|
||||
let mult;
|
||||
|
||||
assert(this.time !== 0);
|
||||
|
||||
if (this.lastRecv === 0 || this.lastSend === 0) {
|
||||
@ -1316,7 +1310,7 @@ Peer.prototype.maybeTimeout = function maybeTimeout() {
|
||||
return;
|
||||
}
|
||||
|
||||
mult = this.version <= common.PONG_VERSION ? 4 : 1;
|
||||
const mult = this.version <= common.PONG_VERSION ? 4 : 1;
|
||||
|
||||
if (now > this.lastRecv + Peer.TIMEOUT_INTERVAL * mult) {
|
||||
this.error('Peer is stalling (recv).');
|
||||
@ -1341,11 +1335,11 @@ Peer.prototype.maybeTimeout = function maybeTimeout() {
|
||||
*/
|
||||
|
||||
Peer.prototype.request = function request(type, timeout) {
|
||||
let entry = this.responseMap.get(type);
|
||||
|
||||
if (this.destroyed)
|
||||
return;
|
||||
|
||||
let entry = this.responseMap.get(type);
|
||||
|
||||
if (!entry) {
|
||||
entry = new RequestEntry();
|
||||
this.responseMap.set(type, entry);
|
||||
@ -1384,14 +1378,12 @@ Peer.prototype.response = function response(type, payload) {
|
||||
|
||||
Peer.prototype.wait = function wait(type, timeout) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let entry;
|
||||
|
||||
if (this.destroyed) {
|
||||
reject(new Error('Peer is destroyed (request).'));
|
||||
return;
|
||||
}
|
||||
|
||||
entry = this.request(type);
|
||||
const entry = this.request(type);
|
||||
|
||||
entry.setTimeout(timeout);
|
||||
entry.addJob(resolve, reject);
|
||||
@ -1405,18 +1397,16 @@ Peer.prototype.wait = function wait(type, timeout) {
|
||||
*/
|
||||
|
||||
Peer.prototype.error = function error(err) {
|
||||
let msg;
|
||||
|
||||
if (this.destroyed)
|
||||
return;
|
||||
|
||||
if (typeof err === 'string') {
|
||||
msg = util.fmt.apply(util, arguments);
|
||||
const msg = util.fmt.apply(util, arguments);
|
||||
err = new Error(msg);
|
||||
}
|
||||
|
||||
if (typeof err.code === 'string' && err.code[0] === 'E') {
|
||||
msg = err.code;
|
||||
const msg = err.code;
|
||||
err = new Error(msg);
|
||||
err.code = msg;
|
||||
err.message = `Socket Error: ${msg}`;
|
||||
@ -1512,10 +1502,10 @@ Peer.prototype.getTX = function getTX(hashes) {
|
||||
*/
|
||||
|
||||
Peer.prototype.getFullBlock = function getFullBlock(hash) {
|
||||
let type = invTypes.BLOCK;
|
||||
|
||||
assert(!this.options.spv);
|
||||
|
||||
let type = invTypes.BLOCK;
|
||||
|
||||
if (this.hasWitness())
|
||||
type |= InvItem.WITNESS_FLAG;
|
||||
|
||||
@ -1577,8 +1567,6 @@ Peer.prototype.readPacket = async function readPacket(packet) {
|
||||
*/
|
||||
|
||||
Peer.prototype.handlePacket = async function handlePacket(packet) {
|
||||
let entry;
|
||||
|
||||
if (this.destroyed)
|
||||
throw new Error('Destroyed peer sent a packet.');
|
||||
|
||||
@ -1599,7 +1587,7 @@ Peer.prototype.handlePacket = async function handlePacket(packet) {
|
||||
this.bip150.reject(new Error('Message before BIP150 auth.'));
|
||||
}
|
||||
|
||||
entry = this.fulfill(packet);
|
||||
const entry = this.fulfill(packet);
|
||||
|
||||
switch (packet.type) {
|
||||
case packetTypes.VERSION:
|
||||
@ -1951,12 +1939,10 @@ Peer.prototype.handleEncack = async function handleEncack(packet) {
|
||||
*/
|
||||
|
||||
Peer.prototype.handleAuthChallenge = async function handleAuthChallenge(packet) {
|
||||
let sig;
|
||||
|
||||
if (!this.bip150)
|
||||
return;
|
||||
|
||||
sig = this.bip150.challenge(packet.hash);
|
||||
const sig = this.bip150.challenge(packet.hash);
|
||||
|
||||
this.send(new packets.AuthReplyPacket(sig));
|
||||
};
|
||||
@ -1969,12 +1955,10 @@ Peer.prototype.handleAuthChallenge = async function handleAuthChallenge(packet)
|
||||
*/
|
||||
|
||||
Peer.prototype.handleAuthReply = async function handleAuthReply(packet) {
|
||||
let hash;
|
||||
|
||||
if (!this.bip150)
|
||||
return;
|
||||
|
||||
hash = this.bip150.reply(packet.signature);
|
||||
const hash = this.bip150.reply(packet.signature);
|
||||
|
||||
if (hash)
|
||||
this.send(new packets.AuthProposePacket(hash));
|
||||
@ -1988,12 +1972,10 @@ Peer.prototype.handleAuthReply = async function handleAuthReply(packet) {
|
||||
*/
|
||||
|
||||
Peer.prototype.handleAuthPropose = async function handleAuthPropose(packet) {
|
||||
let hash;
|
||||
|
||||
if (!this.bip150)
|
||||
return;
|
||||
|
||||
hash = this.bip150.propose(packet.hash);
|
||||
const hash = this.bip150.propose(packet.hash);
|
||||
|
||||
this.send(new packets.AuthChallengePacket(hash));
|
||||
};
|
||||
|
||||
195
lib/net/pool.js
195
lib/net/pool.js
@ -460,7 +460,6 @@ Pool.prototype.discover = async function discover() {
|
||||
Pool.prototype.discoverGateway = async function discoverGateway() {
|
||||
const src = this.options.publicPort;
|
||||
const dest = this.options.port;
|
||||
let wan, host;
|
||||
|
||||
// Pointless if we're not listening.
|
||||
if (!this.options.listen)
|
||||
@ -471,6 +470,8 @@ Pool.prototype.discoverGateway = async function discoverGateway() {
|
||||
if (!this.options.upnp)
|
||||
return;
|
||||
|
||||
let wan = null;
|
||||
|
||||
try {
|
||||
this.logger.debug('Discovering internet gateway (upnp).');
|
||||
wan = await UPNP.discover();
|
||||
@ -480,6 +481,8 @@ Pool.prototype.discoverGateway = async function discoverGateway() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let host = null;
|
||||
|
||||
try {
|
||||
host = await wan.getExternalIP();
|
||||
} catch (e) {
|
||||
@ -513,13 +516,14 @@ Pool.prototype.discoverGateway = async function discoverGateway() {
|
||||
*/
|
||||
|
||||
Pool.prototype.discoverSeeds = async function discoverSeeds(checkPeers) {
|
||||
const max = Math.min(2, this.options.maxOutbound);
|
||||
const size = this.hosts.size();
|
||||
let total = 0;
|
||||
|
||||
if (this.hosts.dnsSeeds.length === 0)
|
||||
return;
|
||||
|
||||
const max = Math.min(2, this.options.maxOutbound);
|
||||
const size = this.hosts.size();
|
||||
|
||||
let total = 0;
|
||||
|
||||
for (let peer = this.peers.head(); peer; peer = peer.next) {
|
||||
if (!peer.outbound)
|
||||
continue;
|
||||
@ -551,7 +555,6 @@ Pool.prototype.discoverSeeds = async function discoverSeeds(checkPeers) {
|
||||
|
||||
Pool.prototype.discoverExternal = async function discoverExternal() {
|
||||
const port = this.options.publicPort;
|
||||
let host4, host6;
|
||||
|
||||
// Pointless if we're not listening.
|
||||
if (!this.options.listen)
|
||||
@ -566,6 +569,8 @@ Pool.prototype.discoverExternal = async function discoverExternal() {
|
||||
if (this.hosts.local.size > 0)
|
||||
return;
|
||||
|
||||
let host4 = null;
|
||||
|
||||
try {
|
||||
host4 = await external.getIPv4();
|
||||
} catch (e) {
|
||||
@ -576,6 +581,8 @@ Pool.prototype.discoverExternal = async function discoverExternal() {
|
||||
if (host4 && this.hosts.addLocal(host4, port, scores.HTTP))
|
||||
this.logger.info('External IPv4 found (http): %s.', host4);
|
||||
|
||||
let host6 = null;
|
||||
|
||||
try {
|
||||
host6 = await external.getIPv6();
|
||||
} catch (e) {
|
||||
@ -594,29 +601,27 @@ Pool.prototype.discoverExternal = async function discoverExternal() {
|
||||
*/
|
||||
|
||||
Pool.prototype.handleSocket = function handleSocket(socket) {
|
||||
let host;
|
||||
|
||||
if (!socket.remoteAddress) {
|
||||
this.logger.debug('Ignoring disconnected peer.');
|
||||
socket.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
host = IP.normalize(socket.remoteAddress);
|
||||
const ip = IP.normalize(socket.remoteAddress);
|
||||
|
||||
if (this.peers.inbound >= this.options.maxInbound) {
|
||||
this.logger.debug('Ignoring peer: too many inbound (%s).', host);
|
||||
this.logger.debug('Ignoring peer: too many inbound (%s).', ip);
|
||||
socket.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.hosts.isBanned(host)) {
|
||||
this.logger.debug('Ignoring banned peer (%s).', host);
|
||||
if (this.hosts.isBanned(ip)) {
|
||||
this.logger.debug('Ignoring banned peer (%s).', ip);
|
||||
socket.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
host = IP.toHostname(host, socket.remotePort);
|
||||
const host = IP.toHostname(ip, socket.remotePort);
|
||||
|
||||
assert(!this.peers.map[host], 'Port collision.');
|
||||
|
||||
@ -630,8 +635,6 @@ Pool.prototype.handleSocket = function handleSocket(socket) {
|
||||
*/
|
||||
|
||||
Pool.prototype.addLoader = function addLoader() {
|
||||
let peer, addr;
|
||||
|
||||
if (!this.loaded)
|
||||
return;
|
||||
|
||||
@ -650,12 +653,12 @@ Pool.prototype.addLoader = function addLoader() {
|
||||
return;
|
||||
}
|
||||
|
||||
addr = this.getHost();
|
||||
const addr = this.getHost();
|
||||
|
||||
if (!addr)
|
||||
return;
|
||||
|
||||
peer = this.createOutbound(addr);
|
||||
const peer = this.createOutbound(addr);
|
||||
|
||||
this.logger.info('Adding loader peer (%s).', peer.hostname());
|
||||
|
||||
@ -761,11 +764,11 @@ Pool.prototype.stopSync = function stopSync() {
|
||||
*/
|
||||
|
||||
Pool.prototype.resync = async function resync(force) {
|
||||
let locator;
|
||||
|
||||
if (!this.syncing)
|
||||
return;
|
||||
|
||||
let locator = null;
|
||||
|
||||
try {
|
||||
locator = await this.chain.getLocator();
|
||||
} catch (e) {
|
||||
@ -822,8 +825,6 @@ Pool.prototype.isSyncable = function isSyncable(peer) {
|
||||
*/
|
||||
|
||||
Pool.prototype.sendSync = async function sendSync(peer) {
|
||||
let locator;
|
||||
|
||||
if (peer.syncing)
|
||||
return false;
|
||||
|
||||
@ -833,6 +834,8 @@ Pool.prototype.sendSync = async function sendSync(peer) {
|
||||
peer.syncing = true;
|
||||
peer.blockTime = util.ms();
|
||||
|
||||
let locator = null;
|
||||
|
||||
try {
|
||||
locator = await this.chain.getLocator();
|
||||
} catch (e) {
|
||||
@ -1061,11 +1064,11 @@ Pool.prototype.getItem = async function getItem(peer, item) {
|
||||
*/
|
||||
|
||||
Pool.prototype.sendBlock = async function sendBlock(peer, item, witness) {
|
||||
let block = this.getBroadcasted(peer, item);
|
||||
const broadcasted = this.getBroadcasted(peer, item);
|
||||
|
||||
// Check for a broadcasted item first.
|
||||
if (block) {
|
||||
peer.send(new packets.BlockPacket(block, witness));
|
||||
if (broadcasted) {
|
||||
peer.send(new packets.BlockPacket(broadcasted, witness));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1078,7 +1081,7 @@ Pool.prototype.sendBlock = async function sendBlock(peer, item, witness) {
|
||||
// If we have the same serialization, we
|
||||
// can write the raw binary to the socket.
|
||||
if (witness || !this.options.hasWitness()) {
|
||||
block = await this.chain.db.getRawBlock(item.hash);
|
||||
const block = await this.chain.db.getRawBlock(item.hash);
|
||||
|
||||
if (block) {
|
||||
peer.sendRaw('block', block);
|
||||
@ -1088,7 +1091,7 @@ Pool.prototype.sendBlock = async function sendBlock(peer, item, witness) {
|
||||
return false;
|
||||
}
|
||||
|
||||
block = await this.chain.db.getBlock(item.hash);
|
||||
const block = await this.chain.db.getBlock(item.hash);
|
||||
|
||||
if (block) {
|
||||
peer.send(new packets.BlockPacket(block, witness));
|
||||
@ -1524,9 +1527,6 @@ Pool.prototype.handlePong = async function handlePong(peer, packet) {
|
||||
*/
|
||||
|
||||
Pool.prototype.handleGetAddr = async function handleGetAddr(peer, packet) {
|
||||
const items = [];
|
||||
let addrs;
|
||||
|
||||
if (this.options.selfish)
|
||||
return;
|
||||
|
||||
@ -1539,7 +1539,8 @@ Pool.prototype.handleGetAddr = async function handleGetAddr(peer, packet) {
|
||||
|
||||
peer.sentAddr = true;
|
||||
|
||||
addrs = this.hosts.toArray();
|
||||
const addrs = this.hosts.toArray();
|
||||
const items = [];
|
||||
|
||||
for (const addr of addrs) {
|
||||
if (!peer.addrFilter.added(addr.hostname, 'ascii'))
|
||||
@ -1630,15 +1631,16 @@ Pool.prototype.handleInv = async function handleInv(peer, packet) {
|
||||
|
||||
Pool.prototype._handleInv = async function handleInv(peer, packet) {
|
||||
const items = packet.items;
|
||||
const blocks = [];
|
||||
const txs = [];
|
||||
let unknown = -1;
|
||||
|
||||
if (items.length > 50000) {
|
||||
peer.increaseBan(100);
|
||||
return;
|
||||
}
|
||||
|
||||
const blocks = [];
|
||||
const txs = [];
|
||||
let unknown = -1;
|
||||
|
||||
for (const item of items) {
|
||||
switch (item.type) {
|
||||
case invTypes.BLOCK:
|
||||
@ -1682,7 +1684,6 @@ Pool.prototype._handleInv = async function handleInv(peer, packet) {
|
||||
|
||||
Pool.prototype.handleBlockInv = async function handleBlockInv(peer, hashes) {
|
||||
const items = [];
|
||||
let hash, exists;
|
||||
|
||||
assert(hashes.length > 0);
|
||||
|
||||
@ -1691,7 +1692,7 @@ Pool.prototype.handleBlockInv = async function handleBlockInv(peer, hashes) {
|
||||
|
||||
// Always keep track of the peer's best hash.
|
||||
if (!peer.loader || this.chain.synced) {
|
||||
hash = hashes[hashes.length - 1];
|
||||
const hash = hashes[hashes.length - 1];
|
||||
peer.bestHash = hash;
|
||||
}
|
||||
|
||||
@ -1711,6 +1712,8 @@ Pool.prototype.handleBlockInv = async function handleBlockInv(peer, hashes) {
|
||||
hashes.length,
|
||||
peer.hostname());
|
||||
|
||||
let exists = null;
|
||||
|
||||
for (let i = 0; i < hashes.length; i++) {
|
||||
const hash = hashes[i];
|
||||
|
||||
@ -1780,11 +1783,6 @@ Pool.prototype.handleTXInv = async function handleTXInv(peer, hashes) {
|
||||
|
||||
Pool.prototype.handleGetData = async function handleGetData(peer, packet) {
|
||||
const items = packet.items;
|
||||
const notFound = [];
|
||||
let txs = 0;
|
||||
let blocks = 0;
|
||||
let compact = 0;
|
||||
let unknown = -1;
|
||||
|
||||
if (items.length > 50000) {
|
||||
this.logger.warning('Peer sent inv with >50k items (%s).', peer.hostname());
|
||||
@ -1793,6 +1791,12 @@ Pool.prototype.handleGetData = async function handleGetData(peer, packet) {
|
||||
return;
|
||||
}
|
||||
|
||||
const notFound = [];
|
||||
let txs = 0;
|
||||
let blocks = 0;
|
||||
let compact = 0;
|
||||
let unknown = -1;
|
||||
|
||||
for (const item of items) {
|
||||
if (item.isTX()) {
|
||||
const tx = await this.getItem(peer, item);
|
||||
@ -1832,8 +1836,6 @@ Pool.prototype.handleGetData = async function handleGetData(peer, packet) {
|
||||
}
|
||||
case invTypes.FILTERED_BLOCK:
|
||||
case invTypes.WITNESS_FILTERED_BLOCK: {
|
||||
let block;
|
||||
|
||||
if (!this.options.bip37) {
|
||||
this.logger.debug(
|
||||
'Peer requested a merkleblock without bip37 enabled (%s).',
|
||||
@ -1847,18 +1849,18 @@ Pool.prototype.handleGetData = async function handleGetData(peer, packet) {
|
||||
continue;
|
||||
}
|
||||
|
||||
block = await this.getItem(peer, item);
|
||||
const block = await this.getItem(peer, item);
|
||||
|
||||
if (!block) {
|
||||
notFound.push(item);
|
||||
continue;
|
||||
}
|
||||
|
||||
block = block.toMerkle(peer.spvFilter);
|
||||
const merkle = block.toMerkle(peer.spvFilter);
|
||||
|
||||
peer.send(new packets.MerkleBlockPacket(block));
|
||||
peer.send(new packets.MerkleBlockPacket(merkle));
|
||||
|
||||
for (const tx of block.txs) {
|
||||
for (const tx of merkle.txs) {
|
||||
peer.send(new packets.TXPacket(tx, item.hasWitness()));
|
||||
txs++;
|
||||
}
|
||||
@ -1869,7 +1871,6 @@ Pool.prototype.handleGetData = async function handleGetData(peer, packet) {
|
||||
}
|
||||
case invTypes.CMPCT_BLOCK: {
|
||||
const height = await this.chain.db.getHeight(item.hash);
|
||||
let block;
|
||||
|
||||
// Fallback to full block.
|
||||
if (height < this.chain.tip.height - 10) {
|
||||
@ -1882,7 +1883,7 @@ Pool.prototype.handleGetData = async function handleGetData(peer, packet) {
|
||||
break;
|
||||
}
|
||||
|
||||
block = await this.getItem(peer, item);
|
||||
const block = await this.getItem(peer, item);
|
||||
|
||||
if (!block) {
|
||||
notFound.push(item);
|
||||
@ -1968,7 +1969,6 @@ Pool.prototype.handleNotFound = async function handleNotFound(peer, packet) {
|
||||
|
||||
Pool.prototype.handleGetBlocks = async function handleGetBlocks(peer, packet) {
|
||||
const blocks = [];
|
||||
let hash;
|
||||
|
||||
if (!this.chain.synced)
|
||||
return;
|
||||
@ -1982,7 +1982,7 @@ Pool.prototype.handleGetBlocks = async function handleGetBlocks(peer, packet) {
|
||||
if (this.chain.options.prune)
|
||||
return;
|
||||
|
||||
hash = await this.chain.findLocator(packet.locator);
|
||||
let hash = await this.chain.findLocator(packet.locator);
|
||||
|
||||
if (hash)
|
||||
hash = await this.chain.db.getNextHash(hash);
|
||||
@ -2013,9 +2013,6 @@ Pool.prototype.handleGetBlocks = async function handleGetBlocks(peer, packet) {
|
||||
*/
|
||||
|
||||
Pool.prototype.handleGetHeaders = async function handleGetHeaders(peer, packet) {
|
||||
const headers = [];
|
||||
let hash, entry;
|
||||
|
||||
if (!this.chain.synced)
|
||||
return;
|
||||
|
||||
@ -2028,6 +2025,8 @@ Pool.prototype.handleGetHeaders = async function handleGetHeaders(peer, packet)
|
||||
if (this.chain.options.prune)
|
||||
return;
|
||||
|
||||
let hash = null;
|
||||
|
||||
if (packet.locator.length > 0) {
|
||||
hash = await this.chain.findLocator(packet.locator);
|
||||
if (hash)
|
||||
@ -2036,9 +2035,13 @@ Pool.prototype.handleGetHeaders = async function handleGetHeaders(peer, packet)
|
||||
hash = packet.stop;
|
||||
}
|
||||
|
||||
let entry = null;
|
||||
|
||||
if (hash)
|
||||
entry = await this.chain.db.getEntry(hash);
|
||||
|
||||
const headers = [];
|
||||
|
||||
while (entry) {
|
||||
headers.push(entry.toHeaders());
|
||||
|
||||
@ -2084,8 +2087,6 @@ Pool.prototype.handleHeaders = async function handleHeaders(peer, packet) {
|
||||
|
||||
Pool.prototype._handleHeaders = async function handleHeaders(peer, packet) {
|
||||
const headers = packet.items;
|
||||
let checkpoint = false;
|
||||
let node;
|
||||
|
||||
if (!this.checkpoints)
|
||||
return;
|
||||
@ -2106,6 +2107,9 @@ Pool.prototype._handleHeaders = async function handleHeaders(peer, packet) {
|
||||
|
||||
assert(this.headerChain.size > 0);
|
||||
|
||||
let checkpoint = false;
|
||||
let node = null;
|
||||
|
||||
for (const header of headers) {
|
||||
const last = this.headerChain.tail;
|
||||
const hash = header.hash('hex');
|
||||
@ -2251,12 +2255,11 @@ Pool.prototype.addBlock = async function addBlock(peer, block, flags) {
|
||||
*/
|
||||
|
||||
Pool.prototype._addBlock = async function addBlock(peer, block, flags) {
|
||||
const hash = block.hash('hex');
|
||||
let entry;
|
||||
|
||||
if (!this.syncing)
|
||||
return;
|
||||
|
||||
const hash = block.hash('hex');
|
||||
|
||||
if (!this.resolveBlock(peer, hash)) {
|
||||
this.logger.warning(
|
||||
'Received unrequested block: %s (%s).',
|
||||
@ -2267,6 +2270,8 @@ Pool.prototype._addBlock = async function addBlock(peer, block, flags) {
|
||||
|
||||
peer.blockTime = util.ms();
|
||||
|
||||
let entry = null;
|
||||
|
||||
try {
|
||||
entry = await this.chain.add(block, flags, peer.id);
|
||||
} catch (err) {
|
||||
@ -2280,8 +2285,6 @@ Pool.prototype._addBlock = async function addBlock(peer, block, flags) {
|
||||
|
||||
// Block was orphaned.
|
||||
if (!entry) {
|
||||
let height;
|
||||
|
||||
if (this.checkpoints) {
|
||||
this.logger.warning(
|
||||
'Peer sent orphan block with getheaders (%s).',
|
||||
@ -2292,7 +2295,7 @@ Pool.prototype._addBlock = async function addBlock(peer, block, flags) {
|
||||
// During a getblocks sync, peers send
|
||||
// their best tip frequently. We can grab
|
||||
// the height commitment from the coinbase.
|
||||
height = block.getCoinbaseHeight();
|
||||
const height = block.getCoinbaseHeight();
|
||||
|
||||
if (height !== -1) {
|
||||
peer.bestHash = hash;
|
||||
@ -2328,8 +2331,6 @@ Pool.prototype._addBlock = async function addBlock(peer, block, flags) {
|
||||
*/
|
||||
|
||||
Pool.prototype.resolveChain = async function resolveChain(peer, hash) {
|
||||
const node = this.headerChain.head;
|
||||
|
||||
if (!this.checkpoints)
|
||||
return;
|
||||
|
||||
@ -2339,6 +2340,8 @@ Pool.prototype.resolveChain = async function resolveChain(peer, hash) {
|
||||
if (peer.destroyed)
|
||||
throw new Error('Peer was destroyed (header chain resolution).');
|
||||
|
||||
const node = this.headerChain.head;
|
||||
|
||||
assert(node);
|
||||
|
||||
if (hash !== node.hash) {
|
||||
@ -2489,7 +2492,6 @@ Pool.prototype._handleTX = async function handleTX(peer, packet) {
|
||||
const hash = tx.hash('hex');
|
||||
const flags = chainCommon.flags.VERIFY_NONE;
|
||||
const block = peer.merkleBlock;
|
||||
let missing;
|
||||
|
||||
if (block) {
|
||||
assert(peer.merkleMatches > 0);
|
||||
@ -2533,6 +2535,8 @@ Pool.prototype._handleTX = async function handleTX(peer, packet) {
|
||||
return;
|
||||
}
|
||||
|
||||
let missing = null;
|
||||
|
||||
try {
|
||||
missing = await this.mempool.addTX(tx, peer.id);
|
||||
} catch (err) {
|
||||
@ -2562,8 +2566,6 @@ Pool.prototype._handleTX = async function handleTX(peer, packet) {
|
||||
*/
|
||||
|
||||
Pool.prototype.handleReject = async function handleReject(peer, packet) {
|
||||
let entry;
|
||||
|
||||
this.logger.warning(
|
||||
'Received reject (%s): msg=%s code=%s reason=%s hash=%s.',
|
||||
peer.hostname(),
|
||||
@ -2575,7 +2577,7 @@ Pool.prototype.handleReject = async function handleReject(peer, packet) {
|
||||
if (!packet.hash)
|
||||
return;
|
||||
|
||||
entry = this.invMap.get(packet.hash);
|
||||
const entry = this.invMap.get(packet.hash);
|
||||
|
||||
if (!entry)
|
||||
return;
|
||||
@ -2684,11 +2686,6 @@ Pool.prototype.handleMerkleBlock = async function handleMerkleBlock(peer, packet
|
||||
*/
|
||||
|
||||
Pool.prototype._handleMerkleBlock = async function handleMerkleBlock(peer, packet) {
|
||||
const block = packet.block;
|
||||
const hash = block.hash('hex');
|
||||
const flags = chainCommon.flags.VERIFY_NONE;
|
||||
let tree;
|
||||
|
||||
if (!this.syncing)
|
||||
return;
|
||||
|
||||
@ -2701,6 +2698,9 @@ Pool.prototype._handleMerkleBlock = async function handleMerkleBlock(peer, packe
|
||||
return;
|
||||
}
|
||||
|
||||
const block = packet.block;
|
||||
const hash = block.hash('hex');
|
||||
|
||||
if (!peer.blockMap.has(hash)) {
|
||||
this.logger.warning(
|
||||
'Peer sent an unrequested merkleblock (%s).',
|
||||
@ -2725,9 +2725,10 @@ Pool.prototype._handleMerkleBlock = async function handleMerkleBlock(peer, packe
|
||||
return;
|
||||
}
|
||||
|
||||
tree = block.getTree();
|
||||
const tree = block.getTree();
|
||||
|
||||
if (tree.matches.length === 0) {
|
||||
const flags = chainCommon.flags.VERIFY_NONE;
|
||||
await this._addBlock(peer, block, flags);
|
||||
return;
|
||||
}
|
||||
@ -2775,7 +2776,6 @@ Pool.prototype.handleCmpctBlock = async function handleCmpctBlock(peer, packet)
|
||||
const hash = block.hash('hex');
|
||||
const witness = peer.compactWitness;
|
||||
const flags = chainCommon.flags.VERIFY_BODY;
|
||||
let result;
|
||||
|
||||
if (!this.syncing)
|
||||
return;
|
||||
@ -2836,6 +2836,7 @@ Pool.prototype.handleCmpctBlock = async function handleCmpctBlock(peer, packet)
|
||||
return;
|
||||
}
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = block.init();
|
||||
} catch (e) {
|
||||
@ -2855,9 +2856,9 @@ Pool.prototype.handleCmpctBlock = async function handleCmpctBlock(peer, packet)
|
||||
return;
|
||||
}
|
||||
|
||||
result = block.fillMempool(witness, this.mempool);
|
||||
const full = block.fillMempool(witness, this.mempool);
|
||||
|
||||
if (result) {
|
||||
if (full) {
|
||||
this.logger.debug(
|
||||
'Received full compact block %s (%s).',
|
||||
block.rhash(), peer.hostname());
|
||||
@ -2897,7 +2898,6 @@ Pool.prototype.handleCmpctBlock = async function handleCmpctBlock(peer, packet)
|
||||
|
||||
Pool.prototype.handleGetBlockTxn = async function handleGetBlockTxn(peer, packet) {
|
||||
const req = packet.request;
|
||||
let res, item, block, height;
|
||||
|
||||
if (this.chain.options.spv)
|
||||
return;
|
||||
@ -2908,9 +2908,9 @@ Pool.prototype.handleGetBlockTxn = async function handleGetBlockTxn(peer, packet
|
||||
if (this.options.selfish)
|
||||
return;
|
||||
|
||||
item = new InvItem(invTypes.BLOCK, req.hash);
|
||||
const item = new InvItem(invTypes.BLOCK, req.hash);
|
||||
|
||||
block = await this.getItem(peer, item);
|
||||
const block = await this.getItem(peer, item);
|
||||
|
||||
if (!block) {
|
||||
this.logger.debug(
|
||||
@ -2920,7 +2920,7 @@ Pool.prototype.handleGetBlockTxn = async function handleGetBlockTxn(peer, packet
|
||||
return;
|
||||
}
|
||||
|
||||
height = await this.chain.db.getHeight(req.hash);
|
||||
const height = await this.chain.db.getHeight(req.hash);
|
||||
|
||||
if (height < this.chain.tip.height - 15) {
|
||||
this.logger.debug(
|
||||
@ -2934,7 +2934,7 @@ Pool.prototype.handleGetBlockTxn = async function handleGetBlockTxn(peer, packet
|
||||
block.rhash(),
|
||||
peer.hostname());
|
||||
|
||||
res = BIP152.TXResponse.fromBlock(block, req);
|
||||
const res = BIP152.TXResponse.fromBlock(block, req);
|
||||
|
||||
peer.send(new packets.BlockTxnPacket(res, peer.compactWitness));
|
||||
};
|
||||
@ -3062,14 +3062,12 @@ Pool.prototype.handleUnknown = async function handleUnknown(peer, packet) {
|
||||
*/
|
||||
|
||||
Pool.prototype.addInbound = function addInbound(socket) {
|
||||
let peer;
|
||||
|
||||
if (!this.loaded) {
|
||||
socket.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
peer = this.createInbound(socket);
|
||||
const peer = this.createInbound(socket);
|
||||
|
||||
this.logger.info('Added inbound peer (%s).', peer.hostname());
|
||||
|
||||
@ -3094,12 +3092,11 @@ Pool.prototype.getHost = function getHost() {
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const entry = this.hosts.getHost();
|
||||
let addr;
|
||||
|
||||
if (!entry)
|
||||
break;
|
||||
|
||||
addr = entry.addr;
|
||||
const addr = entry.addr;
|
||||
|
||||
if (this.peers.has(addr.hostname))
|
||||
continue;
|
||||
@ -3133,8 +3130,6 @@ Pool.prototype.getHost = function getHost() {
|
||||
*/
|
||||
|
||||
Pool.prototype.addOutbound = function addOutbound() {
|
||||
let peer, addr;
|
||||
|
||||
if (!this.loaded)
|
||||
return;
|
||||
|
||||
@ -3146,12 +3141,12 @@ Pool.prototype.addOutbound = function addOutbound() {
|
||||
if (!this.peers.load)
|
||||
return;
|
||||
|
||||
addr = this.getHost();
|
||||
const addr = this.getHost();
|
||||
|
||||
if (!addr)
|
||||
return;
|
||||
|
||||
peer = this.createOutbound(addr);
|
||||
const peer = this.createOutbound(addr);
|
||||
|
||||
this.peers.add(peer);
|
||||
|
||||
@ -3387,9 +3382,6 @@ Pool.prototype.getBlocks = async function getBlocks(peer, tip, stop) {
|
||||
*/
|
||||
|
||||
Pool.prototype.getBlock = function getBlock(peer, hashes) {
|
||||
let now = util.ms();
|
||||
const items = [];
|
||||
|
||||
if (!this.loaded)
|
||||
return;
|
||||
|
||||
@ -3399,6 +3391,9 @@ Pool.prototype.getBlock = function getBlock(peer, hashes) {
|
||||
if (peer.destroyed)
|
||||
throw new Error('Peer is destroyed (getdata).');
|
||||
|
||||
let now = util.ms();
|
||||
const items = [];
|
||||
|
||||
for (const hash of hashes) {
|
||||
if (this.blockMap.has(hash))
|
||||
continue;
|
||||
@ -3431,9 +3426,6 @@ Pool.prototype.getBlock = function getBlock(peer, hashes) {
|
||||
*/
|
||||
|
||||
Pool.prototype.getTX = function getTX(peer, hashes) {
|
||||
let now = util.ms();
|
||||
const items = [];
|
||||
|
||||
if (!this.loaded)
|
||||
return;
|
||||
|
||||
@ -3443,6 +3435,9 @@ Pool.prototype.getTX = function getTX(peer, hashes) {
|
||||
if (peer.destroyed)
|
||||
throw new Error('Peer is destroyed (getdata).');
|
||||
|
||||
let now = util.ms();
|
||||
const items = [];
|
||||
|
||||
for (const hash of hashes) {
|
||||
if (this.txMap.has(hash))
|
||||
continue;
|
||||
@ -4044,12 +4039,10 @@ PoolOptions.prototype.hasNonce = function hasNonce(nonce) {
|
||||
*/
|
||||
|
||||
PoolOptions.prototype.getRate = function getRate(hash) {
|
||||
let entry;
|
||||
|
||||
if (!this.mempool)
|
||||
return -1;
|
||||
|
||||
entry = this.mempool.getEntry(hash);
|
||||
const entry = this.mempool.getEntry(hash);
|
||||
|
||||
if (!entry)
|
||||
return -1;
|
||||
@ -4228,14 +4221,12 @@ PeerList.prototype.destroy = function destroy() {
|
||||
*/
|
||||
|
||||
function BroadcastItem(pool, msg) {
|
||||
let item;
|
||||
|
||||
if (!(this instanceof BroadcastItem))
|
||||
return new BroadcastItem(pool, msg);
|
||||
|
||||
assert(!msg.mutable, 'Cannot broadcast mutable item.');
|
||||
|
||||
item = msg.toInv();
|
||||
const item = msg.toInv();
|
||||
|
||||
this.pool = pool;
|
||||
this.hash = item.hash;
|
||||
|
||||
113
lib/net/socks.js
113
lib/net/socks.js
@ -71,8 +71,6 @@ SOCKS.errors = [
|
||||
];
|
||||
|
||||
SOCKS.prototype.error = function error(err) {
|
||||
let msg;
|
||||
|
||||
if (this.destroyed)
|
||||
return;
|
||||
|
||||
@ -82,7 +80,7 @@ SOCKS.prototype.error = function error(err) {
|
||||
return;
|
||||
}
|
||||
|
||||
msg = util.fmt.apply(util, arguments);
|
||||
const msg = util.fmt.apply(util, arguments);
|
||||
this.emit('error', new Error(msg));
|
||||
this.destroy();
|
||||
};
|
||||
@ -300,7 +298,6 @@ SOCKS.prototype.handleHandshake = function handleHandshake(data) {
|
||||
SOCKS.prototype.sendAuth = function sendAuth() {
|
||||
const user = this.username;
|
||||
const pass = this.password;
|
||||
let ulen, plen, size, packet;
|
||||
|
||||
if (!user) {
|
||||
this.error('No username passed for SOCKS auth.');
|
||||
@ -312,17 +309,19 @@ SOCKS.prototype.sendAuth = function sendAuth() {
|
||||
return;
|
||||
}
|
||||
|
||||
ulen = Buffer.byteLength(user, 'ascii');
|
||||
plen = Buffer.byteLength(pass, 'ascii');
|
||||
size = 3 + ulen + plen;
|
||||
const ulen = Buffer.byteLength(user, 'ascii');
|
||||
const plen = Buffer.byteLength(pass, 'ascii');
|
||||
const size = 3 + ulen + plen;
|
||||
|
||||
packet = new StaticWriter(size);
|
||||
packet.writeU8(0x01);
|
||||
packet.writeU8(ulen);
|
||||
packet.writeString(user, 'ascii');
|
||||
packet.writeU8(plen);
|
||||
packet.writeString(pass, 'ascii');
|
||||
packet = packet.render();
|
||||
const bw = new StaticWriter(size);
|
||||
|
||||
bw.writeU8(0x01);
|
||||
bw.writeU8(ulen);
|
||||
bw.writeString(user, 'ascii');
|
||||
bw.writeU8(plen);
|
||||
bw.writeString(pass, 'ascii');
|
||||
|
||||
const packet = bw.render();
|
||||
|
||||
this.state = SOCKS.states.AUTH;
|
||||
this.socket.write(packet);
|
||||
@ -366,7 +365,7 @@ SOCKS.prototype.auth = function auth() {
|
||||
SOCKS.prototype.sendProxy = function sendProxy() {
|
||||
const host = this.destHost;
|
||||
const port = this.destPort;
|
||||
let ip, len, type, name, packet;
|
||||
let ip, len, type, name;
|
||||
|
||||
switch (IP.getStringType(host)) {
|
||||
case IP.types.IPV4:
|
||||
@ -388,28 +387,26 @@ SOCKS.prototype.sendProxy = function sendProxy() {
|
||||
break;
|
||||
}
|
||||
|
||||
packet = new StaticWriter(6 + len);
|
||||
const bw = new StaticWriter(6 + len);
|
||||
|
||||
packet.writeU8(0x05);
|
||||
packet.writeU8(0x01);
|
||||
packet.writeU8(0x00);
|
||||
packet.writeU8(type);
|
||||
bw.writeU8(0x05);
|
||||
bw.writeU8(0x01);
|
||||
bw.writeU8(0x00);
|
||||
bw.writeU8(type);
|
||||
|
||||
if (type === 0x03)
|
||||
packet.writeU8(name.length);
|
||||
bw.writeU8(name.length);
|
||||
|
||||
packet.writeBytes(name);
|
||||
packet.writeU16BE(port);
|
||||
bw.writeBytes(name);
|
||||
bw.writeU16BE(port);
|
||||
|
||||
packet = packet.render();
|
||||
const packet = bw.render();
|
||||
|
||||
this.state = SOCKS.states.PROXY;
|
||||
this.socket.write(packet);
|
||||
};
|
||||
|
||||
SOCKS.prototype.handleProxy = function handleProxy(data) {
|
||||
let addr;
|
||||
|
||||
if (data.length < 6) {
|
||||
this.error('Bad packet size for SOCKS connect.');
|
||||
return;
|
||||
@ -431,6 +428,8 @@ SOCKS.prototype.handleProxy = function handleProxy(data) {
|
||||
return;
|
||||
}
|
||||
|
||||
let addr = null;
|
||||
|
||||
try {
|
||||
addr = parseAddr(data, 3);
|
||||
} catch (e) {
|
||||
@ -449,24 +448,24 @@ SOCKS.prototype.handleProxy = function handleProxy(data) {
|
||||
SOCKS.prototype.sendResolve = function sendResolve() {
|
||||
const name = this.name;
|
||||
const len = Buffer.byteLength(name, 'utf8');
|
||||
let packet = new StaticWriter(7 + len);
|
||||
|
||||
packet.writeU8(0x05);
|
||||
packet.writeU8(0xf0);
|
||||
packet.writeU8(0x00);
|
||||
packet.writeU8(0x03);
|
||||
packet.writeU8(len);
|
||||
packet.writeString(name, 'utf8');
|
||||
packet.writeU16BE(0);
|
||||
packet = packet.render();
|
||||
const bw = new StaticWriter(7 + len);
|
||||
|
||||
bw.writeU8(0x05);
|
||||
bw.writeU8(0xf0);
|
||||
bw.writeU8(0x00);
|
||||
bw.writeU8(0x03);
|
||||
bw.writeU8(len);
|
||||
bw.writeString(name, 'utf8');
|
||||
bw.writeU16BE(0);
|
||||
|
||||
const packet = bw.render();
|
||||
|
||||
this.state = SOCKS.states.RESOLVE;
|
||||
this.socket.write(packet);
|
||||
};
|
||||
|
||||
SOCKS.prototype.handleResolve = function handleResolve(data) {
|
||||
let addr;
|
||||
|
||||
if (data.length < 6) {
|
||||
this.error('Bad packet size for tor resolve.');
|
||||
return;
|
||||
@ -488,6 +487,8 @@ SOCKS.prototype.handleResolve = function handleResolve(data) {
|
||||
return;
|
||||
}
|
||||
|
||||
let addr = null;
|
||||
|
||||
try {
|
||||
addr = parseAddr(data, 3);
|
||||
} catch (e) {
|
||||
@ -557,11 +558,9 @@ function Proxy(host, port, user, pass) {
|
||||
util.inherits(Proxy, EventEmitter);
|
||||
|
||||
Proxy.prototype.connect = async function connect(port, host) {
|
||||
let options, socket;
|
||||
|
||||
assert(!this.socket, 'Already connected.');
|
||||
|
||||
options = {
|
||||
const options = {
|
||||
host: this.host,
|
||||
port: this.port,
|
||||
username: this.username,
|
||||
@ -570,6 +569,8 @@ Proxy.prototype.connect = async function connect(port, host) {
|
||||
destPort: port
|
||||
};
|
||||
|
||||
let socket = null;
|
||||
|
||||
try {
|
||||
socket = await SOCKS.proxy(options);
|
||||
} catch (e) {
|
||||
@ -673,7 +674,6 @@ Proxy.prototype.destroy = function destroy() {
|
||||
|
||||
function parseProxy(host) {
|
||||
const index = host.indexOf('@');
|
||||
let addr, left, right, parts;
|
||||
|
||||
if (index === -1) {
|
||||
const addr = IP.fromHostname(host, 1080);
|
||||
@ -683,13 +683,13 @@ function parseProxy(host) {
|
||||
};
|
||||
}
|
||||
|
||||
left = host.substring(0, index);
|
||||
right = host.substring(index + 1);
|
||||
const left = host.substring(0, index);
|
||||
const right = host.substring(index + 1);
|
||||
|
||||
parts = left.split(':');
|
||||
const parts = left.split(':');
|
||||
assert(parts.length > 1, 'Bad username and password.');
|
||||
|
||||
addr = IP.fromHostname(right, 1080);
|
||||
const addr = IP.fromHostname(right, 1080);
|
||||
|
||||
return {
|
||||
host: addr.host,
|
||||
@ -701,25 +701,28 @@ function parseProxy(host) {
|
||||
|
||||
function parseAddr(data, offset) {
|
||||
const br = new BufferReader(data);
|
||||
let type, len, host, port;
|
||||
|
||||
if (br.left() < offset + 2)
|
||||
throw new Error('Bad SOCKS address length.');
|
||||
|
||||
br.seek(offset);
|
||||
|
||||
type = br.readU8();
|
||||
const type = br.readU8();
|
||||
|
||||
let host = null;
|
||||
let port = 0;
|
||||
|
||||
switch (type) {
|
||||
case 0x01:
|
||||
case 0x01: {
|
||||
if (br.left() < 6)
|
||||
throw new Error('Bad SOCKS ipv4 length.');
|
||||
|
||||
host = IP.toString(br.readBytes(4));
|
||||
port = br.readU16BE();
|
||||
break;
|
||||
case 0x03:
|
||||
len = br.readU8();
|
||||
}
|
||||
case 0x03: {
|
||||
const len = br.readU8();
|
||||
|
||||
if (br.left() < len + 2)
|
||||
throw new Error('Bad SOCKS domain length.');
|
||||
@ -727,15 +730,18 @@ function parseAddr(data, offset) {
|
||||
host = br.readString(len, 'utf8');
|
||||
port = br.readU16BE();
|
||||
break;
|
||||
case 0x04:
|
||||
}
|
||||
case 0x04: {
|
||||
if (br.left() < 18)
|
||||
throw new Error('Bad SOCKS ipv6 length.');
|
||||
|
||||
host = IP.toString(br.readBytes(16));
|
||||
port = br.readU16BE();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Unknown SOCKS address type: ${type}.`);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
@ -755,9 +761,8 @@ exports.connect = function connect(proxy, destPort, destHost) {
|
||||
const port = addr.port;
|
||||
const user = addr.username;
|
||||
const pass = addr.password;
|
||||
let socket;
|
||||
|
||||
socket = new Proxy(host, port, user, pass);
|
||||
const socket = new Proxy(host, port, user, pass);
|
||||
socket.connect(destPort, destHost);
|
||||
|
||||
return socket;
|
||||
|
||||
@ -153,7 +153,6 @@ UPNP.prototype.discover = async function discover() {
|
||||
|
||||
UPNP.prototype._discover = async function discover() {
|
||||
const socket = dgram.createSocket('udp4');
|
||||
let msg;
|
||||
|
||||
socket.on('error', (err) => {
|
||||
this.rejectJob(err);
|
||||
@ -167,7 +166,7 @@ UPNP.prototype._discover = async function discover() {
|
||||
this.socket = socket;
|
||||
this.startTimeout();
|
||||
|
||||
msg = ''
|
||||
const msg = ''
|
||||
+ 'M-SEARCH * HTTP/1.1\r\n'
|
||||
+ `HOST: ${this.host}:${this.port}\r\n`
|
||||
+ 'MAN: ssdp:discover\r\n'
|
||||
@ -189,11 +188,11 @@ UPNP.prototype._discover = async function discover() {
|
||||
*/
|
||||
|
||||
UPNP.prototype.handleMsg = async function handleMsg(msg) {
|
||||
let headers;
|
||||
|
||||
if (!this.socket)
|
||||
return;
|
||||
|
||||
let headers = null;
|
||||
|
||||
try {
|
||||
headers = UPNP.parseHeader(msg);
|
||||
} catch (e) {
|
||||
@ -218,24 +217,23 @@ UPNP.prototype.handleMsg = async function handleMsg(msg) {
|
||||
|
||||
UPNP.prototype.resolve = async function resolve(location, targets) {
|
||||
const host = parseHost(location);
|
||||
let res, xml, services, service;
|
||||
|
||||
if (!targets)
|
||||
targets = UPNP.WAN_SERVICES;
|
||||
|
||||
res = await request({
|
||||
const res = await request({
|
||||
method: 'GET',
|
||||
uri: location,
|
||||
timeout: UPNP.RESPONSE_TIMEOUT,
|
||||
expect: 'xml'
|
||||
});
|
||||
|
||||
xml = XMLElement.fromRaw(res.body);
|
||||
const xml = XMLElement.fromRaw(res.body);
|
||||
|
||||
services = parseServices(xml);
|
||||
const services = parseServices(xml);
|
||||
assert(services.length > 0, 'No services found.');
|
||||
|
||||
service = extractServices(services, targets);
|
||||
const service = extractServices(services, targets);
|
||||
assert(service, 'No service found.');
|
||||
assert(service.serviceId, 'No service ID found.');
|
||||
assert(service.serviceId.length > 0, 'No service ID found.');
|
||||
@ -265,14 +263,12 @@ UPNP.parseHeader = function parseHeader(str) {
|
||||
const headers = Object.create(null);
|
||||
|
||||
for (let line of lines) {
|
||||
let index, left, right;
|
||||
|
||||
line = line.trim();
|
||||
|
||||
if (line.length === 0)
|
||||
continue;
|
||||
|
||||
index = line.indexOf(':');
|
||||
const index = line.indexOf(':');
|
||||
|
||||
if (index === -1) {
|
||||
left = line.toLowerCase();
|
||||
@ -280,8 +276,8 @@ UPNP.parseHeader = function parseHeader(str) {
|
||||
continue;
|
||||
}
|
||||
|
||||
left = line.substring(0, index);
|
||||
right = line.substring(index + 1);
|
||||
let left = line.substring(0, index);
|
||||
let right = line.substring(index + 1);
|
||||
|
||||
left = left.trim();
|
||||
right = right.trim();
|
||||
@ -371,9 +367,8 @@ UPNPService.prototype.createRequest = function createRequest(action, args) {
|
||||
UPNPService.prototype.soapRequest = async function soapRequest(action, args) {
|
||||
const type = this.serviceType;
|
||||
const req = this.createRequest(action, args);
|
||||
let res, xml, err;
|
||||
|
||||
res = await request({
|
||||
const res = await request({
|
||||
method: 'POST',
|
||||
uri: this.controlURL,
|
||||
timeout: UPNP.RESPONSE_TIMEOUT,
|
||||
@ -387,8 +382,8 @@ UPNPService.prototype.soapRequest = async function soapRequest(action, args) {
|
||||
body: req
|
||||
});
|
||||
|
||||
xml = XMLElement.fromRaw(res.body);
|
||||
err = findError(xml);
|
||||
const xml = XMLElement.fromRaw(res.body);
|
||||
const err = findError(xml);
|
||||
|
||||
if (err)
|
||||
throw err;
|
||||
@ -423,12 +418,11 @@ UPNPService.prototype.getExternalIP = async function getExternalIP() {
|
||||
UPNPService.prototype.addPortMapping = async function addPortMapping(remote, src, dest) {
|
||||
const action = 'AddPortMapping';
|
||||
const local = IP.getPrivate();
|
||||
let xml, child;
|
||||
|
||||
if (local.length === 0)
|
||||
throw new Error('Cannot determine local IP.');
|
||||
|
||||
xml = await this.soapRequest(action, [
|
||||
const xml = await this.soapRequest(action, [
|
||||
['NewRemoteHost', remote],
|
||||
['NewExternalPort', src],
|
||||
['NewProtocol', 'TCP'],
|
||||
@ -439,7 +433,7 @@ UPNPService.prototype.addPortMapping = async function addPortMapping(remote, src
|
||||
['NewLeaseDuration', 0]
|
||||
]);
|
||||
|
||||
child = xml.find('AddPortMappingResponse');
|
||||
const child = xml.find('AddPortMappingResponse');
|
||||
|
||||
if (!child)
|
||||
throw new Error('Port mapping failed.');
|
||||
@ -456,15 +450,14 @@ UPNPService.prototype.addPortMapping = async function addPortMapping(remote, src
|
||||
|
||||
UPNPService.prototype.removePortMapping = async function removePortMapping(remote, port) {
|
||||
const action = 'DeletePortMapping';
|
||||
let xml, child;
|
||||
|
||||
xml = await this.soapRequest(action, [
|
||||
const xml = await this.soapRequest(action, [
|
||||
['NewRemoteHost', remote],
|
||||
['NewExternalPort', port],
|
||||
['NewProtocol', 'TCP']
|
||||
]);
|
||||
|
||||
child = xml.find('DeletePortMappingResponse');
|
||||
const child = xml.find('DeletePortMappingResponse');
|
||||
|
||||
if (!child)
|
||||
throw new Error('Port unmapping failed.');
|
||||
@ -493,15 +486,16 @@ function XMLElement(name) {
|
||||
|
||||
XMLElement.fromRaw = function fromRaw(xml) {
|
||||
const sentinel = new XMLElement('');
|
||||
const stack = [sentinel];
|
||||
|
||||
let current = sentinel;
|
||||
const stack = [];
|
||||
let decl = false;
|
||||
let m;
|
||||
|
||||
stack.push(sentinel);
|
||||
while (xml.length > 0) {
|
||||
let m = null;
|
||||
|
||||
while (xml.length) {
|
||||
if (m = /^<\?xml[^<>]*\?>/i.exec(xml)) {
|
||||
m = /^<\?xml[^<>]*\?>/i.exec(xml);
|
||||
if (m) {
|
||||
xml = xml.substring(m[0].length);
|
||||
assert(current === sentinel, 'XML declaration inside element.');
|
||||
assert(!decl, 'XML declaration seen twice.');
|
||||
@ -509,13 +503,14 @@ XMLElement.fromRaw = function fromRaw(xml) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m = /^<([\w:]+)[^<>]*?(\/?)>/i.exec(xml)) {
|
||||
m = /^<([\w:]+)[^<>]*?(\/?)>/i.exec(xml);
|
||||
if (m) {
|
||||
xml = xml.substring(m[0].length);
|
||||
|
||||
const name = m[1];
|
||||
const trailing = m[2] === '/';
|
||||
const element = new XMLElement(name);
|
||||
|
||||
xml = xml.substring(m[0].length);
|
||||
|
||||
if (trailing) {
|
||||
current.add(element);
|
||||
continue;
|
||||
@ -528,14 +523,15 @@ XMLElement.fromRaw = function fromRaw(xml) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m = /^<\/([\w:]+)[^<>]*>/i.exec(xml)) {
|
||||
const name = m[1];
|
||||
let element;
|
||||
|
||||
m = /^<\/([\w:]+)[^<>]*>/i.exec(xml);
|
||||
if (m) {
|
||||
xml = xml.substring(m[0].length);
|
||||
|
||||
const name = m[1];
|
||||
|
||||
assert(stack.length !== 1, 'No start tag.');
|
||||
element = stack.pop();
|
||||
|
||||
const element = stack.pop();
|
||||
|
||||
assert(element.name === name, 'Tag mismatch.');
|
||||
current = stack[stack.length - 1];
|
||||
@ -546,9 +542,10 @@ XMLElement.fromRaw = function fromRaw(xml) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m = /^([^<]+)/i.exec(xml)) {
|
||||
const text = m[1];
|
||||
m = /^([^<]+)/i.exec(xml);
|
||||
if (m) {
|
||||
xml = xml.substring(m[0].length);
|
||||
const text = m[1];
|
||||
current.text = text.trim();
|
||||
continue;
|
||||
}
|
||||
@ -673,19 +670,19 @@ function findIP(el) {
|
||||
|
||||
function findError(el) {
|
||||
const child = el.find('UPnPError');
|
||||
let code = -1;
|
||||
let desc = 'Unknown';
|
||||
let ccode, cdesc;
|
||||
|
||||
if (!child)
|
||||
return;
|
||||
|
||||
ccode = child.find('errorCode');
|
||||
cdesc = child.find('errorDescription');
|
||||
let code = -1;
|
||||
const ccode = child.find('errorCode');
|
||||
|
||||
if (ccode && /^\d+$/.test(ccode.text))
|
||||
code = +ccode.text;
|
||||
|
||||
let desc = 'Unknown';
|
||||
const cdesc = child.find('errorDescription');
|
||||
|
||||
if (cdesc)
|
||||
desc = cdesc.text;
|
||||
|
||||
|
||||
@ -108,12 +108,11 @@ Config.prototype.load = function load(options) {
|
||||
*/
|
||||
|
||||
Config.prototype.open = function open(file) {
|
||||
let path, text;
|
||||
|
||||
if (fs.unsupported)
|
||||
return;
|
||||
|
||||
path = this.getFile(file);
|
||||
const path = this.getFile(file);
|
||||
let text = null;
|
||||
|
||||
try {
|
||||
text = fs.readFileSync(path, 'utf8');
|
||||
@ -193,15 +192,13 @@ Config.prototype.has = function has(key) {
|
||||
*/
|
||||
|
||||
Config.prototype.get = function get(key, fallback) {
|
||||
let keys, value;
|
||||
|
||||
if (fallback === undefined)
|
||||
fallback = null;
|
||||
|
||||
if (Array.isArray(key)) {
|
||||
keys = key;
|
||||
const keys = key;
|
||||
for (const key of keys) {
|
||||
value = this.get(key);
|
||||
const value = this.get(key);
|
||||
if (value !== null)
|
||||
return value;
|
||||
}
|
||||
@ -406,7 +403,6 @@ Config.prototype.bool = function bool(key, fallback) {
|
||||
|
||||
Config.prototype.buf = function buf(key, fallback) {
|
||||
const value = this.get(key);
|
||||
let data;
|
||||
|
||||
if (fallback === undefined)
|
||||
fallback = null;
|
||||
@ -420,7 +416,7 @@ Config.prototype.buf = function buf(key, fallback) {
|
||||
return value;
|
||||
}
|
||||
|
||||
data = Buffer.from(value, 'hex');
|
||||
const data = Buffer.from(value, 'hex');
|
||||
|
||||
if (data.length !== value.length / 2)
|
||||
throw new Error(`${key} must be a hex string.`);
|
||||
@ -437,7 +433,6 @@ Config.prototype.buf = function buf(key, fallback) {
|
||||
|
||||
Config.prototype.array = function array(key, fallback) {
|
||||
const value = this.get(key);
|
||||
let result, parts;
|
||||
|
||||
if (fallback === undefined)
|
||||
fallback = null;
|
||||
@ -451,8 +446,8 @@ Config.prototype.array = function array(key, fallback) {
|
||||
return value;
|
||||
}
|
||||
|
||||
parts = value.trim().split(/\s*,\s*/);
|
||||
result = [];
|
||||
const parts = value.trim().split(/\s*,\s*/);
|
||||
const result = [];
|
||||
|
||||
for (const part of parts) {
|
||||
if (part.length === 0)
|
||||
@ -582,7 +577,6 @@ Config.prototype.getNetwork = function getNetwork() {
|
||||
|
||||
Config.prototype.getPrefix = function getPrefix() {
|
||||
let prefix = this.str('prefix');
|
||||
let network;
|
||||
|
||||
if (prefix) {
|
||||
if (prefix[0] === '~')
|
||||
@ -591,7 +585,8 @@ Config.prototype.getPrefix = function getPrefix() {
|
||||
}
|
||||
|
||||
prefix = path.join(HOME, `.${this.module}`);
|
||||
network = this.str('network');
|
||||
|
||||
const network = this.str('network');
|
||||
|
||||
if (network) {
|
||||
assert(isAlpha(network), 'Bad network.');
|
||||
@ -647,16 +642,13 @@ Config.prototype.location = function location(file) {
|
||||
*/
|
||||
|
||||
Config.prototype.parseConfig = function parseConfig(text) {
|
||||
let parts;
|
||||
|
||||
assert(typeof text === 'string', 'Config must be text.');
|
||||
|
||||
text = text.trim();
|
||||
parts = text.split(/\n+/);
|
||||
|
||||
const parts = text.split(/\n+/);
|
||||
|
||||
for (let line of parts) {
|
||||
let key, value, eq, col, alias;
|
||||
|
||||
line = line.trim();
|
||||
|
||||
if (line.length === 0)
|
||||
@ -665,12 +657,14 @@ Config.prototype.parseConfig = function parseConfig(text) {
|
||||
if (/^\s*#/.test(line))
|
||||
continue;
|
||||
|
||||
eq = line.indexOf('=');
|
||||
col = line.indexOf(':');
|
||||
let eq = line.indexOf('=');
|
||||
const col = line.indexOf(':');
|
||||
|
||||
if (col !== -1 && (col < eq || eq === -1))
|
||||
eq = col;
|
||||
|
||||
let key, value;
|
||||
|
||||
if (eq === -1) {
|
||||
key = line.trim();
|
||||
value = '';
|
||||
@ -681,7 +675,8 @@ Config.prototype.parseConfig = function parseConfig(text) {
|
||||
|
||||
key = key.replace(/\-/g, '').toLowerCase();
|
||||
|
||||
alias = Config.alias.conf[key];
|
||||
const alias = Config.alias.conf[key];
|
||||
|
||||
if (alias)
|
||||
key = alias;
|
||||
|
||||
@ -702,13 +697,13 @@ Config.prototype.parseConfig = function parseConfig(text) {
|
||||
*/
|
||||
|
||||
Config.prototype.parseArg = function parseArg(argv) {
|
||||
let key;
|
||||
|
||||
if (!argv || typeof argv !== 'object')
|
||||
argv = process.argv;
|
||||
|
||||
assert(Array.isArray(argv));
|
||||
|
||||
let key = null;
|
||||
|
||||
for (let i = 2; i < argv.length; i++) {
|
||||
let arg = argv[i];
|
||||
let value, alias, equals;
|
||||
@ -796,14 +791,12 @@ Config.prototype.parseEnv = function parseEnv(env) {
|
||||
assert(env && typeof env === 'object');
|
||||
|
||||
for (let key of Object.keys(env)) {
|
||||
let value, alias;
|
||||
|
||||
if (key.indexOf(prefix) !== 0)
|
||||
continue;
|
||||
|
||||
assert(typeof env[key] === 'string');
|
||||
|
||||
value = env[key].trim();
|
||||
const value = env[key].trim();
|
||||
|
||||
key = key.substring(prefix.length);
|
||||
key = key.replace(/_/g, '').toLowerCase();
|
||||
@ -814,7 +807,8 @@ Config.prototype.parseEnv = function parseEnv(env) {
|
||||
if (value.length === 0)
|
||||
continue;
|
||||
|
||||
alias = Config.alias.env[key];
|
||||
const alias = Config.alias.env[key];
|
||||
|
||||
if (alias)
|
||||
key = alias;
|
||||
|
||||
@ -869,8 +863,6 @@ Config.prototype.parseHash = function parseHash(hash) {
|
||||
*/
|
||||
|
||||
Config.prototype.parseForm = function parseForm(query, map) {
|
||||
let parts;
|
||||
|
||||
assert(typeof query === 'string');
|
||||
|
||||
if (query.length === 0)
|
||||
@ -879,11 +871,12 @@ Config.prototype.parseForm = function parseForm(query, map) {
|
||||
if (query[0] === '?' || query[0] === '#')
|
||||
query = query.substring(1);
|
||||
|
||||
parts = query.split('&');
|
||||
const parts = query.split('&');
|
||||
|
||||
for (const pair of parts) {
|
||||
const index = pair.indexOf('=');
|
||||
let key, value, alias;
|
||||
|
||||
let key, value;
|
||||
|
||||
if (index === -1) {
|
||||
key = pair;
|
||||
@ -904,7 +897,8 @@ Config.prototype.parseForm = function parseForm(query, map) {
|
||||
if (value.length === 0)
|
||||
continue;
|
||||
|
||||
alias = Config.alias.env[key];
|
||||
const alias = Config.alias.env[key];
|
||||
|
||||
if (alias)
|
||||
key = alias;
|
||||
|
||||
|
||||
@ -254,7 +254,6 @@ Logger.prototype._close = async function close() {
|
||||
|
||||
Logger.prototype.truncate = async function truncate() {
|
||||
const maxSize = Logger.MAX_FILE_SIZE;
|
||||
let stat, data, fd;
|
||||
|
||||
if (!this.filename)
|
||||
return;
|
||||
@ -264,6 +263,8 @@ Logger.prototype.truncate = async function truncate() {
|
||||
|
||||
assert(!this.stream);
|
||||
|
||||
let stat = null;
|
||||
|
||||
try {
|
||||
stat = await fs.stat(this.filename);
|
||||
} catch (e) {
|
||||
@ -277,9 +278,9 @@ Logger.prototype.truncate = async function truncate() {
|
||||
|
||||
this.debug('Truncating log file to %d bytes.', maxSize);
|
||||
|
||||
fd = await fs.open(this.filename, 'r+');
|
||||
const fd = await fs.open(this.filename, 'r+');
|
||||
const data = Buffer.allocUnsafe(maxSize);
|
||||
|
||||
data = Buffer.allocUnsafe(maxSize);
|
||||
await fs.read(fd, data, 0, maxSize, stat.size - maxSize);
|
||||
await fs.ftruncate(fd, maxSize);
|
||||
await fs.write(fd, data, 0, maxSize, 0);
|
||||
@ -518,7 +519,6 @@ Logger.prototype.context = function _context(module) {
|
||||
Logger.prototype.writeConsole = function writeConsole(level, module, args) {
|
||||
const name = Logger.levelsByVal[level];
|
||||
let msg = '';
|
||||
let color;
|
||||
|
||||
assert(name, 'Invalid log level.');
|
||||
|
||||
@ -545,7 +545,7 @@ Logger.prototype.writeConsole = function writeConsole(level, module, args) {
|
||||
}
|
||||
|
||||
if (this.colors) {
|
||||
color = Logger.styles[level];
|
||||
const color = Logger.styles[level];
|
||||
assert(color);
|
||||
|
||||
msg += `\x1b[${color}m[${name}]\x1b[m `;
|
||||
@ -604,8 +604,6 @@ Logger.prototype.writeStream = function writeStream(level, module, args) {
|
||||
*/
|
||||
|
||||
Logger.prototype.logError = function logError(level, module, err) {
|
||||
let msg;
|
||||
|
||||
if (this.closed)
|
||||
return;
|
||||
|
||||
@ -614,7 +612,7 @@ Logger.prototype.logError = function logError(level, module, err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
msg = (err.message + '').replace(/^ *Error: */, '');
|
||||
let msg = (err.message + '').replace(/^ *Error: */, '');
|
||||
|
||||
if (level !== Logger.levels.ERROR)
|
||||
msg = `Error: ${msg}`;
|
||||
@ -843,6 +841,11 @@ function openStream(filename) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const stream = fs.createWriteStream(filename, { flags: 'a' });
|
||||
|
||||
const cleanup = () => {
|
||||
stream.removeListener('error', onError);
|
||||
stream.removeListener('open', onOpen);
|
||||
};
|
||||
|
||||
const onError = (err) => {
|
||||
try {
|
||||
stream.close();
|
||||
@ -858,11 +861,6 @@ function openStream(filename) {
|
||||
resolve(stream);
|
||||
};
|
||||
|
||||
let cleanup = () => {
|
||||
stream.removeListener('error', onError);
|
||||
stream.removeListener('open', onOpen);
|
||||
};
|
||||
|
||||
stream.once('error', onError);
|
||||
stream.once('open', onOpen);
|
||||
});
|
||||
@ -870,6 +868,11 @@ function openStream(filename) {
|
||||
|
||||
function closeStream(stream) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const cleanup = () => {
|
||||
stream.removeListener('error', onError);
|
||||
stream.removeListener('close', onClose);
|
||||
};
|
||||
|
||||
const onError = (err) => {
|
||||
cleanup();
|
||||
reject(err);
|
||||
@ -880,11 +883,6 @@ function closeStream(stream) {
|
||||
resolve(stream);
|
||||
};
|
||||
|
||||
let cleanup = () => {
|
||||
stream.removeListener('error', onError);
|
||||
stream.removeListener('close', onClose);
|
||||
};
|
||||
|
||||
stream.removeAllListeners('error');
|
||||
stream.removeAllListeners('close');
|
||||
stream.once('error', onError);
|
||||
|
||||
@ -267,14 +267,12 @@ Node.prototype.uptime = function uptime() {
|
||||
*/
|
||||
|
||||
Node.prototype.use = function use(plugin) {
|
||||
let instance;
|
||||
|
||||
assert(plugin, 'Plugin must be an object.');
|
||||
assert(typeof plugin.init === 'function', '`init` must be a function.');
|
||||
|
||||
assert(!this.loaded, 'Cannot add plugin after node is loaded.');
|
||||
|
||||
instance = plugin.init(this);
|
||||
const instance = plugin.init(this);
|
||||
|
||||
assert(!instance.open || typeof instance.open === 'function',
|
||||
'`open` must be a function.');
|
||||
|
||||
@ -135,13 +135,12 @@ Address.prototype.getType = function getType() {
|
||||
*/
|
||||
|
||||
Address.prototype.getPrefix = function getPrefix(network) {
|
||||
let prefixes;
|
||||
|
||||
if (!network)
|
||||
network = this.network;
|
||||
|
||||
network = Network.get(network);
|
||||
prefixes = network.addressPrefix;
|
||||
|
||||
const prefixes = network.addressPrefix;
|
||||
|
||||
switch (this.type) {
|
||||
case Address.types.PUBKEYHASH:
|
||||
@ -223,7 +222,6 @@ Address.prototype.toBase58 = function toBase58(network) {
|
||||
Address.prototype.toBech32 = function toBech32(network) {
|
||||
const version = this.version;
|
||||
const hash = this.hash;
|
||||
let hrp;
|
||||
|
||||
assert(version !== -1,
|
||||
'Cannot convert non-program address to bech32.');
|
||||
@ -232,7 +230,8 @@ Address.prototype.toBech32 = function toBech32(network) {
|
||||
network = this.network;
|
||||
|
||||
network = Network.get(network);
|
||||
hrp = network.addressPrefix.bech32;
|
||||
|
||||
const hrp = network.addressPrefix.bech32;
|
||||
|
||||
return bech32.encode(hrp, version, hash);
|
||||
};
|
||||
@ -308,16 +307,17 @@ Address.prototype.inspect = function inspect() {
|
||||
|
||||
Address.prototype.fromRaw = function fromRaw(data, network) {
|
||||
const br = new BufferReader(data, true);
|
||||
let version = -1;
|
||||
let prefix, type, hash;
|
||||
|
||||
if (data.length > 40)
|
||||
throw new Error('Address is too long.');
|
||||
|
||||
prefix = br.readU8();
|
||||
network = Network.fromAddress(prefix, network);
|
||||
type = Address.getType(prefix, network);
|
||||
const prefix = br.readU8();
|
||||
|
||||
network = Network.fromAddress(prefix, network);
|
||||
|
||||
const type = Address.getType(prefix, network);
|
||||
|
||||
let version = -1;
|
||||
if (data.length > 25) {
|
||||
version = br.readU8();
|
||||
|
||||
@ -325,7 +325,7 @@ Address.prototype.fromRaw = function fromRaw(data, network) {
|
||||
throw new Error('Address version padding is non-zero.');
|
||||
}
|
||||
|
||||
hash = br.readBytes(br.left() - 4);
|
||||
const hash = br.readBytes(br.left() - 4);
|
||||
|
||||
br.verifyChecksum();
|
||||
|
||||
@ -382,11 +382,11 @@ Address.fromBase58 = function fromBase58(data, network) {
|
||||
|
||||
Address.prototype.fromBech32 = function fromBech32(data, network) {
|
||||
const type = Address.types.WITNESS;
|
||||
let addr;
|
||||
|
||||
assert(typeof data === 'string');
|
||||
|
||||
addr = bech32.decode(data);
|
||||
const addr = bech32.decode(data);
|
||||
|
||||
network = Network.fromBech32(addr.hrp, network);
|
||||
|
||||
return this.fromHash(addr.hash, type, addr.version, network);
|
||||
|
||||
@ -120,12 +120,10 @@ Block.prototype.toNormal = function toNormal() {
|
||||
*/
|
||||
|
||||
Block.prototype.toWriter = function toWriter(bw) {
|
||||
let raw;
|
||||
|
||||
if (this.mutable)
|
||||
return this.writeWitness(bw);
|
||||
|
||||
raw = this.frame();
|
||||
const raw = this.frame();
|
||||
bw.writeBytes(raw.data);
|
||||
|
||||
return bw;
|
||||
@ -152,8 +150,6 @@ Block.prototype.toNormalWriter = function toNormalWriter(bw) {
|
||||
*/
|
||||
|
||||
Block.prototype.frame = function frame() {
|
||||
let raw;
|
||||
|
||||
if (this.mutable) {
|
||||
assert(!this._raw);
|
||||
return this.frameWitness();
|
||||
@ -162,12 +158,12 @@ Block.prototype.frame = function frame() {
|
||||
if (this._raw) {
|
||||
assert(this._size >= 0);
|
||||
assert(this._witness >= 0);
|
||||
raw = new RawBlock(this._size, this._witness);
|
||||
const raw = new RawBlock(this._size, this._witness);
|
||||
raw.data = this._raw;
|
||||
return raw;
|
||||
}
|
||||
|
||||
raw = this.frameWitness();
|
||||
const raw = this.frameWitness();
|
||||
|
||||
this._raw = raw.data;
|
||||
this._size = raw.size;
|
||||
@ -280,12 +276,11 @@ Block.prototype.indexOf = function indexOf(hash) {
|
||||
|
||||
Block.prototype.createMerkleRoot = function createMerkleRoot(enc) {
|
||||
const leaves = [];
|
||||
let root, malleated;
|
||||
|
||||
for (const tx of this.txs)
|
||||
leaves.push(tx.hash());
|
||||
|
||||
[root, malleated] = merkle.createRoot(leaves);
|
||||
const [root, malleated] = merkle.createRoot(leaves);
|
||||
|
||||
if (malleated)
|
||||
return null;
|
||||
@ -312,7 +307,6 @@ Block.prototype.createWitnessNonce = function createWitnessNonce() {
|
||||
Block.prototype.createCommitmentHash = function createCommitmentHash(enc) {
|
||||
const nonce = this.getWitnessNonce();
|
||||
const leaves = [];
|
||||
let root, hash;
|
||||
|
||||
assert(nonce, 'No witness nonce present.');
|
||||
|
||||
@ -323,12 +317,12 @@ Block.prototype.createCommitmentHash = function createCommitmentHash(enc) {
|
||||
leaves.push(tx.witnessHash());
|
||||
}
|
||||
|
||||
[root] = merkle.createRoot(leaves);
|
||||
const [root] = merkle.createRoot(leaves);
|
||||
|
||||
// Note: malleation check ignored here.
|
||||
// assert(!malleated);
|
||||
|
||||
hash = digest.root256(root, nonce);
|
||||
const hash = digest.root256(root, nonce);
|
||||
|
||||
return enc === 'hex'
|
||||
? hash.toString('hex')
|
||||
@ -354,17 +348,15 @@ Block.prototype.getMerkleRoot = function getMerkleRoot(enc) {
|
||||
*/
|
||||
|
||||
Block.prototype.getWitnessNonce = function getWitnessNonce() {
|
||||
let coinbase, input;
|
||||
|
||||
if (this.txs.length === 0)
|
||||
return null;
|
||||
|
||||
coinbase = this.txs[0];
|
||||
const coinbase = this.txs[0];
|
||||
|
||||
if (coinbase.inputs.length !== 1)
|
||||
return null;
|
||||
|
||||
input = coinbase.inputs[0];
|
||||
const input = coinbase.inputs[0];
|
||||
|
||||
if (input.witness.items.length !== 1)
|
||||
return null;
|
||||
@ -383,12 +375,11 @@ Block.prototype.getWitnessNonce = function getWitnessNonce() {
|
||||
*/
|
||||
|
||||
Block.prototype.getCommitmentHash = function getCommitmentHash(enc) {
|
||||
let coinbase, hash;
|
||||
|
||||
if (this.txs.length === 0)
|
||||
return null;
|
||||
|
||||
coinbase = this.txs[0];
|
||||
const coinbase = this.txs[0];
|
||||
let hash = null;
|
||||
|
||||
for (let i = coinbase.outputs.length - 1; i >= 0; i--) {
|
||||
const output = coinbase.outputs[i];
|
||||
@ -424,12 +415,8 @@ Block.prototype.verifyBody = function verifyBody() {
|
||||
*/
|
||||
|
||||
Block.prototype.checkBody = function checkBody() {
|
||||
let sigops = 0;
|
||||
const scale = consensus.WITNESS_SCALE_FACTOR;
|
||||
let root;
|
||||
|
||||
// Check merkle root.
|
||||
root = this.createMerkleRoot('hex');
|
||||
const root = this.createMerkleRoot('hex');
|
||||
|
||||
// If the merkle is mutated,
|
||||
// we have duplicate txs.
|
||||
@ -451,16 +438,18 @@ Block.prototype.checkBody = function checkBody() {
|
||||
return [false, 'bad-cb-missing', 100];
|
||||
|
||||
// Test all transactions.
|
||||
const scale = consensus.WITNESS_SCALE_FACTOR;
|
||||
let sigops = 0;
|
||||
|
||||
for (let i = 0; i < this.txs.length; i++) {
|
||||
const tx = this.txs[i];
|
||||
let valid, reason, score;
|
||||
|
||||
// The rest of the txs must not be coinbases.
|
||||
if (i > 0 && tx.isCoinbase())
|
||||
return [false, 'bad-cb-multiple', 100];
|
||||
|
||||
// Sanity checks.
|
||||
[valid, reason, score] = tx.checkSanity();
|
||||
const [valid, reason, score] = tx.checkSanity();
|
||||
|
||||
if (!valid)
|
||||
return [valid, reason, score];
|
||||
@ -480,15 +469,13 @@ Block.prototype.checkBody = function checkBody() {
|
||||
*/
|
||||
|
||||
Block.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
|
||||
let coinbase;
|
||||
|
||||
if (this.version < 2)
|
||||
return -1;
|
||||
|
||||
if (this.txs.length === 0)
|
||||
return -1;
|
||||
|
||||
coinbase = this.txs[0];
|
||||
const coinbase = this.txs[0];
|
||||
|
||||
if (coinbase.inputs.length === 0)
|
||||
return -1;
|
||||
@ -640,14 +627,12 @@ Block.fromJSON = function fromJSON(json) {
|
||||
*/
|
||||
|
||||
Block.prototype.fromReader = function fromReader(br) {
|
||||
let witness = 0;
|
||||
let count;
|
||||
|
||||
br.start();
|
||||
|
||||
this.readHead(br);
|
||||
|
||||
count = br.readVarint();
|
||||
const count = br.readVarint();
|
||||
let witness = 0;
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const tx = TX.fromReader(br);
|
||||
|
||||
@ -98,14 +98,14 @@ Input.prototype.clone = function clone() {
|
||||
*/
|
||||
|
||||
Input.prototype.getType = function getType(coin) {
|
||||
let type;
|
||||
|
||||
if (this.isCoinbase())
|
||||
return 'coinbase';
|
||||
|
||||
if (coin)
|
||||
return coin.getType();
|
||||
|
||||
let type;
|
||||
|
||||
if (this.witness.items.length > 0)
|
||||
type = this.witness.getInputType();
|
||||
else
|
||||
@ -122,8 +122,6 @@ Input.prototype.getType = function getType(coin) {
|
||||
*/
|
||||
|
||||
Input.prototype.getRedeem = function getRedeem(coin) {
|
||||
let redeem, prev;
|
||||
|
||||
if (this.isCoinbase())
|
||||
return;
|
||||
|
||||
@ -137,7 +135,8 @@ Input.prototype.getRedeem = function getRedeem(coin) {
|
||||
return;
|
||||
}
|
||||
|
||||
prev = coin.script;
|
||||
let prev = coin.script;
|
||||
let redeem = null;
|
||||
|
||||
if (prev.isScripthash()) {
|
||||
prev = this.script.getRedeem();
|
||||
@ -159,17 +158,15 @@ Input.prototype.getRedeem = function getRedeem(coin) {
|
||||
*/
|
||||
|
||||
Input.prototype.getSubtype = function getSubtype(coin) {
|
||||
let redeem, type;
|
||||
|
||||
if (this.isCoinbase())
|
||||
return;
|
||||
|
||||
redeem = this.getRedeem(coin);
|
||||
const redeem = this.getRedeem(coin);
|
||||
|
||||
if (!redeem)
|
||||
return;
|
||||
|
||||
type = redeem.getType();
|
||||
const type = redeem.getType();
|
||||
|
||||
return Script.typesByVal[type].toLowerCase();
|
||||
};
|
||||
@ -203,8 +200,10 @@ Input.prototype.getAddress = function getAddress(coin) {
|
||||
|
||||
Input.prototype.getHash = function getHash(enc) {
|
||||
const addr = this.getAddress();
|
||||
|
||||
if (!addr)
|
||||
return;
|
||||
|
||||
return addr.getHash(enc);
|
||||
};
|
||||
|
||||
|
||||
@ -176,14 +176,12 @@ KeyRing.prototype.fromPublic = function fromPublic(key, network) {
|
||||
*/
|
||||
|
||||
KeyRing.prototype.generate = function generate(compressed, network) {
|
||||
let key;
|
||||
|
||||
if (typeof compressed !== 'boolean') {
|
||||
network = compressed;
|
||||
compressed = null;
|
||||
}
|
||||
|
||||
key = secp256k1.generatePrivateKey();
|
||||
const key = secp256k1.generatePrivateKey();
|
||||
|
||||
return this.fromKey(key, compressed, network);
|
||||
};
|
||||
@ -331,18 +329,18 @@ KeyRing.prototype.toSecret = function toSecret(network) {
|
||||
|
||||
KeyRing.prototype.fromSecret = function fromSecret(data, network) {
|
||||
const br = new BufferReader(base58.decode(data), true);
|
||||
let version, key, compressed;
|
||||
|
||||
version = br.readU8();
|
||||
const version = br.readU8();
|
||||
|
||||
network = Network.fromWIF(version, network);
|
||||
|
||||
key = br.readBytes(32);
|
||||
const key = br.readBytes(32);
|
||||
|
||||
let compressed = false;
|
||||
|
||||
if (br.left() > 4) {
|
||||
assert(br.readU8() === 1, 'Bad compression flag.');
|
||||
compressed = true;
|
||||
} else {
|
||||
compressed = false;
|
||||
}
|
||||
|
||||
br.verifyChecksum();
|
||||
@ -411,17 +409,16 @@ KeyRing.prototype.getScript = function getScript() {
|
||||
*/
|
||||
|
||||
KeyRing.prototype.getProgram = function getProgram() {
|
||||
let hash, program;
|
||||
|
||||
if (!this.witness)
|
||||
return;
|
||||
|
||||
if (!this._program) {
|
||||
let program;
|
||||
if (!this.script) {
|
||||
hash = digest.hash160(this.publicKey);
|
||||
const hash = digest.hash160(this.publicKey);
|
||||
program = Script.fromProgram(0, hash);
|
||||
} else {
|
||||
hash = this.script.sha256();
|
||||
const hash = this.script.sha256();
|
||||
program = Script.fromProgram(0, hash);
|
||||
}
|
||||
this._program = program;
|
||||
@ -456,15 +453,13 @@ KeyRing.prototype.getNestedHash = function getNestedHash(enc) {
|
||||
*/
|
||||
|
||||
KeyRing.prototype.getNestedAddress = function getNestedAddress(enc) {
|
||||
let hash, address;
|
||||
|
||||
if (!this.witness)
|
||||
return;
|
||||
|
||||
if (!this._nestedAddress) {
|
||||
hash = this.getNestedHash();
|
||||
address = Address.fromScripthash(hash, this.network);
|
||||
this._nestedAddress = address;
|
||||
const hash = this.getNestedHash();
|
||||
const addr = Address.fromScripthash(hash, this.network);
|
||||
this._nestedAddress = addr;
|
||||
}
|
||||
|
||||
if (enc === 'base58')
|
||||
@ -531,20 +526,19 @@ KeyRing.prototype.getScriptHash256 = function getScriptHash256(enc) {
|
||||
*/
|
||||
|
||||
KeyRing.prototype.getScriptAddress = function getScriptAddress(enc) {
|
||||
let hash, address;
|
||||
|
||||
if (!this.script)
|
||||
return;
|
||||
|
||||
if (!this._scriptAddress) {
|
||||
let addr;
|
||||
if (this.witness) {
|
||||
hash = this.getScriptHash256();
|
||||
address = Address.fromWitnessScripthash(hash, this.network);
|
||||
const hash = this.getScriptHash256();
|
||||
addr = Address.fromWitnessScripthash(hash, this.network);
|
||||
} else {
|
||||
hash = this.getScriptHash160();
|
||||
address = Address.fromScripthash(hash, this.network);
|
||||
const hash = this.getScriptHash160();
|
||||
addr = Address.fromScripthash(hash, this.network);
|
||||
}
|
||||
this._scriptAddress = address;
|
||||
this._scriptAddress = addr;
|
||||
}
|
||||
|
||||
if (enc === 'base58')
|
||||
@ -578,15 +572,16 @@ KeyRing.prototype.getKeyHash = function getKeyHash(enc) {
|
||||
*/
|
||||
|
||||
KeyRing.prototype.getKeyAddress = function getKeyAddress(enc) {
|
||||
let hash, address;
|
||||
|
||||
if (!this._keyAddress) {
|
||||
hash = this.getKeyHash();
|
||||
const hash = this.getKeyHash();
|
||||
let addr;
|
||||
|
||||
if (this.witness)
|
||||
address = Address.fromWitnessPubkeyhash(hash, this.network);
|
||||
addr = Address.fromWitnessPubkeyhash(hash, this.network);
|
||||
else
|
||||
address = Address.fromPubkeyhash(hash, this.network);
|
||||
this._keyAddress = address;
|
||||
addr = Address.fromPubkeyhash(hash, this.network);
|
||||
|
||||
this._keyAddress = addr;
|
||||
}
|
||||
|
||||
if (enc === 'base58')
|
||||
@ -880,16 +875,14 @@ KeyRing.prototype.toRaw = function toRaw() {
|
||||
*/
|
||||
|
||||
KeyRing.prototype.fromReader = function fromReader(br, network) {
|
||||
let field, key, script;
|
||||
|
||||
this.network = Network.get(network);
|
||||
|
||||
field = br.readU8();
|
||||
const field = br.readU8();
|
||||
|
||||
this.witness = (field & 1) !== 0;
|
||||
this.nested = (field & 2) !== 0;
|
||||
|
||||
key = br.readVarBytes();
|
||||
const key = br.readVarBytes();
|
||||
|
||||
if (key.length === 32) {
|
||||
const compressed = br.readU8() === 1;
|
||||
@ -900,7 +893,7 @@ KeyRing.prototype.fromReader = function fromReader(br, network) {
|
||||
assert(secp256k1.publicKeyVerify(key), 'Invalid public key.');
|
||||
}
|
||||
|
||||
script = br.readVarBytes();
|
||||
const script = br.readVarBytes();
|
||||
|
||||
if (script.length > 0)
|
||||
this.script = Script.fromRaw(script);
|
||||
|
||||
@ -109,7 +109,7 @@ MemBlock.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
|
||||
|
||||
MemBlock.prototype.parseCoinbaseHeight = function parseCoinbaseHeight() {
|
||||
const br = new BufferReader(this._raw, true);
|
||||
let count, script;
|
||||
let count;
|
||||
|
||||
br.seek(80);
|
||||
|
||||
@ -132,7 +132,7 @@ MemBlock.prototype.parseCoinbaseHeight = function parseCoinbaseHeight() {
|
||||
|
||||
br.seek(36);
|
||||
|
||||
script = br.readVarBytes();
|
||||
const script = br.readVarBytes();
|
||||
|
||||
return Script.getCoinbaseHeight(script);
|
||||
};
|
||||
|
||||
@ -184,31 +184,29 @@ MerkleBlock.prototype.getTree = function getTree() {
|
||||
*/
|
||||
|
||||
MerkleBlock.prototype.extractTree = function extractTree() {
|
||||
let bitsUsed = 0;
|
||||
let hashUsed = 0;
|
||||
const matches = [];
|
||||
const indexes = [];
|
||||
const map = new Map();
|
||||
let failed = false;
|
||||
const hashes = this.hashes;
|
||||
const flags = this.flags;
|
||||
const totalTX = this.totalTX;
|
||||
let bitsUsed = 0;
|
||||
let hashUsed = 0;
|
||||
let failed = false;
|
||||
let height = 0;
|
||||
let root;
|
||||
|
||||
const width = (height) => {
|
||||
return (totalTX + (1 << height) - 1) >>> height;
|
||||
};
|
||||
|
||||
const traverse = (height, pos) => {
|
||||
let parent, hash, left, right;
|
||||
|
||||
if (bitsUsed >= flags.length * 8) {
|
||||
failed = true;
|
||||
return encoding.ZERO_HASH;
|
||||
}
|
||||
|
||||
parent = (flags[bitsUsed / 8 | 0] >>> (bitsUsed % 8)) & 1;
|
||||
const parent = (flags[bitsUsed / 8 | 0] >>> (bitsUsed % 8)) & 1;
|
||||
|
||||
bitsUsed++;
|
||||
|
||||
if (height === 0 || !parent) {
|
||||
@ -217,7 +215,7 @@ MerkleBlock.prototype.extractTree = function extractTree() {
|
||||
return encoding.ZERO_HASH;
|
||||
}
|
||||
|
||||
hash = hashes[hashUsed++];
|
||||
const hash = hashes[hashUsed++];
|
||||
|
||||
if (height === 0 && parent) {
|
||||
const txid = hash.toString('hex');
|
||||
@ -229,7 +227,8 @@ MerkleBlock.prototype.extractTree = function extractTree() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
left = traverse(height - 1, pos * 2);
|
||||
const left = traverse(height - 1, pos * 2);
|
||||
let right = null;
|
||||
|
||||
if (pos * 2 + 1 < width(height - 1)) {
|
||||
right = traverse(height - 1, pos * 2 + 1);
|
||||
@ -257,7 +256,7 @@ MerkleBlock.prototype.extractTree = function extractTree() {
|
||||
while (width(height) > 1)
|
||||
height++;
|
||||
|
||||
root = traverse(height, 0);
|
||||
const root = traverse(height, 0);
|
||||
|
||||
if (failed)
|
||||
throw new Error('Mutated merkle tree.');
|
||||
@ -373,13 +372,11 @@ MerkleBlock.prototype.toRaw = function toRaw() {
|
||||
*/
|
||||
|
||||
MerkleBlock.prototype.fromReader = function fromReader(br) {
|
||||
let count;
|
||||
|
||||
this.readHead(br);
|
||||
|
||||
this.totalTX = br.readU32();
|
||||
|
||||
count = br.readVarint();
|
||||
const count = br.readVarint();
|
||||
|
||||
for (let i = 0; i < count; i++)
|
||||
this.hashes.push(br.readHash());
|
||||
@ -556,19 +553,17 @@ MerkleBlock.fromMatches = function fromMatches(block, matches) {
|
||||
const hashes = [];
|
||||
const totalTX = block.txs.length;
|
||||
let height = 0;
|
||||
let flags, merkle;
|
||||
|
||||
const width = (height) => {
|
||||
return (totalTX + (1 << height) - 1) >>> height;
|
||||
};
|
||||
|
||||
const hash = (height, pos, leaves) => {
|
||||
let left, right;
|
||||
|
||||
if (height === 0)
|
||||
return leaves[pos];
|
||||
|
||||
left = hash(height - 1, pos * 2, leaves);
|
||||
const left = hash(height - 1, pos * 2, leaves);
|
||||
let right = null;
|
||||
|
||||
if (pos * 2 + 1 < width(height - 1))
|
||||
right = hash(height - 1, pos * 2 + 1, leaves);
|
||||
@ -611,13 +606,13 @@ MerkleBlock.fromMatches = function fromMatches(block, matches) {
|
||||
|
||||
traverse(height, 0, leaves, matches);
|
||||
|
||||
flags = Buffer.allocUnsafe((bits.length + 7) / 8 | 0);
|
||||
const flags = Buffer.allocUnsafe((bits.length + 7) / 8 | 0);
|
||||
flags.fill(0);
|
||||
|
||||
for (let p = 0; p < bits.length; p++)
|
||||
flags[p / 8 | 0] |= bits[p] << (p % 8);
|
||||
|
||||
merkle = new MerkleBlock();
|
||||
const merkle = new MerkleBlock();
|
||||
merkle._hash = block._hash;
|
||||
merkle._hhash = block._hhash;
|
||||
merkle.version = block.version;
|
||||
|
||||
@ -172,11 +172,9 @@ MTX.prototype.addOutpoint = function addOutpoint(outpoint) {
|
||||
*/
|
||||
|
||||
MTX.prototype.addCoin = function addCoin(coin) {
|
||||
let input;
|
||||
|
||||
assert(coin instanceof Coin, 'Cannot add non-coin.');
|
||||
|
||||
input = Input.fromCoin(coin);
|
||||
const input = Input.fromCoin(coin);
|
||||
|
||||
this.inputs.push(input);
|
||||
this.view.addCoin(coin);
|
||||
@ -198,15 +196,13 @@ MTX.prototype.addCoin = function addCoin(coin) {
|
||||
*/
|
||||
|
||||
MTX.prototype.addTX = function addTX(tx, index, height) {
|
||||
let input, coin;
|
||||
|
||||
assert(tx instanceof TX, 'Cannot add non-transaction.');
|
||||
|
||||
if (height == null)
|
||||
height = -1;
|
||||
|
||||
input = Input.fromTX(tx, index);
|
||||
coin = Coin.fromTX(tx, index, height);
|
||||
const input = Input.fromTX(tx, index);
|
||||
const coin = Coin.fromTX(tx, index, height);
|
||||
|
||||
this.inputs.push(input);
|
||||
this.view.addCoin(coin);
|
||||
@ -439,7 +435,6 @@ MTX.prototype.checkInputs = function checkInputs(height) {
|
||||
|
||||
MTX.prototype.scriptInput = function scriptInput(index, coin, ring) {
|
||||
const input = this.inputs[index];
|
||||
let prev;
|
||||
|
||||
assert(input, 'Input does not exist.');
|
||||
assert(coin, 'No coin passed.');
|
||||
@ -452,7 +447,7 @@ MTX.prototype.scriptInput = function scriptInput(index, coin, ring) {
|
||||
}
|
||||
|
||||
// Get the previous output's script
|
||||
prev = coin.script;
|
||||
let prev = coin.script;
|
||||
|
||||
// This is easily the hardest part about
|
||||
// building a transaction with segwit:
|
||||
@ -583,8 +578,6 @@ MTX.prototype.scriptVector = function scriptVector(prev, vector, ring) {
|
||||
|
||||
// Multisig
|
||||
if (prev.isMultisig()) {
|
||||
let n;
|
||||
|
||||
if (prev.indexOf(ring.publicKey) === -1)
|
||||
return false;
|
||||
|
||||
@ -594,7 +587,7 @@ MTX.prototype.scriptVector = function scriptVector(prev, vector, ring) {
|
||||
vector.set(0, opcodes.OP_0);
|
||||
|
||||
// Grab `n` value (number of keys).
|
||||
n = prev.getSmall(prev.length - 2);
|
||||
const n = prev.getSmall(prev.length - 2);
|
||||
|
||||
// Fill script with `n` signature slots.
|
||||
for (let i = 0; i < n; i++)
|
||||
@ -635,18 +628,17 @@ MTX.prototype.signInputAsync = function signInputAsync(index, coin, ring, type,
|
||||
|
||||
MTX.prototype.signInput = function signInput(index, coin, ring, type) {
|
||||
const input = this.inputs[index];
|
||||
let version = 0;
|
||||
let redeem = false;
|
||||
const key = ring.privateKey;
|
||||
let prev, value, vector, sig, result;
|
||||
|
||||
assert(input, 'Input does not exist.');
|
||||
assert(coin, 'No coin passed.');
|
||||
|
||||
// Get the previous output's script
|
||||
prev = coin.script;
|
||||
value = coin.value;
|
||||
vector = input.script;
|
||||
const value = coin.value;
|
||||
let prev = coin.script;
|
||||
let vector = input.script;
|
||||
let version = 0;
|
||||
let redeem = false;
|
||||
|
||||
// Grab regular p2sh redeem script.
|
||||
if (prev.isScripthash()) {
|
||||
@ -677,11 +669,11 @@ MTX.prototype.signInput = function signInput(index, coin, ring, type) {
|
||||
}
|
||||
|
||||
// Create our signature.
|
||||
sig = this.signature(index, prev, value, key, type, version);
|
||||
const sig = this.signature(index, prev, value, key, type, version);
|
||||
|
||||
if (redeem) {
|
||||
redeem = vector.pop();
|
||||
result = this.signVector(prev, vector, sig, ring);
|
||||
const redeem = vector.pop();
|
||||
const result = this.signVector(prev, vector, sig, ring);
|
||||
vector.push(redeem);
|
||||
vector.compile();
|
||||
return result;
|
||||
@ -741,9 +733,7 @@ MTX.prototype.signVector = function signVector(prev, vector, sig, ring) {
|
||||
|
||||
// Multisig
|
||||
if (prev.isMultisig()) {
|
||||
let total = 0;
|
||||
const keys = [];
|
||||
let keyIndex;
|
||||
|
||||
// Grab `m` value (number of sigs required).
|
||||
const m = prev.getSmall(0);
|
||||
@ -764,6 +754,7 @@ MTX.prototype.signVector = function signVector(prev, vector, sig, ring) {
|
||||
return false;
|
||||
|
||||
// Count the number of current signatures.
|
||||
let total = 0;
|
||||
for (let i = 1; i < vector.length; i++) {
|
||||
if (Script.isSignature(vector.get(i)))
|
||||
total++;
|
||||
@ -780,7 +771,7 @@ MTX.prototype.signVector = function signVector(prev, vector, sig, ring) {
|
||||
|
||||
// Find the key index so we can place
|
||||
// the signature in the same index.
|
||||
keyIndex = util.indexOf(keys, ring.publicKey);
|
||||
let keyIndex = util.indexOf(keys, ring.publicKey);
|
||||
|
||||
// Our public key is not in the prev_out
|
||||
// script. We tried to sign a transaction
|
||||
@ -863,14 +854,13 @@ MTX.prototype.isSigned = function isSigned() {
|
||||
|
||||
MTX.prototype.isInputSigned = function isInputSigned(index, coin) {
|
||||
const input = this.inputs[index];
|
||||
let prev, vector, redeem, result;
|
||||
|
||||
assert(input, 'Input does not exist.');
|
||||
assert(coin, 'No coin passed.');
|
||||
|
||||
prev = coin.script;
|
||||
vector = input.script;
|
||||
redeem = false;
|
||||
let prev = coin.script;
|
||||
let vector = input.script;
|
||||
let redeem = false;
|
||||
|
||||
// Grab redeem script if possible.
|
||||
if (prev.isScripthash()) {
|
||||
@ -896,8 +886,8 @@ MTX.prototype.isInputSigned = function isInputSigned(index, coin) {
|
||||
}
|
||||
|
||||
if (redeem) {
|
||||
redeem = vector.pop();
|
||||
result = this.isVectorSigned(prev, vector);
|
||||
const redeem = vector.pop();
|
||||
const result = this.isVectorSigned(prev, vector);
|
||||
vector.push(redeem);
|
||||
return result;
|
||||
}
|
||||
@ -954,14 +944,15 @@ MTX.prototype.isVectorSigned = function isVectorSigned(prev, vector) {
|
||||
*/
|
||||
|
||||
MTX.prototype.template = function template(ring) {
|
||||
let total = 0;
|
||||
|
||||
if (Array.isArray(ring)) {
|
||||
let total = 0;
|
||||
for (const key of ring)
|
||||
total += this.template(key);
|
||||
return total;
|
||||
}
|
||||
|
||||
let total = 0;
|
||||
|
||||
for (let i = 0; i < this.inputs.length; i++) {
|
||||
const {prevout} = this.inputs[i];
|
||||
const coin = this.view.getOutput(prevout);
|
||||
@ -991,9 +982,8 @@ MTX.prototype.template = function template(ring) {
|
||||
*/
|
||||
|
||||
MTX.prototype.sign = function sign(ring, type) {
|
||||
let total = 0;
|
||||
|
||||
if (Array.isArray(ring)) {
|
||||
let total = 0;
|
||||
for (const key of ring)
|
||||
total += this.sign(key, type);
|
||||
return total;
|
||||
@ -1001,6 +991,8 @@ MTX.prototype.sign = function sign(ring, type) {
|
||||
|
||||
assert(ring.privateKey, 'No private key available.');
|
||||
|
||||
let total = 0;
|
||||
|
||||
for (let i = 0; i < this.inputs.length; i++) {
|
||||
const {prevout} = this.inputs[i];
|
||||
const coin = this.view.getOutput(prevout);
|
||||
@ -1066,8 +1058,6 @@ MTX.prototype.estimateSize = async function estimateSize(estimate) {
|
||||
// Add size for signatures and public keys
|
||||
for (const {prevout} of this.inputs) {
|
||||
const coin = this.view.getOutput(prevout);
|
||||
let size = 0;
|
||||
let prev;
|
||||
|
||||
// We're out of luck here.
|
||||
// Just assume it's a p2pkh.
|
||||
@ -1077,31 +1067,30 @@ MTX.prototype.estimateSize = async function estimateSize(estimate) {
|
||||
}
|
||||
|
||||
// Previous output script.
|
||||
prev = coin.script;
|
||||
const prev = coin.script;
|
||||
|
||||
// P2PK
|
||||
if (prev.isPubkey()) {
|
||||
// varint script size
|
||||
size += 1;
|
||||
total += 1;
|
||||
// OP_PUSHDATA0 [signature]
|
||||
size += 1 + 73;
|
||||
total += size;
|
||||
total += 1 + 73;
|
||||
continue;
|
||||
}
|
||||
|
||||
// P2PKH
|
||||
if (prev.isPubkeyhash()) {
|
||||
// varint script size
|
||||
size += 1;
|
||||
total += 1;
|
||||
// OP_PUSHDATA0 [signature]
|
||||
size += 1 + 73;
|
||||
total += 1 + 73;
|
||||
// OP_PUSHDATA0 [key]
|
||||
size += 1 + 33;
|
||||
total += size;
|
||||
total += 1 + 33;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prev.isMultisig()) {
|
||||
let size = 0;
|
||||
// Bare Multisig
|
||||
// OP_0
|
||||
size += 1;
|
||||
@ -1115,6 +1104,7 @@ MTX.prototype.estimateSize = async function estimateSize(estimate) {
|
||||
|
||||
// P2WPKH
|
||||
if (prev.isWitnessPubkeyhash()) {
|
||||
let size = 0;
|
||||
// varint-items-len
|
||||
size += 1;
|
||||
// varint-len [signature]
|
||||
@ -1129,7 +1119,7 @@ MTX.prototype.estimateSize = async function estimateSize(estimate) {
|
||||
|
||||
// Call out to the custom estimator.
|
||||
if (estimate) {
|
||||
size = await estimate(prev);
|
||||
const size = await estimate(prev);
|
||||
if (size !== -1) {
|
||||
total += size;
|
||||
continue;
|
||||
@ -1147,6 +1137,7 @@ MTX.prototype.estimateSize = async function estimateSize(estimate) {
|
||||
|
||||
// P2WSH
|
||||
if (prev.isWitnessScripthash()) {
|
||||
let size = 0;
|
||||
// varint-items-len
|
||||
size += 1;
|
||||
// 2-of-3 multisig input
|
||||
@ -1186,12 +1177,11 @@ MTX.prototype.selectCoins = function selectCoins(coins, options) {
|
||||
MTX.prototype.subtractFee = function subtractFee(fee, index) {
|
||||
if (typeof index === 'number') {
|
||||
const output = this.outputs[index];
|
||||
let min;
|
||||
|
||||
if (!output)
|
||||
throw new Error('Subtraction index does not exist.');
|
||||
|
||||
min = fee + output.getDustThreshold();
|
||||
const min = fee + output.getDustThreshold();
|
||||
|
||||
if (output.value < min)
|
||||
throw new Error('Could not subtract fee.');
|
||||
@ -1221,14 +1211,12 @@ MTX.prototype.subtractFee = function subtractFee(fee, index) {
|
||||
*/
|
||||
|
||||
MTX.prototype.fund = async function fund(coins, options) {
|
||||
let select, change;
|
||||
|
||||
assert(options, 'Options are required.');
|
||||
assert(options.changeAddress, 'Change address is required.');
|
||||
assert(this.inputs.length === 0, 'TX is already funded.');
|
||||
|
||||
// Select necessary coins.
|
||||
select = await this.selectCoins(coins, options);
|
||||
const select = await this.selectCoins(coins, options);
|
||||
|
||||
// Add coins to transaction.
|
||||
for (const coin of select.chosen)
|
||||
@ -1239,7 +1227,7 @@ MTX.prototype.fund = async function fund(coins, options) {
|
||||
this.subtractFee(select.fee, select.subtractFee);
|
||||
|
||||
// Add a change output.
|
||||
change = new Output();
|
||||
const change = new Output();
|
||||
change.value = select.change;
|
||||
change.script.fromAddress(select.changeAddress);
|
||||
|
||||
@ -1262,7 +1250,7 @@ MTX.prototype.fund = async function fund(coins, options) {
|
||||
*/
|
||||
|
||||
MTX.prototype.sortMembers = function sortMembers() {
|
||||
let changeOutput;
|
||||
let changeOutput = null;
|
||||
|
||||
if (this.changeIndex !== -1) {
|
||||
changeOutput = this.outputs[this.changeIndex];
|
||||
@ -1649,8 +1637,6 @@ CoinSelector.prototype.isFull = function isFull() {
|
||||
*/
|
||||
|
||||
CoinSelector.prototype.isSpendable = function isSpendable(coin) {
|
||||
let depth;
|
||||
|
||||
if (this.height === -1)
|
||||
return true;
|
||||
|
||||
@ -1667,7 +1653,7 @@ CoinSelector.prototype.isSpendable = function isSpendable(coin) {
|
||||
if (this.depth === -1)
|
||||
return true;
|
||||
|
||||
depth = coin.getDepth(this.height);
|
||||
const depth = coin.getDepth(this.height);
|
||||
|
||||
if (depth < this.depth)
|
||||
return false;
|
||||
@ -1759,15 +1745,13 @@ CoinSelector.prototype.select = async function select(coins) {
|
||||
*/
|
||||
|
||||
CoinSelector.prototype.selectEstimate = async function selectEstimate() {
|
||||
let change;
|
||||
|
||||
// Set minimum fee and do
|
||||
// an initial round of funding.
|
||||
this.fee = CoinSelector.MIN_FEE;
|
||||
this.fund();
|
||||
|
||||
// Add dummy output for change.
|
||||
change = new Output();
|
||||
const change = new Output();
|
||||
|
||||
if (this.changeAddress) {
|
||||
change.script.fromAddress(this.changeAddress);
|
||||
|
||||
@ -278,11 +278,9 @@ NetAddress.fromHost = function fromHost(host, port, network) {
|
||||
*/
|
||||
|
||||
NetAddress.prototype.fromHostname = function fromHostname(hostname, network) {
|
||||
let addr;
|
||||
|
||||
network = Network.get(network);
|
||||
|
||||
addr = IP.fromHostname(hostname, network.port);
|
||||
const addr = IP.fromHostname(hostname, network.port);
|
||||
|
||||
return this.fromHost(addr.host, addr.port, network);
|
||||
};
|
||||
|
||||
@ -207,11 +207,11 @@ TX.prototype.hash = function _hash(enc) {
|
||||
*/
|
||||
|
||||
TX.prototype.witnessHash = function witnessHash(enc) {
|
||||
let hash = this._whash;
|
||||
|
||||
if (!this.hasWitness())
|
||||
return this.hash(enc);
|
||||
|
||||
let hash = this._whash;
|
||||
|
||||
if (!hash) {
|
||||
hash = digest.hash256(this.toRaw());
|
||||
if (!this.mutable)
|
||||
@ -287,8 +287,6 @@ TX.prototype.toNormalWriter = function toNormalWriter(bw) {
|
||||
*/
|
||||
|
||||
TX.prototype.frame = function frame() {
|
||||
let raw;
|
||||
|
||||
if (this.mutable) {
|
||||
assert(!this._raw);
|
||||
if (this.hasWitness())
|
||||
@ -299,11 +297,13 @@ TX.prototype.frame = function frame() {
|
||||
if (this._raw) {
|
||||
assert(this._size >= 0);
|
||||
assert(this._witness >= 0);
|
||||
raw = new RawTX(this._size, this._witness);
|
||||
const raw = new RawTX(this._size, this._witness);
|
||||
raw.data = this._raw;
|
||||
return raw;
|
||||
}
|
||||
|
||||
let raw;
|
||||
|
||||
if (this.hasWitness())
|
||||
raw = this.frameWitness();
|
||||
else
|
||||
@ -445,8 +445,6 @@ TX.prototype.signatureHash = function signatureHash(index, prev, value, type, ve
|
||||
*/
|
||||
|
||||
TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
|
||||
let size, bw;
|
||||
|
||||
if ((type & 0x1f) === hashType.SINGLE) {
|
||||
// Bitcoind used to return 1 as an error code:
|
||||
// it ended up being treated like a hash.
|
||||
@ -458,9 +456,8 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
|
||||
prev = prev.removeSeparators();
|
||||
|
||||
// Calculate buffer size.
|
||||
size = this.hashSize(index, prev, type);
|
||||
|
||||
bw = new StaticWriter(size);
|
||||
const size = this.hashSize(index, prev, type);
|
||||
const bw = new StaticWriter(size);
|
||||
|
||||
bw.writeU32(this.version);
|
||||
|
||||
@ -615,11 +612,10 @@ TX.prototype.hashSize = function hashSize(index, prev, type) {
|
||||
*/
|
||||
|
||||
TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type) {
|
||||
const input = this.inputs[index];
|
||||
let prevouts = encoding.ZERO_HASH;
|
||||
let sequences = encoding.ZERO_HASH;
|
||||
let outputs = encoding.ZERO_HASH;
|
||||
const input = this.inputs[index];
|
||||
let bw, size;
|
||||
|
||||
if (!(type & hashType.ANYONECANPAY)) {
|
||||
if (this._hashPrevouts) {
|
||||
@ -661,12 +657,11 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type
|
||||
outputs = this._hashOutputs;
|
||||
} else {
|
||||
let size = 0;
|
||||
let bw;
|
||||
|
||||
for (const output of this.outputs)
|
||||
size += output.getSize();
|
||||
|
||||
bw = new StaticWriter(size);
|
||||
const bw = new StaticWriter(size);
|
||||
|
||||
for (const output of this.outputs)
|
||||
output.toWriter(bw);
|
||||
@ -681,8 +676,8 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type
|
||||
outputs = digest.hash256(output.toRaw());
|
||||
}
|
||||
|
||||
size = 156 + prev.getVarSize();
|
||||
bw = new StaticWriter(size);
|
||||
const size = 156 + prev.getVarSize();
|
||||
const bw = new StaticWriter(size);
|
||||
|
||||
bw.writeU32(this.version);
|
||||
bw.writeBytes(prevouts);
|
||||
@ -711,13 +706,11 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type
|
||||
*/
|
||||
|
||||
TX.prototype.checksig = function checksig(index, prev, value, sig, key, version) {
|
||||
let type, hash;
|
||||
|
||||
if (sig.length === 0)
|
||||
return false;
|
||||
|
||||
type = sig[sig.length - 1];
|
||||
hash = this.signatureHash(index, prev, value, type, version);
|
||||
const type = sig[sig.length - 1];
|
||||
const hash = this.signatureHash(index, prev, value, type, version);
|
||||
|
||||
return secp256k1.verify(hash, sig.slice(0, -1), key);
|
||||
};
|
||||
@ -736,18 +729,15 @@ TX.prototype.checksig = function checksig(index, prev, value, sig, key, version)
|
||||
*/
|
||||
|
||||
TX.prototype.signature = function signature(index, prev, value, key, type, version) {
|
||||
let hash, sig, bw;
|
||||
|
||||
if (type == null)
|
||||
type = hashType.ALL;
|
||||
|
||||
if (version == null)
|
||||
version = 0;
|
||||
|
||||
hash = this.signatureHash(index, prev, value, type, version);
|
||||
|
||||
sig = secp256k1.sign(hash, key);
|
||||
bw = new StaticWriter(sig.length + 1);
|
||||
const hash = this.signatureHash(index, prev, value, type, version);
|
||||
const sig = secp256k1.sign(hash, key);
|
||||
const bw = new StaticWriter(sig.length + 1);
|
||||
|
||||
bw.writeBytes(sig);
|
||||
bw.writeU8(type);
|
||||
@ -1022,12 +1012,11 @@ TX.prototype._getInputAddresses = function getInputAddresses(view) {
|
||||
for (const input of this.inputs) {
|
||||
const coin = view ? view.getOutputFor(input) : null;
|
||||
const addr = input.getAddress(coin);
|
||||
let hash;
|
||||
|
||||
if (!addr)
|
||||
continue;
|
||||
|
||||
hash = addr.getHash('hex');
|
||||
const hash = addr.getHash('hex');
|
||||
|
||||
if (!table[hash]) {
|
||||
table[hash] = true;
|
||||
@ -1050,12 +1039,11 @@ TX.prototype._getOutputAddresses = function getOutputAddresses() {
|
||||
|
||||
for (const output of this.outputs) {
|
||||
const addr = output.getAddress();
|
||||
let hash;
|
||||
|
||||
if (!addr)
|
||||
continue;
|
||||
|
||||
hash = addr.getHash('hex');
|
||||
const hash = addr.getHash('hex');
|
||||
|
||||
if (!table[hash]) {
|
||||
table[hash] = true;
|
||||
@ -1129,14 +1117,13 @@ TX.prototype.getAddresses = function getAddresses(view) {
|
||||
|
||||
TX.prototype.getInputHashes = function getInputHashes(view, enc) {
|
||||
const hashes = [];
|
||||
let addrs;
|
||||
|
||||
if (enc === 'hex') {
|
||||
const [, table] = this._getInputAddresses(view);
|
||||
return Object.keys(table);
|
||||
}
|
||||
|
||||
addrs = this.getInputAddresses(view);
|
||||
const addrs = this.getInputAddresses(view);
|
||||
|
||||
for (const addr of addrs)
|
||||
hashes.push(addr.getHash());
|
||||
@ -1151,14 +1138,13 @@ TX.prototype.getInputHashes = function getInputHashes(view, enc) {
|
||||
|
||||
TX.prototype.getOutputHashes = function getOutputHashes(enc) {
|
||||
const hashes = [];
|
||||
let addrs;
|
||||
|
||||
if (enc === 'hex') {
|
||||
const [, table] = this._getOutputAddresses();
|
||||
return Object.keys(table);
|
||||
}
|
||||
|
||||
addrs = this.getOutputAddresses();
|
||||
const addrs = this.getOutputAddresses();
|
||||
|
||||
for (const addr of addrs)
|
||||
hashes.push(addr.getHash());
|
||||
@ -1174,14 +1160,13 @@ TX.prototype.getOutputHashes = function getOutputHashes(enc) {
|
||||
|
||||
TX.prototype.getHashes = function getHashes(view, enc) {
|
||||
const hashes = [];
|
||||
let addrs;
|
||||
|
||||
if (enc === 'hex') {
|
||||
const [, table] = this._getAddresses(view);
|
||||
return Object.keys(table);
|
||||
}
|
||||
|
||||
addrs = this.getAddresses(view);
|
||||
const addrs = this.getAddresses(view);
|
||||
|
||||
for (const addr of addrs)
|
||||
hashes.push(addr.getHash());
|
||||
@ -1283,7 +1268,6 @@ TX.prototype.verifySequence = function verifySequence(index, locktime) {
|
||||
const TYPE_FLAG = consensus.SEQUENCE_TYPE_FLAG;
|
||||
const SEQUENCE_MASK = consensus.SEQUENCE_MASK;
|
||||
const input = this.inputs[index];
|
||||
let mask, sequence, predicate;
|
||||
|
||||
assert(input, 'Input does not exist.');
|
||||
assert(locktime >= 0, 'Locktime must be non-negative.');
|
||||
@ -1297,9 +1281,9 @@ TX.prototype.verifySequence = function verifySequence(index, locktime) {
|
||||
if ((input.sequence & DISABLE_FLAG) !== 0)
|
||||
return false;
|
||||
|
||||
mask = TYPE_FLAG | SEQUENCE_MASK;
|
||||
sequence = input.sequence & mask;
|
||||
predicate = locktime & mask;
|
||||
const mask = TYPE_FLAG | SEQUENCE_MASK;
|
||||
const sequence = input.sequence & mask;
|
||||
const predicate = locktime & mask;
|
||||
|
||||
if (!((sequence < TYPE_FLAG && predicate < TYPE_FLAG)
|
||||
|| (sequence >= TYPE_FLAG && predicate >= TYPE_FLAG))) {
|
||||
@ -1588,7 +1572,6 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view) {
|
||||
for (const input of this.inputs) {
|
||||
const witness = input.witness;
|
||||
const coin = view.getOutputFor(input);
|
||||
let prev;
|
||||
|
||||
if (!coin)
|
||||
continue;
|
||||
@ -1596,7 +1579,7 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view) {
|
||||
if (witness.items.length === 0)
|
||||
continue;
|
||||
|
||||
prev = coin.script;
|
||||
let prev = coin.script;
|
||||
|
||||
if (prev.isScripthash()) {
|
||||
prev = input.script.getRedeem();
|
||||
@ -1621,8 +1604,6 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view) {
|
||||
}
|
||||
|
||||
if (prev.isWitnessScripthash()) {
|
||||
let redeem;
|
||||
|
||||
if (witness.items.length - 1 > policy.MAX_P2WSH_STACK)
|
||||
return false;
|
||||
|
||||
@ -1632,7 +1613,7 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view) {
|
||||
return false;
|
||||
}
|
||||
|
||||
redeem = witness.items[witness.items.length - 1];
|
||||
const redeem = witness.items[witness.items.length - 1];
|
||||
|
||||
if (redeem.length > policy.MAX_P2WSH_SIZE)
|
||||
return false;
|
||||
@ -1726,7 +1707,6 @@ TX.prototype.verifyInputs = function verifyInputs(view, height) {
|
||||
|
||||
TX.prototype.checkInputs = function checkInputs(view, height) {
|
||||
let total = 0;
|
||||
let fee, value;
|
||||
|
||||
assert(typeof height === 'number');
|
||||
|
||||
@ -1754,12 +1734,12 @@ TX.prototype.checkInputs = function checkInputs(view, height) {
|
||||
}
|
||||
|
||||
// Overflows already checked in `isSane()`.
|
||||
value = this.getOutputValue();
|
||||
const value = this.getOutputValue();
|
||||
|
||||
if (total < value)
|
||||
return [-1, 'bad-txns-in-belowout', 100];
|
||||
|
||||
fee = total - value;
|
||||
const fee = total - value;
|
||||
|
||||
if (fee < 0)
|
||||
return [-1, 'bad-txns-fee-negative', 100];
|
||||
@ -1779,13 +1759,11 @@ TX.prototype.checkInputs = function checkInputs(view, height) {
|
||||
*/
|
||||
|
||||
TX.prototype.getModifiedSize = function getModifiedSize(size) {
|
||||
let offset;
|
||||
|
||||
if (size == null)
|
||||
size = this.getVirtualSize();
|
||||
|
||||
for (const input of this.inputs) {
|
||||
offset = 41 + Math.min(110, input.script.getSize());
|
||||
const offset = 41 + Math.min(110, input.script.getSize());
|
||||
if (size > offset)
|
||||
size -= offset;
|
||||
}
|
||||
@ -1815,12 +1793,11 @@ TX.prototype.getPriority = function getPriority(view, height, size) {
|
||||
|
||||
for (const {prevout} of this.inputs) {
|
||||
const coin = view.getOutput(prevout);
|
||||
let coinHeight;
|
||||
|
||||
if (!coin)
|
||||
continue;
|
||||
|
||||
coinHeight = view.getHeight(prevout);
|
||||
const coinHeight = view.getHeight(prevout);
|
||||
|
||||
if (coinHeight === -1)
|
||||
continue;
|
||||
@ -1848,12 +1825,11 @@ TX.prototype.getChainValue = function getChainValue(view) {
|
||||
|
||||
for (const {prevout} of this.inputs) {
|
||||
const coin = view.getOutput(prevout);
|
||||
let coinHeight;
|
||||
|
||||
if (!coin)
|
||||
continue;
|
||||
|
||||
coinHeight = view.getHeight(prevout);
|
||||
const coinHeight = view.getHeight(prevout);
|
||||
|
||||
if (coinHeight === -1)
|
||||
continue;
|
||||
@ -2272,8 +2248,6 @@ TX.prototype.fromRaw = function fromRaw(data) {
|
||||
*/
|
||||
|
||||
TX.prototype.fromReader = function fromReader(br) {
|
||||
let count;
|
||||
|
||||
if (TX.isWitness(br))
|
||||
return this.fromWitnessReader(br);
|
||||
|
||||
@ -2281,14 +2255,14 @@ TX.prototype.fromReader = function fromReader(br) {
|
||||
|
||||
this.version = br.readU32();
|
||||
|
||||
count = br.readVarint();
|
||||
const inCount = br.readVarint();
|
||||
|
||||
for (let i = 0; i < count; i++)
|
||||
for (let i = 0; i < inCount; i++)
|
||||
this.inputs.push(Input.fromReader(br));
|
||||
|
||||
count = br.readVarint();
|
||||
const outCount = br.readVarint();
|
||||
|
||||
for (let i = 0; i < count; i++)
|
||||
for (let i = 0; i < outCount; i++)
|
||||
this.outputs.push(Output.fromReader(br));
|
||||
|
||||
this.locktime = br.readU32();
|
||||
@ -2312,33 +2286,31 @@ TX.prototype.fromReader = function fromReader(br) {
|
||||
*/
|
||||
|
||||
TX.prototype.fromWitnessReader = function fromWitnessReader(br) {
|
||||
let flag = 0;
|
||||
let witness = 0;
|
||||
let hasWitness = false;
|
||||
let count;
|
||||
|
||||
br.start();
|
||||
|
||||
this.version = br.readU32();
|
||||
|
||||
assert(br.readU8() === 0, 'Non-zero marker.');
|
||||
|
||||
flag = br.readU8();
|
||||
let flag = br.readU8();
|
||||
|
||||
assert(flag !== 0, 'Flag byte is zero.');
|
||||
|
||||
this.flag = flag;
|
||||
|
||||
count = br.readVarint();
|
||||
const inCount = br.readVarint();
|
||||
|
||||
for (let i = 0; i < count; i++)
|
||||
for (let i = 0; i < inCount; i++)
|
||||
this.inputs.push(Input.fromReader(br));
|
||||
|
||||
count = br.readVarint();
|
||||
const outCount = br.readVarint();
|
||||
|
||||
for (let i = 0; i < count; i++)
|
||||
for (let i = 0; i < outCount; i++)
|
||||
this.outputs.push(Output.fromReader(br));
|
||||
|
||||
let witness = 0;
|
||||
let hasWitness = false;
|
||||
|
||||
if (flag & 1) {
|
||||
flag ^= 1;
|
||||
|
||||
@ -2441,8 +2413,6 @@ TX.prototype.writeNormal = function writeNormal(bw) {
|
||||
*/
|
||||
|
||||
TX.prototype.writeWitness = function writeWitness(bw) {
|
||||
let witness;
|
||||
|
||||
if (this.inputs.length === 0 && this.outputs.length !== 0)
|
||||
throw new Error('Cannot serialize zero-input tx.');
|
||||
|
||||
@ -2460,7 +2430,7 @@ TX.prototype.writeWitness = function writeWitness(bw) {
|
||||
for (const output of this.outputs)
|
||||
output.toWriter(bw);
|
||||
|
||||
witness = bw.written;
|
||||
let witness = bw.written;
|
||||
|
||||
for (const input of this.inputs)
|
||||
input.witness.toWriter(bw);
|
||||
|
||||
@ -146,8 +146,6 @@ Network.prototype.ms = function ms() {
|
||||
*/
|
||||
|
||||
Network.create = function create(options) {
|
||||
let network;
|
||||
|
||||
if (typeof options === 'string')
|
||||
options = networks[options];
|
||||
|
||||
@ -156,7 +154,7 @@ Network.create = function create(options) {
|
||||
if (Network[options.type])
|
||||
return Network[options.type];
|
||||
|
||||
network = new Network(options);
|
||||
const network = new Network(options);
|
||||
|
||||
Network[network.type] = network;
|
||||
|
||||
|
||||
@ -14,7 +14,6 @@
|
||||
const BN = require('../crypto/bn');
|
||||
|
||||
const network = exports;
|
||||
let main, testnet, regtest, simnet;
|
||||
|
||||
/**
|
||||
* Network type list.
|
||||
@ -32,7 +31,7 @@ network.types = ['main', 'testnet', 'regtest', 'simnet'];
|
||||
* @type {Object}
|
||||
*/
|
||||
|
||||
main = network.main = {};
|
||||
const main = {};
|
||||
|
||||
/**
|
||||
* Symbolic network type.
|
||||
@ -478,7 +477,7 @@ main.requestMempool = false;
|
||||
* https://en.bitcoin.it/wiki/Testnet
|
||||
*/
|
||||
|
||||
testnet = network.testnet = {};
|
||||
const testnet = {};
|
||||
|
||||
testnet.type = 'testnet';
|
||||
|
||||
@ -659,7 +658,7 @@ testnet.requestMempool = false;
|
||||
* Regtest
|
||||
*/
|
||||
|
||||
regtest = network.regtest = {};
|
||||
const regtest = {};
|
||||
|
||||
regtest.type = 'regtest';
|
||||
|
||||
@ -819,7 +818,7 @@ regtest.requestMempool = true;
|
||||
* Simnet (btcd)
|
||||
*/
|
||||
|
||||
simnet = network.simnet = {};
|
||||
const simnet = {};
|
||||
|
||||
simnet.type = 'simnet';
|
||||
|
||||
@ -976,3 +975,12 @@ simnet.maxFeeRate = 60000;
|
||||
simnet.selfConnect = false;
|
||||
|
||||
simnet.requestMempool = false;
|
||||
|
||||
/*
|
||||
* Expose
|
||||
*/
|
||||
|
||||
network.main = main;
|
||||
network.testnet = testnet;
|
||||
network.regtest = regtest;
|
||||
network.simnet = simnet;
|
||||
|
||||
@ -322,14 +322,12 @@ exports.STACK_NEGATE = Buffer.from([0x81]);
|
||||
*/
|
||||
|
||||
exports.isHashType = function isHashType(sig) {
|
||||
let type;
|
||||
|
||||
assert(Buffer.isBuffer(sig));
|
||||
|
||||
if (sig.length === 0)
|
||||
return false;
|
||||
|
||||
type = sig[sig.length - 1] & ~exports.hashType.ANYONECANPAY;
|
||||
const type = sig[sig.length - 1] & ~exports.hashType.ANYONECANPAY;
|
||||
|
||||
if (!(type >= exports.hashType.ALL && type <= exports.hashType.SINGLE))
|
||||
return false;
|
||||
@ -451,8 +449,6 @@ exports.isCompressedEncoding = function isCompressedEncoding(key) {
|
||||
*/
|
||||
|
||||
exports.isSignatureEncoding = function isSignatureEncoding(sig) {
|
||||
let lenR, lenS;
|
||||
|
||||
assert(Buffer.isBuffer(sig));
|
||||
|
||||
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash]
|
||||
@ -483,14 +479,14 @@ exports.isSignatureEncoding = function isSignatureEncoding(sig) {
|
||||
return false;
|
||||
|
||||
// Extract the length of the R element.
|
||||
lenR = sig[3];
|
||||
const lenR = sig[3];
|
||||
|
||||
// Make sure the length of the S element is still inside the signature.
|
||||
if (5 + lenR >= sig.length)
|
||||
return false;
|
||||
|
||||
// Extract the length of the S element.
|
||||
lenS = sig[5 + lenR];
|
||||
const lenS = sig[5 + lenR];
|
||||
|
||||
// Verify that the length of the signature matches the sum of the length
|
||||
// of the elements.
|
||||
@ -706,8 +702,6 @@ exports.formatStackASM = function formatStackASM(items, decode) {
|
||||
*/
|
||||
|
||||
exports.num = function num(value, minimal, size) {
|
||||
let result;
|
||||
|
||||
assert(Buffer.isBuffer(value));
|
||||
|
||||
if (size == null)
|
||||
@ -737,7 +731,7 @@ exports.num = function num(value, minimal, size) {
|
||||
if (value.length === 0)
|
||||
return new BN(0);
|
||||
|
||||
result = new BN(value, 'le');
|
||||
const result = new BN(value, 'le');
|
||||
|
||||
// If the input vector's most significant byte is
|
||||
// 0x80, remove it from the result's msb and return
|
||||
@ -764,8 +758,6 @@ exports.num = function num(value, minimal, size) {
|
||||
*/
|
||||
|
||||
exports.array = function array(value) {
|
||||
let neg, result;
|
||||
|
||||
if (util.isNumber(value))
|
||||
value = new BN(value);
|
||||
|
||||
@ -790,8 +782,8 @@ exports.array = function array(value) {
|
||||
// interpreted as a negative when
|
||||
// converting to an integral.
|
||||
|
||||
neg = value.cmpn(0) < 0;
|
||||
result = value.toArray('le');
|
||||
const neg = value.cmpn(0) < 0;
|
||||
const result = value.toArray('le');
|
||||
|
||||
if (result[result.length - 1] & 0x80)
|
||||
result.push(neg ? 0x80 : 0);
|
||||
|
||||
@ -407,8 +407,6 @@ Opcode.from = function from(data) {
|
||||
*/
|
||||
|
||||
Opcode.fromSymbol = function fromSymbol(name) {
|
||||
let op;
|
||||
|
||||
assert(typeof name === 'string');
|
||||
assert(name.length > 0);
|
||||
|
||||
@ -418,7 +416,7 @@ Opcode.fromSymbol = function fromSymbol(name) {
|
||||
if (!util.startsWith(name, 'OP_'))
|
||||
name = `OP_${name}`;
|
||||
|
||||
op = common.opcodes[name];
|
||||
const op = common.opcodes[name];
|
||||
assert(op != null, 'Unknown opcode.');
|
||||
|
||||
return Opcode.fromOp(op);
|
||||
@ -431,12 +429,11 @@ Opcode.fromSymbol = function fromSymbol(name) {
|
||||
|
||||
Opcode.prototype.toSymbol = function toSymbol() {
|
||||
let op = this.value;
|
||||
let symbol;
|
||||
|
||||
if (op === -1)
|
||||
op = 0xff;
|
||||
|
||||
symbol = common.opcodesByVal[op];
|
||||
let symbol = common.opcodesByVal[op];
|
||||
|
||||
if (symbol == null)
|
||||
symbol = util.hex8(op);
|
||||
|
||||
@ -438,7 +438,6 @@ Script.prototype.getSubscript = function getSubscript(lastSep) {
|
||||
|
||||
Script.prototype.removeSeparators = function removeSeparators() {
|
||||
let found = false;
|
||||
let code;
|
||||
|
||||
// Optimizing for the common case:
|
||||
// Check for any separators first.
|
||||
@ -458,7 +457,7 @@ Script.prototype.removeSeparators = function removeSeparators() {
|
||||
// Uncommon case: someone actually
|
||||
// has a code separator. Go through
|
||||
// and remove them all.
|
||||
code = [];
|
||||
const code = [];
|
||||
|
||||
for (const op of this.code) {
|
||||
if (op.value === -1)
|
||||
@ -484,12 +483,12 @@ Script.prototype.removeSeparators = function removeSeparators() {
|
||||
*/
|
||||
|
||||
Script.prototype.execute = function execute(stack, flags, tx, index, value, version) {
|
||||
const state = [];
|
||||
const alt = [];
|
||||
let lastSep = 0;
|
||||
let opCount = 0;
|
||||
let negate = 0;
|
||||
let minimal = false;
|
||||
const state = [];
|
||||
const alt = [];
|
||||
|
||||
if (flags == null)
|
||||
flags = Script.flags.STANDARD_VERIFY_FLAGS;
|
||||
@ -566,8 +565,6 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_CHECKLOCKTIMEVERIFY: {
|
||||
let locktime;
|
||||
|
||||
// OP_CHECKLOCKTIMEVERIFY = OP_NOP2
|
||||
if (!(flags & Script.flags.VERIFY_CHECKLOCKTIMEVERIFY)) {
|
||||
if (flags & Script.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
||||
@ -581,7 +578,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
locktime = Script.num(stack.top(-1), minimal, 5);
|
||||
let locktime = Script.num(stack.top(-1), minimal, 5);
|
||||
|
||||
if (locktime.cmpn(0) < 0)
|
||||
throw new ScriptError('NEGATIVE_LOCKTIME', op, ip);
|
||||
@ -594,8 +591,6 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_CHECKSEQUENCEVERIFY: {
|
||||
let locktime;
|
||||
|
||||
// OP_CHECKSEQUENCEVERIFY = OP_NOP3
|
||||
if (!(flags & Script.flags.VERIFY_CHECKSEQUENCEVERIFY)) {
|
||||
if (flags & Script.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
||||
@ -609,7 +604,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
locktime = Script.num(stack.top(-1), minimal, 5);
|
||||
let locktime = Script.num(stack.top(-1), minimal, 5);
|
||||
|
||||
if (locktime.cmpn(0) < 0)
|
||||
throw new ScriptError('NEGATIVE_LOCKTIME', op, ip);
|
||||
@ -725,27 +720,23 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_2DUP: {
|
||||
let v1, v2;
|
||||
|
||||
if (stack.length < 2)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
v1 = stack.top(-2);
|
||||
v2 = stack.top(-1);
|
||||
const v1 = stack.top(-2);
|
||||
const v2 = stack.top(-1);
|
||||
|
||||
stack.push(v1);
|
||||
stack.push(v2);
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_3DUP: {
|
||||
let v1, v2, v3;
|
||||
|
||||
if (stack.length < 3)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
v1 = stack.top(-3);
|
||||
v2 = stack.top(-2);
|
||||
v3 = stack.top(-1);
|
||||
const v1 = stack.top(-3);
|
||||
const v2 = stack.top(-2);
|
||||
const v3 = stack.top(-1);
|
||||
|
||||
stack.push(v1);
|
||||
stack.push(v2);
|
||||
@ -753,26 +744,22 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_2OVER: {
|
||||
let v1, v2;
|
||||
|
||||
if (stack.length < 4)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
v1 = stack.top(-4);
|
||||
v2 = stack.top(-3);
|
||||
const v1 = stack.top(-4);
|
||||
const v2 = stack.top(-3);
|
||||
|
||||
stack.push(v1);
|
||||
stack.push(v2);
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_2ROT: {
|
||||
let v1, v2;
|
||||
|
||||
if (stack.length < 6)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
v1 = stack.top(-6);
|
||||
v2 = stack.top(-5);
|
||||
const v1 = stack.top(-6);
|
||||
const v2 = stack.top(-5);
|
||||
|
||||
stack.erase(-6, -4);
|
||||
stack.push(v1);
|
||||
@ -788,12 +775,10 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_IFDUP: {
|
||||
let val;
|
||||
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
val = stack.top(-1);
|
||||
const val = stack.top(-1);
|
||||
|
||||
if (Script.bool(val))
|
||||
stack.push(val);
|
||||
@ -833,18 +818,16 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers
|
||||
}
|
||||
case opcodes.OP_PICK:
|
||||
case opcodes.OP_ROLL: {
|
||||
let num, val;
|
||||
|
||||
if (stack.length < 2)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
num = Script.num(stack.top(-1), minimal).toNumber();
|
||||
const num = Script.num(stack.top(-1), minimal).toNumber();
|
||||
stack.pop();
|
||||
|
||||
if (num < 0 || num >= stack.length)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
val = stack.top(-num - 1);
|
||||
const val = stack.top(-num - 1);
|
||||
|
||||
if (op.value === opcodes.OP_ROLL)
|
||||
stack.remove(-num - 1);
|
||||
@ -883,15 +866,13 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers
|
||||
}
|
||||
case opcodes.OP_EQUAL:
|
||||
case opcodes.OP_EQUALVERIFY: {
|
||||
let v1, v2, res;
|
||||
|
||||
if (stack.length < 2)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
v1 = stack.top(-2);
|
||||
v2 = stack.top(-1);
|
||||
const v1 = stack.top(-2);
|
||||
const v2 = stack.top(-1);
|
||||
|
||||
res = v1.equals(v2);
|
||||
const res = v1.equals(v2);
|
||||
|
||||
stack.pop();
|
||||
stack.pop();
|
||||
@ -912,12 +893,10 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers
|
||||
case opcodes.OP_ABS:
|
||||
case opcodes.OP_NOT:
|
||||
case opcodes.OP_0NOTEQUAL: {
|
||||
let num;
|
||||
|
||||
if (stack.length < 1)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
num = Script.num(stack.top(-1), minimal);
|
||||
let num = Script.num(stack.top(-1), minimal);
|
||||
|
||||
switch (op.value) {
|
||||
case opcodes.OP_1ADD:
|
||||
@ -963,13 +942,12 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers
|
||||
case opcodes.OP_GREATERTHANOREQUAL:
|
||||
case opcodes.OP_MIN:
|
||||
case opcodes.OP_MAX: {
|
||||
let n1, n2, num;
|
||||
|
||||
if (stack.length < 2)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
n1 = Script.num(stack.top(-2), minimal);
|
||||
n2 = Script.num(stack.top(-1), minimal);
|
||||
const n1 = Script.num(stack.top(-2), minimal);
|
||||
const n2 = Script.num(stack.top(-1), minimal);
|
||||
let num;
|
||||
|
||||
switch (op.value) {
|
||||
case opcodes.OP_ADD:
|
||||
@ -1038,16 +1016,14 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers
|
||||
break;
|
||||
}
|
||||
case opcodes.OP_WITHIN: {
|
||||
let val, n1, n2, n3;
|
||||
|
||||
if (stack.length < 3)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
n1 = Script.num(stack.top(-3), minimal);
|
||||
n2 = Script.num(stack.top(-2), minimal);
|
||||
n3 = Script.num(stack.top(-1), minimal);
|
||||
const n1 = Script.num(stack.top(-3), minimal);
|
||||
const n2 = Script.num(stack.top(-2), minimal);
|
||||
const n3 = Script.num(stack.top(-1), minimal);
|
||||
|
||||
val = n2.cmp(n1) <= 0 && n1.cmp(n3) < 0;
|
||||
const val = n2.cmp(n1) <= 0 && n1.cmp(n3) < 0;
|
||||
|
||||
stack.pop();
|
||||
stack.pop();
|
||||
@ -1097,19 +1073,16 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers
|
||||
}
|
||||
case opcodes.OP_CHECKSIG:
|
||||
case opcodes.OP_CHECKSIGVERIFY: {
|
||||
let sig, key, res, subscript;
|
||||
|
||||
if (!tx)
|
||||
throw new ScriptError('UNKNOWN_ERROR', 'No TX passed in.');
|
||||
|
||||
if (stack.length < 2)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
sig = stack.top(-2);
|
||||
key = stack.top(-1);
|
||||
res = false;
|
||||
const sig = stack.top(-2);
|
||||
const key = stack.top(-1);
|
||||
|
||||
subscript = this.getSubscript(lastSep);
|
||||
const subscript = this.getSubscript(lastSep);
|
||||
|
||||
if (version === 0)
|
||||
subscript.removeData(sig);
|
||||
@ -1117,6 +1090,8 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers
|
||||
validateSignature(sig, flags);
|
||||
validateKey(key, flags, version);
|
||||
|
||||
let res = false;
|
||||
|
||||
if (sig.length > 0) {
|
||||
const type = sig[sig.length - 1];
|
||||
const hash = tx.signatureHash(index, subscript, value, type, version);
|
||||
@ -1143,17 +1118,15 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers
|
||||
}
|
||||
case opcodes.OP_CHECKMULTISIG:
|
||||
case opcodes.OP_CHECKMULTISIGVERIFY: {
|
||||
let i, m, n, isig, ikey, ikey2, subscript, res;
|
||||
|
||||
if (!tx)
|
||||
throw new ScriptError('UNKNOWN_ERROR', 'No TX passed in.');
|
||||
|
||||
i = 1;
|
||||
let i = 1;
|
||||
if (stack.length < i)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
n = Script.num(stack.top(-i), minimal).toNumber();
|
||||
ikey2 = n + 2;
|
||||
let n = Script.num(stack.top(-i), minimal).toNumber();
|
||||
let ikey2 = n + 2;
|
||||
|
||||
if (!(n >= 0 && n <= consensus.MAX_MULTISIG_PUBKEYS))
|
||||
throw new ScriptError('PUBKEY_COUNT', op, ip);
|
||||
@ -1164,25 +1137,25 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers
|
||||
throw new ScriptError('OP_COUNT', op, ip);
|
||||
|
||||
i++;
|
||||
ikey = i;
|
||||
let ikey = i;
|
||||
i += n;
|
||||
|
||||
if (stack.length < i)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
m = Script.num(stack.top(-i), minimal).toNumber();
|
||||
let m = Script.num(stack.top(-i), minimal).toNumber();
|
||||
|
||||
if (!(m >= 0 && m <= n))
|
||||
throw new ScriptError('SIG_COUNT', op, ip);
|
||||
|
||||
i++;
|
||||
isig = i;
|
||||
let isig = i;
|
||||
i += m;
|
||||
|
||||
if (stack.length < i)
|
||||
throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
|
||||
|
||||
subscript = this.getSubscript(lastSep);
|
||||
const subscript = this.getSubscript(lastSep);
|
||||
|
||||
for (let j = 0; j < m; j++) {
|
||||
const sig = stack.top(-isig - j);
|
||||
@ -1190,7 +1163,7 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers
|
||||
subscript.removeData(sig);
|
||||
}
|
||||
|
||||
res = true;
|
||||
let res = true;
|
||||
while (res && m > 0) {
|
||||
const sig = stack.top(-isig);
|
||||
const key = stack.top(-ikey);
|
||||
@ -1589,12 +1562,10 @@ Script.fromNulldata = function fromNulldata(flags) {
|
||||
*/
|
||||
|
||||
Script.prototype.fromProgram = function fromProgram(version, data) {
|
||||
let op;
|
||||
|
||||
assert(util.isNumber(version) && version >= 0 && version <= 16);
|
||||
assert(Buffer.isBuffer(data) && data.length >= 2 && data.length <= 40);
|
||||
|
||||
op = Opcode.fromSmall(version);
|
||||
const op = Opcode.fromSmall(version);
|
||||
|
||||
this.raw = Buffer.allocUnsafe(2 + data.length);
|
||||
this.raw[0] = op.value;
|
||||
@ -1695,15 +1666,13 @@ Script.fromCommitment = function fromCommitment(hash, flags) {
|
||||
*/
|
||||
|
||||
Script.prototype.getRedeem = function getRedeem() {
|
||||
let redeem;
|
||||
|
||||
if (this.code.length === 0)
|
||||
return;
|
||||
|
||||
if (!this.isPushOnly())
|
||||
return;
|
||||
|
||||
redeem = this.code[this.code.length - 1];
|
||||
const redeem = this.code[this.code.length - 1];
|
||||
|
||||
if (!redeem.data)
|
||||
return;
|
||||
@ -1903,20 +1872,18 @@ Script.prototype.isPubkeyhash = function isPubkeyhash(minimal) {
|
||||
*/
|
||||
|
||||
Script.prototype.isMultisig = function isMultisig(minimal) {
|
||||
let m, n;
|
||||
|
||||
if (this.raw.length < 41)
|
||||
return false;
|
||||
|
||||
if (this.raw[this.raw.length - 1] !== opcodes.OP_CHECKMULTISIG)
|
||||
return false;
|
||||
|
||||
n = common.getSmall(this.raw[this.raw.length - 2]);
|
||||
const n = common.getSmall(this.raw[this.raw.length - 2]);
|
||||
|
||||
if (n < 1)
|
||||
return false;
|
||||
|
||||
m = common.getSmall(this.raw[0]);
|
||||
const m = common.getSmall(this.raw[0]);
|
||||
|
||||
if (!(m >= 1 && m <= n))
|
||||
return false;
|
||||
@ -2053,13 +2020,11 @@ Script.prototype.isProgram = function isProgram() {
|
||||
*/
|
||||
|
||||
Script.prototype.toProgram = function toProgram() {
|
||||
let version, data;
|
||||
|
||||
if (!this.isProgram())
|
||||
return;
|
||||
|
||||
version = common.getSmall(this.raw[0]);
|
||||
data = this.raw.slice(2);
|
||||
const version = common.getSmall(this.raw[0]);
|
||||
const data = this.raw.slice(2);
|
||||
|
||||
return new Program(version, data);
|
||||
};
|
||||
@ -2253,13 +2218,11 @@ Script.prototype.isMultisigInput = function isMultisigInput() {
|
||||
*/
|
||||
|
||||
Script.prototype.isScripthashInput = function isScripthashInput() {
|
||||
let op, redeem;
|
||||
|
||||
if (this.raw.length < 2)
|
||||
return false;
|
||||
|
||||
// Grab the raw redeem script.
|
||||
op = this.code[this.code.length - 1];
|
||||
const op = this.code[this.code.length - 1];
|
||||
|
||||
// Last data element should be an array
|
||||
// for the redeem script.
|
||||
@ -2284,7 +2247,7 @@ Script.prototype.isScripthashInput = function isScripthashInput() {
|
||||
if (common.isKeyEncoding(op.data))
|
||||
return false;
|
||||
|
||||
redeem = Script.fromRaw(op.data);
|
||||
const redeem = Script.fromRaw(op.data);
|
||||
|
||||
if (!redeem.isCode())
|
||||
return false;
|
||||
@ -2308,16 +2271,14 @@ Script.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
|
||||
*/
|
||||
|
||||
Script.getCoinbaseHeight = function getCoinbaseHeight(raw) {
|
||||
let data, height, op;
|
||||
|
||||
if (raw.length === 0)
|
||||
return -1;
|
||||
|
||||
// Small ints are allowed.
|
||||
height = common.getSmall(raw[0]);
|
||||
const smi = common.getSmall(raw[0]);
|
||||
|
||||
if (height !== -1)
|
||||
return height;
|
||||
if (smi !== -1)
|
||||
return smi;
|
||||
|
||||
// No more than 6 bytes (we can't
|
||||
// handle 7 byte JS numbers and
|
||||
@ -2329,9 +2290,10 @@ Script.getCoinbaseHeight = function getCoinbaseHeight(raw) {
|
||||
if (raw.length < 1 + raw[0])
|
||||
return -1;
|
||||
|
||||
data = raw.slice(1, 1 + raw[0]);
|
||||
const data = raw.slice(1, 1 + raw[0]);
|
||||
|
||||
// Deserialize the height.
|
||||
let height;
|
||||
try {
|
||||
height = Script.num(data, true, 6);
|
||||
} catch (e) {
|
||||
@ -2339,7 +2301,7 @@ Script.getCoinbaseHeight = function getCoinbaseHeight(raw) {
|
||||
}
|
||||
|
||||
// Reserialize the height.
|
||||
op = Opcode.fromNumber(height);
|
||||
const op = Opcode.fromNumber(height);
|
||||
|
||||
// Should have been OP_0-OP_16.
|
||||
if (!op.data)
|
||||
@ -2619,14 +2581,14 @@ Script.prototype.getSigops = function getSigops(accurate) {
|
||||
*/
|
||||
|
||||
Script.prototype.getScripthashSigops = function getScripthashSigops(input) {
|
||||
let op, redeem;
|
||||
|
||||
if (!this.isScripthash())
|
||||
return this.getSigops(true);
|
||||
|
||||
if (input.code.length === 0)
|
||||
return 0;
|
||||
|
||||
let op;
|
||||
|
||||
for (op of input.code) {
|
||||
if (op.data)
|
||||
continue;
|
||||
@ -2641,7 +2603,7 @@ Script.prototype.getScripthashSigops = function getScripthashSigops(input) {
|
||||
if (!op.data)
|
||||
return 0;
|
||||
|
||||
redeem = new Script(op.data);
|
||||
const redeem = new Script(op.data);
|
||||
|
||||
return redeem.getSigops(true);
|
||||
};
|
||||
@ -2702,8 +2664,6 @@ Script.prototype.getWitnessSigops = function getWitnessSigops(input, witness) {
|
||||
*/
|
||||
|
||||
Script.prototype.fromString = function fromString(code) {
|
||||
let bw;
|
||||
|
||||
assert(typeof code === 'string');
|
||||
|
||||
code = code.trim();
|
||||
@ -2712,7 +2672,8 @@ Script.prototype.fromString = function fromString(code) {
|
||||
return this;
|
||||
|
||||
code = code.split(/\s+/);
|
||||
bw = new BufferWriter();
|
||||
|
||||
const bw = new BufferWriter();
|
||||
|
||||
for (let op of code) {
|
||||
let symbol = op;
|
||||
@ -2777,7 +2738,7 @@ Script.fromString = function fromString(code) {
|
||||
*/
|
||||
|
||||
Script.verify = function verify(input, witness, output, tx, i, value, flags) {
|
||||
let stack, copy, raw, redeem, hadWitness;
|
||||
let hadWitness = false;
|
||||
|
||||
if (flags == null)
|
||||
flags = Script.flags.STANDARD_VERIFY_FLAGS;
|
||||
@ -2788,12 +2749,13 @@ Script.verify = function verify(input, witness, output, tx, i, value, flags) {
|
||||
}
|
||||
|
||||
// Setup a stack.
|
||||
stack = new Stack();
|
||||
let stack = new Stack();
|
||||
|
||||
// Execute the input script
|
||||
input.execute(stack, flags, tx, i, value, 0);
|
||||
|
||||
// Copy the stack for P2SH
|
||||
let copy;
|
||||
if (flags & Script.flags.VERIFY_P2SH)
|
||||
copy = stack.clone();
|
||||
|
||||
@ -2832,8 +2794,8 @@ Script.verify = function verify(input, witness, output, tx, i, value, flags) {
|
||||
throw new ScriptError('EVAL_FALSE');
|
||||
|
||||
// Grab the real redeem script
|
||||
raw = stack.pop();
|
||||
redeem = new Script(raw);
|
||||
const raw = stack.pop();
|
||||
const redeem = new Script(raw);
|
||||
|
||||
// Execute the redeem script.
|
||||
redeem.execute(stack, flags, tx, i, value, 0);
|
||||
@ -2891,7 +2853,7 @@ Script.verify = function verify(input, witness, output, tx, i, value, flags) {
|
||||
Script.verifyProgram = function verifyProgram(witness, output, flags, tx, i, value) {
|
||||
const program = output.toProgram();
|
||||
const stack = witness.toStack();
|
||||
let witnessScript, redeem;
|
||||
let redeem;
|
||||
|
||||
assert(program, 'verifyProgram called on non-witness-program.');
|
||||
assert((flags & Script.flags.VERIFY_WITNESS) !== 0);
|
||||
@ -2901,7 +2863,7 @@ Script.verifyProgram = function verifyProgram(witness, output, flags, tx, i, val
|
||||
if (stack.length === 0)
|
||||
throw new ScriptError('WITNESS_PROGRAM_WITNESS_EMPTY');
|
||||
|
||||
witnessScript = stack.pop();
|
||||
const witnessScript = stack.pop();
|
||||
|
||||
if (!digest.sha256(witnessScript).equals(program.data))
|
||||
throw new ScriptError('WITNESS_PROGRAM_MISMATCH');
|
||||
@ -2963,10 +2925,8 @@ Script.verifyProgram = function verifyProgram(witness, output, flags, tx, i, val
|
||||
Script.verifyMast = function verifyMast(program, stack, output, flags, tx, i, value) {
|
||||
let mastRoot = new BufferWriter();
|
||||
let scriptRoot = new BufferWriter();
|
||||
const scripts = new BufferWriter();
|
||||
let scripts = new BufferWriter();
|
||||
let version = 0;
|
||||
let pathdata, depth, path, posdata, pos;
|
||||
let metadata, subscripts, ops, script;
|
||||
|
||||
assert(program.version === 1);
|
||||
assert((flags & Script.flags.VERIFY_MAST) !== 0);
|
||||
@ -2974,15 +2934,15 @@ Script.verifyMast = function verifyMast(program, stack, output, flags, tx, i, va
|
||||
if (stack.length < 4)
|
||||
throw new ScriptError('INVALID_MAST_STACK');
|
||||
|
||||
metadata = stack.top(-1);
|
||||
const metadata = stack.top(-1);
|
||||
if (metadata.length < 1 || metadata.length > 5)
|
||||
throw new ScriptError('INVALID_MAST_STACK');
|
||||
|
||||
subscripts = metadata[0];
|
||||
const subscripts = metadata[0];
|
||||
if (subscripts === 0 || stack.length < subscripts + 3)
|
||||
throw new ScriptError('INVALID_MAST_STACK');
|
||||
|
||||
ops = subscripts;
|
||||
let ops = subscripts;
|
||||
scriptRoot.writeU8(subscripts);
|
||||
|
||||
if (metadata[metadata.length - 1] === 0x00)
|
||||
@ -3001,12 +2961,12 @@ Script.verifyMast = function verifyMast(program, stack, output, flags, tx, i, va
|
||||
|
||||
mastRoot.writeU32(version);
|
||||
|
||||
pathdata = stack.top(-2);
|
||||
const pathdata = stack.top(-2);
|
||||
|
||||
if (pathdata.length & 0x1f)
|
||||
throw new ScriptError('INVALID_MAST_STACK');
|
||||
|
||||
depth = pathdata.length >>> 5;
|
||||
const depth = pathdata.length >>> 5;
|
||||
|
||||
if (depth > 32)
|
||||
throw new ScriptError('INVALID_MAST_STACK');
|
||||
@ -3017,17 +2977,17 @@ Script.verifyMast = function verifyMast(program, stack, output, flags, tx, i, va
|
||||
throw new ScriptError('OP_COUNT');
|
||||
}
|
||||
|
||||
path = [];
|
||||
const path = [];
|
||||
|
||||
for (let j = 0; j < depth; j++)
|
||||
path.push(pathdata.slice(j * 32, j * 32 + 32));
|
||||
|
||||
posdata = stack.top(-3);
|
||||
const posdata = stack.top(-3);
|
||||
|
||||
if (posdata.length > 4)
|
||||
throw new ScriptError('INVALID_MAST_STACK');
|
||||
|
||||
pos = 0;
|
||||
let pos = 0;
|
||||
if (posdata.length > 0) {
|
||||
if (posdata[posdata.length - 1] === 0x00)
|
||||
throw new ScriptError('INVALID_MAST_STACK');
|
||||
@ -3047,7 +3007,7 @@ Script.verifyMast = function verifyMast(program, stack, output, flags, tx, i, va
|
||||
scripts.writeBytes(output.raw);
|
||||
|
||||
for (let j = 0; j < subscripts; j++) {
|
||||
script = stack.top(-(4 + j));
|
||||
const script = stack.top(-(4 + j));
|
||||
if (version === 0) {
|
||||
if ((scripts.written + script.length) > consensus.MAX_SCRIPT_SIZE)
|
||||
throw new ScriptError('SCRIPT_SIZE');
|
||||
@ -3073,7 +3033,8 @@ Script.verifyMast = function verifyMast(program, stack, output, flags, tx, i, va
|
||||
throw new ScriptError('PUSH_SIZE');
|
||||
}
|
||||
|
||||
output = new Script(scripts.render());
|
||||
scripts = scripts.render();
|
||||
output = new Script(scripts);
|
||||
output.execute(stack, flags, tx, i, value, 1);
|
||||
|
||||
if (stack.length !== 0)
|
||||
|
||||
@ -321,7 +321,7 @@ ScriptNum.fromRaw = function fromRaw(data, minimal, limit) {
|
||||
ScriptNum.prototype.toRaw = function toRaw() {
|
||||
let value = this.value;
|
||||
let negative = false;
|
||||
let data, offset, size;
|
||||
let offset, size;
|
||||
|
||||
// Zeroes are always empty arrays.
|
||||
if (value === 0)
|
||||
@ -357,7 +357,7 @@ ScriptNum.prototype.toRaw = function toRaw() {
|
||||
}
|
||||
|
||||
// Write number.
|
||||
data = Buffer.allocUnsafe(size + offset);
|
||||
const data = Buffer.allocUnsafe(size + offset);
|
||||
|
||||
switch (size) {
|
||||
case 6:
|
||||
|
||||
@ -100,17 +100,15 @@ SigCache.prototype.has = function has(hash, sig, key) {
|
||||
*/
|
||||
|
||||
SigCache.prototype.verify = function verify(msg, sig, key) {
|
||||
let hash, result;
|
||||
|
||||
if (this.size === 0)
|
||||
return secp256k1.verify(msg, sig, key);
|
||||
|
||||
hash = msg.toString('hex');
|
||||
const hash = msg.toString('hex');
|
||||
|
||||
if (this.has(hash, sig, key))
|
||||
return true;
|
||||
|
||||
result = secp256k1.verify(msg, sig, key);
|
||||
const result = secp256k1.verify(msg, sig, key);
|
||||
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
@ -260,16 +260,14 @@ Stack.prototype.set = function set(i, value) {
|
||||
*/
|
||||
|
||||
Stack.prototype.swap = function swap(i1, i2) {
|
||||
let v1, v2;
|
||||
|
||||
if (i1 < 0)
|
||||
i1 = this.items.length + i1;
|
||||
|
||||
if (i2 < 0)
|
||||
i2 = this.items.length + i2;
|
||||
|
||||
v1 = this.items[i1];
|
||||
v2 = this.items[i2];
|
||||
const v1 = this.items[i1];
|
||||
const v2 = this.items[i2];
|
||||
|
||||
this.items[i1] = v2;
|
||||
this.items[i2] = v1;
|
||||
|
||||
@ -76,11 +76,9 @@ Witness.prototype.__defineSetter__('length', function(length) {
|
||||
*/
|
||||
|
||||
Witness.prototype.fromOptions = function fromOptions(options) {
|
||||
let items;
|
||||
|
||||
assert(options, 'Witness data is required.');
|
||||
|
||||
items = options.items;
|
||||
let items = options.items;
|
||||
|
||||
if (!items)
|
||||
items = options;
|
||||
@ -295,12 +293,10 @@ Witness.prototype.test = function test(filter) {
|
||||
*/
|
||||
|
||||
Witness.prototype.getRedeem = function getRedeem() {
|
||||
let redeem;
|
||||
|
||||
if (this.items.length === 0)
|
||||
return;
|
||||
|
||||
redeem = this.items[this.items.length - 1];
|
||||
const redeem = this.items[this.items.length - 1];
|
||||
|
||||
if (!redeem)
|
||||
return;
|
||||
|
||||
@ -46,10 +46,9 @@ const ASN1 = exports;
|
||||
ASN1.readTag = function readTag(br) {
|
||||
let type = br.readU8();
|
||||
const primitive = (type & 0x20) === 0;
|
||||
let oct;
|
||||
|
||||
if ((type & 0x1f) === 0x1f) {
|
||||
oct = type;
|
||||
let oct = type;
|
||||
type = 0;
|
||||
while ((oct & 0x80) === 0x80) {
|
||||
oct = br.readU8();
|
||||
@ -77,7 +76,6 @@ ASN1.readTag = function readTag(br) {
|
||||
|
||||
ASN1.readSize = function readSize(br, primitive) {
|
||||
let size = br.readU8();
|
||||
let bytes, i, j;
|
||||
|
||||
// Indefinite form
|
||||
if (!primitive && size === 0x80)
|
||||
@ -90,16 +88,15 @@ ASN1.readSize = function readSize(br, primitive) {
|
||||
}
|
||||
|
||||
// Long form
|
||||
bytes = size & 0x7f;
|
||||
const bytes = size & 0x7f;
|
||||
|
||||
if (bytes > 3)
|
||||
throw new Error('Length octet is too long.');
|
||||
|
||||
size = 0;
|
||||
for (i = 0; i < bytes; i++) {
|
||||
for (let i = 0; i < bytes; i++) {
|
||||
size <<= 8;
|
||||
j = br.readU8();
|
||||
size |= j;
|
||||
size |= br.readU8();
|
||||
}
|
||||
|
||||
return size;
|
||||
@ -209,12 +206,12 @@ ASN1.readBitstr = function readBitstr(br) {
|
||||
|
||||
ASN1.readString = function readString(br) {
|
||||
const tag = ASN1.readTag(br);
|
||||
let str;
|
||||
|
||||
switch (tag.type) {
|
||||
case 0x03: // bitstr
|
||||
str = br.readBytes(tag.size);
|
||||
case 0x03: { // bitstr
|
||||
const str = br.readBytes(tag.size);
|
||||
return ASN1.alignBitstr(str);
|
||||
}
|
||||
// Note:
|
||||
// Fuck all these.
|
||||
case 0x04: // octstr
|
||||
@ -229,10 +226,12 @@ ASN1.readString = function readString(br) {
|
||||
case 0x1b: // genstr
|
||||
case 0x1c: // unistr
|
||||
case 0x1d: // charstr
|
||||
case 0x1e: // bmpstr
|
||||
case 0x1e: { // bmpstr
|
||||
return br.readString('utf8', tag.size);
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Unexpected tag: ${tag.type}.`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -247,15 +246,14 @@ ASN1.alignBitstr = function alignBitstr(data) {
|
||||
const bits = (data.length - 1) * 8 - padding;
|
||||
const buf = data.slice(1);
|
||||
const shift = 8 - (bits % 8);
|
||||
let i, out;
|
||||
|
||||
if (shift === 8 || buf.length === 0)
|
||||
return buf;
|
||||
|
||||
out = Buffer.allocUnsafe(buf.length);
|
||||
const out = Buffer.allocUnsafe(buf.length);
|
||||
out[0] = buf[0] >>> shift;
|
||||
|
||||
for (i = 1; i < buf.length; i++) {
|
||||
for (let i = 1; i < buf.length; i++) {
|
||||
out[i] = buf[i - 1] << (8 - shift);
|
||||
out[i] |= buf[i] >>> shift;
|
||||
}
|
||||
@ -422,7 +420,6 @@ ASN1.formatOID = function formatOID(data) {
|
||||
const ids = [];
|
||||
let ident = 0;
|
||||
let subident = 0;
|
||||
let result, first, second;
|
||||
|
||||
while (br.left()) {
|
||||
subident = br.readU8();
|
||||
@ -437,9 +434,9 @@ ASN1.formatOID = function formatOID(data) {
|
||||
if (subident & 0x80)
|
||||
ids.push(ident);
|
||||
|
||||
first = (ids[0] / 40) | 0;
|
||||
second = ids[0] % 40;
|
||||
result = [first, second].concat(ids.slice(1));
|
||||
const first = (ids[0] / 40) | 0;
|
||||
const second = ids[0] % 40;
|
||||
const result = [first, second].concat(ids.slice(1));
|
||||
|
||||
return result.join('.');
|
||||
};
|
||||
@ -452,14 +449,13 @@ ASN1.formatOID = function formatOID(data) {
|
||||
|
||||
ASN1.readAlgIdent = function readAlgIdent(br) {
|
||||
let params = null;
|
||||
let alg, tag;
|
||||
|
||||
br = ASN1.seq(br);
|
||||
|
||||
alg = ASN1.readOID(br);
|
||||
const alg = ASN1.readOID(br);
|
||||
|
||||
if (br.left() > 0) {
|
||||
tag = ASN1.readTag(br);
|
||||
const tag = ASN1.readTag(br);
|
||||
params = br.readBytes(tag.size);
|
||||
if (params.length === 0)
|
||||
params = null;
|
||||
|
||||
@ -116,18 +116,17 @@ AsyncEmitter.prototype._unshift = function _unshift(type, handler, once) {
|
||||
*/
|
||||
|
||||
AsyncEmitter.prototype.removeListener = function removeListener(type, handler) {
|
||||
let i, listeners, listener;
|
||||
let index = -1;
|
||||
|
||||
assert(typeof type === 'string', '`type` must be a string.');
|
||||
|
||||
listeners = this._events[type];
|
||||
const listeners = this._events[type];
|
||||
|
||||
if (!listeners)
|
||||
return;
|
||||
|
||||
for (i = 0; i < listeners.length; i++) {
|
||||
listener = listeners[i];
|
||||
let index = -1;
|
||||
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
const listener = listeners[i];
|
||||
if (listener.handler === handler) {
|
||||
index = i;
|
||||
break;
|
||||
@ -179,17 +178,16 @@ AsyncEmitter.prototype.removeAllListeners = function removeAllListeners(type) {
|
||||
*/
|
||||
|
||||
AsyncEmitter.prototype.listeners = function listeners(type) {
|
||||
let listeners, listener;
|
||||
const result = [];
|
||||
|
||||
assert(typeof type === 'string', '`type` must be a string.');
|
||||
|
||||
listeners = this._events[type];
|
||||
const listeners = this._events[type];
|
||||
|
||||
if (!listeners)
|
||||
return result;
|
||||
|
||||
for (listener of listeners)
|
||||
const result = [];
|
||||
|
||||
for (const listener of listeners)
|
||||
result.push(listener.handler);
|
||||
|
||||
return result;
|
||||
@ -201,11 +199,9 @@ AsyncEmitter.prototype.listeners = function listeners(type) {
|
||||
*/
|
||||
|
||||
AsyncEmitter.prototype.listenerCount = function listenerCount(type) {
|
||||
let listeners;
|
||||
|
||||
assert(typeof type === 'string', '`type` must be a string.');
|
||||
|
||||
listeners = this._events[type];
|
||||
const listeners = this._events[type];
|
||||
|
||||
if (!listeners)
|
||||
return 0;
|
||||
@ -222,29 +218,29 @@ AsyncEmitter.prototype.listenerCount = function listenerCount(type) {
|
||||
*/
|
||||
|
||||
AsyncEmitter.prototype.emit = function emit(type) {
|
||||
let i, j, listeners, error, err, args, listener, handler;
|
||||
|
||||
assert(typeof type === 'string', '`type` must be a string.');
|
||||
|
||||
listeners = this._events[type];
|
||||
const listeners = this._events[type];
|
||||
|
||||
if (!listeners || listeners.length === 0) {
|
||||
if (type === 'error') {
|
||||
error = arguments[1];
|
||||
const error = arguments[1];
|
||||
|
||||
if (error instanceof Error)
|
||||
throw error;
|
||||
|
||||
err = new Error(`Uncaught, unspecified "error" event. (${error})`);
|
||||
const err = new Error(`Uncaught, unspecified "error" event. (${error})`);
|
||||
err.context = error;
|
||||
throw err;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < listeners.length; i++) {
|
||||
listener = listeners[i];
|
||||
handler = listener.handler;
|
||||
let args = null;
|
||||
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
const listener = listeners[i];
|
||||
const handler = listener.handler;
|
||||
|
||||
if (listener.once) {
|
||||
listeners.splice(i, 1);
|
||||
@ -267,7 +263,7 @@ AsyncEmitter.prototype.emit = function emit(type) {
|
||||
default:
|
||||
if (!args) {
|
||||
args = new Array(arguments.length - 1);
|
||||
for (j = 1; j < arguments.length; j++)
|
||||
for (let j = 1; j < arguments.length; j++)
|
||||
args[j - 1] = arguments[j];
|
||||
}
|
||||
handler.apply(null, args);
|
||||
@ -285,29 +281,29 @@ AsyncEmitter.prototype.emit = function emit(type) {
|
||||
*/
|
||||
|
||||
AsyncEmitter.prototype.fire = async function fire(type) {
|
||||
let i, j, listeners, error, err, args, listener, handler;
|
||||
|
||||
assert(typeof type === 'string', '`type` must be a string.');
|
||||
|
||||
listeners = this._events[type];
|
||||
const listeners = this._events[type];
|
||||
|
||||
if (!listeners || listeners.length === 0) {
|
||||
if (type === 'error') {
|
||||
error = arguments[1];
|
||||
const error = arguments[1];
|
||||
|
||||
if (error instanceof Error)
|
||||
throw error;
|
||||
|
||||
err = new Error(`Uncaught, unspecified "error" event. (${error})`);
|
||||
const err = new Error(`Uncaught, unspecified "error" event. (${error})`);
|
||||
err.context = error;
|
||||
throw err;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < listeners.length; i++) {
|
||||
listener = listeners[i];
|
||||
handler = listener.handler;
|
||||
let args = null;
|
||||
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
const listener = listeners[i];
|
||||
const handler = listener.handler;
|
||||
|
||||
if (listener.once) {
|
||||
listeners.splice(i, 1);
|
||||
@ -330,7 +326,7 @@ AsyncEmitter.prototype.fire = async function fire(type) {
|
||||
default:
|
||||
if (!args) {
|
||||
args = new Array(arguments.length - 1);
|
||||
for (j = 1; j < arguments.length; j++)
|
||||
for (let j = 1; j < arguments.length; j++)
|
||||
args[j - 1] = arguments[j];
|
||||
}
|
||||
await handler.apply(null, args);
|
||||
|
||||
@ -190,15 +190,15 @@ AsyncObject.prototype.fire = async function fire() {
|
||||
*/
|
||||
|
||||
AsyncObject.prototype.fireHook = async function fireHook(type) {
|
||||
let listeners, args;
|
||||
|
||||
assert(typeof type === 'string', '`type` must be a string.');
|
||||
|
||||
listeners = this._hooks[type];
|
||||
const listeners = this._hooks[type];
|
||||
|
||||
if (!listeners || listeners.length === 0)
|
||||
return;
|
||||
|
||||
let args = null;
|
||||
|
||||
for (const handler of listeners) {
|
||||
switch (arguments.length) {
|
||||
case 1:
|
||||
|
||||
@ -37,24 +37,24 @@ for (let i = 0; i < base58.length; i++)
|
||||
|
||||
exports.encode = function encode(data) {
|
||||
let zeroes = 0;
|
||||
let length = 0;
|
||||
let str = '';
|
||||
let i, b58, carry, j, k;
|
||||
let i = 0;
|
||||
|
||||
for (i = 0; i < data.length; i++) {
|
||||
for (; i < data.length; i++) {
|
||||
if (data[i] !== 0)
|
||||
break;
|
||||
zeroes++;
|
||||
}
|
||||
|
||||
b58 = Buffer.allocUnsafe(((data.length * 138 / 100) | 0) + 1);
|
||||
const b58 = Buffer.allocUnsafe(((data.length * 138 / 100) | 0) + 1);
|
||||
b58.fill(0);
|
||||
|
||||
for (; i < data.length; i++) {
|
||||
carry = data[i];
|
||||
j = 0;
|
||||
let length = 0;
|
||||
|
||||
for (k = b58.length - 1; k >= 0; k--, j++) {
|
||||
for (; i < data.length; i++) {
|
||||
let carry = data[i];
|
||||
let j = 0;
|
||||
|
||||
for (let k = b58.length - 1; k >= 0; k--, j++) {
|
||||
if (carry === 0 && j >= length)
|
||||
break;
|
||||
carry += 256 * b58[k];
|
||||
@ -70,7 +70,9 @@ exports.encode = function encode(data) {
|
||||
while (i < b58.length && b58[i] === 0)
|
||||
i++;
|
||||
|
||||
for (j = 0; j < zeroes; j++)
|
||||
let str = '';
|
||||
|
||||
for (let j = 0; j < zeroes; j++)
|
||||
str += '1';
|
||||
|
||||
for (; i < b58.length; i++)
|
||||
@ -92,28 +94,29 @@ if (native)
|
||||
|
||||
exports.decode = function decode(str) {
|
||||
let zeroes = 0;
|
||||
let length = 0;
|
||||
let i = 0;
|
||||
let b256, ch, carry, j, k, out;
|
||||
|
||||
for (i = 0; i < str.length; i++) {
|
||||
for (; i < str.length; i++) {
|
||||
if (str[i] !== '1')
|
||||
break;
|
||||
zeroes++;
|
||||
}
|
||||
|
||||
b256 = Buffer.allocUnsafe(((str.length * 733) / 1000 | 0) + 1);
|
||||
const b256 = Buffer.allocUnsafe(((str.length * 733) / 1000 | 0) + 1);
|
||||
b256.fill(0);
|
||||
|
||||
let length = 0;
|
||||
|
||||
for (; i < str.length; i++) {
|
||||
ch = unbase58[str[i]];
|
||||
const ch = unbase58[str[i]];
|
||||
|
||||
if (ch == null)
|
||||
throw new Error('Non-base58 character.');
|
||||
|
||||
carry = ch;
|
||||
j = 0;
|
||||
let carry = ch;
|
||||
let j = 0;
|
||||
|
||||
for (k = b256.length - 1; k >= 0; k--, j++) {
|
||||
for (let k = b256.length - 1; k >= 0; k--, j++) {
|
||||
if (carry === 0 && j >= length)
|
||||
break;
|
||||
carry += 58 * b256[k];
|
||||
@ -129,8 +132,9 @@ exports.decode = function decode(str) {
|
||||
while (i < b256.length && b256[i] === 0)
|
||||
i++;
|
||||
|
||||
out = Buffer.allocUnsafe(zeroes + (b256.length - i));
|
||||
const out = Buffer.allocUnsafe(zeroes + (b256.length - i));
|
||||
|
||||
let j;
|
||||
for (j = 0; j < zeroes; j++)
|
||||
out[j] = 0;
|
||||
|
||||
|
||||
@ -76,10 +76,10 @@ function polymod(pre) {
|
||||
function serialize(hrp, data) {
|
||||
let str = '';
|
||||
let chk = 1;
|
||||
let i, ch;
|
||||
let i;
|
||||
|
||||
for (i = 0; i < hrp.length; i++) {
|
||||
ch = hrp.charCodeAt(i);
|
||||
const ch = hrp.charCodeAt(i);
|
||||
|
||||
if ((ch >> 5) === 0)
|
||||
throw new Error('Invalid bech32 character.');
|
||||
@ -92,16 +92,16 @@ function serialize(hrp, data) {
|
||||
|
||||
chk = polymod(chk);
|
||||
|
||||
for (i = 0; i < hrp.length; i++) {
|
||||
ch = hrp.charCodeAt(i);
|
||||
for (let i = 0; i < hrp.length; i++) {
|
||||
const ch = hrp.charCodeAt(i);
|
||||
chk = polymod(chk) ^ (ch & 0x1f);
|
||||
str += hrp[i];
|
||||
}
|
||||
|
||||
str += '1';
|
||||
|
||||
for (i = 0; i < data.length; i++) {
|
||||
ch = data[i];
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const ch = data[i];
|
||||
|
||||
if ((ch >> 5) !== 0)
|
||||
throw new Error('Invalid bech32 value.');
|
||||
@ -110,12 +110,12 @@ function serialize(hrp, data) {
|
||||
str += CHARSET[ch];
|
||||
}
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
for (let i = 0; i < 6; i++)
|
||||
chk = polymod(chk);
|
||||
|
||||
chk ^= 1;
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
for (let i = 0; i < 6; i++)
|
||||
str += CHARSET[(chk >>> ((5 - i) * 5)) & 0x1f];
|
||||
|
||||
return str;
|
||||
@ -128,12 +128,7 @@ function serialize(hrp, data) {
|
||||
*/
|
||||
|
||||
function deserialize(str) {
|
||||
let chk = 1;
|
||||
let lower = false;
|
||||
let upper = false;
|
||||
let hrp = '';
|
||||
let dlen = 0;
|
||||
let i, hlen, ch, v, data;
|
||||
|
||||
if (str.length < 8 || str.length > 90)
|
||||
throw new Error('Invalid bech32 string length.');
|
||||
@ -141,16 +136,22 @@ function deserialize(str) {
|
||||
while (dlen < str.length && str[(str.length - 1) - dlen] !== '1')
|
||||
dlen++;
|
||||
|
||||
hlen = str.length - (1 + dlen);
|
||||
const hlen = str.length - (1 + dlen);
|
||||
|
||||
if (hlen < 1 || dlen < 6)
|
||||
throw new Error('Invalid bech32 data length.');
|
||||
|
||||
dlen -= 6;
|
||||
data = Buffer.allocUnsafe(dlen);
|
||||
|
||||
for (i = 0; i < hlen; i++) {
|
||||
ch = str.charCodeAt(i);
|
||||
const data = Buffer.allocUnsafe(dlen);
|
||||
|
||||
let chk = 1;
|
||||
let lower = false;
|
||||
let upper = false;
|
||||
let hrp = '';
|
||||
|
||||
for (let i = 0; i < hlen; i++) {
|
||||
let ch = str.charCodeAt(i);
|
||||
|
||||
if (ch < 0x21 || ch > 0x7e)
|
||||
throw new Error('Invalid bech32 character.');
|
||||
@ -168,14 +169,15 @@ function deserialize(str) {
|
||||
|
||||
chk = polymod(chk);
|
||||
|
||||
let i;
|
||||
for (i = 0; i < hlen; i++)
|
||||
chk = polymod(chk) ^ (str.charCodeAt(i) & 0x1f);
|
||||
|
||||
i++;
|
||||
|
||||
while (i < str.length) {
|
||||
ch = str.charCodeAt(i);
|
||||
v = (ch & 0x80) ? -1 : TABLE[ch];
|
||||
const ch = str.charCodeAt(i);
|
||||
const v = (ch & 0x80) ? -1 : TABLE[ch];
|
||||
|
||||
if (ch >= 0x61 && ch <= 0x7a)
|
||||
lower = true;
|
||||
@ -215,17 +217,16 @@ function deserialize(str) {
|
||||
*/
|
||||
|
||||
function convert(data, output, frombits, tobits, pad, off) {
|
||||
const maxv = (1 << tobits) - 1;
|
||||
let acc = 0;
|
||||
let bits = 0;
|
||||
const maxv = (1 << tobits) - 1;
|
||||
let j = 0;
|
||||
let i, value;
|
||||
|
||||
if (pad !== -1)
|
||||
output[j++] = pad;
|
||||
|
||||
for (i = off; i < data.length; i++) {
|
||||
value = data[i];
|
||||
for (let i = off; i < data.length; i++) {
|
||||
const value = data[i];
|
||||
|
||||
if ((value >> frombits) !== 0)
|
||||
throw new Error('Invalid bech32 bits.');
|
||||
@ -260,7 +261,6 @@ function convert(data, output, frombits, tobits, pad, off) {
|
||||
|
||||
function encode(hrp, version, hash) {
|
||||
const output = POOL65;
|
||||
let data;
|
||||
|
||||
if (version < 0 || version > 16)
|
||||
throw new Error('Invalid bech32 version.');
|
||||
@ -268,7 +268,7 @@ function encode(hrp, version, hash) {
|
||||
if (hash.length < 2 || hash.length > 40)
|
||||
throw new Error('Invalid bech32 data length.');
|
||||
|
||||
data = convert(hash, output, 8, 5, version, 0);
|
||||
const data = convert(hash, output, 8, 5, version, 0);
|
||||
|
||||
return serialize(hrp, data);
|
||||
}
|
||||
@ -284,7 +284,6 @@ if (native)
|
||||
|
||||
function decode(str) {
|
||||
const [hrp, data] = deserialize(str);
|
||||
let version, hash, output;
|
||||
|
||||
if (data.length === 0 || data.length > 65)
|
||||
throw new Error('Invalid bech32 data length.');
|
||||
@ -292,9 +291,9 @@ function decode(str) {
|
||||
if (data[0] > 16)
|
||||
throw new Error('Invalid bech32 version.');
|
||||
|
||||
version = data[0];
|
||||
output = data;
|
||||
hash = convert(data, output, 5, 8, -1, 1);
|
||||
const version = data[0];
|
||||
const output = data;
|
||||
const hash = convert(data, output, 5, 8, -1, 1);
|
||||
|
||||
if (hash.length < 2 || hash.length > 40)
|
||||
throw new Error('Invalid bech32 data length.');
|
||||
|
||||
@ -117,15 +117,13 @@ Bloom.flagsByVal = {
|
||||
*/
|
||||
|
||||
Bloom.prototype.fromOptions = function fromOptions(size, n, tweak, update) {
|
||||
let filter;
|
||||
|
||||
assert(typeof size === 'number', '`size` must be a number.');
|
||||
assert(size > 0, '`size` must be greater than zero.');
|
||||
assert(size % 1 === 0, '`size` must be an integer.');
|
||||
|
||||
size -= size % 8;
|
||||
|
||||
filter = Buffer.allocUnsafe(size / 8);
|
||||
const filter = Buffer.allocUnsafe(size / 8);
|
||||
filter.fill(0);
|
||||
|
||||
if (tweak == null || tweak === -1)
|
||||
@ -258,15 +256,13 @@ Bloom.prototype.added = function added(val, enc) {
|
||||
*/
|
||||
|
||||
Bloom.fromRate = function fromRate(items, rate, update) {
|
||||
let size, n;
|
||||
|
||||
assert(typeof items === 'number', '`items` must be a number.');
|
||||
assert(items > 0, '`items` must be greater than zero.');
|
||||
assert(items % 1 === 0, '`items` must be an integer.');
|
||||
assert(typeof rate === 'number', '`rate` must be a number.');
|
||||
assert(rate >= 0 && rate <= 1, '`rate` must be between 0.0 and 1.0.');
|
||||
|
||||
size = (-1 / LN2SQUARED * items * Math.log(rate)) | 0;
|
||||
let size = (-1 / LN2SQUARED * items * Math.log(rate)) | 0;
|
||||
size = Math.max(8, size);
|
||||
|
||||
if (update !== -1) {
|
||||
@ -274,7 +270,7 @@ Bloom.fromRate = function fromRate(items, rate, update) {
|
||||
'Bloom filter size violates policy limits!');
|
||||
}
|
||||
|
||||
n = Math.max(1, (size / items * LN2) | 0);
|
||||
const n = Math.max(1, (size / items * LN2) | 0);
|
||||
|
||||
if (update !== -1) {
|
||||
assert(n <= Bloom.MAX_HASH_FUNCS,
|
||||
|
||||
@ -47,11 +47,11 @@ function exec(gen) {
|
||||
next.value.then(succeed, fail);
|
||||
};
|
||||
|
||||
let succeed = (value) => {
|
||||
const succeed = (value) => {
|
||||
step(value, false);
|
||||
};
|
||||
|
||||
let fail = (value) => {
|
||||
const fail = (value) => {
|
||||
step(value, true);
|
||||
};
|
||||
|
||||
@ -161,14 +161,12 @@ function promisify(func) {
|
||||
|
||||
function callbackify(func) {
|
||||
return function(...args) {
|
||||
let callback;
|
||||
|
||||
if (args.length === 0
|
||||
|| typeof args[args.length - 1] !== 'function') {
|
||||
throw new Error(`${func.name || 'Function'} requires a callback.`);
|
||||
}
|
||||
|
||||
callback = args.pop();
|
||||
const callback = args.pop();
|
||||
|
||||
func.call(this, ...args).then((value) => {
|
||||
setImmediate(() => callback(null, value));
|
||||
|
||||
@ -346,7 +346,6 @@ encoding.read53BE = function read53BE(data, off) {
|
||||
|
||||
encoding._write64 = function _write64(dst, num, off, be) {
|
||||
const negative = num < 0;
|
||||
let hi, lo;
|
||||
|
||||
if (negative) {
|
||||
num = -num;
|
||||
@ -355,8 +354,8 @@ encoding._write64 = function _write64(dst, num, off, be) {
|
||||
|
||||
enforce(num <= MAX_SAFE_INTEGER, off, 'Number exceeds 2^53-1');
|
||||
|
||||
hi = (num * (1 / 0x100000000)) | 0;
|
||||
lo = num | 0;
|
||||
let hi = (num * (1 / 0x100000000)) | 0;
|
||||
let lo = num | 0;
|
||||
|
||||
if (negative) {
|
||||
hi = ~hi;
|
||||
@ -697,21 +696,21 @@ encoding.sizeVarint = function sizeVarint(num) {
|
||||
*/
|
||||
|
||||
encoding.readVarintBN = function readVarintBN(data, off) {
|
||||
let result, value, size;
|
||||
|
||||
assert(off < data.length, off);
|
||||
|
||||
switch (data[off]) {
|
||||
case 0xff:
|
||||
size = 9;
|
||||
case 0xff: {
|
||||
const size = 9;
|
||||
assert(off + size <= data.length, off);
|
||||
value = encoding.readU64BN(data, off + 1);
|
||||
const value = encoding.readU64BN(data, off + 1);
|
||||
enforce(value.bitLength() > 32, off, 'Non-canonical varint');
|
||||
return new Varint(size, value);
|
||||
default:
|
||||
result = encoding.readVarint(data, off);
|
||||
}
|
||||
default: {
|
||||
const result = encoding.readVarint(data, off);
|
||||
result.value = new BN(result.value);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -756,12 +755,11 @@ encoding.sizeVarintBN = function sizeVarintBN(num) {
|
||||
encoding.readVarint2 = function readVarint2(data, off) {
|
||||
let num = 0;
|
||||
let size = 0;
|
||||
let ch;
|
||||
|
||||
for (;;) {
|
||||
assert(off < data.length, off);
|
||||
|
||||
ch = data[off++];
|
||||
const ch = data[off++];
|
||||
size++;
|
||||
|
||||
enforce(num < 0x3fffffffffff, off, 'Number exceeds 2^53-1');
|
||||
@ -815,11 +813,10 @@ encoding.writeVarint2 = function writeVarint2(dst, num, off) {
|
||||
|
||||
encoding.skipVarint2 = function skipVarint2(data, off) {
|
||||
let size = 0;
|
||||
let ch;
|
||||
|
||||
for (;;) {
|
||||
assert(off < data.length, off);
|
||||
ch = data[off++];
|
||||
const ch = data[off++];
|
||||
size++;
|
||||
if ((ch & 0x80) === 0)
|
||||
break;
|
||||
@ -857,12 +854,11 @@ encoding.sizeVarint2 = function sizeVarint2(num) {
|
||||
encoding.readVarint2BN = function readVarint2BN(data, off) {
|
||||
let num = 0;
|
||||
let size = 0;
|
||||
let ch;
|
||||
|
||||
while (num < 0x3fffffffffff) {
|
||||
assert(off < data.length, off);
|
||||
|
||||
ch = data[off++];
|
||||
const ch = data[off++];
|
||||
size++;
|
||||
|
||||
num = (num * 0x80) + (ch & 0x7f);
|
||||
@ -878,7 +874,7 @@ encoding.readVarint2BN = function readVarint2BN(data, off) {
|
||||
for (;;) {
|
||||
assert(off < data.length, off);
|
||||
|
||||
ch = data[off++];
|
||||
const ch = data[off++];
|
||||
size++;
|
||||
|
||||
enforce(num.bitLength() <= 64, off, 'Number exceeds 64 bits');
|
||||
@ -1013,12 +1009,10 @@ encoding.sizeVarlen = function sizeVarlen(len) {
|
||||
*/
|
||||
|
||||
encoding.sizeVarString = function sizeVarString(str, enc) {
|
||||
let len;
|
||||
|
||||
if (typeof str !== 'string')
|
||||
return encoding.sizeVarBytes(str);
|
||||
|
||||
len = Buffer.byteLength(str, enc);
|
||||
const len = Buffer.byteLength(str, enc);
|
||||
|
||||
return encoding.sizeVarint(len) + len;
|
||||
};
|
||||
|
||||
@ -133,13 +133,12 @@ exports.mkdirp = async function mkdirp(dir, mode) {
|
||||
};
|
||||
|
||||
function getParts(path) {
|
||||
let root = '';
|
||||
let parts;
|
||||
|
||||
path = path.replace(/\\/g, '/');
|
||||
path = path.replace(/(^|\/)\.\//, '$1');
|
||||
path = path.replace(/\/+\.?$/, '');
|
||||
parts = path.split(/\/+/);
|
||||
|
||||
const parts = path.split(/\/+/);
|
||||
let root = '';
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
if (parts[0].indexOf(':') !== -1)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user