browser: improve webpack build.

This commit is contained in:
Christopher Jeffrey 2017-12-14 19:07:25 -08:00
parent e4ad8b457f
commit 11c7dab3c4
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
14 changed files with 458 additions and 590 deletions

View File

@ -1,6 +1,9 @@
all: all:
@npm run webpack @npm run webpack
app:
@npm run webpack-app
browser: browser:
@npm run webpack-browser @npm run webpack-browser
@ -22,4 +25,4 @@ lint:
test: test:
@npm test @npm test
.PHONY: all browser compat node clean docs lint test .PHONY: all app browser compat node clean docs lint test

View File

@ -1,106 +1,110 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<title>bcoin</title> <title>bcoin</title>
<style> <meta charset="utf-8">
html { <style>
height: 100%; html {
} height: 100%;
body { }
height: 90%; body {
padding: 20px; height: 90%;
} padding: 20px;
h1 { }
font: 3em monospace; h1 {
margin: 10px; font: 3em monospace;
padding: 0; margin: 10px;
} padding: 0;
small { }
margin: 10px; small {
width: 50%; margin: 10px;
display: block; width: 50%;
} display: block;
.log { }
padding: 5px; .log {
margin-left: 10px; padding: 5px;
overflow-y: scroll; margin-left: 10px;
border: 1px solid black; overflow-y: scroll;
white-space: pre-wrap; border: 1px solid black;
height: 40%; white-space: pre-wrap;
width: 40%; height: 40%;
font: 1em monospace; width: 40%;
margin-top: 10px; font: 1em monospace;
} margin-top: 10px;
.wallet { }
padding: 5px; .wallet {
margin-left: 5px; padding: 5px;
margin-top: 10px; margin-left: 5px;
font: 1em monospace; margin-top: 10px;
} font: 1em monospace;
.rpc, .send { }
padding: 5px; .rpc, .send {
margin-left: 5px; padding: 5px;
margin-top: 10px; margin-left: 5px;
font: 1em monospace; margin-top: 10px;
} font: 1em monospace;
#newaddr{ }
display: block; #newaddr{
margin-left: 10px; display: block;
} margin-left: 10px;
.tx { }
float: right; .tx {
font: 1em monospace; float: right;
padding: 5px; font: 1em monospace;
border: 1px solid black; padding: 5px;
margin-top: 10px; border: 1px solid black;
} margin-top: 10px;
a { }
text-decoration: none; a {
} text-decoration: none;
.floating { }
font: 1em monospace; .floating {
white-space: pre-wrap; font: 1em monospace;
position: absolute; white-space: pre-wrap;
display: none; position: absolute;
padding: 5px; display: none;
background: white; padding: 5px;
border: 1px solid black; background: white;
width: 40%; border: 1px solid black;
height: 30%; width: 40%;
top: 50%; height: 30%;
left: 50%; top: 50%;
margin-left: -20%; left: 50%;
margin-top: -15%; margin-left: -20%;
overflow-y: scroll; margin-top: -15%;
} overflow-y: scroll;
</style> }
<script src="/bcoin.js"></script> </style>
</head> <script src="/app.js" defer></script>
<body> </head>
<h1>Bcoin, the browser full node</h1> <body>
<small>Welcome. Your machine is currently validating the blockchain. <h1>Bcoin, the browser full node</h1>
The blocks and wallet are stored on your local disk with indexed DB. You are <small>
connecting to the actual bitcoin P2P network via a websocket-&gt;tcp proxy. Welcome. Your machine is currently validating the blockchain. The blocks
Enjoy. (See the <a href="https://github.com/bcoin-org/bcoin" target="_blank">bcoin repo</a> for and wallet are stored on your local disk with indexed DB. You are
more bitcoin magic).</small> connecting to the actual bitcoin P2P network via a websocket-&gt;tcp
<div class="tx"> proxy. Enjoy. (See the
<div>Chain State: <span id="state"></span></div> <a href="https://github.com/bcoin-org/bcoin"
<div>Last 20 Blocks/TXs:</div> target="_blank">bcoin repo</a>
<div id="tx"></div> for more bitcoin magic).
</div> </small>
<div id="log" class="log"></div> <div class="tx">
<form id="rpc" class="rpc" action="#"> <div>Chain State: <span id="state"></span></div>
<input type="text" name="cmd" id="cmd" <div>Last 20 Blocks/TXs:</div>
placeholder="RPC command (e.g. getblockchaininfo)"> <div id="tx"></div>
</form> </div>
<div id="wallet" class="wallet"></div> <div id="log" class="log"></div>
<form id="send" class="send" action="#"> <form id="rpc" class="rpc" action="#">
<input type="text" name="address" id="address" placeholder="Address"> <input type="text" name="cmd" id="cmd"
<input type="text" name="amount" id="amount" placeholder="Amount (BTC)"> placeholder="RPC command (e.g. getblockchaininfo)">
<input type="submit" value="Send"> </form>
</form> <div id="wallet" class="wallet"></div>
<input type="button" id="newaddr" value="New Address"> <form id="send" class="send" action="#">
<div id="floating" class="floating"></div> <input type="text" name="address" id="address" placeholder="Address">
<script src="/index.js"></script> <input type="text" name="amount" id="amount" placeholder="Amount (BTC)">
</body> <input type="submit" value="Send">
</form>
<input type="button" id="newaddr" value="New Address">
<div id="floating" class="floating"></div>
</body>
</html> </html>

View File

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

View File

@ -5,13 +5,10 @@ const fs = require('bfile');
const WSProxy = require('./wsproxy'); const WSProxy = require('./wsproxy');
const index = fs.readFileSync(`${__dirname}/index.html`); const index = fs.readFileSync(`${__dirname}/index.html`);
const indexjs = fs.readFileSync(`${__dirname}/index.js`); const app = fs.readFileSync(`${__dirname}/app.js`);
const debug = fs.readFileSync(`${__dirname}/debug.html`); const worker = fs.readFileSync(`${__dirname}/worker.js`);
const bcoin = fs.readFileSync(`${__dirname}/bcoin.js`);
const worker = fs.readFileSync(`${__dirname}/bcoin-worker.js`);
const proxy = new WSProxy({ const proxy = new WSProxy({
pow: process.argv.indexOf('--pow') !== -1,
ports: [8333, 18333, 18444, 28333, 28901] ports: [8333, 18333, 18444, 28333, 28901]
}); });
@ -20,6 +17,8 @@ const server = bweb.server({
sockets: false sockets: false
}); });
server.use(server.router());
proxy.on('error', (err) => { proxy.on('error', (err) => {
console.error(err.stack); console.error(err.stack);
}); });
@ -28,27 +27,15 @@ server.on('error', (err) => {
console.error(err.stack); console.error(err.stack);
}); });
server.get('/favicon.ico', (req, res) => {
res.send(404, '', 'txt');
});
server.get('/', (req, res) => { server.get('/', (req, res) => {
res.send(200, index, 'html'); res.send(200, index, 'html');
}); });
server.get('/index.js', (req, res) => { server.get('/app.js', (req, res) => {
res.send(200, indexjs, 'js'); res.send(200, app, 'js');
}); });
server.get('/debug', (req, res) => { server.get('/worker.js', (req, res) => {
res.send(200, debug, 'html');
});
server.get('/bcoin.js', (req, res) => {
res.send(200, bcoin, 'js');
});
server.get('/bcoin-worker.js', (req, res) => {
res.send(200, worker, 'js'); res.send(200, worker, 'js');
}); });

284
browser/src/app.js Normal file
View File

@ -0,0 +1,284 @@
'use strict';
const Logger = require('blgr');
const FullNode = require('../../lib/node/fullnode');
const Amount = require('../../lib/btc/amount');
const plugin = require('../../lib/wallet/plugin');
const ProxySocket = require('./proxysocket');
const body = document.getElementsByTagName('body')[0];
const log = document.getElementById('log');
const wdiv = document.getElementById('wallet');
const tdiv = document.getElementById('tx');
const floating = document.getElementById('floating');
const send = document.getElementById('send');
const newaddr = document.getElementById('newaddr');
const chainState = document.getElementById('state');
const rpc = document.getElementById('rpc');
const cmd = document.getElementById('cmd');
const items = [];
let scrollback = 0;
const logger = new Logger({
level: 'debug',
console: true
});
if (0)
logger.writeConsole = function writeConsole(level, module, args) {
const name = Logger.levelsByVal[level];
const msg = this.fmt(args, false);
if (++scrollback > 1000) {
log.innerHTML = '';
scrollback = 1;
}
const now = Math.floor(Date.now() / 1000);
log.innerHTML += `<span style="color:blue;">${now}</span> `;
if (name === 'error') {
log.innerHTML += `<span style="color:red;">[${name}] `;
if (module)
log.innerHTML += `(${module}) `;
log.innerHTML += '</span>';
} else {
log.innerHTML += `[${name}] `;
if (module)
log.innerHTML += `(${module}) `;
}
log.innerHTML += escape(msg) + '\n';
log.scrollTop = log.scrollHeight;
};
const node = new FullNode({
hash: true,
query: true,
prune: true,
network: 'main',
memory: false,
coinCache: 30,
logConsole: true,
workers: true,
workerFile: '/worker.js',
createSocket: (port, host) => {
return ProxySocket.connect('ws://127.0.0.1:8080', port, host);
},
logger: logger,
plugins: [plugin]
});
const {wdb} = node.require('walletdb');
window.onunhandledrejection = function onunhandledrejection(event) {
throw event.reason;
};
body.onmouseup = function onmouseup() {
floating.style.display = 'none';
};
floating.onmouseup = function onmouseup(ev) {
ev.stopPropagation();
return false;
};
function show(obj) {
const json = obj && obj.toJSON ? obj.toJSON() : null;
floating.innerHTML = escape(JSON.stringify(json, null, 2));
floating.style.display = 'block';
}
rpc.onsubmit = function onsubmit(ev) {
const text = cmd.value || '';
const argv = text.trim().split(/\s+/);
const method = argv.shift();
const params = [];
cmd.value = '';
for (const arg of argv) {
let param;
try {
param = JSON.parse(arg);
} catch (e) {
param = arg;
}
params.push(param);
}
(async () => {
try {
const result = await node.rpc.execute({ method, params });
show(result);
} catch (e) {
show(e);
}
})();
ev.preventDefault();
ev.stopPropagation();
return false;
};
send.onsubmit = function onsubmit(ev) {
const value = document.getElementById('amount').value;
const address = document.getElementById('address').value;
const options = {
outputs: [{
address: address,
value: Amount.value(value)
}]
};
(async () => {
try {
const mtx = await wdb.primary.createTX(options);
await wdb.primary.sign(mtx);
await node.relay(mtx.toTX());
show(mtx);
} catch (e) {
show(e);
}
})();
ev.preventDefault();
ev.stopPropagation();
return false;
};
newaddr.onmouseup = function onmouseup() {
(async () => {
try {
await wdb.primary.createReceive();
formatWallet(wdb.primary);
} catch (e) {
show(e);
}
})();
};
function kb(size) {
size /= 1000;
return size.toFixed(2) + 'kb';
}
function create(html) {
const el = document.createElement('div');
el.innerHTML = html;
return el.firstChild;
}
function escape(html, encode) {
return html
.replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function addItem(item, entry) {
const height = entry ? entry.height : -1;
if (items.length === 20) {
const el = items.shift();
tdiv.removeChild(el);
el.onmouseup = null;
}
const el = create(''
+ `<a style="display:block;" href="#${item.rhash()}">`
+ `${item.rhash()} (${height} - ${kb(item.getSize())})`
+ '</a>'
);
tdiv.appendChild(el);
setMouseup(el, item);
items.push(el);
chainState.innerHTML = ''
+ `tx=${node.chain.db.state.tx} `
+ `coin=${node.chain.db.state.coin} `
+ `value=${Amount.btc(node.chain.db.state.value)}`;
}
function setMouseup(el, obj) {
el.onmouseup = function onmouseup(ev) {
show(obj);
ev.stopPropagation();
return false;
};
}
async function formatWallet(wallet) {
try {
await _formatWallet(wallet);
} catch (e) {
show(e);
}
}
async function _formatWallet(wallet) {
const {key, mnemonic} = wallet.master.toJSON(node.network, true);
const account = await wallet.getAccount('default');
const receive = account.receiveAddress();
const nested = account.nestedAddress();
const raddr = receive.toString(node.network);
const naddr = nested ? nested.toString(node.network) : null;
let html = '';
html += '<b>Wallet</b><br>';
if (naddr) {
html += `Current Address (p2wpkh): <b>${raddr}</b><br>`;
html += `Current Address (p2wpkh behind p2sh): <b>${naddr}</b><br>`;
} else {
html += `Current Address: <b>${raddr}</b><br>`;
}
html += `Extended Private Key: <b>${key.xprivkey}</b><br>`;
html += `Mnemonic: <b>${mnemonic.phrase}</b><br>`;
const balance = await wallet.getBalance();
html += `Confirmed Balance: <b>${Amount.btc(balance.confirmed)}</b><br>`;
html += `Unconfirmed Balance: <b>${Amount.btc(balance.unconfirmed)}</b><br>`;
const txs = await wallet.getHistory();
const det = await wallet.toDetails(txs);
html += 'TXs:\n';
wdiv.innerHTML = html;
for (const tx of det) {
const el = create(
`<a style="display:block;" href="#${tx.hash}">${tx.hash}</a>`);
wdiv.appendChild(el);
setMouseup(el, tx.toJSON());
}
}
node.chain.on('block', addItem);
node.mempool.on('tx', addItem);
(async () => {
await node.open();
await node.connect();
node.startSync();
wdb.primary.on('balance', () => {
formatWallet(wdb.primary);
});
formatWallet(wdb.primary);
})().catch((err) => {
throw err;
});

View File

@ -9,20 +9,18 @@
const assert = require('assert'); const assert = require('assert');
const EventEmitter = require('events'); const EventEmitter = require('events');
const bsock = require('bsock'); const bsock = require('bsock');
const hash256 = require('bcrypto/lib/hash256');
const bio = require('bufio');
class ProxySocket extends EventEmitter { class ProxySocket extends EventEmitter {
constructor(uri) { constructor(uri) {
super(); super();
this.info = null; this.socket = bsock.socket();
this.socket.reconnection = false;
this.socket.connect(uri);
this.socket = bsock.connect(uri);
this.sendBuffer = []; this.sendBuffer = [];
this.recvBuffer = []; this.recvBuffer = [];
this.paused = false; this.paused = false;
this.snonce = null;
this.bytesWritten = 0; this.bytesWritten = 0;
this.bytesRead = 0; this.bytesRead = 0;
this.remoteAddress = null; this.remoteAddress = null;
@ -34,20 +32,6 @@ class ProxySocket extends EventEmitter {
} }
init() { init() {
this.socket.bind('info', (info) => {
if (this.closed)
return;
this.info = info;
if (info.pow) {
this.snonce = Buffer.from(info.snonce, 'hex');
this.target = Buffer.from(info.target, 'hex');
}
this.emit('info', info);
});
this.socket.on('error', (err) => { this.socket.on('error', (err) => {
console.error(err); console.error(err);
}); });
@ -87,7 +71,7 @@ class ProxySocket extends EventEmitter {
this.emit('timeout'); this.emit('timeout');
}); });
this.socket.bind('disconnect', () => { this.socket.on('disconnect', () => {
if (this.closed) if (this.closed)
return; return;
this.closed = true; this.closed = true;
@ -104,37 +88,7 @@ class ProxySocket extends EventEmitter {
return; return;
} }
if (!this.info) { this.socket.fire('tcp connect', port, host);
this.once('info', connect.bind(this, port, host));
return;
}
let nonce = 0;
if (this.info.pow) {
const bw = bio.write();
bw.writeU32(nonce);
bw.writeBytes(this.snonce);
bw.writeU32(port);
bw.writeString(host, 'ascii');
const pow = bw.render();
console.log(
'Solving proof of work to create socket (%d, %s) -- please wait.',
port, host);
do {
nonce += 1;
assert(nonce <= 0xffffffff, 'Could not create socket.');
pow.writeUInt32LE(nonce, 0, true);
} while (hash256.digest(pow).compare(this.target) > 0);
console.log('Solved proof of work: %d', nonce);
}
this.socket.fire('tcp connect', port, host, nonce);
for (const chunk of this.sendBuffer) for (const chunk of this.sendBuffer)
this.write(chunk); this.write(chunk);
@ -157,15 +111,6 @@ class ProxySocket extends EventEmitter {
} }
write(data, callback) { write(data, callback) {
if (!this.info) {
this.sendBuffer.push(data);
if (callback)
callback();
return true;
}
this.bytesWritten += data.length; this.bytesWritten += data.length;
this.socket.fire('tcp data', data.toString('hex')); this.socket.fire('tcp data', data.toString('hex'));

View File

@ -4,13 +4,7 @@ const assert = require('assert');
const net = require('net'); const net = require('net');
const EventEmitter = require('events'); const EventEmitter = require('events');
const bsock = require('bsock'); const bsock = require('bsock');
const hash256 = require('bcrypto/lib/hash256');
const IP = require('binet'); const IP = require('binet');
const bio = require('bufio');
const TARGET = Buffer.from(
'0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
'hex');
class WSProxy extends EventEmitter { class WSProxy extends EventEmitter {
constructor(options) { constructor(options) {
@ -20,8 +14,6 @@ class WSProxy extends EventEmitter {
options = {}; options = {};
this.options = options; this.options = options;
this.target = options.target || TARGET;
this.pow = options.pow === true;
this.ports = new Set(); this.ports = new Set();
this.io = bsock.server(); this.io = bsock.server();
this.sockets = new WeakMap(); this.sockets = new WeakMap();
@ -51,18 +43,16 @@ class WSProxy extends EventEmitter {
// mutating the websocket object. // mutating the websocket object.
this.sockets.set(ws, state); this.sockets.set(ws, state);
ws.fire('info', state.toInfo());
ws.on('error', (err) => { ws.on('error', (err) => {
this.emit('error', err); this.emit('error', err);
}); });
ws.bind('tcp connect', (port, host, nonce) => { ws.bind('tcp connect', (port, host) => {
this.handleConnect(ws, port, host, nonce); this.handleConnect(ws, port, host);
}); });
} }
handleConnect(ws, port, host, nonce) { handleConnect(ws, port, host) {
const state = this.sockets.get(ws); const state = this.sockets.get(ws);
assert(state); assert(state);
@ -80,30 +70,6 @@ class WSProxy extends EventEmitter {
return; return;
} }
if (this.pow) {
if ((nonce >>> 0) !== nonce) {
this.log('Client did not solve proof of work (%s).', state.host);
ws.fire('tcp close');
ws.destroy();
return;
}
const bw = bio.write();
bw.writeU32(nonce);
bw.writeBytes(state.snonce);
bw.writeU32(port);
bw.writeString(host, 'ascii');
const pow = bw.render();
if (hash256.digest(pow).compare(this.target) > 0) {
this.log('Client did not solve proof of work (%s).', state.host);
ws.fire('tcp close');
ws.destroy();
return;
}
}
let raw, addr; let raw, addr;
try { try {
raw = IP.toBuffer(host); raw = IP.toBuffer(host);
@ -206,7 +172,7 @@ class WSProxy extends EventEmitter {
socket.resume(); socket.resume();
}); });
ws.bind('disconnect', () => { ws.on('disconnect', () => {
socket.destroy(); socket.destroy();
}); });
} }
@ -223,22 +189,11 @@ class WSProxy extends EventEmitter {
class SocketState { class SocketState {
constructor(server, socket) { constructor(server, socket) {
this.pow = server.pow;
this.target = server.target;
this.snonce = nonce();
this.socket = null; this.socket = null;
this.host = socket.host; this.host = socket.host;
this.remoteHost = null; this.remoteHost = null;
} }
toInfo() {
return {
pow: this.pow,
target: this.target.toString('hex'),
snonce: this.snonce.toString('hex')
};
}
connect(port, host) { connect(port, host) {
this.socket = net.connect(port, host); this.socket = net.connect(port, host);
this.remoteHost = IP.toHostname(host, port); this.remoteHost = IP.toHostname(host, port);
@ -246,11 +201,4 @@ class SocketState {
} }
} }
function nonce() {
const buf = Buffer.allocUnsafe(8);
buf.writeUInt32LE(Math.random() * 0x100000000, 0, true);
buf.writeUInt32LE(Math.random() * 0x100000000, 4, true);
return buf;
}
module.exports = WSProxy; module.exports = WSProxy;

View File

@ -33,12 +33,10 @@ bcoin.set = function set(network) {
* Expose * Expose
*/ */
/*
// Blockchain // Blockchain
bcoin.blockchain = require('./blockchain'); bcoin.blockchain = require('./blockchain');
bcoin.Chain = require('./blockchain/chain'); bcoin.Chain = require('./blockchain/chain');
bcoin.ChainEntry = require('./blockchain/chainentry'); bcoin.ChainEntry = require('./blockchain/chainentry');
*/
// BTC // BTC
bcoin.btc = require('./btc'); bcoin.btc = require('./btc');
@ -57,7 +55,6 @@ bcoin.HDPrivateKey = require('./hd/private');
bcoin.HDPublicKey = require('./hd/public'); bcoin.HDPublicKey = require('./hd/public');
bcoin.Mnemonic = require('./hd/mnemonic'); bcoin.Mnemonic = require('./hd/mnemonic');
/*
// Mempool // Mempool
bcoin.mempool = require('./mempool'); bcoin.mempool = require('./mempool');
bcoin.Fees = require('./mempool/fees'); bcoin.Fees = require('./mempool/fees');
@ -79,7 +76,6 @@ bcoin.node = require('./node');
bcoin.Node = require('./node/node'); bcoin.Node = require('./node/node');
bcoin.FullNode = require('./node/fullnode'); bcoin.FullNode = require('./node/fullnode');
bcoin.SPVNode = require('./node/spvnode'); bcoin.SPVNode = require('./node/spvnode');
*/
// Primitives // Primitives
bcoin.primitives = require('./primitives'); bcoin.primitives = require('./primitives');
@ -117,7 +113,6 @@ bcoin.Witness = require('./script/witness');
bcoin.utils = require('./utils'); bcoin.utils = require('./utils');
bcoin.util = require('./utils/util'); bcoin.util = require('./utils/util');
/*
// Wallet // Wallet
bcoin.wallet = require('./wallet'); bcoin.wallet = require('./wallet');
bcoin.WalletDB = require('./wallet/walletdb'); bcoin.WalletDB = require('./wallet/walletdb');
@ -125,7 +120,6 @@ bcoin.WalletDB = require('./wallet/walletdb');
// Workers // Workers
bcoin.workers = require('./workers'); bcoin.workers = require('./workers');
bcoin.WorkerPool = require('./workers/workerpool'); bcoin.WorkerPool = require('./workers/workerpool');
*/
// Package Info // Package Info
bcoin.pkg = require('./pkg'); bcoin.pkg = require('./pkg');

View File

@ -69,7 +69,7 @@
"bcoin-spvnode": "./bin/spvnode" "bcoin-spvnode": "./bin/spvnode"
}, },
"scripts": { "scripts": {
"clean": "rm -f {browser/,}{bcoin.js,bcoin-worker.js}", "clean": "rm -f {browser/,}{bcoin.js,bcoin-worker.js,app.js,worker.js}",
"docs": "jsdoc -c jsdoc.json", "docs": "jsdoc -c jsdoc.json",
"lint": "eslint $(cat .eslintfiles) || exit 0", "lint": "eslint $(cat .eslintfiles) || exit 0",
"lint-file": "eslint", "lint-file": "eslint",
@ -82,6 +82,6 @@
"webpack": "webpack --config webpack.browser.js", "webpack": "webpack --config webpack.browser.js",
"webpack-browser": "webpack --config webpack.browser.js", "webpack-browser": "webpack --config webpack.browser.js",
"webpack-compat": "webpack --config webpack.compat.js", "webpack-compat": "webpack --config webpack.compat.js",
"webpack-node": "webpack --config webpack.node.js" "webpack-app": "webpack --config webpack.app.js"
} }
} }

32
webpack.app.js Normal file
View File

@ -0,0 +1,32 @@
'use strict';
const Path = require('path');
const webpack = require('webpack');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const str = JSON.stringify;
const env = process.env;
module.exports = {
target: 'web',
entry: {
'app': './browser/src/app',
'worker': './lib/workers/worker'
},
output: {
path: Path.join(__dirname, 'browser'),
filename: '[name].js'
},
resolve: {
modules: ['node_modules'],
extensions: ['-browser.js', '.js', '.json']
},
plugins: [
new webpack.DefinePlugin({
'process.env.BCOIN_NETWORK':
str(env.BCOIN_NETWORK || 'main'),
'process.env.BCOIN_WORKER_FILE':
str(env.BCOIN_WORKER_FILE || '/bcoin-worker.js')
}),
new UglifyJsPlugin()
]
};

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const Path = require('path');
const webpack = require('webpack'); const webpack = require('webpack');
const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const str = JSON.stringify; const str = JSON.stringify;
const env = process.env; const env = process.env;
@ -9,11 +9,13 @@ const env = process.env;
module.exports = { module.exports = {
target: 'web', target: 'web',
entry: { entry: {
'bcoin': './lib/bcoin-browser', 'bcoin': './lib/bcoin',
'bcoin-worker': './lib/workers/worker' 'bcoin-worker': './lib/workers/worker'
}, },
output: { output: {
path: path.join(__dirname, 'browser'), library: 'bcoin',
libraryTarget: 'umd',
path: Path.join(__dirname, 'browser'),
filename: '[name].js' filename: '[name].js'
}, },
resolve: { resolve: {
@ -27,10 +29,6 @@ module.exports = {
'process.env.BCOIN_WORKER_FILE': 'process.env.BCOIN_WORKER_FILE':
str(env.BCOIN_WORKER_FILE || '/bcoin-worker.js') str(env.BCOIN_WORKER_FILE || '/bcoin-worker.js')
}), }),
new UglifyJsPlugin({ new UglifyJsPlugin()
compress: {
warnings: true
}
})
] ]
}; };

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const Path = require('path');
const webpack = require('webpack'); const webpack = require('webpack');
const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const str = JSON.stringify; const str = JSON.stringify;
const env = process.env; const env = process.env;
@ -9,11 +9,13 @@ const env = process.env;
module.exports = { module.exports = {
target: 'web', target: 'web',
entry: { entry: {
'bcoin': './lib/bcoin-browser', 'bcoin': './lib/bcoin',
'bcoin-worker': './lib/workers/worker' 'bcoin-worker': './lib/workers/worker'
}, },
output: { output: {
path: path.join(__dirname, 'browser'), library: 'bcoin',
libraryTarget: 'umd',
path: Path.join(__dirname, 'browser'),
filename: '[name].js' filename: '[name].js'
}, },
resolve: { resolve: {
@ -23,7 +25,6 @@ module.exports = {
module: { module: {
rules: [{ rules: [{
test: /\.js$/, test: /\.js$/,
exclude: /node_modules\/(?!bcoin|elliptic|bn\.js|n64)/,
loader: 'babel-loader' loader: 'babel-loader'
}] }]
}, },
@ -34,10 +35,6 @@ module.exports = {
'process.env.BCOIN_WORKER_FILE': 'process.env.BCOIN_WORKER_FILE':
str(env.BCOIN_WORKER_FILE || '/bcoin-worker.js') str(env.BCOIN_WORKER_FILE || '/bcoin-worker.js')
}), }),
new UglifyJsPlugin({ new UglifyJsPlugin()
compress: {
warnings: false
}
})
] ]
}; };

View File

@ -1,49 +0,0 @@
'use strict';
const webpack = require('webpack');
const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const str = JSON.stringify;
const env = process.env;
module.exports = {
target: 'node',
entry: {
'bcoin': './lib/bcoin-browser',
'bcoin-worker': './lib/workers/worker'
},
output: {
path: __dirname,
filename: '[name].js',
libraryTarget: 'commonjs2'
},
resolve: {
modules: ['node_modules'],
extensions: ['.node', '.js', '.json'],
alias: {
'bindings': path.resolve(__dirname, 'webpack', 'bindings.js')
}
},
node: {
__dirname: false,
__filename: false
},
module: {
rules: [{
test: /\.node$/,
loader: 'node-loader'
}]
},
plugins: [
new webpack.DefinePlugin({
'process.env.BCOIN_WORKER_FILE':
str(env.BCOIN_WORKER_FILE || 'bcoin-worker.js')
}),
new webpack.IgnorePlugin(/^utf-8-validate|bufferutil$/),
new UglifyJsPlugin({
compress: {
warnings: true
}
})
]
};

View File

@ -1,13 +0,0 @@
'use strict';
module.exports = function bindings(name) {
switch (name) {
case 'leveldown':
return require('leveldown/build/Release/leveldown.node');
case 'bcoin-native':
return require('bcoin-native/build/Release/bcoin-native.node');
case 'secp256k1':
return require('secp256k1/build/Release/secp256k1.node');
}
throw new Error(`Cannot find module "${name}".`);
};