Dear BitCoin developers and mining pool owners,
Looking @ work of
http://www.tricone-mining.com/limp.html and having experience with high performance stuff, I would like to point that overall many of these ways to deliver shares are highly suboptimal. As basically getwork/shares submission do not require such facilities of TCP like ORDER of packets sent/received from miner to bitcoind or pool. So individual packet acknowledgement would work better, especially when miner is behind of poor internet connectivity like myself.
So - I have proposal to stop re-inventing wheel all of the time and make this once and for many years. Also light-weight protocol would make burdens of ddos mitigation much easier. Basically unlike implementing HTTP protocol, this protocol when implemented even by not very skilled programmer could easily withstand gigabits of incoming bandwidth, just throw-in better network card into your server.
So - lightweight getwork protocol.
Single UDP packet may contain multiple messages, building up to 1400 bytes in size. 1400 choosen because mostly when you get access with several VPNs, your MTU would be cut down from 1500. So 1400 is safe compromise value. But mining client could correct this value to one of his choice. And even more - server shall not reply with more messages in single UDP packet, than client requested! So one could get 8 works to getwork requests only if client requested 8 getworks at once.
So - UDP packet is basically concatenation of several messages of following format:
struct msg_header {
unsigned char msg_size;
unsigned char msg_opcode;
unsigned char msg_context_uuid[16];
};
struct msg_work {
struct msg_header hdr; /* This is basically C-way of inheritation... in C++ this would be msg_work : msg_header */
unsigned char work[80]; /* last 32-bit is nonce, but can contain bitstream unlock sequence (special for EldenTyrell) */
};
Opcodes:
REQUESTING WORK:
msg_opcode == 1 - getwork request, typically answer is 10, 11 or 12
msg_opcode == 10 - structure with msg_work returned, miner shall process that work
msg_opcode == 11 - getwork negative acknowledgement - too many requests, this opcode may be sent to friendly nodes
in case of too many getwork requests, so miner would not ambush server more;
msg_opcode == 12 - work is invalidated (when new block calculations started);
GETTING ANSWERS:
msg_opcode == 20 - answer message type is msg_work;
msg_opcode == 30 - successfully accepted msg_work;
msg_opcode == 31 - share rejected - stale;
msg_opcode == 32 - share rejected - invalid;
msg_opcode == 33 - share rejected - unknown;
msg_opcode == 34 - share rejected - duplicate;
FEDERATION OF SERVERS INTERNAL COMMUNICATION:
msg_opcode == 40 - I want to posses right to process this getwork request;
msg_opcode == 50 - I have no objection, proceed with that getwork;
msg_opcode == 51 - I have already processed that getwork, drop it;
TYPICAL MINER <--> BITCOIND OR POOL COMMUNICATION:
msg_opcode == 1 - sent from miner to bitcoind taking about 46 bytes to request work;
msg_opcode == 10 - 126 bytes (just 126! not 2 KB!) returned from pool to miner msg_work;
msg_opcode == 20 - msg_work with found nonce returned from miner to bitcoind;
msg_opcode == 30 - share is good - returned from bitcoind to miner;
Packet loss is ALWAYS handled on miner's side - if no reply received, request is re-tried with some delay,
with exponential backoff.
Bitcoind / pool NEVER retransmits packets on its own.
For miners behind firewall, special proxy can be launched that converts messages from TCP to UDP protocol. However
such proxies will be subject to DDOS attacks due to TCP itself... beware...
THEN - how DDOS mitigation can be implemented in this protocol (don't know whether this good for pool or for bitcoind):
Server collects frame of requests for say 100 milliseconds. On 1 Gbps internet that can be as many as 6'000'000 incoming messages for getwork. Then server should get only 100 to 1000 best getworks in his opinion from that buffer and silently drop rest of requests. How then server may choose ? Quite simply - by priority sorting - first server would rank higher those, who sent more shares within last 60 seconds, then sort by ip address, where ip that requested less getworks would rank higher to cut off botnets. Then drop all of the rest 5'999'000 requests. But well... if such protocol used through all stages, it can easily process 10'000 getworks per second on simple VPS!
Then - why UDP ?! Is it more complex ?
Actually not ... because in UDP it is EASY to setup replication of communication... Say you add up to your mining rig connected to ADSL additionally GSM or 3G internet... And you can transmit same getwork request over 2 channels simultaneously, and to 3 servers of your beloved pool.... That would increase traffic, but also would increase reliability by MAGNITUDE... So while pools are fighting 1% more or 1% less, many of miners loose about 2-3% for internet outages, some with bad internet connectivity loose about 10-12% (like me).
For TCP on other side you would always have hassle with maintaining connection state, etc. While in UDP you would have to remember _multiple_ miner "return addresses" for about 60 seconds, while getting packets from him is actual. And you would broadcast answers to all of these addresses.
I am going to implement this protocol soon for own purposes, but it ridiculous when finally I convert all of that into HTTP-JSON based getwork.
So I wanted to ask:
1. Who also would support such initiative/have similar problems ?
2. How code to bitcoind should be submitted/approved ? Is this addition subject to be added to existing bitcoind ? As maintenance of separate patch-set could be quite boring... Also there may be questions on how this would be implemented in best way (say bitcoind mainly relies on boost::asio).
Kind regards,
V. // BitFury :-)