def create(self, chain, blocknumber, prev_blockheaderhash, hashedtransactions, reveal_hash, vote_hash, fee_reward): """ Create a block header based on the parameters :param chain: :param blocknumber: :param prev_blockheaderhash: :param hashedtransactions: :param reveal_hash: :param vote_hash: :param fee_reward: :return: >>> BlockHeader().create(None, 0, b'0', b'0', b'0', b'0', 0.1) is None True >>> b = BlockHeader(); b.create(None, 0, b'0', b'0', b'0', b'0', 0.1); b.epoch 0 >>> b = BlockHeader(); b.create(None, 0, b'0', b'0', b'0', b'0', 0.1); b.epoch # doctest: +SKIP 0 """ self.blocknumber = blocknumber self.timestamp = 0 self.epoch = self.blocknumber // config.dev.blocks_per_epoch if self.blocknumber != 0: self.timestamp = int(ntp.getTime()) if self.timestamp == 0: logger.warning('Failed to get NTP timestamp') return self.prev_blockheaderhash = prev_blockheaderhash self.tx_merkle_root = hashedtransactions self.reveal_hash = reveal_hash self.vote_hash = vote_hash self.fee_reward = fee_reward self.stake_selector = '' self.block_reward = 0 if self.blocknumber != 0: if self.blocknumber == 1: tmp_chain, _ = chain.select_hashchain( last_block_headerhash=chain.block_chain_buffer.get_strongest_headerhash(0), hashchain=chain.hash_chain, blocknumber=self.blocknumber) self.stake_selector = chain.mining_address self.block_reward = self.block_reward_calc() self.headerhash = self.generate_headerhash()
def validate_block_timestamp(self, last_block_timestamp): if last_block_timestamp >= self.blockheader.timestamp: return False curr_time = ntp.getTime() if curr_time == 0: return False max_block_number = int((curr_time - last_block_timestamp) / config.dev.block_creation_seconds) if self.blockheader.blocknumber > max_block_number: return False
def validate_block_timestamp(self, last_block_timestamp): # TODO: Add minimum minting delay if last_block_timestamp >= self.timestamp: return False curr_time = ntp.getTime() if curr_time == 0: return False max_block_number = int((curr_time - last_block_timestamp) / config.dev.block_creation_seconds) if self.blocknumber > max_block_number: return False
def create(self, chain, blocknumber, hashchain_link, prev_blockheaderhash, hashedtransactions, reveal_list, vote_hashes): """ Create a block header based on the parameters :param chain: :param blocknumber: :param hashchain_link: :param prev_blockheaderhash: :param hashedtransactions: :param reveal_list: :param vote_hashes: :return: """ self.blocknumber = blocknumber self.hash = hashchain_link if self.blocknumber == 0: self.timestamp = 0 else: self.timestamp = ntp.getTime() if self.timestamp == 0: logger.warning('Failed to get NTP timestamp') return self.prev_blockheaderhash = prev_blockheaderhash self.tx_merkle_root = hashedtransactions self.reveal_list = reveal_list self.vote_hashes = vote_hashes self.epoch = self.blocknumber // config.dev.blocks_per_epoch if self.blocknumber == 0: self.stake_selector = '' self.block_reward = 0 else: if self.blocknumber == 1: tmp_chain, _ = chain.select_hashchain( last_block_headerhash=chain.block_chain_buffer.get_strongest_headerhash(0), hashchain=chain.hash_chain, blocknumber=self.blocknumber) self.stake_selector = chain.mining_address self.block_reward = self.block_reward_calc() self.headerhash = self.generate_headerhash()
def restart_post_block_logic(self, blocknumber=-1, delay=None): if blocknumber == -1: blocknumber = self.buffered_chain.height + 1 if not delay: last_block = self.buffered_chain.get_block(blocknumber - 1) last_block_timestamp = last_block.timestamp curr_timestamp = int(ntp.getTime()) delay = max( 5, last_block_timestamp + config.dev.minimum_minting_delay - curr_timestamp) self.stop_post_block_logic() self.pos_callLater = reactor.callLater(delay, self.post_block_logic, blocknumber=blocknumber) should_vote = False if blocknumber > 1: stake_list = self.buffered_chain.stake_list_get(blocknumber - 1) if self.buffered_chain.staking_address in stake_list: stake_validator = stake_list[ self.buffered_chain.staking_address] if stake_validator.is_active and not stake_validator.is_banned: should_vote = True else: genesis_block = self.buffered_chain.get_block(0) for genesisBalance in genesis_block.genesis_balance: if genesisBalance.address.encode( ) == self.buffered_chain.staking_address: should_vote = True break if should_vote: vote_delay = max( 0, delay - config.dev.vote_x_seconds_before_next_block) self.vote_callLater = reactor.callLater(vote_delay, self.create_vote_tx, blocknumber=blocknumber - 1) self.pos_blocknum = blocknumber
def create(staking_address: bytes, blocknumber: int, prev_blockheaderhash: bytes, hashedtransactions: bytes, reveal_hash: bytes, fee_reward: int): """ Create a block header based on the parameters >>> BlockHeader.create(bytes(b'someaddress'), 0, b'0', b'0', b'0', 1) is not None True >>> b = BlockHeader.create(bytes(b'someaddress'), 0, b'0', b'0', b'0', 1); b.epoch 0 >>> b = BlockHeader.create(bytes(b'someaddress'), 0, b'0', b'0', b'0', 1); b.epoch 0 """ bh = BlockHeader() bh._data.block_number = blocknumber bh._data.epoch = bh._data.block_number // config.dev.blocks_per_epoch if bh._data.block_number != 0: bh._data.timestamp.seconds = int(ntp.getTime()) if bh._data.timestamp == 0: logger.warning('Failed to get NTP timestamp') return bh._data.hash_header_prev = prev_blockheaderhash bh._data.merkle_root = hashedtransactions bh._data.hash_reveal = reveal_hash bh._data.reward_fee = fee_reward bh._data.stake_selector = b'' bh._data.reward_block = 0 if bh._data.block_number != 0: bh._data.stake_selector = staking_address bh._data.reward_block = bh.block_reward_calc() bh._data.hash_header = bh.generate_headerhash() return bh
def test_getTime(self): setDrift() time = getTime() self.assertIsNotNone(time)
def isSynced(self, block_timestamp) -> bool: if block_timestamp + config.dev.minimum_minting_delay > ntp.getTime(): self.update_node_state(ESyncState.synced) return True return False
def validate_block(self, chain): # check validity of new block.. """ block validation :param chain: :return: """ b = self.blockheader last_blocknum = b.blocknumber - 1 tmp_last_block = chain.block_chain_buffer.get_block_n(last_blocknum) curr_timestamp = ntp.getTime() if b.timestamp <= tmp_last_block.blockheader.timestamp: logger.warning('BLOCK timestamp is less than prev block timestamp') logger.warning('block timestamp %s ', b.timestamp) logger.warning('must be greater than %s', tmp_last_block.blockheader.timestamp) return False if b.generate_headerhash() != b.headerhash: logger.warning('Headerhash false for block: failed validation') return False if tmp_last_block.blockheader.timestamp + config.dev.minimum_minting_delay > b.timestamp: logger.warning( 'BLOCK created without waiting for minimum minting delay') logger.warning('prev_block timestamp %s ', tmp_last_block.blockheader.timestamp) logger.warning('current_block timestamp %s ', b.timestamp) return False if tmp_last_block.blockheader.headerhash != b.prev_blockheaderhash: logger.warning('Headerhash not in sequence: failed validation') return False if tmp_last_block.blockheader.blocknumber != b.blocknumber - 1: logger.warning('Block numbers out of sequence: failed validation') return False if len(self.transactions) == 0: logger.warning('BLOCK : There must be atleast 1 txn') return False coinbase_tx = self.transactions[0] try: if coinbase_tx.subtype != TX_SUBTYPE_COINBASE: logger.warning('BLOCK : First txn must be a COINBASE txn') return False except Exception as e: logger.exception(e) return False sv_list = chain.block_chain_buffer.stake_list_get( self.blockheader.blocknumber) if coinbase_tx.txto != self.blockheader.stake_selector: logger.info('Non matching txto and stake_selector') logger.info('txto: %s stake_selector %s', coinbase_tx.txfrom, self.blockheader.stake_selector) return False if coinbase_tx.amount != self.blockheader.block_reward + self.blockheader.fee_reward: logger.info('Block_reward doesnt match') logger.info('Found: %s', coinbase_tx.amount) logger.info( 'Expected: %s', self.blockheader.block_reward + self.blockheader.fee_reward) logger.info('block_reward: %s', self.blockheader.block_reward) logger.info('fee_reward: %s', self.blockheader.fee_reward) return False if b.timestamp == 0 and b.blocknumber > 0: logger.warning('Invalid block timestamp ') return False if b.block_reward != b.block_reward_calc(): logger.warning( 'Block reward incorrect for block: failed validation') return False if b.epoch != b.blocknumber // config.dev.blocks_per_epoch: logger.warning('Epoch incorrect for block: failed validation') return False if b.blocknumber == 1: x = 0 for tx in self.transactions: if tx.subtype == TX_SUBTYPE_STAKE: if tx.txfrom == b.stake_selector: x = 1 reveal_hash, vote_hash = chain.select_hashchain( chain.m_blockchain[-1].blockheader.headerhash, self.transactions[0].txto, tx.hash, blocknumber=1) if sha256(b.reveal_hash) != reveal_hash: logger.warning( 'reveal_hash does not hash correctly to terminator: failed validation' ) return False if sha256(b.vote_hash) != vote_hash: logger.warning( 'vote_hash does not hash correctly to terminator: failed validation' ) return False if x != 1: logger.warning( 'Stake selector not in block.stake: failed validation') return False else: # we look in stake_list for the hash terminator and hash to it.. stake_validators_list = chain.block_chain_buffer.get_stake_validators_list( self.blockheader.blocknumber) if self.transactions[0].txto not in stake_validators_list.sv_list: logger.warning( 'Stake selector not in stake_list for this epoch..') return False if not stake_validators_list.validate_hash( b.reveal_hash, b.blocknumber, config.dev.hashchain_nums - 1, self.transactions[0].txto): logger.warning( 'Supplied hash does not iterate to terminator: failed validation' ) return False target_chain = select_target_hashchain(b.prev_blockheaderhash) if not stake_validators_list.validate_hash( b.vote_hash, b.blocknumber, target_chain, self.transactions[0].txto): logger.warning('Not all the reveal_hashes are valid..') return False if not self._validate_tx_in_block(chain): logger.warning( 'Block validate_tx_in_block error: failed validation') return False return True