Ejemplo n.º 1
0
def checkShare(share):
	shareTime = share['time'] = time()
	
	username = share['username']
	if 'data' in share:
		# getwork/GBT
		checkData(share)
		data = share['data']
		
		if username not in workLog:
			raise RejectedShare('unknown-user')
		MWL = workLog[username]
		
		shareMerkleRoot = data[36:68]
		if 'blkdata' in share:
			pl = share['blkdata']
			(txncount, pl) = varlenDecode(pl)
			cbtxn = bitcoin.txn.Txn(pl)
			othertxndata = cbtxn.disassemble(retExtra=True)
			coinbase = cbtxn.getCoinbase()
			wliPos = coinbase[0] + 2
			wliLen = coinbase[wliPos - 1]
			wli = coinbase[wliPos:wliPos+wliLen]
			mode = 'MC'
			moden = 1
		else:
			wli = shareMerkleRoot
			mode = 'MRD'
			moden = 0
			coinbase = None
	else:
		# Stratum
		MWL = workLog[None]
		wli = share['jobid']
		buildStratumData(share, b'\0' * 32)
		mode = 'MC'
		moden = 1
		othertxndata = b''
	
	if wli not in MWL:
		raise RejectedShare('unknown-work')
	(wld, issueT) = MWL[wli]
	share[mode] = wld
	
	share['issuetime'] = issueT
	
	(workMerkleTree, workCoinbase) = wld[1:3]
	if 'jobid' in share:
		cbtxn = deepcopy(workMerkleTree.data[0])
		coinbase = workCoinbase + share['extranonce1'] + share['extranonce2']
		cbtxn.setCoinbase(coinbase)
		cbtxn.assemble()
		data = buildStratumData(share, workMerkleTree.withFirst(cbtxn))
		shareMerkleRoot = data[36:68]
	
	if data in DupeShareHACK:
		raise RejectedShare('duplicate')
	DupeShareHACK[data] = None
	
	blkhash = PoWHash(data)
	blkhashn = LEhash2int(blkhash)
	
	global networkTarget
	logfunc = getattr(checkShare.logger, 'info' if blkhashn <= networkTarget else 'debug')
	logfunc('BLKHASH: %64x' % (blkhashn,))
	logfunc(' TARGET: %64x' % (networkTarget,))
	
	# NOTE: this isn't actually needed for MC mode, but we're abusing it for a trivial share check...
	txlist = workMerkleTree.data
	txlist = [deepcopy(txlist[0]),] + txlist[1:]
	cbtxn = txlist[0]
	cbtxn.setCoinbase(coinbase or workCoinbase)
	cbtxn.assemble()
	
	if blkhashn <= networkTarget:
		logfunc("Submitting upstream")
		RBDs.append( deepcopy( (data, txlist, share.get('blkdata', None), workMerkleTree, share, wld) ) )
		if not moden:
			payload = assembleBlock(data, txlist)
		else:
			payload = share['data']
			if len(othertxndata):
				payload += share['blkdata']
			else:
				payload += assembleBlock(data, txlist)[80:]
		logfunc('Real block payload: %s' % (b2a_hex(payload).decode('utf8'),))
		RBPs.append(payload)
		threading.Thread(target=blockSubmissionThread, args=(payload, blkhash, share)).start()
		bcnode.submitBlock(payload)
		if config.DelayLogForUpstream:
			share['upstreamRejectReason'] = PendingUpstream
		else:
			share['upstreamRejectReason'] = None
			share['upstreamResult'] = True
		MM.updateBlock(blkhash)
	
	# Gotwork hack...
	if gotwork and blkhashn <= config.GotWorkTarget:
		try:
			coinbaseMrkl = cbtxn.data
			coinbaseMrkl += blkhash
			steps = workMerkleTree._steps
			coinbaseMrkl += pack('B', len(steps))
			for step in steps:
				coinbaseMrkl += step
			coinbaseMrkl += b"\0\0\0\0"
			info = {}
			info['hash'] = b2a_hex(blkhash).decode('ascii')
			info['header'] = b2a_hex(data).decode('ascii')
			info['coinbaseMrkl'] = b2a_hex(coinbaseMrkl).decode('ascii')
			thr = threading.Thread(target=submitGotwork, args=(info,))
			thr.daemon = True
			thr.start()
		except:
			checkShare.logger.warning('Failed to build gotwork request')
	
	if 'target' in share:
		workTarget = share['target']
	elif len(wld) > 6:
		workTarget = wld[6]
	else:
		workTarget = None
	
	if workTarget is None:
		workTarget = config.ShareTarget
	if blkhashn > workTarget:
		raise RejectedShare('high-hash')
	share['target'] = workTarget
	share['difficulty'] = config.ShareTarget / workTarget
	share['_targethex'] = '%064x' % (workTarget,)
	
	shareTimestamp = unpack('<L', data[68:72])[0]
	if shareTime < issueT - 120:
		raise RejectedShare('stale-work')
	if shareTimestamp < shareTime - 300:
		raise RejectedShare('time-too-old')
	if shareTimestamp > shareTime + 7200:
		raise RejectedShare('time-too-new')
	
	if config.DynamicTargetting and username in userStatus:
		# NOTE: userStatus[username] only doesn't exist across restarts
		status = userStatus[username]
		target = status[0] or config.ShareTarget
		if target == workTarget:
			userStatus[username][2] += 1
		else:
			userStatus[username][2] += float(target) / workTarget
	
	if moden:
		cbpre = workCoinbase
		cbpreLen = len(cbpre)
		if coinbase[:cbpreLen] != cbpre:
			raise RejectedShare('bad-cb-prefix')
		
		# Filter out known "I support" flags, to prevent exploits
		for ff in (b'/P2SH/', b'NOP2SH', b'p2sh/CHV', b'p2sh/NOCHV'):
			if coinbase.find(ff) > max(-1, cbpreLen - len(ff)):
				raise RejectedShare('bad-cb-flag')
		
		if len(coinbase) > 100:
			raise RejectedShare('bad-cb-length')
		
		if shareMerkleRoot != workMerkleTree.withFirst(cbtxn):
			raise RejectedShare('bad-txnmrklroot')
		
		if len(othertxndata):
			allowed = assembleBlock(data, txlist)[80:]
			if allowed != share['blkdata']:
				raise RejectedShare('bad-txns')
Ejemplo n.º 2
0
def checkShare(share):
    global rskLastReceivedShareTime
    global rskSubmittedShares

    shareTime = share['time'] = time()

    username = share['username']
    checkQuickDiffAdjustment = False
    if 'data' in share:
        # getwork/GBT
        data = share['data']

        shareMerkleRoot = data[36:68]
        if 'blkdata' in share:
            pl = share['blkdata']
            (txncount, pl) = varlenDecode(pl)
            cbtxn = bitcoin.txn.Txn(pl)
            othertxndata = cbtxn.disassemble(retExtra=True)
            coinbase = cbtxn.getCoinbase()
            wliPos = coinbase[0] + 2
            wliLen = coinbase[wliPos - 1]
            wli = coinbase[wliPos:wliPos + wliLen]
            mode = 'MC'
            moden = 1
        else:
            wli = shareMerkleRoot
            mode = 'MRD'
            moden = 0
            coinbase = None

        (wld, issueT) = LookupWork(username, wli)
        checkData(share, wld)
    else:
        # Stratum
        checkQuickDiffAdjustment = config.DynamicTargetQuick
        wli = share['jobid']
        (wld, issueT) = LookupWork(None, wli)
        mode = 'MC'
        moden = 1
        othertxndata = b''

    share[mode] = wld

    share['issuetime'] = issueT

    (workMerkleTree, workCoinbase) = wld[1:3]
    share['merkletree'] = workMerkleTree
    if 'jobid' in share:
        cbtxn = deepcopy(workMerkleTree.data[0])
        coinbase = workCoinbase + share['extranonce1'] + share['extranonce2']
        cbtxn.setCoinbase(coinbase)
        cbtxn.assemble()
        data = buildStratumData(share, workMerkleTree.withFirst(cbtxn),
                                workMerkleTree.MP['_BlockVersionBytes'])
        shareMerkleRoot = data[36:68]

    if data in DupeShareHACK:
        raise RejectedShare('duplicate')
    DupeShareHACK[data] = None

    blkhash = dblsha(data)

    if not hasattr(config, 'DEV_MODE_ON') or not config.DEV_MODE_ON:
        if not _reachesLowestDifficulty(blkhash):

            if len(share[mode]) >= 4:
                # currentblock may be changed, so we retry looking up some previous block saved (in RKS could be usefull prev blocks).
                blockToUse = (share[mode][3], share[mode][0], share[mode][4])
                retryData = buildStratumData(
                    share, workMerkleTree.withFirst(cbtxn),
                    workMerkleTree.MP['_BlockVersionBytes'], blockToUse)

                shareMerkleRoot = retryData[36:68]

                blkhash = dblsha(retryData)

                # retryData could be equal than data so we check again previous conditions
                if retryData == data or not _reachesLowestDifficulty(blkhash):
                    raise RejectedShare('H-not-zero')

                data = retryData
                DupeShareHACK[data] = None

            else:
                raise RejectedShare('H-not-zero')

    blkhashn = LEhash2int(blkhash)

    global networkTarget
    logfunc = getattr(checkShare.logger,
                      'info' if blkhashn <= networkTarget else 'debug')
    logfunc('BLKHASH: %64x' % (blkhashn, ))
    logfunc(' TARGET: %64x' % (networkTarget, ))

    # NOTE: this isn't actually needed for MC mode, but we're abusing it for a trivial share check...
    txlist = workMerkleTree.data
    txlist = [
        deepcopy(txlist[0]),
    ] + txlist[1:]
    cbtxn = txlist[0]
    cbtxn.setCoinbase(coinbase or workCoinbase)
    cbtxn.assemble()

    rootstockBlockHash = None
    rootstockTarget = None

    if hasattr(workMerkleTree, "rootstockBlockInfo"
               ) and workMerkleTree.rootstockBlockInfo is not None:
        rootstockBlockHash = workMerkleTree.rootstockBlockInfo[0]
        if hasattr(config, 'DEV_MODE_ON') and config.DEV_MODE_ON:
            rootstockTarget = bdiff2target(config.RSK_ELOIPOOL_DIFF)
        else:
            rootstockTarget = workMerkleTree.rootstockBlockInfo[1]

    submitRootstock = rootstockTarget is not None and blkhashn <= rootstockTarget

    if rskLastReceivedShareTime is None:
        rskLastReceivedShareTime = int(round(time() * 1000))
        rskSubmittedShares = 0
    lastReceivedShareTimeNow = int(round(time() * 1000))

    if lastReceivedShareTimeNow - rskLastReceivedShareTime >= 1000:
        rskSubmittedShares = 0
        rskLastReceivedShareTime = lastReceivedShareTimeNow

    checkShare.logger.info(
        "ROOTSTOCK_DEBUG: RSKValidShare: {0} {1} {2}".format(
            blkhashn, rootstockTarget, submitRootstock))
    if lastReceivedShareTimeNow - rskLastReceivedShareTime < 1000 and rskSubmittedShares < 1 and submitRootstock:
        rskSubmittedShares += 1
    else:
        submitRootstock = False

    submitBitcoin = blkhashn <= networkTarget
    #checkShare.logger.info("ROOTSTOCK_DEBUG: BTCValidShare: {0} {1} {2}".format(blkhashn, networkTarget, submitBitcoin))

    if submitBitcoin or submitRootstock:
        if submitBitcoin:
            share['BTC_SOLUTION'] = True
            logfunc("Submitting upstream")
            RBDs.append(
                deepcopy((data, txlist, share.get('blkdata', None),
                          workMerkleTree, share, wld)))

        if not moden:
            payload = assembleBlock(data, txlist)
        else:
            payload = share['data']
            if len(othertxndata):
                payload += share['blkdata']
            else:
                payload += assembleBlock(data, txlist)[80:]

        if submitRootstock:
            share['RSK_SOLUTION'] = True

            blockhashHexRskSubmit = b2a_hex(blkhash).decode('ascii')
            blockheaderHexRskSubmit = b2a_hex(share['data']).decode('ascii')
            coinbaseHexRskSubmit = b2a_hex(cbtxn.data).decode('ascii')

            coinbaseHashHexRskSubmit = b2a_hex(cbtxn.txid).decode('ascii')
            merkleHashesRskSubmit = [
                b2a_hex(x).decode('ascii') for x in workMerkleTree._steps
            ]
            merkleHashesRskSubmit.insert(0, coinbaseHashHexRskSubmit)
            merkleHashesRskSubmit = ' '.join(merkleHashesRskSubmit)

            txnCountRskSubmit = hex(len(txlist))[2:]
            threading.Thread(target=rootstockSubmissionThread,
                             args=(blockhashHexRskSubmit,
                                   blockheaderHexRskSubmit,
                                   coinbaseHexRskSubmit, merkleHashesRskSubmit,
                                   txnCountRskSubmit, share)).start()

        if not submitBitcoin:
            return

        logfunc('Real block payload: %s' % (b2a_hex(payload).decode('utf8'), ))
        RBPs.append(payload)
        threading.Thread(target=blockSubmissionThread,
                         args=(payload, blkhash, share)).start()
        bcnode.submitBlock(payload)
        if config.DelayLogForUpstream:
            share['upstreamRejectReason'] = PendingUpstream
        else:
            share['upstreamRejectReason'] = None
            share['upstreamResult'] = True
        MM.updateBlock(blkhash)

    # Gotwork hack...
    if gotwork and blkhashn <= config.GotWorkTarget:
        try:
            coinbaseMrkl = cbtxn.data
            coinbaseMrkl += blkhash
            steps = workMerkleTree._steps
            coinbaseMrkl += pack('B', len(steps))
            for step in steps:
                coinbaseMrkl += step
            coinbaseMrkl += b"\0\0\0\0"
            info = {}
            info['hash'] = b2a_hex(blkhash).decode('ascii')
            info['header'] = b2a_hex(data).decode('ascii')
            info['coinbaseMrkl'] = b2a_hex(coinbaseMrkl).decode('ascii')
            thr = threading.Thread(target=submitGotwork, args=(info, ))
            thr.daemon = True
            thr.start()
        except:
            checkShare.logger.warning('Failed to build gotwork request')

    if 'target' in share:
        workTarget = share['target']
    elif len(wld) > 6:
        workTarget = wld[6]
    else:
        workTarget = None

    if workTarget is None:
        workTarget = config.ShareTarget
    if blkhashn > workTarget:
        raise RejectedShare('high-hash')
    share['target'] = workTarget
    share['_targethex'] = '%064x' % (workTarget, )

    shareTimestamp = unpack('<L', data[68:72])[0]
    if shareTime < issueT - config.StaleWorkTimeout:
        raise RejectedShare('stale-work')
    if shareTimestamp < shareTime - 300:
        raise RejectedShare('time-too-old')
    if shareTimestamp > shareTime + 7200:
        raise RejectedShare('time-too-new')

    if moden:
        cbpre = workCoinbase
        cbpreLen = len(cbpre)
        if coinbase[:cbpreLen] != cbpre:
            raise RejectedShare('bad-cb-prefix')

        # Filter out known "I support" flags, to prevent exploits
        for ff in (b'/P2SH/', b'NOP2SH', b'p2sh/CHV', b'p2sh/NOCHV'):
            if coinbase.find(ff) > max(-1, cbpreLen - len(ff)):
                raise RejectedShare('bad-cb-flag')

        if len(coinbase) > 100:
            raise RejectedShare('bad-cb-length')

        if shareMerkleRoot != workMerkleTree.withFirst(cbtxn):
            raise RejectedShare('bad-txnmrklroot')

        if len(othertxndata):
            allowed = assembleBlock(data, txlist)[80:]
            if allowed != share['blkdata']:
                raise RejectedShare('bad-txns')

    if config.DynamicTargetting and username in userStatus:
        # NOTE: userStatus[username] only doesn't exist across restarts
        status = userStatus[username]
        target = status[0] or config.ShareTarget
        if target == workTarget:
            userStatus[username][2] += 1
        else:
            userStatus[username][2] += float(target) / workTarget
        if checkQuickDiffAdjustment and userStatus[username][
                2] > config.DynamicTargetGoal * 2:
            stratumsrv.quickDifficultyUpdate(username)