def check_block(block: Block): # 挿入前にBlockの正当性チェック if block.f_orphan: raise BlockChainError('Block is orphan.') elif len(block.txs) == 0: raise BlockChainError('Block don\'t have any txs.') elif block.getsize() > C.SIZE_BLOCK_LIMIT: raise BlockChainError('Block size is too large [{}b>{}b]'.format(block.getsize(), C.SIZE_BLOCK_LIMIT)) bits = get_bits_by_hash(previous_hash=block.previous_hash, consensus=block.flag)[0] if block.bits != bits: raise BlockChainError('Block bits differ from calc. [{}!={}]'.format(block.bits, bits)) logging.debug("Checked block {}.".format(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")