def set_blockchain_params(genesis_block): assert 'spawn' in multiprocessing.get_all_start_methods(), 'Not found spawn method.' setting_tx = genesis_block.txs[0] params = bjson.loads(setting_tx.message) V.BLOCK_GENESIS_HASH = genesis_block.hash V.BLOCK_PREFIX = params.get('prefix') V.BLOCK_CONTRACT_PREFIX = params.get('contract_prefix') V.BLOCK_GENESIS_TIME = params.get('genesis_time') V.BLOCK_ALL_SUPPLY = params.get('all_supply') V.BLOCK_TIME_SPAN = params.get('block_span') V.BLOCK_REWARD = params.get('block_reward') V.CONTRACT_VALIDATOR_ADDRESS = params.get('validator_address') V.COIN_DIGIT = params.get('digit_number') V.COIN_MINIMUM_PRICE = params.get('minimum_price') V.CONTRACT_MINIMUM_AMOUNT = params.get('contract_minimum_amount') consensus = params.get('consensus') if isinstance(consensus, dict): V.BLOCK_CONSENSUS = consensus V.BLOCK_BASE_CONSENSUS = min(consensus.keys()) else: # TODO: remove after test pow_ratio = params.get('pow_ratio') V.BLOCK_CONSENSUS = {C.BLOCK_YES_POW: pow_ratio, C.BLOCK_POS: 100 - pow_ratio} V.BLOCK_BASE_CONSENSUS = C.BLOCK_YES_POW GompertzCurve.setup_params()
async def chain_info(request): best_height = builder.best_block.height best_block = builder.best_block old_block_height = builder.best_chain[0].height - 1 old_block_hash = hexlify(builder.get_block_hash(old_block_height)).decode() data = {'best': best_block.getinfo()} difficulty = dict() for consensus, ratio in V.BLOCK_CONSENSUSES.items(): name = C.consensus2name[consensus] target = get_bits_by_hash(previous_hash=best_block.hash, consensus=consensus)[1] block_time = round(V.BLOCK_TIME_SPAN / ratio * 100) diff = (MAX_256_INT // target) / 100000000 bias = get_bias_by_hash(previous_hash=best_block.previous_hash, consensus=consensus) difficulty[name] = { 'number': consensus, 'diff': round(diff / 100000000, 8), 'bias': round(bias, 8), 'fixed_diff': round(diff / bias, 8), 'hashrate(kh/s)': round((MAX_256_INT//target)/block_time/1000, 3), 'is_base': V.BLOCK_BASE_CONSENSUS == consensus, } data['mining'] = difficulty data['size'] = best_block.getsize() data['checkpoint'] = {'height': old_block_height, 'blockhash': old_block_hash} data['money_supply'] = GompertzCurve.calc_total_supply(best_height) data['total_supply'] = GompertzCurve.k return web_base.json_res(data)
def check_tx_pow_reward(tx, include_block): if not (len(tx.inputs) == 0 and len(tx.outputs) == 1): raise BlockChainError('Inout is 0, output is 1 len.') elif include_block.txs.index(tx) != 0: raise BlockChainError('Proof tx is index 0.') elif not (tx.gas_price == 0 and tx.gas_amount == 0): raise BlockChainError('Pow gas info is wrong. [{}, {}]'.format( tx.gas_price, tx.gas_amount)) elif len(tx.message) > 96: raise BlockChainError('Pow msg is less than 96bytes. [{}b>96b]'.format( len(tx.message))) address, coin_id, amount = tx.outputs[0] reward = GompertzCurve.calc_block_reward(include_block.height) fees = sum(tx.gas_amount * tx.gas_price for tx in include_block.txs) if not (include_block.time == tx.time == tx.deadline - 10800): raise BlockChainError('TX time is wrong 3. [{}={}={}-10800]'.format( include_block.time, tx.time, tx.deadline)) elif not (coin_id == 0 and amount <= reward + fees): raise BlockChainError( 'Input and output is wrong coin={} [{}<={}+{}]'.format( coin_id, amount, reward, fees)) elif not include_block.pow_check(): include_block.work2diff() include_block.target2diff() print(include_block.getinfo()) raise BlockChainError('Proof of work check is failed. [{}<{}]'.format( include_block.difficulty, include_block.work_difficulty))
def create_mining_block(consensus): global mining_address # setup mining address for PoW with mining_address_lock: if mining_address is None: if V.MINING_ADDRESS is None: with create_db(V.DB_ACCOUNT_PATH) as db: cur = db.cursor() mining_address = generate_new_address_by_userid( C.ANT_UNKNOWN, cur) db.commit() else: mining_address = V.MINING_ADDRESS if unconfirmed_txs is None: raise FailedGenerateWarning('unconfirmed_txs is None') if previous_block is None: raise FailedGenerateWarning('previous_block is None') # create proof_tx reward = GompertzCurve.calc_block_reward(previous_block.height + 1) fees = sum(tx.gas_amount * tx.gas_price for tx in unconfirmed_txs) proof_tx = TX.from_dict( tx={ 'type': C.TX_POW_REWARD, 'inputs': list(), 'outputs': [(mining_address, 0, reward + fees)], 'gas_price': 0, 'gas_amount': 0, 'message_type': C.MSG_NONE, 'message': b'' }) proof_tx.update_time() # create mining block bits, target = get_bits_by_hash(previous_hash=previous_block.hash, consensus=consensus) mining_block = Block.from_dict( block={ 'merkleroot': b'\xff' * 32, 'time': 0, 'previous_hash': previous_block.hash, 'bits': bits, 'nonce': b'\xff\xff\xff\xff' }) proof_tx.height = previous_block.height + 1 mining_block.height = proof_tx.height mining_block.flag = consensus mining_block.bits2target() mining_block.txs.append(proof_tx) if unconfirmed_txs is None: raise FailedGenerateWarning('unconfirmed_txs is None') mining_block.txs.extend(unconfirmed_txs) mining_block.update_merkleroot() mining_block.update_time(proof_tx.time) return mining_block
def check_tx_pos_reward(tx, include_block): # POS報酬TXの検査 if not (len(tx.inputs) == len(tx.outputs) == 1): raise BlockChainError('Inputs and outputs is only 1 len.') elif include_block.txs.index(tx) != 0: raise BlockChainError('Proof tx is index 0.') elif not (tx.gas_price == 0 and tx.gas_amount == 0): raise BlockChainError('Pos gas info is wrong. [{}, {}]'.format( tx.gas_price, tx.gas_amount)) elif not (tx.message_type == C.MSG_NONE and tx.message == b''): raise BlockChainError('Pos msg is None type. [{},{}]'.format( tx.message_type, tx.message)) txhash, txindex = tx.inputs[0] base_tx = tx_builder.get_tx(txhash) if base_tx is None: print(list(tx_builder.chained_tx.values())) raise BlockChainError('Not found PosBaseTX:{} of {}.'.format( hexlify(txhash).decode(), tx)) input_address, input_coin_id, input_amount = base_tx.outputs[txindex] tx.pos_amount = input_amount output_address, output_coin_id, output_amount = tx.outputs[0] reward = GompertzCurve.calc_block_reward(include_block.height) include_block.bits2target() if input_address != output_address: raise BlockChainError( 'Input address differ from output address. [{}!={}]'.format( input_address, output_address)) elif not (input_coin_id == output_coin_id == 0): raise BlockChainError('Input and output coinID is zero.') elif input_amount + reward != output_amount: raise BlockChainError('Inout amount wrong [{}+{}!={}]'.format( input_amount, reward, output_amount)) elif tx.version != __chain_version__ or tx.message_type != C.MSG_NONE: raise BlockChainError('Not correct tx version or msg_type.') elif base_tx.height is None: raise BlockChainError('Source TX is unconfirmed. {}'.format(base_tx)) elif not (include_block.height > base_tx.height + C.MATURE_HEIGHT): raise BlockChainError( 'Source TX height is too young. [{}>{}+{}]'.format( include_block.height, base_tx.height, C.MATURE_HEIGHT)) elif not (include_block.time == tx.time == tx.deadline - 10800): raise BlockChainError('TX time is wrong 1. [{}={}={}-10800]'.format( include_block.time, tx.time, tx.deadline)) elif not tx.pos_check(include_block.previous_hash, include_block.target_hash): raise BlockChainError('Proof of stake check is failed.')
async def chain_info(request): try: best_height = chain_builder.best_block.height best_block = chain_builder.best_block old_block_height = chain_builder.best_chain[0].height - 1 old_block_hash = chain_builder.get_block_hash(old_block_height).hex() data = {'best': best_block.getinfo()} difficulty = dict() for consensus, ratio in V.BLOCK_CONSENSUSES.items(): name = C.consensus2name[consensus] bits, target = get_bits_by_hash(previous_hash=best_block.hash, consensus=consensus) target = float(target) block_time = round(V.BLOCK_TIME_SPAN / ratio * 100) diff = round(DEFAULT_TARGET / target, 8) bias = get_bias_by_hash(previous_hash=best_block.previous_hash, consensus=consensus) difficulty[name] = { 'number': consensus, 'bits': bits.to_bytes(4, 'big').hex(), 'diff': round(diff, 8), 'bias': round(bias, 8), 'fixed_diff': round(diff / bias, 8), 'hashrate(kh/s)': round((MAX_256_FLOAT / target) / block_time / 1000, 3) } data['mining'] = difficulty data['size'] = best_block.size data['checkpoint'] = { 'height': old_block_height, 'blockhash': old_block_hash } data['money_supply'] = GompertzCurve.calc_total_supply(best_height) data['total_supply'] = GompertzCurve.k if F_ADD_CASHE_INFO: data['cashe'] = { 'get_bits_by_hash': str(get_bits_by_hash.cache_info()), 'get_bias_by_hash': str(get_bias_by_hash.cache_info()) } return utils.json_res(data) except Exception: return utils.error_res()
def create_mining_block(consensus): global mining_address # create proof_tx mining_address = mining_address or V.MINING_ADDRESS or new_key() reward = GompertzCurve.calc_block_reward(previous_block.height + 1) fees = sum(tx.gas_amount * tx.gas_price for tx in unconfirmed_txs) proof_tx = TX( tx={ 'type': C.TX_POW_REWARD, 'inputs': list(), 'outputs': [(mining_address, 0, reward + fees)], 'gas_price': 0, 'gas_amount': 0, 'message_type': C.MSG_PLAIN if V.MINING_MESSAGE else C.MSG_NONE, 'message': V.MINING_MESSAGE if V.MINING_MESSAGE else b'' }) proof_tx.update_time() # create mining block bits, target = get_bits_by_hash(previous_hash=previous_block.hash, consensus=consensus) mining_block = Block( block={ 'merkleroot': b'\xff' * 32, 'time': 0, 'previous_hash': previous_block.hash, 'bits': bits, 'nonce': b'\xff\xff\xff\xff' }) proof_tx.height = previous_block.height + 1 mining_block.height = proof_tx.height mining_block.flag = consensus mining_block.bits2target() mining_block.txs.append(proof_tx) mining_block.txs.extend(unconfirmed_txs) mining_block.update_merkleroot() mining_block.update_time(proof_tx.time) return mining_block
def proof_of_stake(self): global staking_limit limit_deque = deque(maxlen=10) self.event_close.set() while self.event_close.is_set(): # check start mining if previous_block is None or unconfirmed_txs is None or unspents_txs is None: sleep(0.1) continue if len(unspents_txs) == 0: logging.info("No unspents for staking, wait 180s..") sleep(180) continue start = time() # create staking block bits, target = get_bits_by_hash(previous_hash=previous_block.hash, consensus=C.BLOCK_POS) reward = GompertzCurve.calc_block_reward(previous_block.height + 1) staking_block = Block( block={ 'merkleroot': b'\xff' * 32, 'time': 0, 'previous_hash': previous_block.hash, 'bits': bits, 'nonce': b'\xff\xff\xff\xff' }) staking_block.height = previous_block.height + 1 staking_block.flag = C.BLOCK_POS staking_block.bits2target() staking_block.txs.append(None) # Dummy proof tx staking_block.txs.extend(unconfirmed_txs) calculate_nam = 0 for proof_tx in unspents_txs.copy(): address = proof_tx.outputs[0][0] proof_tx.outputs[0] = (address, 0, proof_tx.pos_amount + reward) proof_tx.update_time() calculate_nam += 1 # next check block if previous_block is None or unconfirmed_txs is None or unspents_txs is None: logging.debug("Reset by \"nothing params found\"") sleep(1) break elif previous_block.hash != staking_block.previous_hash: logging.debug("Reset by \"Don't match previous_hash\"") sleep(1) break elif not proof_tx.pos_check( previous_hash=previous_block.hash, pos_target_hash=staking_block.target_hash): continue else: # Staked yay!! proof_tx.height = staking_block.height proof_tx.signature = [ message2signature(proof_tx.b, proof_tx.outputs[0][0]) ] staking_block.txs[0] = proof_tx # Fit block size while staking_block.getsize() > C.SIZE_BLOCK_LIMIT: tx = staking_block.txs.pop() if tx.type == C.TX_FINISH_CONTRACT: staking_block.txs.pop() staking_block.update_time(proof_tx.time) staking_block.update_merkleroot() confirmed_generating_block(staking_block) break else: # check time used = time() - start remain = 1.0 - used max_limit = max(50, int(calculate_nam / max(0.0001, used))) limit_deque.append(int(max_limit * self.power_limit)) staking_limit = sum(limit_deque) // len(limit_deque) if int(time()) % 90 == 0: logging.info("Staking... margin={}% limit={}".format( round(remain * 100, 1), staking_limit)) self.hashrate = (calculate_nam, time()) sleep(max(0.0, remain)) logging.info("Close signal")
def proof_of_capacity(self): dir_path: str = self.config.get('path', os.path.join(V.DB_HOME_DIR, 'plots')) while self.f_enable: # check start mining if previous_block is None or unconfirmed_txs is None: sleep(0.1) continue if not os.path.exists(dir_path): sleep(30) continue s = time() previous_hash = previous_block.hash height = previous_block.height + 1 block_time = int(s - V.BLOCK_GENESIS_TIME) bits, target = get_bits_by_hash(previous_hash=previous_hash, consensus=C.BLOCK_CAP_POS) reward = GompertzCurve.calc_block_reward(height) # start staking by capacity count = 0 for file_name in os.listdir(dir_path): m = optimize_file_name_re.match(file_name) if m is None: continue count += int(m.group(3)) - int(m.group(2)) if count < 1: log.debug("not found plot file, wait 60 sec") sleep(60) continue # let's seek files nonce, work_hash, address = multi_seek(dir=dir_path, previous_hash=previous_hash, target=target.to_bytes( 32, 'little'), time=block_time, worker=os.cpu_count()) if work_hash is None: # return failed => (None, None, err-msg) if int(s) % 300 == 0: log.debug("PoC mining info by \"{}\"".format(address)) else: # return success => (nonce, workhash, address) if previous_block is None or unconfirmed_txs is None: continue if previous_block.hash != previous_hash: continue # Staked by capacity yay!! total_fee = sum(tx.gas_price * tx.gas_amount for tx in unconfirmed_txs) staked_block = Block.from_dict( block={ 'version': 0, # always 0 'previous_hash': previous_hash, 'merkleroot': b'\x00' * 32, 'time': 0, 'bits': bits, 'nonce': nonce, 'height': height, 'flag': C.BLOCK_CAP_POS }) staked_proof_tx = TX.from_dict( tx={ 'type': C.TX_POS_REWARD, 'time': block_time, 'deadline': block_time + 10800, 'gas_price': 0, 'gas_amount': 0, 'outputs': [(address, 0, reward + total_fee)] }) staked_block.txs.append(staked_proof_tx) staked_block.txs.extend(unconfirmed_txs) while staked_block.size > C.SIZE_BLOCK_LIMIT: staked_block.txs.pop() staked_block.update_time(staked_proof_tx.time) staked_block.update_merkleroot() staked_block.work_hash = work_hash signature = sign_message_by_address(raw=staked_block.b, address=address) staked_proof_tx.signature.append(signature) confirmed_generating_block(staked_block) # finish all used_time = time() - s self.hashrate = (count, time()) sleep(max(1 - used_time, 0)) log.info("Close signal")
def proof_of_stake(self): global staking_limit limit_deque = deque(maxlen=10) while self.f_enable: # check start mining if previous_block is None or unconfirmed_txs is None or unspents_txs is None: sleep(0.1) continue if len(unspents_txs) == 0: log.info("No unspents for staking, wait 180s") sleep(180) continue start = time() # create staking block bits, target = get_bits_by_hash(previous_hash=previous_block.hash, consensus=C.BLOCK_COIN_POS) reward = GompertzCurve.calc_block_reward(previous_block.height + 1) staking_block = Block.from_dict( block={ 'version': 0, # always 0 'merkleroot': b'\xff' * 32, 'time': 0, 'previous_hash': previous_block.hash, 'bits': bits, 'nonce': b'\xff\xff\xff\xff' }) staking_block.height = previous_block.height + 1 staking_block.flag = C.BLOCK_COIN_POS staking_block.bits2target() staking_block.txs.append(None) # Dummy proof tx if unconfirmed_txs is None: raise FailedGenerateWarning('unconfirmed_txs is None') staking_block.txs.extend(unconfirmed_txs) calculate_nam = 0 for proof_tx in unspents_txs.copy(): address = proof_tx.outputs[0][0] proof_tx.outputs[0] = (address, 0, proof_tx.pos_amount + reward) proof_tx.update_time() calculate_nam += 1 # next check block if previous_block is None or unconfirmed_txs is None or unspents_txs is None: log.debug("Reset by \"nothing params found\"") sleep(1) break elif previous_block.hash != staking_block.previous_hash: log.debug("Reset by \"Don't match previous_hash\"") sleep(1) break elif not stake_coin_check( tx=proof_tx, previous_hash=previous_block.hash, target_hash=staking_block.target_hash): continue else: # Staked yay!! proof_tx.height = staking_block.height staking_block.txs[0] = proof_tx # Fit block size while staking_block.size > C.SIZE_BLOCK_LIMIT: staking_block.txs.pop() staking_block.update_time(proof_tx.time) staking_block.update_merkleroot() signature = sign_message_by_address(raw=staking_block.b, address=address) proof_tx.signature.append(signature) confirmed_generating_block(staking_block) break else: # check time used = time() - start remain = 1.0 - used max_limit = max(50, int(calculate_nam / max(0.0001, used))) limit_deque.append(int(max_limit * self.power_limit)) staking_limit = sum(limit_deque) // len(limit_deque) if int(time()) % 90 == 0: log.info("Staking... margin={}% limit={}".format( round(remain * 100, 1), staking_limit)) self.hashrate = (calculate_nam, time()) sleep(max(0.0, remain + random() - 0.5)) log.info("Close signal")