Bugfix: Avoid trying to decode None objects
[bitcoin:eloipool.git] / jsonrpc_getmemorypool.py
1 # Eloipool - Python Bitcoin pool server
2 # Copyright (C) 2011-2012  Luke Dashjr <luke-jr+eloipool@utopios.org>
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as
6 # published by the Free Software Foundation, either version 3 of the
7 # License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU Affero General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 # NOTE: This implements an obsolete draft of BIP 22 and is provided only for backward compatibility
18 # NOTE: See jsonrpc_getblocktemplate.py for current BIP 22 support
19 # NOTE: If you want to enable this module, add TWO lines to your config file:
20 # NOTE:     import jsonrpc_getblocktemplate
21 # NOTE:     import jsonrpc_getmemorypool
22 # NOTE: It is important that getblocktemplate be included first, if full backward compatibility is desired (getmemorypool's more-compatible submitblock will override getblocktemplate's)
23
24 from binascii import b2a_hex
25 from copy import deepcopy
26 from jsonrpcserver import JSONRPCHandler
27 from time import time
28 from util import RejectedShare
29
30 _NoParams = {}
31
32 class _getmemorypool:
33         def final_init(server):
34                 ShareTargetHex = '%064x' % (server.ShareTarget,)
35                 JSONRPCHandler.getmemorypool_rv_template['target'] = ShareTargetHex
36         
37         getmemorypool_rv_template = {
38                 'longpoll': '/LP',
39                 'mutable': [
40                         'coinbase/append',
41                 ],
42                 'noncerange': '00000000ffffffff',
43                 'target': '00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
44                 'version': 2,
45                 'submitold': True,
46         }
47         def doJSON_getmemorypool(self, params = _NoParams, sp = _NoParams):
48                 if isinstance(params, str):
49                         if sp.get('mode', 'submit') != 'submit':
50                                 raise AttributeError('getmemorypool mode "%s" not supported' % (sp['mode'],))
51                         rr = self.doJSON_submitblock(params, sp)
52                         if sp is _NoParams:
53                                 return rr is None
54                         return rr
55                 elif not sp is _NoParams:
56                         raise TypeError('getmemorypool() takes at most 2 positional arguments (%d given)' % (len(a),))
57                 elif params.get('mode', 'template') != 'template':
58                         raise AttributeError('getmemorypool mode "%s" not supported' % (sp['mode'],))
59                 
60                 if 'longpollid' in params:
61                         self.processLP(params['longpollid'])
62                 
63                 rv = dict(self.getmemorypool_rv_template)
64                 (MC, wld, target) = self.server.getBlockTemplate(self.Username)
65                 (dummy, merkleTree, cb, prevBlock, bits) = MC[:5]
66                 rv['previousblockhash'] = b2a_hex(prevBlock[::-1]).decode('ascii')
67                 rv['longpollid'] = str(self.server.LPId)
68                 tl = []
69                 for txn in merkleTree.data[1:]:
70                         tl.append(b2a_hex(txn.data).decode('ascii'))
71                 rv['transactions'] = tl
72                 now = int(time())
73                 rv['time'] = now
74                 # FIXME: ensure mintime is always >= real mintime, both here and in share acceptance
75                 rv['mintime'] = now - 180
76                 rv['maxtime'] = now + 120
77                 rv['bits'] = b2a_hex(bits[::-1]).decode('ascii')
78                 rv['target'] = '%064x' % (target,)
79                 t = deepcopy(merkleTree.data[0])
80                 t.setCoinbase(cb)
81                 t.assemble()
82                 rv['coinbasetxn'] = b2a_hex(t.data).decode('ascii')
83                 return rv
84         
85         def doJSON_submitblock(self, data, params = _NoParams):
86                 data = bytes.fromhex(data)
87                 share = {
88                         'data': data[:80],
89                         'blkdata': data[80:],
90                         'username': self.Username,
91                         'remoteHost': self.remoteHost,
92                         'userAgent': self.UA,
93                         'submitProtocol': 'GMP',
94                 }
95                 try:
96                         self.server.receiveShare(share)
97                 except RejectedShare as rej:
98                         if 'SBB' in self.quirks:
99                                 return False
100                         return str(rej)
101                 if 'SBB' in self.quirks:
102                         return True
103                 return None
104
105 JSONRPCHandler._register(_getmemorypool)