Exemplo n.º 1
0
class Block(object):
    @staticmethod
    def isHashPresent(txhash, buffer, blocknumber):
        if not buffer:
            return False

        min_blocknum = min(buffer)
        max_blocknum = min(blocknumber - 1, max(buffer))

        for blocknum in range(min_blocknum, max_blocknum + 1):
            if txhash in buffer[blocknum]:
                return True

        return False

    def create(self, chain, hashchain_link, reveal_list=None, vote_hashes=None, last_block_number=-1):
        # FIXME: probably this should turn into a constructor
        if not reveal_list:
            reveal_list = []
        if not vote_hashes:
            vote_hashes = []

        data = None
        if last_block_number == -1:
            data = chain.block_chain_buffer.get_last_block()  # m_get_last_block()
        else:
            data = chain.block_chain_buffer.get_block_n(last_block_number)

        last_block_number = data.blockheader.blocknumber
        prev_blockheaderhash = data.blockheader.headerhash

        hashedtransactions = []
        self.transactions = [None]

        for tx in chain.transaction_pool:
            hashedtransactions.append(tx.txhash)
            self.transactions.append(tx)  # copy memory rather than sym link

        if not hashedtransactions:
            hashedtransactions = sha256('')

        hashedtransactions = merkle_tx_hash(hashedtransactions)

        self.blockheader = BlockHeader()
        self.blockheader.create(chain=chain,
                                blocknumber=last_block_number + 1,
                                reveal_list=reveal_list,
                                vote_hashes=vote_hashes,
                                hashchain_link=hashchain_link,
                                prev_blockheaderhash=prev_blockheaderhash,
                                hashedtransactions=hashedtransactions)

        coinbase_tx = transaction.CoinBase().create(self.blockheader.block_reward, self.blockheader.headerhash,
                                                    chain.my[0][1])
        self.transactions[0] = coinbase_tx
        coinbase_tx.nonce = chain.block_chain_buffer.get_stxn_state(last_block_number + 1, chain.mining_address)[0] + 1

    def json_to_block(self, json_block):
        self.blockheader = BlockHeader()
        self.blockheader.json_to_blockheader(json_block['blockheader'])

        transactions = json_block['transactions']
        self.transactions = []
        for tx in transactions:
            self.transactions.append(Transaction.get_tx_obj(tx))

        if self.blockheader.blocknumber == 0:
            self.state = json_block['state']
            self.stake_list = json_block['stake_list']

    @staticmethod
    def from_json(json_block):
        """
        Constructor a block from a json string
        :param json_block: a block serialized as a json string
        :return: A block
        """
        tmp_block = Block()
        tmp_block.json_to_block(json.loads(json_block))
        return tmp_block

    def validate_tx_in_block(self):
        # Validating coinbase txn
        coinbase_txn = self.transactions[0]
        valid = coinbase_txn.validate_tx(block_headerhash=self.blockheader.headerhash)

        if not valid:
            logger.warning('coinbase txn in block failed')
            return False

        for tx_num in range(1, len(self.transactions)):
            tx = self.transactions[tx_num]
            if tx.validate_tx() is False:
                logger.warning('invalid tx in block')
                logger.warning('subtype: %s txhash: %s txfrom: %s', tx.subtype, tx.txhash, tx.txfrom)
                return False

        return True

    def validate_block(self, chain, verify_block_reveal_list=True):  # check validity of new block..
        """
        block validation
        :param chain:
        :param verify_block_reveal_list:
        :return:
        """
        b = self.blockheader
        last_blocknum = b.blocknumber - 1

        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 != transaction.TX_SUBTYPE_COINBASE:
                logger.warning('BLOCK : First txn must be a COINBASE txn')
                return False
        except Exception as e:
            logger.exception(e)
            return False

        if coinbase_tx.txfrom != 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:
            logger.info('Block_reward doesnt match')
            logger.info('Found: %d Expected: %d', coinbase_tx.amount, self.blockheader.block_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 == transaction.TX_SUBTYPE_STAKE:
                    if tx.txfrom == b.stake_selector:
                        x = 1
                        hash, _ = chain.select_hashchain(chain.m_blockchain[-1].blockheader.headerhash,
                                                         b.stake_selector,
                                                         tx.hash, blocknumber=1)

                        if sha256(b.hash) != hash or hash not in tx.hash:
                            logger.warning('Hashchain_link 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..
            found = False
            terminator = sha256(b.hash)
            for _ in range(b.blocknumber - (b.epoch * config.dev.blocks_per_epoch) + 1):
                terminator = sha256(terminator)
            tmp_stake_list = chain.state.stake_list_get()
            for st in tmp_stake_list:
                if st[0] == b.stake_selector:
                    found = True

                    if terminator != st[1][-1]:
                        logger.warning('Supplied hash does not iterate to terminator: failed validation')
                        return False

            if not found:
                logger.warning('Stake selector not in stake_list for this epoch..')
                return False

            if len(b.reveal_list) != len(set(b.reveal_list)):
                logger.warning('Repetition in reveal_list')
                return False

            if verify_block_reveal_list:
                i = 0
                for r in b.reveal_list:
                    t = sha256(r)
                    for _ in range(b.blocknumber - (
                                b.epoch * config.dev.blocks_per_epoch) + 1):  # +1 as reveal has 1 extra hash
                        t = sha256(t)
                    for s in tmp_stake_list:
                        if t == s[1][-1]:
                            i += 1

                if i != len(b.reveal_list):
                    logger.warning('Not all the reveal_hashes are valid..')
                    return False

                i = 0
                target_chain = select_target_hashchain(b.prev_blockheaderhash)
                for r in b.vote_hashes:
                    t = sha256(r)
                    for x in range(b.blocknumber - (b.epoch * config.dev.blocks_per_epoch)):
                        t = sha256(t)
                    for s in tmp_stake_list:
                        if t == s[1][target_chain]:
                            i += 1

                if i != len(b.vote_hashes):
                    logger.warning('Not all the reveal_hashes are valid..')
                    return False

        if b.generate_headerhash() != b.headerhash:
            logger.warning('Headerhash false for block: failed validation')
            return False

        tmp_last_block = chain.block_chain_buffer.get_block_n(last_blocknum)

        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 not self.validate_tx_in_block():
            logger.warning('Block validate_tx_in_block error: failed validation')
            return False

        if len(self.transactions) == 1:
            txhashes = sha256('')
        else:
            txhashes = []
            for tx_num in range(1, len(self.transactions)):
                tx = self.transactions[tx_num]
                txhashes.append(tx.txhash)

        if merkle_tx_hash(txhashes) != b.tx_merkle_root:
            logger.warning('Block hashedtransactions error: failed validation')
            return False

        return True

    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
Exemplo n.º 2
0
class Block(object):
    def __init__(self):
        self.blockheader = None
        self.transactions = None
        self.duplicate_transactions = None

        self.state = None
        self.stake_list = None

    def create(self, chain, reveal_hash, vote_hash, last_block_number=-1):
        # FIXME: probably this should turn into a constructor
        reveal_hash = reveal_hash
        vote_hash = vote_hash

        data = None
        if last_block_number == -1:
            data = chain.block_chain_buffer.get_last_block(
            )  # m_get_last_block()
        else:
            data = chain.block_chain_buffer.get_block_n(last_block_number)

        last_block_number = data.blockheader.blocknumber
        prev_blockheaderhash = data.blockheader.headerhash

        hashedtransactions = []
        self.transactions = [None]
        fee_reward = 0

        for tx in chain.transaction_pool:
            if tx.subtype == TX_SUBTYPE_TX:
                fee_reward += tx.fee
            hashedtransactions.append(tx.txhash)
            self.transactions.append(tx)  # copy memory rather than sym link

        self.duplicate_transactions = []

        for tx in chain.duplicate_tx_pool:
            self.duplicate_transactions.append(chain.duplicate_tx_pool[tx])

        if not hashedtransactions:
            hashedtransactions = [sha256('')]

        hashedtransactions = merkle_tx_hash(hashedtransactions)

        self.blockheader = BlockHeader()
        self.blockheader.create(chain=chain,
                                blocknumber=last_block_number + 1,
                                reveal_hash=reveal_hash,
                                vote_hash=vote_hash,
                                prev_blockheaderhash=prev_blockheaderhash,
                                hashedtransactions=hashedtransactions,
                                fee_reward=fee_reward)

        coinbase_tx = CoinBase().create(
            self.blockheader,
            chain.block_chain_buffer.get_slave_xmss(last_block_number + 1))
        # coinbase_tx = CoinBase().create(self.blockheader.block_reward + self.blockheader.fee_reward,
        #                                            self.blockheader.headerhash,
        #                                            chain.wallet.address_bundle[0].xmss.get_address(),
        #                                            chain.block_chain_buffer.get_slave_xmss(last_block_number + 1))

        self.transactions[0] = coinbase_tx
        sv_list = chain.block_chain_buffer.get_stake_validators_list(
            last_block_number + 1).sv_list
        coinbase_tx.nonce = sv_list[chain.mining_address].nonce + 1

    def validate_block(self, chain):  # check validity of new block..
        """
        block validation
        :param chain:
        :return:
        """

        try:
            blk_header = self.blockheader
            last_blocknum = blk_header.blocknumber - 1
            last_block = chain.block_chain_buffer.get_block_n(last_blocknum)

            if not self.blockheader.validate(last_block.blockheader):
                return False

            if len(self.transactions) == 0:
                logger.warning('BLOCK : There must be atleast 1 txn')
                return False

            coinbase_tx = self.transactions[0]

            if coinbase_tx.subtype != TX_SUBTYPE_COINBASE:
                logger.warning('BLOCK : First txn must be a COINBASE txn')
                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 blk_header.blocknumber == 1:
                found = False
                for tx in self.transactions:
                    if tx.subtype == TX_SUBTYPE_STAKE:
                        if tx.txfrom == blk_header.stake_selector:
                            found = True
                            reveal_hash, vote_hash = chain.select_hashchain(
                                chain.m_blockchain[-1].blockheader.headerhash,
                                self.transactions[0].txto,
                                tx.hash,
                                blocknumber=1)

                            if sha256(blk_header.reveal_hash) != reveal_hash:
                                logger.warning(
                                    'reveal_hash does not hash correctly to terminator: failed validation'
                                )
                                return False

                if not found:
                    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(
                        blk_header.reveal_hash, blk_header.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(
                    blk_header.prev_blockheaderhash)

                if not stake_validators_list.validate_hash(
                        blk_header.vote_hash, blk_header.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

        except Exception as e:
            logger.exception(e)
            return False

        return True

    def _validate_tx_in_block(self, chain):
        # Validating coinbase txn
        coinbase_txn = self.transactions[0]
        valid = coinbase_txn.validate_tx(chain=chain,
                                         blockheader=self.blockheader)

        if not valid:
            logger.warning('coinbase txn in block failed')
            return False

        for tx_num in range(1, len(self.transactions)):
            tx = self.transactions[tx_num]
            if not tx.validate_tx():
                logger.warning('invalid tx in block')
                logger.warning('subtype: %s txhash: %s txfrom: %s', tx.subtype,
                               tx.txhash, tx.txfrom)
                return False

        for tx in self.duplicate_transactions:
            if not tx.validate_tx():
                logger.warning('invalid duplicate tx in block')
                logger.warning('txhash: %s tx_stake_selector: %s',
                               tx.get_message_hash(), tx.coinbase1.txto)
                return False

        return True

    @staticmethod
    def from_json(json_block):
        """
        Constructor a block from a json string
        :param json_block: a block serialized as a json string
        :return: A block
        """
        tmp_block = Block()
        json_block = json.loads(json_block)
        tmp_block.blockheader = BlockHeader.from_json(
            json_block['blockheader'])

        if tmp_block.blockheader.blocknumber == 0:
            tmp_block.state = json_block['state']
            tmp_block.stake_list = json_block['stake_list']

        json_transactions = json_block['transactions']
        json_duplicate_transactions = json_block['duplicate_transactions']

        tmp_block.transactions = [
            Transaction.from_txdict(tx) for tx in json_transactions
        ]
        tmp_block.duplicate_transactions = [
            DuplicateTransaction().from_txdict(tx)
            for tx in json_duplicate_transactions
        ]

        return tmp_block
Exemplo n.º 3
0
class Block(object):
    @staticmethod
    def isHashPresent(txhash, buffer, blocknumber):
        """
        :param txhash:
        :type txhash:
        :param buffer:
        :type buffer:
        :param blocknumber:
        :type blocknumber:
        :return:
        :rtype:
        >>> Block.isHashPresent(None, None, None)
        False
        """
        if not buffer:
            return False

        min_blocknum = min(buffer)
        max_blocknum = min(blocknumber - 1, max(buffer))

        for blocknum in range(min_blocknum, max_blocknum + 1):
            if txhash in buffer[blocknum]:
                return True

        return False

    def create(self, chain, reveal_hash, vote_hash, last_block_number=-1):
        # FIXME: probably this should turn into a constructor
        reveal_hash = reveal_hash
        vote_hash = vote_hash

        data = None
        if last_block_number == -1:
            data = chain.block_chain_buffer.get_last_block(
            )  # m_get_last_block()
        else:
            data = chain.block_chain_buffer.get_block_n(last_block_number)

        last_block_number = data.blockheader.blocknumber
        prev_blockheaderhash = data.blockheader.headerhash

        hashedtransactions = []
        self.transactions = [None]
        fee_reward = 0

        for tx in chain.transaction_pool:
            if tx.subtype == TX_SUBTYPE_TX:
                fee_reward += tx.fee
            hashedtransactions.append(tx.txhash)
            self.transactions.append(tx)  # copy memory rather than sym link

        self.duplicate_transactions = []

        for tx in chain.duplicate_tx_pool:
            self.duplicate_transactions.append(chain.duplicate_tx_pool[tx])

        if not hashedtransactions:
            hashedtransactions = [sha256('')]

        hashedtransactions = merkle_tx_hash(hashedtransactions)

        self.blockheader = BlockHeader()
        self.blockheader.create(chain=chain,
                                blocknumber=last_block_number + 1,
                                reveal_hash=reveal_hash,
                                vote_hash=vote_hash,
                                prev_blockheaderhash=prev_blockheaderhash,
                                hashedtransactions=hashedtransactions,
                                fee_reward=fee_reward)

        coinbase_tx = CoinBase().create(
            self.blockheader,
            chain.block_chain_buffer.get_slave_xmss(last_block_number + 1))
        #coinbase_tx = CoinBase().create(self.blockheader.block_reward + self.blockheader.fee_reward,
        #                                            self.blockheader.headerhash,
        #                                            chain.wallet.address_bundle[0].xmss.get_address(),
        #                                            chain.block_chain_buffer.get_slave_xmss(last_block_number + 1))

        self.transactions[0] = coinbase_tx
        sv_list = chain.block_chain_buffer.get_stake_validators_list(
            last_block_number + 1).sv_list
        coinbase_tx.nonce = sv_list[chain.mining_address].nonce + 1

    def json_to_block(self, json_block):
        self.blockheader = BlockHeader()
        self.blockheader.json_to_blockheader(json_block['blockheader'])

        transactions = json_block['transactions']
        self.transactions = []
        for tx in transactions:
            self.transactions.append(Transaction.from_txdict(tx))

        duplicate_transactions = json_block['duplicate_transactions']
        self.duplicate_transactions = []
        for tx in duplicate_transactions:
            self.duplicate_transactions.append(
                DuplicateTransaction().from_txdict(tx))

        if self.blockheader.blocknumber == 0:
            self.state = json_block['state']
            self.stake_list = json_block['stake_list']

    @staticmethod
    def from_json(json_block):
        """
        Constructor a block from a json string
        :param json_block: a block serialized as a json string
        :return: A block
        """
        tmp_block = Block()
        tmp_block.json_to_block(json.loads(json_block))
        return tmp_block

    def _validate_tx_in_block(self, chain):
        # Validating coinbase txn
        coinbase_txn = self.transactions[0]
        valid = coinbase_txn.validate_tx(chain=chain,
                                         blockheader=self.blockheader)

        if not valid:
            logger.warning('coinbase txn in block failed')
            return False

        for tx_num in range(1, len(self.transactions)):
            tx = self.transactions[tx_num]
            if not tx.validate_tx():
                logger.warning('invalid tx in block')
                logger.warning('subtype: %s txhash: %s txfrom: %s', tx.subtype,
                               tx.txhash, tx.txfrom)
                return False

        for tx in self.duplicate_transactions:
            if not tx.validate_tx():
                logger.warning('invalid duplicate tx in block')
                logger.warning('txhash: %s tx_stake_selector: %s',
                               tx.get_message_hash(), tx.coinbase1.txto)
                return False

        return True

    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

    def validate_block_timestamp(self, last_block_timestamp):
        # TODO: Add minimum minting delay
        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