事件和套接字
要监听hsd中的事件并做出响应,必须在运行时脚本中添加监听器。
例如,如果您运行的是完整节点,则可能已经熟悉了hsd节点启动脚本,
该脚本实例化 FullNode
对象,添加钱包并开始连接和同步。
该脚本以实际启动这些过程的异步函数结尾,这是添加事件侦听器的好地方。使用下表的事件目录,
您可以发现每种事件类型需要侦听哪个对象。注意,因为钱包是作为插件添加的,所以它的对象层次结构路径有点……笨拙:-)
// Based on https://github.com/handshake-org/hsd/blob/master/bin/node(async () => {await node.ensure();await node.open();await node.connect();node.startSync();// add event listeners after everything is open, connected, and started// NODEnode.on('tx', (details) => {console.log(' -- node tx -- \n', details)});node.on('block', (details) => {console.log(' -- node block -- \n', details)});// MEMPOOLnode.mempool.on('confirmed', (details) => {console.log(' -- mempool confirmed -- \n', details)});// WALLETnode.plugins.walletdb.wdb.on('balance', (details) => {console.log(' -- wallet balance -- \n', details)});node.plugins.walletdb.wdb.on('confirmed', (details) => {console.log(' -- wallet confirmed -- \n', details)});node.plugins.walletdb.wdb.on('address', (details) => {console.log(' -- wallet address -- \n', details)});})().catch((err) => {console.error(err.stack);process.exit(1);});
事件目录
该列表对于涵盖所有Handshake交易,钱包和区块链活动。 为了简单起见,已省略了有关错误,套接字连接和对等连接的事件。 请注意,某些方法发出相同的事件,但返回对象不同,并不是所有的所有重新发射器都返回它们接收的所有内容。
Event | Returns | Origin | Re-Emitters |
---|---|---|---|
tip | ChainEntry | Chain: open() , disconnect() , reconnect() , setBestChain() , reset() | |
connect | ChainEntry, Block, CoinView | Chain: setBestChain() , reconnect() | chain→FullNode (returns ChainEntry, Block only) chain→SPVNode (returns ChainEntry, Block only) SPVNode, FullNode→NodeClient (emits as block connect , returns ChainEntry, Block.txs only) |
disconnect | ChainEntry, Headers, CoinView | Chain: reorganizeSPV() | chain→FullNode (returns ChainEntry, Headers only) chain→SPVNode (returns ChainEntry, Headers only) SPVNode, FullNode→NodeClient (emits as block disconnect , returns ChainEntry only) |
disconnect | ChainEntry, Block, CoinView | Chain: disconnect() | chain→FullNode (returns ChainEntry, Block only) chain→SPVNode (returns ChainEntry, Block only) SPVNode, FullNode→NodeClient (emits as block disconnect , returns ChainEntry only) |
reconnect | ChainEntry, Block | Chain: reconnect() | |
reorganize | tip (ChainEntry), competitor (ChainEntry) | Chain: reorganize() , reorganizeSPV() | chain→FullNode chain→SPVNode |
block | Block, ChainEntry | Chain: setBestChain() CPUMiner: _start() | chain→Pool chain→FullNode (returns Block only) chain→SPVNode (returns Block only) |
competitor | Block, ChainEntry | Chain: saveAlternate() | |
bad orphan | Error, ID | Chain: handleOrphans() Mempool: handleOrphans() | |
resolved | Block, ChainEntry | Chain: handleOrphans() | |
checkpoint | Hash, Height | Chain: verifyCheckpoint() | |
orphan | Block | Chain: storeOrphan() | |
full | Chain: maybeSync() | chain→Pool | |
confirmed | TX, ChainEntry | Mempool: _addBlock() | |
confirmed | TX, Details | TXDB: confirm() | txdb→WalletDB (also returns Wallet) txdb→Wallet |
unconfirmed | TX, Block | Mempool: _removeBlock() | |
unconfirmed | TX, Details | TXDB: disconnect() | txdb→WalletDB (also returns Wallet) txdb→Wallet |
conflict | TX | Mempool: _removeBlock() | |
conflict | TX, Details | TXDB: disconnect() | txdb→WalletDB (also returns Wallet) txdb→Wallet |
tx | TX, CoinView | Mempool: addEntry() | mempool→Pool (returns TX only) mempool→pool→SPVNode (returns TX only) mempool→FullNode (returns TX only) SPVNode, FullNode→NodeClient (returns TX only) |
tx | TX | Pool: _handleTX() (only if there is no mempool, i.e. SPV) | pool→SPVNode |
tx | TX, Details | TXDB: insert() | txdb→WalletDB (also returns Wallet) txdb→Wallet |
double spend | MempoolEntry | Mempool: removeDoubleSpends() | |
balance | Balance | TXDB: insert() , confirm() , disconnect() , erase() | txdb→WalletDB (also returns Wallet) txdb→Wallet |
address | [WalletKey] | Wallet: _add() , | wallet→WalletDB (returns parent Wallet, [WalletKey]) |
Socket事件
hsd中的Websocket连接由两个服务处理,一个用于Node
,一个用于Wallet
。
每个服务都有子对象,如Chain
,Mempool
,Pool
,WalletDB
,并从它们的套接字中中继事件。
为了接收事件,套接字客户端必须监听一个频道(例如chain
,mempool
或auth
),或加入一个钱包(用户定义为primary
,hot-wallet
或multisig1
)。
所有钱包都可以通过'*'
一次连接起来。
用bsock监听Socket事件
要建立与hsd的套接字连接,您需要运行一个websocket客户端。
幸运的是,bcoin和hsd开发人员已经开发了bsock,这是socket.io协议的一种仅基于Websocket的最小实现。
默认情况下,bsock监听localhost
,并且您只需要向其传递一个端口号即可连接到其中一台hsd服务器。
下面的示例说明了如何建立套接字连接,如何使用用户定义的API密钥进行身份验证以及如何发送和接收事件!
有关hsd中可用的调用和事件的完整列表,请参见下面的套接字事件目录
。
// bsock-example.jsconst bsock = require('bsock');const {Network, ChainEntry} = require('hsd');const network = Network.get('regtest');const apiKey = 'api-key';nodeSocket = bsock.connect(network.rpcPort);walletSocket = bsock.connect(network.walletPort);nodeSocket.on('connect', async (e) => {try {console.log('Node - Connect event:\n', e);// `auth` must be called before any other actionsconsole.log('Node - Attempting auth:\n', await nodeSocket.call('auth', apiKey));// `watch chain` subscirbes us to chain events like `block`console.log('Node - Attempting watch chain:\n', await nodeSocket.call('watch chain'));// Some calls simply request information from the server like an http requestconsole.log('Node - Attempting get tip:');const tip = await nodeSocket.call('get tip');console.log(ChainEntry.from(tip));} catch (e) {console.log('Node - Connection Error:\n', e);}});// listen for new blocksnodeSocket.bind('chain connect', (raw, txs) => {console.log('Node - Chain Connect Event:\n', ChainEntry.fromRaw(raw));});walletSocket.on('connect', async (e) => {try {console.log('Wallet - Connect event:\n', e);// `auth` is required before proceedingconsole.log('Wallet - Attempting auth:\n', await walletSocket.call('auth', apiKey));// here we join all wallets, but we could also just join `primary` or any other walletconsole.log('Wallet - Attempting join *:\n', await walletSocket.call('join', '*'));} catch (e) {console.log('Wallet - Connection Error:\n', e);}});// listen for new wallet transactionswalletSocket.bind('tx', (wallet, tx) => {console.log('Wallet - TX Event -- wallet:\n', wallet);console.log('Wallet - TX Event -- tx:\n', tx);});// listen for new address events// (only fired when current account address receives a transaction)walletSocket.bind('address', (wallet, json) => {console.log('Wallet - Address Event -- wallet:\n', wallet);console.log('Wallet - Address Event -- json:\n', json);});
要查看此脚本的运行情况,请首先启动hsd:
hsd --daemon --network=regtest
运行脚本(这是事件输出的打印位置):
node bsock-example.js
然后,在单独的终端窗口中,运行一些命令来触发事件!
hsd-cli rpc generatetoaddress 1 rs1qyep4stuujjkdfv483nfse53vvgtfuqr9z6v4cm
更易用的Sockets: hs-client
bsock
是用于处理套接字的出色的底层库,但是我们还有hs-client,它可以简化套接字和常规的http连接。
终端中的一个单行命令可以侦听所有钱包事件并打印所有返回的数据:
hsw-cli listen
hs-client
也可以在脚本中用于侦听事件。如果您已经熟悉了hsd-cli API,将轻车熟路。这是上面脚本的一部分,使用hs-client来代替bsock:
const {NodeClient} = require('hs-client');const {Network, ChainEntry} = require('hsd');const network = Network.get('regtest');const clientOptions = {network: network.type,port: network.rpcPort,apiKey: 'api-key'}const client = new NodeClient(clientOptions);(async () => {// bclient handles the connection, the auth, and the channel subscriptionsawait client.open();// use socket connection to request dataconst tip = await client.getTip();console.log(tip);})();// listen for new blocksclient.bind('chain connect', (raw) => {console.log('Node - Chain Connect Event:\n', ChainEntry.fromRaw(raw));});
套接字事件目录
钱包
所有钱包事件均由 WalletDB
对象广播,可由其父对象 TXDB
或 Wallet
触发。
套接字发出事件以及钱包ID以及上面列出的相同“ Returns”。
Event | Returns |
---|---|
tx | WalletID, TX Details |
confirmed | WalletID, TX Details |
unconfirmed | WalletID, TX Details |
conflict | WalletID, TX Details |
balance | WalletID, Balance |
address | WalletID, [WalletKey] |
节点
Event | Returns | Channel | Origin | Original Event |
---|---|---|---|---|
chain connect | ChainEntry.toRaw() | chain | Chain | connect |
block connect | ChainEntry.toRaw(), Block.txs | chain | Chain | connect |
chain disconnect | ChainEntry.toRaw() | chain | Chain | disconnect |
block disconnect | ChainEntry.toRaw() | chain | Chain | disconnect |
tx | TX.toRaw() | mempool | Pool | tx |
服务器勾子
某些事件也可以从客户端发送回服务器,以请求新数据或触发服务器操作。客户端动作是一个“调用”,而服务器等待着一个“勾子”。
钱包
Event | Args | Returns |
---|---|---|
auth | 1. api key | null |
join | 1. wallet id 2. wallet token | null |
leave | 1. wallet id | null |
节点
Event | Args | Returns |
---|---|---|
auth | 1. api key | null |
watch chain | (none) | null |
unwatch chain | (none) | null |
watch mempool | (none) | null |
unwatch mempool | (none) | null |
set filter | 1. Bloom filter (Buffer) | null |
get tip | (none) | ChainEntry.toRaw() |
get entry | 1. hash | ChainEntry.toRaw() |
get hashes | 1. start (int) 2. end (int) | [hashes] |
add filter | 1. filter ([Buffer]) | null |
reset filter | (none) | null |
estimate fee | 1. blocks (int) | fee rate (float) |
send | 1. tx (Buffer) | null |
rescan | 1. hash | null |