Exemple #1
0
    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()
Exemple #2
0
    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
Exemple #3
0
    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
Exemple #4
0
    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()
Exemple #5
0
    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
Exemple #6
0
    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
Exemple #7
0
 def test_getTime(self):
     setDrift()
     time = getTime()
     self.assertIsNotNone(time)
Exemple #8
0
 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
Exemple #9
0
    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