Bitcoin Binary Data Protocol
Contents
0. The URLs
URL: http://yyz.us/bitcoin/pushpool-0.4.tar.gz Repo: https://github.com/jgarzik/pushpool
1. The Problem
With the recent slashdotting and resultant influx in new users, the ‘getwork’ network protocol used in mining is showing some strain, particularly on the pools. Miners request work once every 5-10 seconds using HTTP JSON-RPC, which has several glaring inefficiencies that lead to unnecessary server load: HTTP/1.1 persistent connections are uncommon, possibly because bitcoind does not support them. This results in a new TCP connection from every miner, every 5-10 seconds, to the same network host. ‘getwork’ data is a mere 256 bytes, but HTTP headers and binary-to-hexidecimal encoding for JSON increase the payload to more than double that official bitcoin client’s RPC server implementation is essentially a single-threaded loop, where requests from clients B, C, and D will be stalled and ignored until client A’s request is finished — or a 30 second timeout (see -rpctimeout). This algorithm does not tolerate a high TCP request rate from multiple threads / computers.
Several people, pool operators in particular, have a keen interest in solving these problems. In addition, push mining (see below) has been discussed as a future alternative to the ‘getwork’ polling method currently employed.
2. Design goals for a solution
I have written a demonstration pool server (aka a ‘getwork’ proxy server) that functions in a similar fashion to the recently-discussed poold.py: large numbers of miners connect to the pool server, which proxies ‘getwork’ JSON-RPC requests to the official bitcoin client. This demonstration server implements a new binary protocol that was designed to meet the following goals:
Persistent TCP connections, to eliminate TCP disconnect+reconnect behavior by miners Network-efficient for the common use case: one network packet for ‘getwork’, one network packet for the returned data. Network-efficient for similar use cases (monitorblocks, monitortx) where clients connect, and then passively wait for real-time events to be delivered Existing miner client workflows supported, to minimize network protocol change impact on miners Support “push mining,” where server delivers new work to miners unsolicited (ie. without the miner first sending a ‘getwork’ message)
This is not intended to replace JSON-RPC API, but to supplement it for specific use cases. Yes, that means bitcoind will listen to three network ports: P2P network, JSON-RPC, and binary RPC (though as now, only P2P is required for operation; the servers are always optional).
3. Let’s start with a protocol example: today’s getwork mining
The specific details of the protocol itself are in ubbp.h and protocol.h of the above URL (pushpool-0.1.1.tar.gz). Here is an example, to provide a suitable introduction:
- TCP connection is broken up into messages. Each message has a 64-bit header, with 8-bit opcode and 24-bit length fields.
- Miner client connects to TCP server, and issues a LOGIN message, which is compressed JSON login data + sha256 hash of (data + shared secret).
- Server responds with an OP_LOGIN_RESP msg, compressed JSON, indicating options and capabilities
- Client issues an OP_GETWORK msg (8 bytes)
- Server responds with an OP_WORK msg (264 bytes)
- Client uses its CPU/GPU to work on proof-of-work solution…
- Client issues an OP_GETWORK msg (8 bytes)
- Server responds with an OP_WORK msg (264 bytes)
The above example intentionally matches existing ‘getwork’ JSON-RPC miner client workflow today. Miner clients may even support stateless operation by pipelining the OP_LOGIN and OP_GETWORK requests together, and closing the TCP connection. Stateless operation is not recommended, but it is supported, in order to support the widest range of existing mining clients.
4. Tomorrow’s mining: push mining
When a block or tx arrives, it is preferable to begin working immediately on the new work. From the server’s perspective, this is a classic data-broadcast problem, where the server wants to broadcast N different pieces of work to N miners. Hence, “push mining” where the server pushes new work pro-actively to the miner clients.
This new network protocol supports pushing mining, as demonstrated in this example:
- Client connects to server, issues a LOGIN message with the “send_me_work” flag set
- Server responds with OP_LOGIN_RESP msg
- Server sends a OP_WORK msg
- Server sends a OP_WORK msg
- Server sends a OP_WORK msg
5. A similar use case: monitorblocks
Gavin Andresen has a patch in his github which provides a very useful feature: when a new block is received (monitorblocks) or new wallet transaction (monitortx), bitcoind sends an HTTP POST to the specified URL. Thus, monitorblocks provides real-time monitoring of the bitcoin network, and monitortx provides real-time monitoring of the local wallet. This sort of featureset pushes data as events occur, rather than forcing a website operator to poll JSON-RPC for certain operations to complete.
Monitoring new blocks on the bitcoin network is a very easy data broadcasting problem that this binary network protocol may easily support:
- Client connects to server, issues a LOGIN message with the “send_me_blocks” flag set
- Server responds with OP_LOGIN_RESP msg
- Server sends a OP_BLOCK msg
- Server sends a OP_BLOCK msg
- Server sends a OP_BLOCK msg
…
monitortx is more complicated, because one may specify transaction-matching criteria. But with this new protocol’s support of JSON, flexibility is not a problem.