Exemple #1
0
    def rollback_tx_metadata(state: State, block, batch):
        fee_reward = 0
        for protobuf_txn in block.transactions:
            txn = Transaction.from_pbdata(protobuf_txn)
            fee_reward += txn.fee
            TransactionMetadata.remove_tx_metadata(state, txn, batch)

        txn = Transaction.from_pbdata(block.transactions[0])  # Coinbase Transaction
        state._update_total_coin_supply(fee_reward - txn.amount, batch)
        LastTransactions._remove_last_tx(state, block, batch)
Exemple #2
0
    def validate(self, chain_manager, future_blocks: OrderedDict) -> bool:
        if chain_manager.get_block_is_duplicate(self):
            logger.warning('Duplicate Block #%s %s', self.block_number,
                           bin2hstr(self.headerhash))
            return False

        parent_block = chain_manager.get_block(self.prev_headerhash)

        # If parent block not found in state, then check if its in the future block list
        if not parent_block:
            try:
                parent_block = future_blocks[self.prev_headerhash]
            except KeyError:
                logger.warning('Parent block not found')
                logger.warning('Parent block headerhash %s',
                               bin2hstr(self.prev_headerhash))
                return False

        if not self._validate_parent_child_relation(parent_block):
            logger.warning('Failed to validate blocks parent child relation')
            return False

        if not chain_manager.validate_mining_nonce(self.blockheader):
            logger.warning('Failed PoW Validation')
            return False

        fee_reward = 0
        for index in range(1, len(self.transactions)):
            fee_reward += self.transactions[index].fee

        if len(self.transactions) == 0:
            return False

        try:
            coinbase_txn = Transaction.from_pbdata(self.transactions[0])
            coinbase_amount = coinbase_txn.amount

            if not coinbase_txn.validate_extended(self.block_number):
                return False

        except Exception as e:
            logger.warning('Exception %s', e)
            return False

        hashedtransactions = []

        for tx in self.transactions:
            tx = Transaction.from_pbdata(tx)
            hashedtransactions.append(tx.txhash)

        if not self.blockheader.validate(fee_reward, coinbase_amount,
                                         merkle_tx_hash(hashedtransactions)):
            return False

        return True
Exemple #3
0
def tx_push(ctx, txblob):
    """
    Sends a signed transaction blob to a node
    """
    tx = None
    try:
        txbin = parse_hexblob(txblob)
        pbdata = qrl_pb2.Transaction()
        pbdata.ParseFromString(txbin)
        tx = Transaction.from_pbdata(pbdata)
    except Exception as e:
        click.echo("tx blob is not valid")
        quit(1)

    tmp_json = tx.to_json()
    # FIXME: binary fields are represented in base64. Improve output
    print(tmp_json)
    if len(tx.signature) == 0:
        click.echo('Signature missing')
        quit(1)

    stub = ctx.obj.get_stub_public_api()
    pushTransactionReq = qrl_pb2.PushTransactionReq(
        transaction_signed=tx.pbdata)
    pushTransactionResp = stub.PushTransaction(pushTransactionReq,
                                               timeout=CONNECTION_TIMEOUT)
    print(pushTransactionResp.error_code)
Exemple #4
0
    def PushTransaction(self, request: qrl_pb2.PushTransactionReq,
                        context) -> qrl_pb2.PushTransactionResp:
        logger.debug("[PublicAPI] PushTransaction")
        answer = qrl_pb2.PushTransactionResp()

        try:
            tx = Transaction.from_pbdata(request.transaction_signed)
            tx.update_txhash()

            # FIXME: Full validation takes too much time. At least verify there is a signature
            # the validation happens later in the tx pool
            if len(tx.signature) > 1000:
                self.qrlnode.submit_send_tx(tx)
                answer.error_code = qrl_pb2.PushTransactionResp.SUBMITTED
                answer.tx_hash = tx.txhash
            else:
                answer.error_description = 'Signature too short'
                answer.error_code = qrl_pb2.PushTransactionResp.VALIDATION_FAILED

        except Exception as e:
            error_str = traceback.format_exception(None, e, e.__traceback__)
            answer.error_description = str(''.join(error_str))
            answer.error_code = qrl_pb2.PushTransactionResp.ERROR

        return answer
Exemple #5
0
 def get_tx_metadata(state: State, txhash: bytes):
     try:
         tx_metadata = TransactionMetadata.deserialize(state._db.get_raw(txhash))
         data, block_number = tx_metadata.transaction, tx_metadata.block_number
         return Transaction.from_pbdata(data), block_number
     except Exception:
         return None
Exemple #6
0
    def apply_state_changes(self, address_txn) -> bool:
        coinbase_tx = Transaction.from_pbdata(self.transactions[0])

        if not coinbase_tx.validate_extended(self.block_number):
            logger.warning('Coinbase transaction failed')
            return False

        coinbase_tx.apply_state_changes(address_txn)

        len_transactions = len(self.transactions)
        for tx_idx in range(1, len_transactions):
            tx = Transaction.from_pbdata(self.transactions[tx_idx])

            if isinstance(tx, CoinBase):
                logger.warning('Found another coinbase transaction')
                return False

            if not tx.validate():
                return False

            addr_from_pk_state = address_txn[tx.addr_from]
            addr_from_pk = Transaction.get_slave(tx)
            if addr_from_pk:
                addr_from_pk_state = address_txn[addr_from_pk]

            if not tx.validate_extended(address_txn[tx.addr_from],
                                        addr_from_pk_state):
                return False

            expected_nonce = addr_from_pk_state.nonce + 1

            if tx.nonce != expected_nonce:
                logger.warning('nonce incorrect, invalid tx')
                logger.warning('subtype: %s', tx.type)
                logger.warning('%s actual: %s expected: %s', tx.addr_from,
                               tx.nonce, expected_nonce)
                return False

            if addr_from_pk_state.ots_key_reuse(tx.ots_key):
                logger.warning('pubkey reuse detected: invalid tx %s',
                               bin2hstr(tx.txhash))
                logger.warning('subtype: %s', tx.type)
                return False

            tx.apply_state_changes(address_txn)

        return True
Exemple #7
0
    def update_tx_metadata(state: State, block, batch) -> bool:
        fee_reward = 0

        for protobuf_txn in block.transactions:
            txn = Transaction.from_pbdata(protobuf_txn)
            fee_reward += txn.fee
            if not TransactionMetadata.put_tx_metadata(state,
                                                       txn,
                                                       block.block_number,
                                                       block.timestamp,
                                                       batch):
                return False

        txn = Transaction.from_pbdata(block.transactions[0])  # Coinbase Transaction
        state._update_total_coin_supply(txn.amount - fee_reward, batch)
        LastTransactions._update_last_tx(state, block, batch)

        return True
Exemple #8
0
 def test_update_mining_address(self):
     self.block.update_mining_address(dev_config=config.dev, mining_address=bob.address)
     coinbase_tx = Transaction.from_pbdata(self.block.transactions[0])
     self.assertTrue(isinstance(coinbase_tx, CoinBase))
     self.assertEqual(coinbase_tx.addr_to, bob.address)
     hashedtransactions = []
     for tx in self.block.transactions:
         hashedtransactions.append(tx.transaction_hash)
     self.assertEqual(self.block.blockheader.tx_merkle_root, merkle_tx_hash(hashedtransactions))
Exemple #9
0
    def rollback_tx_metadata(self, block, batch):
        fee_reward = 0
        for protobuf_txn in block.transactions:
            txn = Transaction.from_pbdata(protobuf_txn)
            fee_reward += txn.fee
            self.remove_tx_metadata(txn, batch)
            # FIXME: Being updated without batch, need to fix,
            if isinstance(txn, TransferTokenTransaction):
                self.remove_transfer_token_metadata(txn)
            elif isinstance(txn, TokenTransaction):
                self.remove_token_metadata(txn)
            self._decrease_txn_count(self.get_txn_count(txn.addr_from),
                                     txn.addr_from)

        txn = Transaction.from_pbdata(
            block.transactions[0])  # Coinbase Transaction
        self._update_total_coin_supply(fee_reward - txn.amount)
        self._remove_last_tx(block, batch)
Exemple #10
0
    def update_mining_address(self, dev_config: DevConfig, mining_address: bytes):
        coinbase_tx = Transaction.from_pbdata(self.transactions[0])
        coinbase_tx.update_mining_address(mining_address)
        hashedtransactions = []

        for tx in self.transactions:
            hashedtransactions.append(tx.transaction_hash)

        self.blockheader.update_merkle_root(dev_config, merkle_tx_hash(hashedtransactions))

        self._data.header.MergeFrom(self.blockheader.pbdata)
Exemple #11
0
    def update_tx_metadata(self, block, batch):
        fee_reward = 0
        # TODO (cyyber): Move To State Cache, instead of writing directly
        for protobuf_txn in block.transactions:
            txn = Transaction.from_pbdata(protobuf_txn)
            fee_reward += txn.fee
            self.put_tx_metadata(txn, block.block_number, block.timestamp,
                                 batch)
            # FIXME: Being updated without batch, need to fix,
            if isinstance(txn, TransferTokenTransaction):
                self.update_token_metadata(txn)
            elif isinstance(txn, TokenTransaction):
                self.create_token_metadata(txn)
            self._increase_txn_count(self.get_txn_count(txn.addr_from),
                                     txn.addr_from)

        txn = Transaction.from_pbdata(
            block.transactions[0])  # Coinbase Transaction
        self._update_total_coin_supply(txn.amount - fee_reward)
        self._update_last_tx(block, batch)
Exemple #12
0
    def prepare_address_list(block) -> set:
        addresses = set()
        for proto_tx in block.transactions:
            tx = Transaction.from_pbdata(proto_tx)
            tx.set_affected_address(addresses)

        for genesis_balance in GenesisBlock().genesis_balance:
            bytes_addr = genesis_balance.address
            if bytes_addr not in addresses:
                addresses.add(bytes_addr)

        return addresses
Exemple #13
0
    def _remove_last_tx(self, block, batch):
        if len(block.transactions) == 0:
            return

        try:
            last_txn = LastTransactions.deserialize(
                self._db.get_raw(b'last_txn'))
        except:  # noqa
            return

        for protobuf_txn in block.transactions:
            txn = Transaction.from_pbdata(protobuf_txn)
            i = 0
            while i < len(last_txn.tx_metadata):
                tx = Transaction.from_pbdata(
                    last_txn.tx_metadata[i].transaction)
                if txn.txhash == tx.txhash:
                    del last_txn.tx_metadata[i]
                    break
                i += 1

        self._db.put_raw(b'last_txn', last_txn.serialize(), batch)
Exemple #14
0
def get_genesis_with_only_coin_base_txn(coin_base_reward_addr, dev_config):
    g = GenesisBlock()

    coin_base_tx = Transaction.from_pbdata(g.transactions[0])
    coin_base_tx.update_mining_address(coin_base_reward_addr)

    # Remove all other transaction except CoinBase txn
    del g.transactions[:]

    g.pbdata.transactions.extend([coin_base_tx.pbdata])
    g.blockheader.generate_headerhash(dev_config)

    return g
Exemple #15
0
    def _remove_block_from_mainchain(self, block: Block,
                                     latest_block_number: int, batch):
        addresses_set = self._state.prepare_address_list(block)
        addresses_state = self._state.get_state_mainchain(addresses_set)
        for tx_idx in range(len(block.transactions) - 1, -1, -1):
            tx = Transaction.from_pbdata(block.transactions[tx_idx])
            tx.revert_state_changes(addresses_state, self)

        self.tx_pool.add_tx_from_block_to_pool(block, latest_block_number)
        self._state.update_mainchain_height(block.block_number - 1, batch)
        self._state.rollback_tx_metadata(block, batch)
        self._state.remove_blocknumber_mapping(block.block_number, batch)
        self._state.put_addresses_state(addresses_state, batch)
Exemple #16
0
    def get_last_txs(self):
        try:
            last_txn = LastTransactions.deserialize(
                self._db.get_raw(b'last_txn'))
        except:  # noqa
            return []

        txs = []
        for tx_metadata in last_txn.tx_metadata:
            data = tx_metadata.transaction
            tx = Transaction.from_pbdata(data)
            txs.append(tx)

        return txs
Exemple #17
0
 def add_tx_from_block_to_pool(self, block: Block, current_block_number):
     """
     Move all transactions from block to transaction pool.
     :param block:
     :return:
     """
     for protobuf_tx in block.transactions[1:]:
         if not self.add_tx_to_pool(Transaction.from_pbdata(protobuf_tx),
                                    current_block_number):
             logger.warning(
                 'Failed to Add transaction into transaction pool')
             logger.warning('Block #%s %s', block.block_number,
                            bin2hstr(block.headerhash))
             return
Exemple #18
0
 def test_update_mining_address(self):
     alice_xmss = get_alice_xmss()
     bob_xmss = get_bob_xmss()
     block = Block.create(block_number=5,
                          prev_headerhash=bytes(sha2_256(b'test')),
                          prev_timestamp=10,
                          transactions=[],
                          miner_address=alice_xmss.address)
     block.update_mining_address(mining_address=bob_xmss.address)
     coinbase_tx = Transaction.from_pbdata(block.transactions[0])
     self.assertTrue(isinstance(coinbase_tx, CoinBase))
     self.assertEqual(coinbase_tx.addr_to, bob_xmss.address)
     hashedtransactions = []
     for tx in block.transactions:
         hashedtransactions.append(tx.transaction_hash)
     self.assertEqual(block.blockheader.tx_merkle_root,
                      merkle_tx_hash(hashedtransactions))
    def get_last_txs(state: State):
        try:
            last_txn = LastTransactions.deserialize(
                state._db.get_raw(b'last_txn'))
        except KeyError:
            return []
        except Exception as e:  # noqa
            logger.warning("[get_last_txs] Exception during call %s", e)
            return []

        txs = []
        for tx_metadata in last_txn.tx_metadata:
            data = tx_metadata.transaction
            tx = Transaction.from_pbdata(data)
            txs.append(tx)

        return txs
Exemple #20
0
def tx_inspect(ctx, txblob):
    """
    Inspected a transaction blob
    """
    tx = None
    try:
        txbin = parse_hexblob(txblob)
        pbdata = qrl_pb2.Transaction()
        pbdata.ParseFromString(txbin)
        tx = Transaction.from_pbdata(pbdata)
    except Exception as e:
        click.echo("tx blob is not valid")
        quit(1)

    tmp_json = tx.to_json()
    # FIXME: binary fields are represented in base64. Improve output
    print(tmp_json)
Exemple #21
0
def gen_blocks(block_count, state, miner_address):
    blocks = []
    block = None
    with mock.patch('qrl.core.misc.ntp.getTime') as time_mock:
        time_mock.return_value = 1615270948
        addresses_state = dict()
        for i in range(0, block_count):
            if i == 0:
                block = GenesisBlock()
                for genesis_balance in GenesisBlock().genesis_balance:
                    bytes_addr = genesis_balance.address
                    addresses_state[bytes_addr] = AddressState.get_default(
                        bytes_addr)
                    addresses_state[
                        bytes_addr]._data.balance = genesis_balance.balance
            else:
                block = Block.create(block_number=i,
                                     prev_headerhash=block.headerhash,
                                     prev_timestamp=block.timestamp,
                                     transactions=[],
                                     miner_address=miner_address)
                addresses_set = state.prepare_address_list(block)
                for address in addresses_set:
                    addresses_state[address] = state.get_address_state(address)
                for tx_protobuf in block.transactions:
                    tx = Transaction.from_pbdata(tx_protobuf)
                    tx.apply_state_changes(addresses_state)

                block.set_nonces(10, 0)
            blocks.append(block)

            metadata = BlockMetadata()
            metadata.set_block_difficulty(StringToUInt256('256'))
            state.put_block_metadata(block.headerhash, metadata, None)

            state.put_block(block, None)
            bm = qrl_pb2.BlockNumberMapping(
                headerhash=block.headerhash,
                prev_headerhash=block.prev_headerhash)

            state.put_block_number_mapping(block.block_number, bm, None)
            state.update_mainchain_height(block.block_number, None)
            state.put_addresses_state(addresses_state)

    return blocks
Exemple #22
0
    def handle_transfer_token_transaction(source, message: qrllegacy_pb2.LegacyMessage):
        """
        Transfer Token Transaction
        This function processes whenever a Transaction having
        subtype TRANSFERTOKEN is received.
        :return:
        """
        P2PBaseObserver._validate_message(message, qrllegacy_pb2.LegacyMessage.TT)
        try:
            tx = Transaction.from_pbdata(message.ttData)
        except Exception as e:
            logger.error('Transfer Token Txn rejected - unable to decode serialised data - closing connection')
            logger.exception(e)
            source.loseConnection()
            return

        if source.factory.master_mr.isRequested(tx.get_message_hash(), source):
            source.factory.add_unprocessed_txn(tx, source.peer.ip)
Exemple #23
0
    def handle_slave(source, message: qrllegacy_pb2.LegacyMessage):
        """
        Receives Slave Transaction
        :param source:
        :param message:
        :return:
        """
        P2PBaseObserver._validate_message(message, qrllegacy_pb2.LegacyMessage.SL)
        try:
            tx = Transaction.from_pbdata(message.slData)
        except Exception as e:
            logger.error('slave_txn rejected - unable to decode serialised data - closing connection')
            logger.exception(e)
            source.loseConnection()
            return

        if source.factory.master_mr.isRequested(tx.get_message_hash(), source):
            source.factory.add_unprocessed_txn(tx, source.peer.ip)
Exemple #24
0
    def _update_last_tx(self, block, batch):
        if len(block.transactions) == 0:
            return
        last_txn = LastTransactions()

        try:
            last_txn = LastTransactions.deserialize(
                self._db.get_raw(b'last_txn'))
        except:  # noqa
            pass

        for protobuf_txn in block.transactions[-20:]:
            txn = Transaction.from_pbdata(protobuf_txn)
            if isinstance(txn, CoinBase):
                continue
            last_txn.add(txn, block.block_number, block.timestamp)

        self._db.put_raw(b'last_txn', last_txn.serialize(), batch)
Exemple #25
0
    def handle_tx(source, message: qrllegacy_pb2.LegacyMessage):
        """
        Transaction
        Executed whenever a new TX type message is received.
        :return:
        """
        P2PBaseObserver._validate_message(message, qrllegacy_pb2.LegacyMessage.TX)
        try:
            tx = Transaction.from_pbdata(message.txData)
        except Exception as e:
            logger.error('Message Txn rejected - unable to decode serialised data - closing connection')
            logger.exception(e)
            source.loseConnection()
            return

        # NOTE: Connects to MR
        if source.factory.master_mr.isRequested(tx.get_message_hash(), source):
            source.factory.add_unprocessed_txn(tx, source.peer.ip)
Exemple #26
0
    def remove_tx_in_block_from_pool(self, block_obj: Block):
        for protobuf_tx in block_obj.transactions[
                1:]:  # Ignore first transaction, as it is a coinbase txn
            tx = Transaction.from_pbdata(protobuf_tx)
            if tx.ots_key < config.dev.max_ots_tracking_index:
                idx = self.get_tx_index_from_pool(tx.txhash)
                if idx > -1:
                    del self.transaction_pool[idx]
            else:
                i = 0
                while i < len(self.transaction_pool):
                    txn = self.transaction_pool[i][1].transaction
                    if txn.PK == tx.PK:
                        if txn.ots_key >= config.dev.max_ots_tracking_index:
                            if txn.ots_key <= tx.ots_key:
                                del self.transaction_pool[i]
                                continue
                    i += 1

        heapq.heapify(self.transaction_pool)
Exemple #27
0
    def GetObject(self, request: qrl_pb2.GetObjectReq, context) -> qrl_pb2.GetObjectResp:
        logger.debug("[PublicAPI] GetObject")
        answer = qrl_pb2.GetObjectResp()
        answer.found = False

        # FIXME: We need a unified way to access and validate data.
        query = bytes(request.query)  # query will be as a string, if Q is detected convert, etc.

        try:
            if AddressState.address_is_valid(query):
                if self.qrlnode.get_address_is_used(query):
                    address_state = self.qrlnode.get_address_state(query)
                    if address_state is not None:
                        answer.found = True
                        answer.address_state.CopyFrom(address_state.pbdata)
                        return answer
        except ValueError:
            pass

        transaction_block_number = self.qrlnode.get_transaction(query)
        transaction = None
        blockheader = None
        if transaction_block_number:
            transaction, block_number = transaction_block_number
            answer.found = True
            block = self.qrlnode.get_block_from_index(block_number)
            blockheader = block.blockheader.pbdata
            timestamp = block.blockheader.timestamp
        else:
            transaction_timestamp = self.qrlnode.get_unconfirmed_transaction(query)
            if transaction_timestamp:
                transaction, timestamp = transaction_timestamp
                answer.found = True

        if transaction:
            txextended = qrl_pb2.TransactionExtended(header=blockheader,
                                                     tx=transaction.pbdata,
                                                     addr_from=transaction.addr_from,
                                                     size=transaction.size,
                                                     timestamp_seconds=timestamp)
            answer.transaction.CopyFrom(txextended)
            return answer

        # NOTE: This is temporary, indexes are accepted for blocks
        try:
            block = self.qrlnode.get_block_from_hash(query)
            if block is None:
                query_str = query.decode()
                query_index = int(query_str)
                block = self.qrlnode.get_block_from_index(query_index)
                if not block:
                    return answer

            answer.found = True
            block_extended = qrl_pb2.BlockExtended()
            block_extended.header.CopyFrom(block.blockheader.pbdata)
            block_extended.size = block.size
            for transaction in block.transactions:
                tx = Transaction.from_pbdata(transaction)
                extended_tx = qrl_pb2.TransactionExtended(tx=transaction,
                                                          addr_from=tx.addr_from,
                                                          size=tx.size,
                                                          timestamp_seconds=block.blockheader.timestamp)
                block_extended.extended_transactions.extend([extended_tx])
            answer.block_extended.CopyFrom(block_extended)
            return answer
        except Exception:
            pass

        return answer
Exemple #28
0
    def load(self, genesis_block):
        # load() has the following tasks:
        # Write Genesis Block into State immediately
        # Register block_number <-> blockhash mapping
        # Calculate difficulty Metadata for Genesis Block
        # Generate AddressStates from Genesis Block balances
        # Apply Genesis Block's transactions to the state
        # Detect if we are forked from genesis block and if so initiate recovery.
        height = self._state.get_mainchain_height()

        if height == -1:
            self._state.put_block(genesis_block, None)
            block_number_mapping = qrl_pb2.BlockNumberMapping(
                headerhash=genesis_block.headerhash,
                prev_headerhash=genesis_block.prev_headerhash)

            self._state.put_block_number_mapping(genesis_block.block_number,
                                                 block_number_mapping, None)
            parent_difficulty = StringToUInt256(
                str(config.user.genesis_difficulty))

            self.current_difficulty, _ = DifficultyTracker.get(
                measurement=config.dev.mining_setpoint_blocktime,
                parent_difficulty=parent_difficulty)

            block_metadata = BlockMetadata.create()
            block_metadata.set_block_difficulty(self.current_difficulty)
            block_metadata.set_cumulative_difficulty(self.current_difficulty)

            self._state.put_block_metadata(genesis_block.headerhash,
                                           block_metadata, None)
            addresses_state = dict()
            for genesis_balance in GenesisBlock().genesis_balance:
                bytes_addr = genesis_balance.address
                addresses_state[bytes_addr] = AddressState.get_default(
                    bytes_addr)
                addresses_state[
                    bytes_addr]._data.balance = genesis_balance.balance

            for tx_idx in range(1, len(genesis_block.transactions)):
                tx = Transaction.from_pbdata(
                    genesis_block.transactions[tx_idx])
                for addr in tx.addrs_to:
                    addresses_state[addr] = AddressState.get_default(addr)

            coinbase_tx = Transaction.from_pbdata(
                genesis_block.transactions[0])

            if not isinstance(coinbase_tx, CoinBase):
                return False

            addresses_state[coinbase_tx.addr_to] = AddressState.get_default(
                coinbase_tx.addr_to)

            if not coinbase_tx.validate_extended(genesis_block.block_number):
                return False

            coinbase_tx.apply_state_changes(addresses_state)

            for tx_idx in range(1, len(genesis_block.transactions)):
                tx = Transaction.from_pbdata(
                    genesis_block.transactions[tx_idx])
                tx.apply_state_changes(addresses_state)

            self._state.put_addresses_state(addresses_state)
            self._state.update_tx_metadata(genesis_block, None)
            self._state.update_mainchain_height(0, None)
        else:
            self._last_block = self.get_block_by_number(height)
            self.current_difficulty = self._state.get_block_metadata(
                self._last_block.headerhash).block_difficulty
            fork_state = self._state.get_fork_state()
            if fork_state:
                block = self._state.get_block(fork_state.initiator_headerhash)
                self._fork_recovery(block, fork_state)
Exemple #29
0
def gen_blocks(block_count, state, miner_address):
    blocks = []
    block = None
    with mock.patch('qrl.core.misc.ntp.getTime') as time_mock:
        time_mock.return_value = 1615270948
        addresses_state = dict()
        for i in range(0, block_count):
            if i == 0:
                block = GenesisBlock()
                for genesis_balance in GenesisBlock().genesis_balance:
                    bytes_addr = genesis_balance.address
                    addresses_state[
                        bytes_addr] = OptimizedAddressState.get_default(
                            bytes_addr)
                    addresses_state[
                        bytes_addr]._data.balance = genesis_balance.balance
            else:
                block = Block.create(dev_config=config.dev,
                                     block_number=i,
                                     prev_headerhash=block.headerhash,
                                     prev_timestamp=block.timestamp,
                                     transactions=[],
                                     miner_address=miner_address,
                                     seed_height=None,
                                     seed_hash=None)
                addresses_set = ChainManager.set_affected_address(block)
                coin_base_tx = Transaction.from_pbdata(block.transactions[0])
                coin_base_tx.set_affected_address(addresses_set)

                chain_manager = ChainManager(state)
                state_container = chain_manager.new_state_container(
                    addresses_set, block.block_number, False, None)
                coin_base_tx.apply(state, state_container)

                for tx_idx in range(1, len(block.transactions)):
                    tx = Transaction.from_pbdata(block.transactions[tx_idx])
                    if not chain_manager.update_state_container(
                            tx, state_container):
                        return False
                    tx.apply(state, state_container)

                block.set_nonces(dev_config=config.dev,
                                 mining_nonce=10,
                                 extra_nonce=0)
            blocks.append(block)

            metadata = BlockMetadata()
            metadata.set_block_difficulty(StringToUInt256('256'))
            BlockMetadata.put_block_metadata(state, block.headerhash, metadata,
                                             None)

            Block.put_block(state, block, None)
            bm = qrl_pb2.BlockNumberMapping(
                headerhash=block.headerhash,
                prev_headerhash=block.prev_headerhash)

            Block.put_block_number_mapping(state, block.block_number, bm, None)
            state.update_mainchain_height(block.block_number, None)
            OptimizedAddressState.put_optimized_addresses_state(
                state, addresses_state)

    return blocks
Exemple #30
0
    def validate(self, chain_manager, future_blocks: OrderedDict) -> bool:
        if chain_manager.get_block_is_duplicate(self):
            logger.warning('Duplicate Block #%s %s', self.block_number, bin2hstr(self.headerhash))
            return False

        parent_block = chain_manager.get_block(self.prev_headerhash)
        dev_config = chain_manager.get_config_by_block_number(self.block_number)

        # If parent block not found in state, then check if its in the future block list
        if not parent_block:
            try:
                parent_block = future_blocks[self.prev_headerhash]
            except KeyError:
                logger.warning('Parent block not found')
                logger.warning('Parent block headerhash %s', bin2hstr(self.prev_headerhash))
                return False

        if not self._validate_parent_child_relation(parent_block):
            logger.warning('Failed to validate blocks parent child relation')
            return False

        if not chain_manager.validate_mining_nonce(self.blockheader, dev_config):
            logger.warning('Failed PoW Validation')
            return False

        if len(self.transactions) == 0:
            return False

        try:
            state_container = chain_manager.new_state_container(set(),
                                                                self.block_number,
                                                                False,
                                                                None)

            coinbase_txn = Transaction.from_pbdata(self.transactions[0])
            coinbase_amount = coinbase_txn.amount

            if not coinbase_txn.validate_all(state_container):
                return False

            if self.block_number != 2078158:
                for proto_tx in self.transactions[1:]:
                    if proto_tx.WhichOneof('transactionType') == 'coinbase':
                        logger.warning("Multiple coinbase transaction found")
                        return False

        except Exception as e:
            logger.warning('Exception %s', e)
            return False

        # Build transaction merkle tree, calculate fee reward, and then see if BlockHeader also agrees.
        hashedtransactions = []

        for tx in self.transactions:
            tx = Transaction.from_pbdata(tx)
            hashedtransactions.append(tx.txhash)

        fee_reward = 0
        for index in range(1, len(self.transactions)):
            fee_reward += self.transactions[index].fee

        qn = Qryptonight()
        seed_block = chain_manager.get_block_by_number(qn.get_seed_height(self.block_number))

        self.blockheader._seed_height = seed_block.block_number
        self.blockheader._seed_hash = seed_block.headerhash

        if not self.blockheader.validate(fee_reward,
                                         coinbase_amount,
                                         merkle_tx_hash(hashedtransactions),
                                         dev_config):
            return False

        return True