Example #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]
	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))
		shareMerkleRoot = data[36:68]
	
	if data in DupeShareHACK:
		raise RejectedShare('duplicate')
	DupeShareHACK[data] = None
	
	blkhash = dblsha(data)
	if blkhash[28:] != b'\0\0\0\0':
		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()
	
	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['_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')
Example #2
0
def checkShare(share):
    shareTime = share["time"] = time()

    username = share["username"]
    isstratum = False
    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
        isstratum = True
        wli = share["jobid"]
        buildStratumData(share, b"\0" * 32)
        mode = "MC"
        moden = 1
        othertxndata = b""
        if None not in workLog:
            # We haven't yet sent any stratum work for this block
            raise RejectedShare("unknown-work")
        MWL = workLog[None]

    if wli not in MWL:
        raise RejectedShare("unknown-work")
    (wld, issueT) = MWL[wli]
    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))
        shareMerkleRoot = data[36:68]

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

    blkhash = dblsha(data)
    if blkhash[28:] != b"\0\0\0\0":
        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()

    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["_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 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 isstratum and userStatus[username][2] > config.DynamicTargetGoal * 2:
            stratumsrv.quickDifficultyUpdate(username)