def verify_header(self, header, prev_hash, bits, target): height = header.get('block_height') if prev_hash != header.get('prev_block_hash'): raise Exception("prev hash mismatch: %s vs %s" % (prev_hash, header.get('prev_block_hash'))) # DGWv3 PastBlocksMax = 24 Because checkpoint don't have preblock data. if height % 2016 != 0 and height // 2016 < len( self.checkpoints) or height >= len( self.checkpoints) * 2016 and height <= len( self.checkpoints) * 2016 + 24: return if constants.net.TESTNET: return if bits != header.get('bits'): raise Exception("bits mismatch: %s vs %s" % (bits, header.get('bits'))) if height < 450000: _powhash = rev_hex( bh2u(scryptGetHash(bfh(serialize_header(header))))) else: _powhash = rev_hex( bh2u(lyra2re2_hash.getPoWHash(bfh(serialize_header(header))))) if int('0x' + _powhash, 16) > target: raise Exception("insufficient proof of work: %s vs target %s" % (int('0x' + _powhash, 16), target))
def verify_header(cls, header: dict, prev_hash: str, target: int, expected_header_hash: str = None) -> None: height = header.get('block_height') _hash = hash_header(header) if expected_header_hash and expected_header_hash != _hash: raise Exception("hash mismatches with expected: {} vs {}".format( expected_header_hash, _hash)) if prev_hash != header.get('prev_block_hash'): raise Exception("prev hash mismatch: %s vs %s" % (prev_hash, header.get('prev_block_hash'))) # DGWv3 PastBlocksMax = 24 Because checkpoint don't have preblock data. if height // 2016 < len(constants.net.CHECKPOINTS) and height % 2016 != 2015 or \ height >= len(constants.net.CHECKPOINTS)*2016 and height <= len(constants.net.CHECKPOINTS)*2016 + 24: return if constants.net.TESTNET: return bits = cls.target_to_bits(target) if bits != header.get('bits'): raise Exception("bits mismatch: %s vs %s" % (bits, header.get('bits'))) if height < 450000: _powhash = rev_hex( bh2u(scryptGetHash(bfh(serialize_header(header))))) else: _powhash = rev_hex( bh2u(lyra2re2_hash.getPoWHash(bfh(serialize_header(header))))) if int('0x' + _powhash, 16) > target: raise Exception("insufficient proof of work: %s vs target %s" % (int('0x' + _powhash, 16), target))
def pow_hash_header(self, header): height = header.get('block_height') if height >= 347000: return rev_hex(lyra2re2_hash.getPoWHash(self.serialize_header(header).decode('hex')).encode('hex')) elif height >= 208301: return rev_hex(lyra2re_hash.getPoWHash(self.serialize_header(header).decode('hex')).encode('hex')) else: return rev_hex(vtc_scrypt.getPoWHash(self.serialize_header(header).decode('hex')).encode('hex'))
def header_hash(cls, header): ''' Given a header return the hash for Kreds. Need to download `lyra2re2_hash` module Source code: https://github.com/metalicjames/lyra2re-hash-python ''' import lyra2re2_hash return lyra2re2_hash.getPoWHash(header)
def pow_hash_header(header): height = header.get('block_height') header_bytes = bfh(serialize_header(header)) if height >= 347000: return hash_encode(lyra2re2_hash.getPoWHash(header_bytes)) elif height >= 208301: return hash_encode(lyra2re_hash.getPoWHash(header_bytes)) else: return hash_encode(vtc_scrypt_new.getPoWHash(header_bytes))
def calc_sha256(self): if self.sha256 is None: r = b"" r += struct.pack("<i", self.nVersion) r += ser_uint256(self.hashPrevBlock) r += ser_uint256(self.hashMerkleRoot) r += struct.pack("<I", self.nTime) r += struct.pack("<I", self.nBits) r += struct.pack("<I", self.nNonce) self.sha256 = uint256_from_str(hash256(r)) self.hash = encode(hash256(r)[::-1], 'hex_codec').decode('ascii') self.lyra2re2Hash = uint256_from_str(lyra2re2_hash.getPoWHash(r)) self.lyra2rec0banHash = uint256_from_str( lyra2rec0ban_hash.getPoWHash(r))
def verify_header(self, header, prev_header, bits, target): prev_hash = hash_header(prev_header) if prev_hash != header.get('prev_block_hash'): raise BaseException("prev hash mismatch: %s vs %s" % (prev_hash, header.get('prev_block_hash'))) if bitcoin.NetworkConstants.TESTNET: return height = header.get('block_height') if height < 450000 : _powhash = rev_hex(bh2u(scryptGetHash(bfh(serialize_header(header))))) else: _powhash = rev_hex(bh2u(lyra2re2_hash.getPoWHash(bfh(serialize_header(header))))) if bits != header.get('bits'): raise BaseException("bits mismatch: %s vs %s" % (bits, header.get('bits'))) if int('0x' + _powhash, 16) > target: raise BaseException("insufficient proof of work: %s vs target %s" % (int('0x' + _powhash, 16), target))
def pow_hash_header(header): if header['version'] & (15 << 11) == (4 << 11): blake_state = cblake() blake_state.update(bfh(serialize_header(header))) return hash_encode(blake_state.final()) if header['version'] & (15 << 11) == (2 << 11): return hash_encode( groestl_hash.getPoWHash(bfh(serialize_header(header)))) if header['version'] & (15 << 11) == (10 << 11): return hash_encode( lyra2re2_hash.getPoWHash(bfh(serialize_header(header)))) if header['version'] & (15 << 11) == (3 << 11): return hash_encode(x17_hash.x17_gethash(bfh(serialize_header(header)))) if header['version'] & (15 << 11) == (11 << 11): return hash_encode( shield_x16s_hash.getPoWHash(bfh(serialize_header(header)))) return hash_encode(getPoWHash(bfh(serialize_header(header))))
def header_hash(cls, header): '''Given a header return the hash.''' import lyra2re2_hash return lyra2re2_hash.getPoWHash(header)
def submit_share(self, job_id, worker_name, extranonce1_bin, extranonce2, ntime, nonce, difficulty): '''Check parameters and finalize block template. If it leads to valid block candidate, asynchronously submits the block back to the bitcoin network. - extranonce1_bin is binary. No checks performed, it should be from session data - job_id, extranonce2, ntime, nonce - in hex form sent by the client - difficulty - decimal number from session, again no checks performed - submitblock_callback - reference to method which receive result of submitblock() ''' # Check if extranonce2 looks correctly. extranonce2 is in hex form... if len(extranonce2) != self.extranonce2_size * 2: raise SubmitException("Incorrect size of extranonce2. Expected %d chars" % (self.extranonce2_size*2)) # Check for job job = self.get_job(job_id) if job == None: raise SubmitException("Job '%s' not found" % job_id) # Check if ntime looks correct if len(ntime) != 8: raise SubmitException("Incorrect size of ntime. Expected 8 chars") if not job.check_ntime(int(ntime, 16)): raise SubmitException("Ntime out of range") # Check nonce if len(nonce) != 8: raise SubmitException("Incorrect size of nonce. Expected 8 chars") # Convert from hex to binary extranonce2_bin = binascii.unhexlify(extranonce2) ntime_bin = binascii.unhexlify(ntime) nonce_bin = binascii.unhexlify(nonce) # Check for duplicated submit if not job.register_submit(extranonce1_bin, extranonce2_bin, ntime_bin, nonce_bin): log.info("Duplicate from %s, (%s %s %s %s)" % \ (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce)) raise SubmitException("Duplicate share") # Now let's do the hard work! # --------------------------- # 1. Build coinbase coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin) coinbase_hash = util.doublesha(coinbase_bin) # 2. Calculate merkle root merkle_root_bin = job.merkletree.withFirst(coinbase_hash) merkle_root_int = util.uint256_from_str(merkle_root_bin) # 3. Serialize header with given merkle, ntime and nonce header_bin = job.serialize_header(merkle_root_int, ntime_bin, nonce_bin) # 4. Reverse header and compare it with target of the user hash_bin = lyra2re2_hash.getPoWHash(''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ])) hash_int = util.uint256_from_str(hash_bin) block_hash_hex = "%064x" % hash_int header_hex = binascii.hexlify(header_bin) target_user = self.diff_to_target(difficulty) if hash_int > target_user: raise SubmitException("Share is above target") # Mostly for debugging purposes target_info = self.diff_to_target(100000) if hash_int <= target_info: log.info("Yay, share with diff above 100000") # 5. Compare hash with target of the network if hash_int <= job.target: # Yay! It is block candidate! log.info("We found a block candidate! %s" % block_hash_hex) # 6. Finalize and serialize block object job.finalize(merkle_root_int, extranonce1_bin, extranonce2_bin, int(ntime, 16), int(nonce, 16)) if not job.is_valid(): # Should not happen log.error("Final job validation failed!") # 7. Submit block to the network serialized = binascii.hexlify(job.serialize()) on_submit = self.bitcoin_rpc.submitblock(serialized) return (header_hex, block_hash_hex, on_submit) return (header_hex, block_hash_hex, None)
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import threading from . import util from . import bitcoin from .bitcoin import * try: import lyra2re2_hash getPoWHash = lambda x: lyra2re2_hash.getPoWHash(x) except ImportError as e: exit("Please run 'sudo pip3 install https://github.com/straks/lyra2re-hash-python/archive/master.zip'") class VerifyError(Exception): '''Exception used for blockchain verification errors.''' MAX_TARGET = 0x00000fffff000000000000000000000000000000000000000000000000000000 def bits_to_work(bits): return (1 << 256) // (bits_to_target(bits) + 1) def bits_to_target(bits): bitsN = (bits >> 24) & 0xff if not (bitsN >= 0x03 and bitsN <= 0x1e): raise BaseException("First part of bits should be in [0x03, 0x1e]")
import lyra2re2_hash import weakref import binascii import StringIO from binascii import unhexlify, hexlify teststart = '700000005d385ba114d079971b29a9418fd0549e7d68a95c7f168621a314201000000000578586d149fd07b22f3a8a347c516de7052f034d2b76ff68e0d6ecff9b77a45489e3fd511732011df0731000' testbin = unhexlify(teststart) hash_bin = lyra2re2_hash.getPoWHash(testbin) print hexlify(hash_bin)
x += (harr[i + 1] + harr[i]) return x def little_endian(value): return hexlify(pack("L", value))[0:8] # STRAKS BLOCK 10 header_hex = ( little_endian(536870912) + swap_order( "00000491760a7e6cf8fb72ef96626eae4b10242b2999c629336175252582e33a") + swap_order( "15b4d0b16c968c98a7f61ac344925398a7a1466620271e0abd28e823d547c9f6") + little_endian(1510792864) + little_endian(504122572) + little_endian(53233)) print "header_hex:", header_hex header_bin = unhexlify(header_hex) hash_bin = lyra2re2_hash.getPoWHash(header_bin) unswapped_hhash = hexlify(hash_bin) header_hash = swap_order(hexlify(hash_bin)) print unswapped_hhash print header_hash print ">> matches target hash:", header_hash == "0000025f19e1714fd575bfe9e18e137625e731036da615f416d79f7edbdc1e81"
def powhash(header): return rev_hex(bh2u(lyra2re2_hash.getPoWHash(bfh(header))))
import lyra2re2_hash import weakref import binascii import StringIO from binascii import unhexlify, hexlify teststart = '700000005d385ba114d079971b29a9418fd0549e7d68a95c7f168621a314201000000000578586d149fd07b22f3a8a347c516de7052f034d2b76ff68e0d6ecff9b77a45489e3fd511732011df0731000'; testbin = unhexlify(teststart) hash_bin = lyra2re2_hash.getPoWHash(testbin) print hexlify(hash_bin)
def submit(self, connection_ref, _id, _params): # TODO: Job ID Check 구현해야함 # TODO: Diff Check 해서 그냥 Share 기록 or Submit 구별 해야함 # TODO: Share Result를 Database에 기록 해야함 - Database 는 Redis가 될듯 session_id = connection_ref.get_session() _worker_name = _params[0] _split_worker_name = _worker_name.strip().split('.') username = _split_worker_name[0] if len(_split_worker_name) == 2: worker = _split_worker_name[1] else: worker = None _job_id = _params[1] _nonce_1 = self.job_manager.get_nonce_from_session_id(session_id) _block_template = self.job_manager.get_block_template(_job_id) if _block_template is None: logger.info('rejected share, worker : %s, reason : job not found' % _worker_name) return {'id': _id, 'result': False, 'error': [21, 'job not found']} if os.getenv("COIN_TYPE") == 'bitcoin': _nonce_2 = _params[2] _time = _params[3] _time_reverse = hash_util.hex_to_reverse_hex(_time) _nonce = _params[4] _nonce_reverse = hash_util.hex_to_reverse_hex(_nonce) if len(_nonce) != 8: logger.info( 'rejected share, worker : %s, reason : incorrect size of nonce' % _worker_name) return { 'id': _id, 'result': False, 'error': [20, 'incorrect size of nonce'] } coinbase = binascii.hexlify(_block_template.coinbase_tx).split( _block_template.extranonce_placeholder) serialized_coinbase = binascii.unhexlify(coinbase[0] + _nonce_1 + _nonce_2.encode() + coinbase[1]) if os.getenv("COIN_ALGORITHM") == 'keccak': coinbase_hash = binascii.hexlify( hash_util.reverse_bytes( hash_util.sha(serialized_coinbase))) else: coinbase_hash = hash_util.bytes_to_reverse_hash( serialized_coinbase) tx_hashes = [coinbase_hash ] + [h['hash'] for h in _block_template.transactions] merkle_root_reverse_hex = hash_util.hex_to_reverse_hex( hash_util.merkle_root(tx_hashes)) # Header POW 종류별 구별 해야댐 header = _block_template.serialize_block_header( _time_reverse, _nonce_reverse, merkle_root_reverse_hex) # 80 bytes block_hex = _block_template.serialize_block( header, None, serialized_coinbase) if os.getenv("COIN_ALGORITHM") == 'lyra2rev2': import lyra2re2_hash header_hash = lyra2re2_hash.getPoWHash(header) elif os.getenv("COIN_ALGORITHM") == 'lyra2rev3': import lyra2re3_hash header_hash = lyra2re3_hash.getPoWHash(header) elif os.getenv("COIN_ALGORITHM") == 'keccak' or os.getenv( "COIN_ALGORITHM") == 'keccakc': import sha3 header_hash = sha3.keccak_256(header).digest() elif os.getenv("COIN_ALGORITHM") == 'x13-bcd': import x13bcd_hash header_hash = x13bcd_hash.getPoWHash(header) elif os.getenv("COIN_ALGORITHM") == 'neoscrypt': import neoscrypt header_hash = neoscrypt.getPoWHash(header) elif os.getenv("COIN_ALGORITHM") == 'yescrypt': import yescrypt_hash header_hash = yescrypt_hash.getHash(header, len(header)) elif os.getenv("COIN_ALGORITHM") == 'xevan': import xevan_hash header_hash = xevan_hash.getPoWHash(header) elif os.getenv("COIN_ALGORITHM") == 'phi2': import phi2_hash header_hash = phi2_hash.getPoWHash(header) elif os.getenv("COIN_ALGORITHM") == 'x16r': import x16r_hash header_hash = x16r_hash.getPoWHash(header) elif os.getenv("COIN_ALGORITHM") == 'x16s': import x16s_hash header_hash = x16s_hash.getPoWHash(header) elif os.getenv("COIN_ALGORITHM") == 'timetravel10': import timetravel10_hash header_hash = timetravel10_hash.getPoWHash(header) else: header_hash = double_sha(header) elif os.getenv("COIN_TYPE") == 'zcash': _time = _params[2] _nonce_2 = _params[3] _soln = _params[4] _nonce = _nonce_1 + _nonce_2.encode() if len(_nonce) != 64: return { 'id': _id, 'result': False, 'error': [20, 'incorrect size of nonce'] } if os.getenv("COIN_ALGORITHM") == 'zhash' and len(_soln) != 202: return { 'id': _id, 'result': False, 'error': [20, 'incorrect size of solution'] } elif os.getenv("COIN_ALGORITHM") != 'zhash' and len(_soln) != 2694: return { 'id': _id, 'result': False, 'error': [20, 'incorrect size of solution'] } n_time_int = int(_time, 16) curtime_int = int(_block_template.curtime, 16) if n_time_int < curtime_int: return { 'id': _id, 'result': False, 'error': [20, 'ntime out of range'] } header = _block_template.serialize_block_header( _time.encode(), _nonce) # 140 bytes header_soln = header + binascii.unhexlify(_soln) header_hash = double_sha(header_soln) block_hex = _block_template.serialize_block( header, binascii.unhexlify(_soln), None) else: raise Exception('invalid coin type') header_bignum = uint256_from_str(header_hash) share_diff = os.getenv("POW_LIMIT") / header_bignum logger.debug('share diff : {0:.8f}'.format(share_diff)) diff = self.user_diffs[connection_ref.username] if share_diff < diff: # logger.debug('low difficulty share of %s' % share_diff) logger.info( 'rejected share, worker : %s, reason : low difficulty share' % _worker_name) self.database_ref.insert_accepted_share( username, worker, False, False, _block_template.block_height, share_diff, _block_template.pool_reward, diff) return { 'id': _id, 'result': None, 'error': [23, 'low difficulty share of %s' % share_diff] } if not self.job_manager.register_submit(_nonce_1, _nonce_2, _nonce, _time): logger.info( 'rejected share, worker : %s, reason : duplicate share' % _worker_name) return { 'id': _id, 'result': None, 'error': [22, 'duplicate share'] } if share_diff >= _block_template.difficulty * 0.99: block_hash = binascii.hexlify( hash_util.reverse_bytes(header_hash)).decode() if os.getenv("COIN") in [ 'monacoin', 'feathercoin', 'phoenixcoin', 'vertcoin', 'shield' ]: temp_hash = double_sha(header) block_hash = binascii.hexlify( hash_util.reverse_bytes(temp_hash)).decode() logger.info('Try new block share, worker : %s, share diff : %s' % (_worker_name, share_diff)) share_result = self.coin_rpc.submit_block( binascii.hexlify(block_hex).decode()) if share_result is None: logger.info('Found Block, result : %s, block hash : %s' % (share_result, block_hash)) result_hash = Interfaces.block_updater.update_block( repeat=False, block_hash=block_hash) if result_hash is not None: block_hash = result_hash self.database_ref.insert_accepted_share( username, worker, True, True, _block_template.block_height, share_diff, _block_template.pool_reward, diff, block_hash) else: logger.error( 'undefined share_result %s, block hash %s, coinbase tx %s' % (share_result, block_hash, binascii.hexlify(_block_template.coinbase_tx))) self.database_ref.insert_accepted_share( username, worker, False, False, _block_template.block_height, share_diff, _block_template.pool_reward, diff) if os.getenv("COIN_TYPE") == 'bitcoin': logger.error('Header : %s' % binascii.hexlify(header).decode()) else: logger.error('Header : %s' % binascii.hexlify(header_soln).decode()) return { 'id': _id, 'result': None, 'error': [20, 'invalid solution'] } else: logger.info('accepted share, worker : %s, share diff : %s' % (_worker_name, '{0:.8f}'.format(share_diff))) self.database_ref.insert_accepted_share( username, worker, True, False, _block_template.block_height, share_diff, _block_template.pool_reward, diff) return {'id': _id, 'result': True, 'error': None}