docs: update examples and readme

This commit is contained in:
Matthew Zipkin 2019-01-13 13:17:54 -08:00
parent de8b2f7ba2
commit d296c13247
No known key found for this signature in database
GPG Key ID: E7E2984B6289C93A
18 changed files with 352 additions and 487 deletions

View File

@ -99,7 +99,7 @@ To advertise your node on the P2P network `--public-host=[your-public-ip]` and `
## Using an API Key
If listening publicly on the HTTP server, an API key is required. One will be generated and reported in the logs automatically if no key was chosen. An api key can be chosen with the `--api-key` option.
If listening publicly on the HTTP server, an API key is required. One will be randomly generated if no key was chosen, but not explicitly reported to the user. An API key can be chosen with the `--api-key` option.
Example:
@ -113,11 +113,12 @@ API keys are used with HTTP Basic Auth:
$ curl http://x:hunter2@localhost:8332/
```
Bcoin CLI is the prepackaged tool for hitting both the REST and RPC api.
[bclient](https://github.com/bcoin-org/bclient) is the prepackaged tool for querying both the REST and RPC APIs. If bcoin is installed globally, both `bcoin-cli` and `bwallet-cli` should be on your path.
``` bash
$ bcoin cli info --api-key hunter2
$ bcoin rpc getblockchaininfo --api-key hunter2
$ bcoin-cli info --api-key hunter2
$ bcoin-cli rpc getblockchaininfo --api-key hunter2
$ bwallet-cli balance
```
## Using Tor/SOCKS
@ -144,10 +145,10 @@ $ bcoin --nodes foo.example.com:8333,1.2.3.4:8333,5.6.7.8:8333
If chosen, bcoin will _always_ try to connect to these nodes as outbound peers. They are top priority and whitelisted (not susceptible to permanent bans, only disconnections).
To _only_ connect to these nodes. `--max-outbound` could be set to 3:
To _only_ connect to these nodes, use `--only`
``` bash
$ bcoin --nodes foo.example.com,1.2.3.4,5.6.7.8 --max-outbound 3
$ bcoin --only foo.example.com,1.2.3.4,5.6.7.8
```
## Disabling Listening
@ -169,5 +170,5 @@ Note: Selfish mode is not recommended. We encourage you to _help_ the network by
See [Configuration][configuration].
[keybase]: https://keybase.io/chjj#show-public
[node]: https://nodejs.org/dist/v7.5.0/
[node]: https://nodejs.org
[configuration]: Configuration.md

View File

@ -1,235 +1,69 @@
Bcoin ships with bcoin-cli as its default HTTP client for command line access.
Bcoin ships with [bclient](https://github.com/bcoin-org/bclient) as its default client
to the [API](https://bcoin.io/api-docs) for command line access.
## Configuration
Examples:
``` bash
Using environment variables:
```bash
$ export BCOIN_API_KEY=hunter2
$ export BCOIN_NETWORK=main
$ export BCOIN_URI=http://localhost:8332
$ bcoin cli info
$ export BCOIN_NETWORK=testnet
$ bcoin --daemon
$ bcoin-cli info
```
``` bash
$ bcoin cli info --api-key=hunter2 --uri=http://localhost
With command-line arguments:
```bash
$ bcoin-cli --network=testnet --api-key=hunter2 info
```
``` bash
$ echo 'api-key: hunter2' > ~/cli.conf
$ bcoin cli info --config=~/cli.conf
```
You can also use `~/.bcoin/bcoin.conf` for configuration options, see [Configuration](Configuration.md) for the full details.
## Examples
``` bash
$ export BCOIN_API_KEY=your-api-key
Common node commands:
```bash
# View the genesis block
$ bcoin cli block 0
$ bcoin-cli block 0
# View the mempool
$ bcoin cli mempool
$ bcoin-cli mempool
# Execute an RPC command to list network peers
$ bcoin-cli rpc getpeerinfo
```
Common wallet commands:
```bash
# View primary wallet
$ bcoin wallet get
$ bwallet-cli get
# View transaction history
$ bcoin wallet history
$ bwallet-cli history
# Send a transaction
$ bcoin wallet send [address] 0.01
$ bwallet-cli send <address> 0.01
# View balance
$ bcoin wallet balance
$ bwallet-cli balance
# Derive new address
$ bcoin wallet address
$ bwallet-cli address
# Create a new account
$ bcoin wallet account create foo
$ bwallet-cli account create foo
# Send from account
$ bcoin wallet send [address] 0.01 --account=foo
$ bwallet-cli send <address> 0.01 --account=foo
```
RPC examples:
Get more help:
``` bash
$ bcoin rpc getblockchaininfo
$ bcoin rpc getwalletinfo
$ bcoin rpc getpeerinfo
$ bcoin rpc getbalance
$ bcoin rpc listtransactions
$ bcoin rpc sendtoaddress [address] 0.01
```
## Commands
bcoin-cli commands are split into 3 categories: cli, rpc, and wallet.
### Top-level Commands
- `info`: Get server info.
- `wallets`: List all wallets.
- `wallet create [id]`: Create wallet.
- `broadcast [tx-hex]`: Broadcast transaction.
- `mempool`: Get mempool snapshot.
- `tx [hash/address]`: View transactions.
- `coin [hash+index/address]`: View coins.
- `block [hash/height]`: View block.
- `rescan [height]`: Rescan for transactions.
- `reset [height/hash]`: Reset chain to desired block.
- `resend`: Resend pending transactions.
- `backup [path]`: Backup the wallet db.
- `wallet [command]`: Execute wallet command.
- `rpc [command] [args]`: Execute RPC command.
### Wallet Commands
- `listen`: Listen for events.
- `get`: View wallet.
- `master`: View wallet master key.
- `shared add [xpubkey]`: Add key to wallet.
- `shared remove [xpubkey]`: Remove key from wallet.
- `balance`: Get wallet balance.
- `history`: View TX history.
- `pending`: View pending TXs.
- `coins`: View wallet coins.
- `account list`: List account names.
- `account create [account-name]`: Create account.
- `account get [account-name]`: Get account details.
- `address`: Derive new receiving address.
- `change`: Derive new change address.
- `nested`: Derive new nested address.
- `retoken`: Create new api key.
- `send [address] [value]`: Send transaction.
- `mktx [address] [value]`: Create transaction.
- `sign [tx-hex]`: Sign transaction.
- `zap [age?]`: Zap pending wallet TXs.
- `tx [hash]`: View transaction details.
- `blocks`: List wallet blocks.
- `block [height]`: View wallet block.
- `view [tx-hex]`: Parse and view transaction.
- `import [wif|hex]`: Import private or public key.
- `watch [address]`: Import an address.
- `key [address]`: Get wallet key by address.
- `dump [address]`: Get wallet key WIF by address.
- `lock`: Lock wallet.
- `unlock [passphrase] [timeout?]`: Unlock wallet.
- `resend`: Resend pending transactions.
### RPC Commands
Bcoin implements nearly all bitcoind calls along with some custom calls.
- `stop`
- `help`
- `getblockchaininfo`
- `getbestblockhash`
- `getblockcount`
- `getblock`
- `getblockhash`
- `getblockheader`
- `getchaintips`
- `getdifficulty`
- `getmempoolancestors`
- `getmempooldescendants`
- `getmempoolentry`
- `getmempoolinfo`
- `getrawmempool`
- `gettxout`
- `gettxoutsetinfo`
- `verifychain`
- `invalidateblock`
- `reconsiderblock`
- `getnetworkhashps`
- `getmininginfo`
- `prioritisetransaction`
- `getwork`
- `getworklp`
- `getblocktemplate`
- `submitblock`
- `setgenerate`
- `getgenerate`
- `generate`
- `generatetoaddress`
- `estimatefee`
- `estimatepriority`
- `estimatesmartfee`
- `estimatesmartpriority`
- `getinfo`
- `validateaddress`
- `createmultisig`
- `createwitnessaddress`
- `verifymessage`
- `signmessagewithprivkey`
- `setmocktime`
- `getconnectioncount`
- `ping`
- `getpeerinfo`
- `addnode`
- `disconnectnode`
- `getaddednodeinfo`
- `getnettotals`
- `getnetworkinfo`
- `setban`
- `listbanned`
- `clearbanned`
- `getrawtransaction`
- `createrawtransaction`
- `decoderawtransaction`
- `decodescript`
- `sendrawtransaction`
- `signrawtransaction`
- `gettxoutproof`
- `verifytxoutproof`
- `fundrawtransaction`
- `resendwallettransactions`
- `abandontransaction`
- `addmultisigaddress`
- `addwitnessaddress`
- `backupwallet`
- `dumpprivkey`
- `dumpwallet`
- `encryptwallet`
- `getaccountaddress`
- `getaccount`
- `getaddressesbyaccount`
- `getbalance`
- `getnewaddress`
- `getrawchangeaddress`
- `getreceivedbyaccount`
- `getreceivedbyaddress`
- `gettransaction`
- `getunconfirmedbalance`
- `getwalletinfo`
- `importprivkey`
- `importwallet`
- `importaddress`
- `importprunedfunds`
- `importpubkey`
- `keypoolrefill`
- `listaccounts`
- `listaddressgroupings`
- `listlockunspent`
- `listreceivedbyaccount`
- `listreceivedbyaddress`
- `listsinceblock`
- `listtransactions`
- `listunspent`
- `lockunspent`
- `move`
- `sendfrom`
- `sendmany`
- `sendtoaddress`
- `setaccount`
- `settxfee`
- `signmessage`
- `walletlock`
- `walletpassphrasechange`
- `walletpassphrase`
- `removeprunedfunds`
- `getmemory`
- `selectwallet`
- `setloglevel`
```bash
$ bcoin-cli help
$ bcoin-cli rpc help
$ bwallet-cli help
$ bwallet-cli rpc help
```

View File

@ -20,7 +20,8 @@ http client -> tx -> http server -> mempool
```
Not only does the loose coupling make testing easier, it ensures people can
utilize bcoin for many use cases.
utilize bcoin for many use cases. Learn more about specific events and
event emitters at http://bcoin.io/guides/events.html
### Performance
@ -43,19 +44,19 @@ blockchain and mempool do not block the master process very much. It also means
transaction verification can be parallelized.
Strangely enough, workers are faster in the browser than they are in node since
you are allowed to share memory between threads using the transferrable api
you are allowed to share memory between threads using the transferable API
(Uint8Arrays can be "transferred" to another thread). In node, you have to pipe
data to another process.
But of course, there is a benefit to having a multi-process architecture: the
worker processes can die on their own without disturbing the master process.
Bcoin uses [secp256k1-node][secp256k1-node] for ecdsa verification, which is a
Bcoin uses [secp256k1-node][secp256k1-node] for ECDSA verification, which is a
node.js binding to Pieter Wuille's blazingly fast [libsecp256k1][libsecp256k1]
library.
In the browser, bcoin will use [elliptic][elliptic], the fastest javascript
ecdsa implementation. It will obviously never beat C and hand-optimized
ECDSA implementation. It will obviously never beat C and hand-optimized
assembly, but it's still usable.
#### Benefits

View File

@ -7,22 +7,23 @@ const network = bcoin.Network.get('regtest');
const node = new bcoin.FullNode({
network: 'regtest',
apiKey: 'foo',
walletAuth: true,
db: 'memory'
});
node.use(plugin);
const wallet = new client.WalletClient({
port: network.walletPort,
apiKey: 'foo'
const walletClient = new client.WalletClient({
port: network.walletPort
});
const nodeClient = new client.NodeClient({
port: network.rpcPort
});
async function fundWallet(wdb, addr) {
// Coinbase
const mtx = new bcoin.MTX();
mtx.addOutpoint(new bcoin.Outpoint());
mtx.addOutpoint(new bcoin.Outpoint(bcoin.consensus.ZERO_HASH, 0));
mtx.addOutput(addr, 50460);
mtx.addOutput(addr, 50460);
mtx.addOutput(addr, 50460);
@ -30,19 +31,19 @@ async function fundWallet(wdb, addr) {
const tx = mtx.toTX();
wallet.once('balance', (balance) => {
walletClient.bind('balance', (walletID, balance) => {
console.log('New Balance:');
console.log(balance);
console.log(walletID, balance);
});
wallet.once('address', (receive) => {
walletClient.bind('address', (walletID, receive) => {
console.log('New Receiving Address:');
console.log(receive);
console.log(walletID, receive);
});
wallet.once('tx', (details) => {
walletClient.bind('tx', (walletID, details) => {
console.log('New Wallet TX:');
console.log(details);
console.log(walletID, details);
});
await wdb.addTX(tx);
@ -58,18 +59,23 @@ async function sendTX(addr, value) {
}]
};
const tx = await wallet.send('test', options);
// API call: walletClient.send('test', options)
const tx = await walletClient.request('POST', '/wallet/test/send', options);
return tx.hash;
}
async function callNodeApi() {
const info = await wallet.client.getInfo();
// API call: nodeClient.getInfo()
const info = await nodeClient.request('GET', '/');
console.log('Server Info:');
console.log(info);
const json = await wallet.client.rpc.execute('getblocktemplate', []);
const json = await nodeClient.execute(
'getblocktemplate',
[{rules: ['segwit']}]
);
console.log('Block Template (RPC):');
console.log(json);
@ -80,21 +86,39 @@ async function callNodeApi() {
await node.open();
const w = await wallet.createWallet('test');
// API call: walletClient.createWallet('test')
const testWallet = await walletClient.request('PUT', '/wallet/test');
console.log('Wallet:');
console.log(w);
console.log(testWallet);
// open socket to listen for events
await walletClient.open();
// subscribe to events from all wallets
walletClient.all()
// Fund default account.
const receive = await wallet.createAddress('test', 'default');
// API call: walletClient.createAddress('test', 'default')
const receive = await walletClient.request(
'POST',
'/wallet/test/address',
{account: 'default'}
);
await fundWallet(wdb, receive.address);
const balance = await wallet.getBalance('test', 'default');
// API call: walletClient.getBalance('test', 'default')
const balance = await walletClient.request(
'GET',
'/wallet/test/balance',
{account: 'default'}
);
console.log('Balance:');
console.log(balance);
const acct = await wallet.createAccount('test', 'foo');
// API call: walletClient.createAccount('test', 'foo')
const acct = await walletClient.request('PUT', '/wallet/test/account/foo');
console.log('Account:');
console.log(acct);
@ -105,12 +129,15 @@ async function callNodeApi() {
console.log('Sent TX:');
console.log(hash);
const tx = await wallet.getTX(hash);
// API call: walletClient.getTX('test', hash)
const tx = await walletClient.request('GET', `/wallet/test/tx/${hash}`);
console.log('Sent TX details:');
console.log(tx);
await callNodeApi();
await walletClient.close();
await node.close();
})().catch((err) => {
console.error(err.stack);
process.exit(1);

View File

@ -1,19 +1,25 @@
'use strict';
// Usage: $ node ./docs/Examples/connect-to-peer.js [ip]:[port]
/*
* Usage:
* Run another Bitcoin node on local regtest network, for example
* $ ../../bin/bcoin --network=regtest
* Execute this script with the other node's address and port
* $ node connect-to-peer.js 127.0.0.1:48444
*/
const bcoin = require('../..');
const network = bcoin.Network.get('testnet');
const network = bcoin.Network.get('regtest');
const peer = bcoin.Peer.fromOptions({
network: 'testnet',
network: 'regtest',
agent: 'my-subversion',
hasWitness: () => {
return false;
}
});
const addr = bcoin.net.NetAddress.fromHostname(process.argv[2], 'testnet');
const addr = bcoin.net.NetAddress.fromHostname(process.argv[2], 'regtest');
console.log(`Connecting to ${addr.hostname}`);

View File

@ -1,11 +1,12 @@
'use strict';
const bcoin = require('../..').set('main');
const Logger = require('blgr');
// Setup logger to see what's Bcoin doing.
const logger = new Logger({
level: 'debug'
level: 'info'
});
// Create a blockchain and store it in memory.
@ -41,21 +42,25 @@ const pool = new bcoin.Pool({
pool.startSync();
// Watch the action
const color = '\x1b[31m';
chain.on('block', (block) => {
console.log('Connected block to blockchain:');
console.log(block);
console.log(color, 'Added mainnet block:');
console.log(block.rhash());
});
mempool.on('tx', (tx) => {
console.log('Added tx to mempool:');
console.log(tx);
console.log(color, 'Added mainnet tx to mempool:');
console.log(tx.rhash);
});
pool.on('tx', (tx) => {
console.log('Saw transaction:');
console.log(color, 'Saw mainnet transaction:');
console.log(tx.rhash);
});
})();
})().catch((err) => {
console.error(err.stack);
process.exit(1);
});;
// Start up a testnet sync in-memory
// while we're at it (because we can).
@ -91,19 +96,20 @@ const tpool = new bcoin.Pool({
// Start the blockchain sync.
tpool.startSync();
const color = '\x1b[32m';
tchain.on('block', (block) => {
console.log('Added testnet block:');
console.log(block);
console.log(color, 'Added testnet block:');
console.log(block.rhash());
});
tmempool.on('tx', (tx) => {
console.log('Added testnet tx to mempool:');
console.log(tx);
console.log(color, 'Added testnet tx to mempool:');
console.log(tx.rhash);
});
tpool.on('tx', (tx) => {
console.log('Saw testnet transaction:');
console.log(tx);
console.log(color, 'Saw testnet transaction:');
console.log(tx.rhash);
});
})().catch((err) => {
console.error(err.stack);

View File

@ -1,4 +1,5 @@
'use strict';
const bcoin = require('../..');
// Default network (so we can avoid passing
@ -32,7 +33,7 @@ const miner = new bcoin.Miner({
const block = await job.mineAsync();
// Add the block to the chain
console.log('Adding %s to the blockchain.', block.rhash);
console.log('Adding %s to the blockchain.', block.rhash());
console.log(block);
await chain.add(block);
console.log('Added block!');

View File

@ -7,7 +7,7 @@ const assert = require('assert');
(async () => {
const master = bcoin.hd.generate();
const key = master.derivePath('m/44/0/0/0/0');
const key = master.derivePath("m/44'/0'/0'/0/0");
const keyring = new bcoin.wallet.WalletKey(key.privateKey);
const cb = new bcoin.MTX();

View File

@ -1,82 +0,0 @@
'use strict';
const bcoin = require('../..').set('main');
const walletPlugin = bcoin.wallet.plugin;
const node = new bcoin.FullNode({
checkpoints: true,
// Primary wallet passphrase
passsphrase: 'node',
logLevel: 'info'
});
node.use(walletPlugin);
// We get a lot of errors sometimes,
// usually from peers hanging up on us.
// Just ignore them for now.
node.on('error', (err) => {
;
});
// New Address we'll be sending to.
const newReceiving = 'AddressHere';
// Start the node
(async () => {
await node.open();
const options = {
id: 'mywallet',
passphrase: 'foo',
witness: false,
type: 'pubkeyhash'
};
const walletdb = node.require('walletdb').wdb;
const wallet = await walletdb.create(options);
console.log('Created wallet with address: %s', wallet.receiveAddress());
await node.connect();
// Start syncing the blockchain
node.startSync();
// Wait for balance and send it to a new address.
wallet.once('balance', async (balance) => {
// Create a transaction, fill
// it with coins, and sign it.
const options = {
subtractFee: true,
outputs: [{
address: newReceiving,
value: balance.total
}]
};
const tx = await wallet.createTX(options);
const stx = await wallet.sign(tx, 'foo');
console.log('sending tx:');
console.log(stx);
await node.sendTX(stx);
console.log('tx sent!');
});
node.chain.on('block', (block) => {
;
});
node.mempool.on('tx', (tx) => {
;
});
node.chain.on('full', () => {
node.mempool.getHistory().then(console.log);
});
})().catch((err) => {
console.error(err.stack);
process.exit(1);
});

View File

@ -1,46 +1,80 @@
'use strict';
const bcoin = require('../..');
const Logger = require('blgr');
const fs = require('bfile');
// Setup logger to see what's Bcoin doing.
const logger = new Logger({
level: 'debug'
// Create chain for testnet, stored in memory by default.
// To store the chain on disk at the `prefix` location,
// set `memory: false`.
const chain = new bcoin.Chain({
network: 'testnet',
indexTX: true,
indexAddress: true,
db: 'leveldb',
prefix: '/tmp/bcoin-testnet-example',
memory: true
});
// Create chain for testnet, specify chain directory
const chain = new bcoin.Chain({
logger: logger,
network: 'testnet',
db: 'leveldb',
prefix: '/tmp/bcon-testnet',
indexTX: true,
indexAddress: true
// Create a network pool of peers with a limit of 8 peers.
const pool = new bcoin.Pool({
chain: chain,
maxPeers: 8
});
(async () => {
await logger.open();
// Ensure the directory exists if we are writing to disk
if (!chain.options.memory)
await fs.mkdirp(chain.options.prefix);
await chain.open();
console.log('Current height:', chain.height);
// Connect the blockchain to the network
await pool.open();
await pool.connect();
pool.startSync();
const entry = await chain.getEntry(50000);
console.log('Block at 50k:', entry);
// Monitor blockchain height and react when we hit the target
chain.on('connect', async (entry, block) => {
const height = entry.height;
console.log(
`Height: ${chain.height} ` +
`Block: ${entry.rhash()} ` +
`TXs: ${block.txs.length}`
);
// eslint-disable-next-line max-len
const txhash = '4dd628123dcde4f2fb3a8b8a18b806721b56007e32497ebe76cde598ce1652af';
const txmeta = await chain.db.getMeta(bcoin.util.revHex(txhash));
const tx = txmeta.tx;
const coinview = await chain.db.getSpentView(tx);
if (height === 1000) {
const entry = await chain.getEntry(1000);
console.log('Block at height 1000:\n', entry);
console.log(`Tx with hash ${txhash}:`, txmeta);
console.log(`Tx input: ${tx.getInputValue(coinview)},` +
` output: ${tx.getOutputValue()}, fee: ${tx.getFee(coinview)}`);
// testnet tx at height 500
const txhash =
'fc407d7a3b819daa5cf1ecc2c2a4b103c3782104d1425d170993bd534779a0da';
const txhashBuffer = Buffer.from(txhash, 'hex').reverse();
// eslint-disable-next-line max-len
const bhash = '00000000077eacdd2c803a742195ba430a6d9545e43128ba55ec3c80beea6c0c';
const block = await chain.db.getBlock(bcoin.util.revHex(bhash));
console.log(`Block with hash ${bhash}:`, block);
const txmeta = await chain.db.getMeta(txhashBuffer);
const tx = txmeta.tx;
const coinview = await chain.db.getSpentView(tx);
console.log(`Tx with hash ${txhash}:\n`, txmeta);
console.log(
`\n Input value: ${tx.getInputValue(coinview)}` +
`\n Output value: ${tx.getOutputValue()}` +
`\n Fee: ${tx.getFee(coinview)}`
);
// testnet block at height 800
const hash =
Buffer.from(
'000000004df86f64cca38c6587df348e0c6849ebee628b3f840f552c707cc862',
'hex'
);
// chainDB indexes blocks by the REVERSE (little endian) hash
const block = await chain.getBlock(hash.reverse());
console.log(`Block with hash ${hash.toString('hex')}:`, block);
process.exit(1);
}
});
})().catch((err) => {
console.error(err.stack);
process.exit(1);

View File

@ -16,12 +16,12 @@ const chain = new bcoin.Chain({
const miner = new bcoin.Miner({
chain: chain,
addresses: [key.getAddress()],
coinbaseFlags: 'my-miner',
workers: workers
coinbaseFlags: 'my-miner'
});
(async () => {
await miner.open();
await chain.open();
const tmpl = await miner.createBlock();
@ -33,12 +33,16 @@ const miner = new bcoin.Miner({
console.log('Mined block:');
console.log(block);
console.log('Coinbase transaction:');
console.log(block.txs[0]);
await chain.add(block);
console.log('New tip:');
console.log(chain.tip);
await workers.close();
})().catch((err) => {
console.error(err.stack);
process.exit(1);

View File

@ -43,15 +43,7 @@ node.use(MyPlugin);
plugin.sayPeers();
node.on('connect', (entry, block) => {
console.log('%s (%d) added to chain.', entry.rhash(), entry.height);
});
node.on('tx', (tx) => {
console.log('%s added to mempool.', tx.txid());
});
node.startSync();
await node.close();
})().catch((err) => {
console.error(err.stack);
process.exit(1);

View File

@ -2,50 +2,81 @@
const bcoin = require('../..');
bcoin.set('testnet');
bcoin.set('regtest');
// SPV chains only store the chain headers.
const chain = new bcoin.Chain({
memory: false,
location: '/tmp/bcoin/spvchain',
spv: true
});
const pool = new bcoin.Pool({
chain: chain,
spv: true,
maxPeers: 8
maxOutbound: 1
});
const walletdb = new bcoin.wallet.WalletDB({ memory: true });
// Full node will provide tx data to SPV node
const full = {};
full.chain = new bcoin.Chain();
full.pool = new bcoin.Pool({
chain: full.chain,
port: 44444,
bip37: true,
listen: true
});
(async () => {
await pool.open();
await walletdb.open();
await chain.open();
await pool.connect();
await full.pool.open();
await full.chain.open();
await full.pool.connect();
const wallet = await walletdb.create();
const walletAddress = await wallet.receiveAddress();
console.log('Created wallet with address %s', walletAddress);
console.log('Created wallet with address %s', await wallet.receiveAddress());
// Add our address to the spv filter.
pool.watchAddress(await wallet.receiveAddress());
// Connect, start retrieving and relaying txs
await pool.connect();
// Add our address to the SPV filter.
pool.watchAddress(walletAddress);
// Start the blockchain sync.
pool.startSync();
pool.on('tx', async (tx) => {
console.log('received TX');
// Get ready to receive transactions!
pool.on('tx', (tx) => {
console.log('Received TX:\n', tx);
await walletdb.addTX(tx);
console.log('Transaction added to walletDB');
walletdb.addTX(tx);
console.log('TX added to wallet DB!');
});
wallet.on('balance', (balance) => {
console.log('Balance updated.');
console.log(bcoin.amount.btc(balance.unconfirmed));
console.log('Balance updated:\n', balance.toJSON());
});
// Connect the SPV node to the full node server
const netAddr = await pool.hosts.addNode('127.0.0.1:44444');
const peer = pool.createOutbound(netAddr);
pool.peers.add(peer);
full.pool.on('peer open', async () => {
console.log('SPV node peers:\n', pool.peers);
console.log('Full node peers:\n', full.pool.peers);
// Create a dummy transaction and send it from full to SPV node
const mtx = new bcoin.MTX();
mtx.addOutpoint(new bcoin.Outpoint(bcoin.consensus.ZERO_HASH, 0));
mtx.addOutput(walletAddress, 12000);
const tx = mtx.toTX();
// Give the node a few seconds to process connection before sending
console.log('Waiting for transaction...');
await new Promise(r => setTimeout(r, 3000));
await full.pool.broadcast(tx);
});
})().catch((err) => {
console.error(err.stack);

View File

@ -34,12 +34,11 @@ const walletdb = new bcoin.wallet.WalletDB({
const tx = mtx.toTX();
wallet.on('tx', (tx) => {
console.log('Received transaciton:\n', tx);
})
await walletdb.addTX(tx);
const wtx = await wallet.getTX(tx.hash());
console.log('Added transaction');
console.log(wtx);
})().catch((err) => {
console.error(err.stack);
process.exit(1);

View File

@ -1,31 +1,21 @@
const {HDPrivateKey,Network} = require('bcoin');
const {Mnemonic} = require('bcoin/lib/hd');
const {WalletClient} = require('bclient');
'use strict';
const bcoin = require('../..');
(async () => {
// use well know test passphrase
// use well known test mnemonic
const phrase = [
'abandon',
'abandon',
'abandon',
'abandon',
'abandon',
'abandon',
'abandon',
'abandon',
'abandon',
'abandon',
'abandon',
'about',
'abandon', 'abandon', 'abandon', 'abandon',
'abandon', 'abandon', 'abandon', 'abandon',
'abandon', 'abandon', 'abandon', 'about'
].join(' ');
const network = Network.get('main');
const network = bcoin.Network.get('regtest');
const mnemonic = Mnemonic.fromPhrase(phrase);
const mnemonic = bcoin.Mnemonic.fromPhrase(phrase);
// m'
const priv = HDPrivateKey.fromMnemonic(mnemonic);
const priv = bcoin.HDPrivateKey.fromMnemonic(mnemonic);
// m'/44'
const bip44Key = priv.derive(44, true);
@ -40,23 +30,41 @@ const {WalletClient} = require('bclient');
// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#Serialization_format
const xpub = accountKey.xpubkey(network.type);
console.log('xpub to import:\n', xpub);
// recommended to use hardware wallet to derive keys
// see github.com/bcoin-org/bledger
const client = new WalletClient({
network: network.type,
port: network.walletPort,
});
// create watch only wallet
// the wallet will generate lookahead
// addresses from the account extended public key
// and can find spendable coins in the blockchain state
const response = await client.createWallet('mywallet', {
accountKey: xpub,
watchOnly: true,
const wdb = new bcoin.wallet.WalletDB({
network: 'regtest',
memory: true
});
await wdb.open();
// new wallet still generates a master private key, but it will not be used
const wallet = await wdb.create({
name: 'my-watch-only-wallet',
accountKey: xpub,
watchOnly: true
});
// xpub account key placed at Account 0. Address 0 is already derived.
const acct0 = await wallet.getAccount(0);
// create new receive addresses through the deterministic chain
const key1 = await wallet.createReceive(0);
const addr1 = key1.getAddress('string', 'regtest');
const key2 = await wallet.createReceive(0);
const addr2 = key2.getAddress('string', 'regtest');
console.log('Wallet:\n', wallet);
console.log('Account:\n', acct0);
console.log('Address 1:\n', addr1);
console.log('Address 2:\n', addr2);
})();

View File

@ -1,53 +1,29 @@
Welcome to the bcoin docs!
## Getting Started
- [Getting Started][getting-started]
- [Configuration][configuration]
- [Wallet System][wallet-system]
- [Design][design]
- [Guides][guides]
- [Getting Started](Beginner's-Guide.md)
- [Configuration](Configuration.md)
- [Wallet System](Wallet-System.md)
- [Design](Design.md)
- [Guides](https://bcoin.io/guides.html)
## Running
- [Bcoin CLI][cli]
- [Running in the Browser][browser]
- [REST and RPC API][rest-rpc]
- [Bcoin CLI](CLI.md)
- [Running in the Browser](https://bcoin.io/guides/browser.html)
- [REST and RPC API](https://bcoin.io/api-docs/index.html#introduction)
## Code Examples
- [Simple Fullnode][example-simple-fullnode]
- [Connect to Peer][example-connect-peer]
- [Connecting to the P2P Network][example-p2p]
- [Creating a Blockchain and Mempool][example-blockchain]
- [Wallet with Dummy TX][example-wallet-dummy]
- [Fullnode Object][example-fullnode-wallet]
- [SPV Sync][example-spv]
- [Plugin Example][example-peers-plugin]
- [Client API Usage][example-client-api]
- [Miner with WorkerPool][example-miner-configs]
- [Create and Sign TX][example-tx-create-sign]
- [Get Transaction from Chain][example-tx-from-chain]
- [Create Watch Only Wallet][example-watch-only-wallet]
These code examples are designed to demonstrate how to integrate bcoin modules
with minimal configuration.
[getting-started]: Beginner's-Guide.md
[configuration]: Configuration.md
[design]: Design.md
[wallet-system]: Wallet-System.md
[guides]: http://bcoin.io/guides.html
[cli]: CLI.md
[browser]: Running-in-the-browser.md
[rest-rpc]: http://bcoin.io/api-docs/index.html#introduction
[example-p2p]: Examples/connect-to-the-p2p-network.js
[example-blockchain]: Examples/create-a-blockchain-and-mempool.js
[example-fullnode-wallet]: Examples/fullnode-and-wallet.js
[example-spv]: Examples/spv-sync-wallet.js
[example-wallet-dummy]: Examples/wallet.js
[example-peers-plugin]: Examples/peers-plugin.js
[example-client-api]: Examples/client-api.js
[example-miner-configs]: Examples/miner-configs.js
[example-connect-peer]: Examples/connect-to-peer.js
[example-simple-fullnode]: Examples/fullnode.js
[example-tx-create-sign]: Examples/create-sign-tx.js
[example-tx-from-chain]: Examples/get-tx-from-chain.js
[example-watch-only-wallet]: Examples/watch-only-wallet.js
- [Simple Fullnode](Examples/fullnode.js) - Creates a `FullNode` object and connects to `testnet`.
- [Connect to Peer](Examples/connect-to-peer.js) - Connects to a user-defined peer in `regtest` mode.
- [Connecting to the P2P Network](Examples/connect-to-the-p2p-network.js) - Creates `chain`, `pool`, and `mempool` objects for both main and testnet networks.
- [Creating a Blockchain and Mempool](Examples/create-a-blockchain-and-mempool.js) - Mines a block from the mempool to the chain.
- [Wallet with Dummy TX](Examples/wallet.js) - Adds a "dummy" transaction to the wallet and `tx` event is handled.
- [SPV Sync](Examples/spv-sync-wallet.js) - A transaction matching the SPV node's bloom filter is broadcast by a minimal full node to the SPV node.
- [Plugin Example](Examples/peers-plugin.js) - Demonstrates the `plugin` feature of bcoin's `node` object.
- [Client API Usage](Examples/client-api.js) - Demonstrates usage of the node and wallet API.
- [Miner with WorkerPool](Examples/miner-configs.js) - Creates a regtest `chain` and `miner`, which mines a block using workers.
- [Create and Sign TX](Examples/create-sign-tx.js) - Demonstrates how to use `mtx` and `keyring` modules to sign a transaction.
- [Get Transaction from Chain](Examples/get-tx-from-chain.js) - Connects to live testnet network and syncs the first 1000 blocks with tx indexing active.
- [Create Watch Only Wallet](Examples/watch-only-wallet.js) - Imports an `xpub` into a new watch-only wallet that can derive addresses.

View File

@ -1,2 +0,0 @@
This page has been moved to [https://bcoin.io/guides/browser.html](https://bcoin.io/guides/browser.html)

View File

@ -1,22 +1,51 @@
Wallet REST API: [REST-RPC-API](REST-RPC-API.md)
## Notes on wallet system
Bcoin maintains a wallet database which contains every wallet. Wallets are _not
usable_ without also using a wallet database. For testing, the wallet database
can be in-memory, but it must be there.
Wallets in bcoin use bip44. They also originally supported bip45 for multisig,
but support was removed to reduce code complexity, and also because bip45
Wallets in bcoin are based on BIP44. They also originally supported BIP45 for
multisig, but support was removed to reduce code complexity, and also because BIP45
doesn't seem to add any benefit in practice.
The wallet database can contain many different wallets, with many different
accounts, with many different addresses for each account. Bcoin should
theoretically be able to scale to hundreds of thousands of
wallets/accounts/addresses.
The wallet database can contain many wallets, with many accounts, with many
addresses for each account. Bcoin should theoretically be able to scale to
hundreds of thousands of wallets/accounts/addresses.
### Deviation from BIP44
**It's important to backup the wallet database.** There are several deviations from
[BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) that break
determinism, and therefore it's recommended to backup the wallet database any time
an account is created, as there are several possible configurations of an account.
There is a command available via the wallet RPC called `backupwallet` that can clone
the database to a new destination. There are also the RPC calls `dumpwallet` and
`dumpprivkey` for exporting private keys. After shutting down the wallet process,
it's also possible to copy the LevelDB database from the default location at
`~/.bcoin/wallet` for main net or `~/.bcoin/<network>/wallet` for others. Copying
LevelDB while the process is running can result in a corrupted copy. LevelDB is
also prone to [database corruption](https://en.wikipedia.org/wiki/LevelDB#Bugs_and_reliability).
Each account can be of a different type. You could have a pubkeyhash account,
as well as a multisig account, a witness pubkeyhash account, etc.
a multisig account, and a witness pubkeyhash account all in the same wallet.
Accounts can be configured with or without Segregated Witness and both base58
(nested-in-P2SH) and bech32 (native) P2WPKH addresses can be derived from the
same account.
Note that accounts should not be accessed directly from the public API. They do
not have locks which can lead to race conditions during writes.
Bcoin adds a third branch to each account for nested SegWit addresses.
Branch `0` and `1` are for `receive` and `change` addresses respectively (which
is BIP44 standard) but branch `2` is used by bcoin to derive
[nested SegWit addresses.](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#P2WPKH_nested_in_BIP16_P2SH)
Accounts in a bcoin wallet can be configured for multisig and import xpubs
from cosigners. Externally-generated Extended Private Keys (`xpriv`) and non-HD
single address private keys can all be imported into a bcoin wallet. Balances
of those addresses can be watched as well spent from (in the case of a private
key).
Unlike [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki),
bcoin does not limit account depth and a new account can be created
after an empty account. This can create issues with deterministic account
discovery from the master node (seed) as there are `2 ^ 31 - 1` _(worst case)_
possible accounts to search.