7 logging.basicConfig(level=logging.DEBUG)
9 def RaiseRedFlags(reason):
10 logging.getLogger('redflag').critical(reason)
14 from bitcoin.node import BitcoinLink
15 UpstreamBitcoind = BitcoinLink( config.UpstreamBitcoindNode, config.UpstreamNetworkId )
18 from bitcoin.script import BitcoinScript
19 from bitcoin.txn import Txn
20 from base58 import b58decode
21 from struct import pack
25 CoinbasePrefix = config.CoinbasePrefix if hasattr(config, 'CoinbasePrefix') else b''
29 if now > makeCoinbase.last:
30 makeCoinbase.last = now
31 makeCoinbase.extranonce = 0
33 makeCoinbase.extranonce += 1
34 return CoinbasePrefix + pack('>L', now) + pack('>Q', makeCoinbase.extranonce).lstrip(b'\0')
37 def makeCoinbaseTxn(coinbaseValue):
39 t.setCoinbase(makeCoinbase())
41 if hasattr(config, 'CoinbaserCmd'):
44 cmd = config.CoinbaserCmd
45 cmd = cmd.replace('%d', str(coinbaseValue))
46 p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
47 nout = int(p.stdout.readline())
49 amount = int(p.stdout.readline())
50 addr = p.stdout.readline().rstrip(b'\n').decode('utf8')
51 pkScript = BitcoinScript.toAddress(addr)
52 t.addOutput(amount, pkScript)
55 coinbased = coinbaseValue + 1
56 if coinbased >= coinbaseValue:
57 logging.getLogger('makeCoinbaseTxn').error('Coinbaser failed!')
60 coinbaseValue -= coinbased
62 pkScript = BitcoinScript.toAddress(config.TrackerAddr)
63 t.addOutput(coinbaseValue, pkScript)
67 # TODO: red flag on dupe coinbase
71 from util import Bits2Target
77 global MM, networkTarget
78 networkTarget = Bits2Target(MM.currentBlock[1])
82 from merklemaker import merkleMaker
84 MM.__dict__.update(config.__dict__)
85 MM.makeCoinbaseTxn = makeCoinbaseTxn
86 MM.onBlockChange = blockChanged
87 MM._THISISUGLY = UpstreamBitcoind
91 from binascii import b2a_hex
92 from struct import pack, unpack
94 from util import RejectedShare, dblsha, hash2int
96 def getBlockHeader(username):
98 (merkleRoot, merkleTree, coinbaseTxn, prevBlock, bits, rollPrevBlk) = MRD
99 timestamp = pack('<L', int(time()))
100 hdr = b'\1\0\0\0' + prevBlock + merkleRoot + timestamp + bits + b'iolE'
101 workLog.setdefault(username, {})[merkleRoot] = MRD
104 def checkShare(share):
106 (prevBlock, bits) = MM.currentBlock
107 sharePrevBlock = data[4:36]
108 if sharePrevBlock != prevBlock:
109 if sharePrevBlock == MM.lastBlock[0]:
110 raise RejectedShare('stale-prevblk')
111 raise RejectedShare('bad-prevblk')
113 shareMerkleRoot = data[36:68]
115 username = share['username']
116 if username not in workLog:
117 raise RejectedShare('unknown-user')
118 MWL = workLog[username]
119 if shareMerkleRoot not in MWL:
120 raise RejectedShare('unknown-work')
121 MRD = MWL[shareMerkleRoot]
124 shareTimestamp = unpack('<L', data[68:72])[0]
125 shareTime = share['time'] = time()
126 if shareTimestamp < shareTime - 300:
127 raise RejectedShare('time-too-old')
128 if shareTimestamp > shareTime + 7200:
129 raise RejectedShare('time-too-new')
130 if data[72:76] != bits:
131 raise RejectedShare('bad-diffbits')
132 if data[:4] != b'\1\0\0\0':
133 raise RejectedShare('bad-version')
135 blkhash = dblsha(data)
136 if blkhash[28:] != b'\0\0\0\0':
137 raise RejectedShare('H-not-zero')
138 blkhashn = hash2int(blkhash)
141 logfunc = getattr(checkShare.logger, 'info' if blkhashn <= networkTarget else 'debug')
142 logfunc('BLKHASH: %64x' % (blkhashn,))
143 logfunc(' TARGET: %64x' % (networkTarget,))
145 if blkhashn <= networkTarget:
146 logfunc("Submitting upstream")
147 MRD[1].data[0] = MRD[2]
148 UpstreamBitcoind.submitBlock(data, MRD[1].data)
149 checkShare.logger = logging.getLogger('checkShare')
151 def receiveShare(share):
152 # TODO: username => userid
156 def newBlockNotification(signum, frame):
157 MM.updateMerkleTree()
158 # TODO: Force RESPOND TO LONGPOLLS?
161 from signal import signal, SIGUSR1
162 signal(SIGUSR1, newBlockNotification)
165 from jsonrpcserver import JSONRPCServer
166 import interactivemode
168 if __name__ == "__main__":
169 server = JSONRPCServer(('', 8444))
170 server.getBlockHeader = getBlockHeader
171 server.receiveShare = receiveShare
172 server.RaiseRedFlags = RaiseRedFlags
173 server.serve_forever()