Beispiel #1
0
    def validate_block(self, block, address_txn) -> bool:
        len_transactions = len(block.transactions)

        if len_transactions < 1:
            return False

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

        if not isinstance(coinbase_tx, CoinBase):
            return False

        if not coinbase_tx.validate_extended():
            return False

        if not PoWValidator().validate_mining_nonce(self.state,
                                                    block.blockheader):
            return False

        coinbase_tx.apply_on_state(address_txn)

        # TODO: check block reward must be equal to coinbase amount

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

            if isinstance(tx, CoinBase):
                return False

            if not tx.validate(
            ):  # TODO: Move this validation, before adding txn to pool
                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',
                               tx.txhash)
                logger.warning('subtype: %s', tx.type)
                return False

            tx.apply_on_state(address_txn)

        return True
Beispiel #2
0
    def load(self, genesis_block):
        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.dev.genesis_difficulty))

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

            block_metadata = BlockMetadata.create()

            block_metadata.set_orphan(False)
            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():
                return False

            coinbase_tx.apply_on_state(addresses_state)

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

            self.state.state_objects.update_current_state(addresses_state)
            self.state.state_objects.update_tx_metadata(genesis_block, None)
            self.state.state_objects.push(genesis_block.headerhash)
        else:
            self.last_block = self.get_block_by_number(height)
            self.current_difficulty = self.state.get_block_metadata(self.last_block.headerhash).block_difficulty
Beispiel #3
0
    def handle_slave(self, source, message: qrllegacy_pb2.LegacyMessage):
        """
        Receives Lattice Public Key Transaction
        :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 not source.factory.master_mr.isRequested(tx.get_message_hash(),
                                                    source):
            return

        if not tx.validate():
            logger.warning('>>>Slave Txn %s invalid state validation failed..',
                           tx.hash)
            return

        source.factory.add_unprocessed_txn(tx, source.peer_ip)
Beispiel #4
0
    def rollback(self, rollback_headerhash, hash_path, latest_block_number):
        while self.last_block.headerhash != rollback_headerhash:
            self.remove_block_from_mainchain(self.last_block,
                                             latest_block_number, None)
            self.last_block = self.state.get_block(
                self.last_block.prev_headerhash)

        for header_hash in hash_path[-1::-1]:
            block = self.state.get_block(header_hash)
            address_set = self.state.prepare_address_list(
                block)  # Prepare list for current block
            addresses_state = self.state.get_state_mainchain(address_set)

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

            self.state.put_addresses_state(addresses_state)
            self.last_block = block
            self._update_mainchain(block, None)
            self.tx_pool.remove_tx_in_block_from_pool(block)
            self.state.update_mainchain_height(block.block_number, None)
            self.state.update_tx_metadata(block, None)

        self.trigger_miner = True
Beispiel #5
0
Datei: Block.py Projekt: grx7/QRL
    def validate(self, state) -> bool:
        if not PoWValidator().validate_mining_nonce(state, 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():
                return False

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

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

        parent_block = state.get_block(self.prev_headerhash)
        if not self.validate_parent_child_relation(parent_block):
            logger.warning('Failed to validate blocks parent child relation')
            return False

        return True
Beispiel #6
0
    def handle_message_transaction(self, source,
                                   message: qrllegacy_pb2.LegacyMessage):
        """
        Message Transaction
        This function processes whenever a Transaction having
        subtype MESSAGE is received.
        :return:
        """
        P2PBaseObserver._validate_message(message,
                                          qrllegacy_pb2.LegacyMessage.MT)
        try:
            tx = Transaction.from_pbdata(message.mtData)
        except Exception as e:
            logger.error(
                'Message Txn rejected - unable to decode serialised data - closing connection'
            )
            logger.exception(e)
            source.loseConnection()
            return

        if not source.factory.master_mr.isRequested(tx.get_message_hash(),
                                                    source):
            return

        if tx.txhash in source.factory.buffered_chain.tx_pool.pending_tx_pool_hash:
            return

        source.factory.add_unprocessed_txn(tx, source.peer_ip)
Beispiel #7
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 not source.factory.master_mr.isRequested(tx.get_message_hash(),
                                                    source):
            return

        source.factory.add_unprocessed_txn(tx, source.peer_ip)
Beispiel #8
0
    def apply_state_changes(self, address_txn) -> bool:
        coinbase_tx = Transaction.from_pbdata(self.transactions[0])

        if not coinbase_tx.validate_extended():
            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
Beispiel #9
0
def slave_tx_generate(ctx, src, addr_from, number_of_slaves, access_type, fee, pk, otsidx):
    """
    Generates Slave Transaction for the wallet
    """
    try:
        address_src, src_xmss = _select_wallet(ctx, src)
        src_xmss.set_ots_index(otsidx)
        if len(addr_from.strip()) == 0:
            addr_from = address_src
        if src_xmss:
            address_src_pk = src_xmss.pk
        else:
            address_src_pk = pk.encode()

        fee_shor = int(fee * 1.e9)
    except Exception as e:
        click.echo("Error validating arguments")
        quit(1)

    slave_xmss = []
    slave_pks = []
    access_types = []
    slave_xmss_seed = []
    if number_of_slaves > 100:
        click.echo("Error: Max Limit for the number of slaves is 100")
        quit(1)

    for i in range(number_of_slaves):
        print("Generating Slave #" + str(i + 1))
        xmss = XMSS.from_height(config.dev.xmss_tree_height)
        slave_xmss.append(xmss)
        slave_xmss_seed.append(xmss.extended_seed)
        slave_pks.append(xmss.pk)
        access_types.append(access_type)
        print("Successfully Generated Slave %s/%s" % (str(i + 1), number_of_slaves))

    channel = grpc.insecure_channel(ctx.obj.node_public_address)
    stub = qrl_pb2_grpc.PublicAPIStub(channel)
    # FIXME: This could be problematic. Check
    slaveTxnReq = qrl_pb2.SlaveTxnReq(address_from=addr_from,
                                      slave_pks=slave_pks,
                                      access_types=access_types,
                                      fee=fee_shor,
                                      xmss_pk=address_src_pk, )

    try:
        slaveTxnResp = stub.GetSlaveTxn(slaveTxnReq, timeout=5)
        tx = Transaction.from_pbdata(slaveTxnResp.transaction_unsigned)
        tx.sign(src_xmss)
        with open('slaves.json', 'w') as f:
            json.dump([bin2hstr(src_xmss.address), slave_xmss_seed, tx.to_json()], f)
        click.echo('Successfully created slaves.json')
        click.echo('Move slaves.json file from current directory to the mining node inside ~/.qrl/')
    except grpc.RpcError as e:
        click.echo(e.details())
        quit(1)
    except Exception as e:
        click.echo("Unhandled error: {}".format(str(e)))
        quit(1)
Beispiel #10
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)
Beispiel #11
0
    def remove_tx_in_block_from_pool(self, block_obj: Block):
        for protobuf_tx in block_obj.transactions:
            tx = Transaction.from_pbdata(protobuf_tx)
            idx = self.get_tx_index_from_pool(tx.txhash)
            if idx > -1:
                del self.transaction_pool[idx]

        heapq.heapify(self.transaction_pool)
Beispiel #12
0
 def update_vote_metadata(self, prev_stake_validators_tracker):
     self.total_stake_amount = prev_stake_validators_tracker.get_total_stake_amount(
     )
     for vote_protobuf in self.block.vote:
         vote = Transaction.from_pbdata(vote_protobuf)
         if vote.headerhash == self.block.prev_headerhash:
             self.voted_weight += prev_stake_validators_tracker.get_stake_balance(
                 vote.txfrom)
Beispiel #13
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.

        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

        transaction, block_number = self.qrlnode.get_transaction(query)
        if transaction is not None:
            answer.found = True
            blockheader = None
            if block_number is not None:
                block = self.qrlnode.get_block_from_index(block_number)
                blockheader = block.blockheader.pbdata

            txextended = qrl_pb2.TransactionExtended(
                header=blockheader,
                tx=transaction.pbdata,
                addr_from=transaction.addr_from,
                size=transaction.size)
            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)

            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)
                block_extended.extended_transactions.extend([extended_tx])
            answer.block_extended.CopyFrom(block_extended)
            return answer
        except Exception:
            pass

        return answer
Beispiel #14
0
 def _parse_tx_object(source, message: qrllegacy_pb2.LegacyMessage, kind):
     tx = None
     try:
         tx = Transaction.from_pbdata(message.mtData)
     except Exception as e:
         logger.error('Message Txn rejected - unable to decode serialised data - closing connection')
         logger.exception(e)
         source.loseConnection()
     return tx
Beispiel #15
0
 def search(self, query):
     # FIXME: Refactor this. Prepare a look up in the DB
     for block in self.blockchain:
         for protobuf_tx in block.transactions:
             tx = Transaction.from_pbdata(protobuf_tx)
             if tx.txhash == query or tx.txfrom == query or tx.txto == query:
                 logger.info('%s found in block %s', query,
                             str(block.block_number))
                 return tx
     return None
Beispiel #16
0
    def PushTransaction(self, request: qrl_pb2.PushTransactionReq, context) -> qrl_pb2.PushTransactionResp:
        logger.debug("[PublicAPI] PushTransaction")
        tx = Transaction.from_pbdata(request.transaction_signed)
        submitted = self.qrlnode.submit_send_tx(tx)

        # FIXME: Improve response type
        # Prepare response
        answer = qrl_pb2.PushTransactionResp()
        answer.some_response = str(submitted)
        return answer
Beispiel #17
0
    def PushTransaction(self, request: qrl_pb2.PushTransactionReq, context) -> qrl_pb2.PushTransactionResp:
        logger.debug("[PublicAPI] PushTransaction")
        tx = Transaction.from_pbdata(request.transaction_signed)
        submitted = self.qrlnode.submit_send_tx(tx)

        # FIXME: Improve response type
        # Prepare response
        answer = qrl_pb2.PushTransactionResp()
        answer.some_response = str(submitted)
        return answer
Beispiel #18
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)
Beispiel #19
0
    def update_mining_address(self, mining_address: bytes):
        coinbase_tx = Transaction.from_pbdata(self.transactions[0])
        coinbase_tx.update_mining_address(mining_address)
        hashedtransactions = [coinbase_tx.txhash]

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

        self.blockheader.update_merkle_root(merkle_tx_hash(hashedtransactions))

        self._data.header.MergeFrom(self.blockheader.pbdata)
Beispiel #20
0
    def get_state(self, header_hash: bytes, addresses_set: set):
        tmp_header_hash = header_hash
        parent_headerhash = None

        addresses_state = dict()
        for address in addresses_set:
            addresses_state[address] = None

        while True:
            if self.state_objects.contains(header_hash):
                parent_headerhash = header_hash
                self.set_addresses_state(addresses_state, header_hash)
                break
            block = self.get_block(header_hash)
            if not block:
                logger.warning('[get_state] No Block Found %s', header_hash)
                break
            if block.block_number == 0:
                break
            header_hash = block.prev_headerhash

        for genesis_balance in GenesisBlock().genesis_balance:
            bytes_addr = genesis_balance.address
            if not addresses_state[bytes_addr]:
                addresses_state[bytes_addr] = AddressState.get_default(
                    bytes_addr)
                addresses_state[
                    bytes_addr]._data.balance = genesis_balance.balance

        for address in addresses_state:
            if not addresses_state[address]:
                addresses_state[address] = AddressState.get_default(address)

        header_hash = tmp_header_hash
        hash_path = []
        while True:
            if parent_headerhash == header_hash:
                break
            block = self.get_block(header_hash)
            if not block:
                break
            hash_path.append(header_hash)
            header_hash = block.prev_headerhash
            if block.block_number == 0:
                break

        for header_hash in hash_path[-1::-1]:
            block = self.get_block(header_hash)

            for tx_pbdata in block.transactions:
                tx = Transaction.from_pbdata(tx_pbdata)
                tx.apply_on_state(addresses_state)

        return addresses_state
Beispiel #21
0
    def remove_tx_in_block_from_pool(self, block_obj: Block):
        for protobuf_tx in block_obj.transactions:
            tx = Transaction.from_pbdata(protobuf_tx)
            idx = self.get_tx_index_from_pool(tx.txhash)
            if idx > -1:
                del self.transaction_pool[idx]

                addr_ots_hash = self.calc_addr_ots_hash(tx)
                self.address_ots_hash.remove(addr_ots_hash)

        heapq.heapify(self.transaction_pool)
Beispiel #22
0
    def get_state(self, header_hash: bytes, addresses_set: set):
        tmp_header_hash = header_hash

        hash_path = []
        while True:
            block = self.get_block(header_hash)
            if not block:
                raise Exception('[get_state] No Block Found %s, Initiator %s',
                                header_hash, tmp_header_hash)
            mainchain_block = self.get_block_by_number(block.block_number)
            if mainchain_block and mainchain_block.headerhash == block.headerhash:
                break
            if block.block_number == 0:
                raise Exception(
                    '[get_state] Alternate chain genesis is different, Initiator %s',
                    tmp_header_hash)
            hash_path.append(header_hash)
            header_hash = block.prev_headerhash

        rollback_headerhash = header_hash

        addresses_state = dict()
        for address in addresses_set:
            addresses_state[address] = self.get_address_state(address)

        block = self.last_block
        while block.headerhash != rollback_headerhash:
            # Deplay transactions in reverse order, otherwise could result into negative value
            for tx_protobuf in block.transactions[-1::-1]:
                tx = Transaction.from_pbdata(tx_protobuf)
                tx.unapply_on_state(addresses_state, self)
            block = self.get_block(block.prev_headerhash)

        for header_hash in hash_path[-1::-1]:
            block = self.get_block(header_hash)

            for tx_pbdata in block.transactions:
                tx = Transaction.from_pbdata(tx_pbdata)
                tx.apply_on_state(addresses_state)

        return addresses_state, rollback_headerhash, hash_path
Beispiel #23
0
    def prepare_address_list(block) -> set:
        addresses = set()
        for proto_tx in block.transactions:
            tx = Transaction.from_pbdata(proto_tx)
            tx.set_effected_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
Beispiel #24
0
def tx_transfer(ctx, src, master, dst, amounts, fee, ots_key_index):
    """
    Transfer coins from src to dst
    """
    if not ctx.obj.remote:
        click.echo('This command is unsupported for local wallets')
        return

    try:
        _, src_xmss = _select_wallet(ctx, src)
        if not src_xmss:
            click.echo("A local wallet is required to sign the transaction")
            quit(1)

        address_src_pk = src_xmss.pk
        src_xmss.set_ots_index(ots_key_index)
        addresses_dst = []
        for addr in dst.split(' '):
            addresses_dst.append(bytes(hstr2bin(addr[1:])))

        shor_amounts = []
        for amount in amounts.split(' '):
            shor_amounts.append(int(float(amount) * 1.e9))

        fee_shor = int(fee * 1.e9)
    except Exception:
        click.echo("Error validating arguments")
        quit(1)

    try:
        channel = grpc.insecure_channel(ctx.obj.node_public_address)
        stub = qrl_pb2_grpc.PublicAPIStub(channel)
        transferCoinsReq = qrl_pb2.TransferCoinsReq(
            addresses_to=addresses_dst,
            amounts=shor_amounts,
            fee=fee_shor,
            xmss_pk=address_src_pk,
            master_addr=master.encode())

        transferCoinsResp = stub.TransferCoins(transferCoinsReq, timeout=5)

        tx = Transaction.from_pbdata(
            transferCoinsResp.extended_transaction_unsigned.tx)
        tx.sign(src_xmss)

        pushTransactionReq = qrl_pb2.PushTransactionReq(
            transaction_signed=tx.pbdata)
        pushTransactionResp = stub.PushTransaction(pushTransactionReq,
                                                   timeout=5)

        print(pushTransactionResp)
    except Exception as e:
        print("Error {}".format(str(e)))
Beispiel #25
0
    def remove_block_from_mainchain(self, block: Block, 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, 0, -1):
            tx = Transaction.from_pbdata(block.transactions[tx_idx])
            tx.unapply_on_state(addresses_state, self.state)

        # TODO: Move txn from block to pool
        # self.tx_pool.add_tx_in_block_from_pool(block)
        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)
Beispiel #26
0
    def prepare_address_list(block) -> set:
        addresses = set()
        for proto_tx in block.transactions:
            tx = Transaction.from_pbdata(proto_tx)
            tx.set_effected_address(addresses)

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

        return addresses
Beispiel #27
0
    def update_tx_metadata(self, block, batch):
        if len(block.transactions) == 0:
            return

        token_list = []

        # FIXME: Inconsistency in the keys/types
        for protobuf_txn in block.transactions:
            txn = Transaction.from_pbdata(protobuf_txn)
            if txn.subtype in (qrl_pb2.Transaction.TRANSFER,
                               qrl_pb2.Transaction.COINBASE,
                               qrl_pb2.Transaction.MESSAGE,
                               qrl_pb2.Transaction.TOKEN,
                               qrl_pb2.Transaction.TRANSFERTOKEN):

                self._db.put(bin2hstr(txn.txhash),
                             [txn.to_json(), block.block_number, block.timestamp],
                             batch)

                if txn.subtype in (qrl_pb2.Transaction.TRANSFER,
                                   qrl_pb2.Transaction.MESSAGE,
                                   qrl_pb2.Transaction.TOKEN,
                                   qrl_pb2.Transaction.TRANSFERTOKEN):
                    # FIXME: Being updated without batch, need to fix,
                    # as its making get request, and batch get not possible
                    # Thus cache is required to have only 1 time get
                    self.update_address_tx_hashes(txn.txfrom, txn.txhash)

                    if txn.subtype == qrl_pb2.Transaction.TOKEN:
                        self.update_address_tx_hashes(txn.owner, txn.txhash)
                        for initial_balance in txn.initial_balances:
                            if initial_balance.address == txn.owner:
                                continue
                            self.update_address_tx_hashes(initial_balance.address, txn.txhash)

                if txn.subtype in (qrl_pb2.Transaction.TRANSFER,
                                   qrl_pb2.Transaction.COINBASE,
                                   qrl_pb2.Transaction.TRANSFERTOKEN):
                    # FIXME: Being updated without batch, need to fix,
                    if txn.subtype == qrl_pb2.Transaction.TRANSFERTOKEN:
                        self.update_token_metadata(txn)
                    self.update_address_tx_hashes(txn.txto, txn.txhash)
                    self.increase_txn_count(txn.txto)

                if txn.subtype == qrl_pb2.Transaction.TOKEN:
                    self.create_token_metadata(txn)
                    token_list.append(txn.txhash)

                self.increase_txn_count(txn.txfrom)

        if token_list:
            self.update_token_list(token_list, batch)
Beispiel #28
0
    def get_state(self, header_hash, addresses_set):
        tmp_header_hash = header_hash
        parent_headerhash = None

        addresses_state = dict()
        for address in addresses_set:
            addresses_state[address] = None

        while True:
            if self.state_objects.contains(header_hash):
                parent_headerhash = header_hash
                self.set_addresses_state(addresses_state, header_hash)
                break
            block = self.get_block(header_hash)
            if not block:
                logger.warning('[get_state] No Block Found %s', header_hash)
                break
            if block.block_number == 0:
                break
            header_hash = block.prev_headerhash

        for genesis_balance in GenesisBlock().genesis_balance:
            bytes_addr = genesis_balance.address.encode()
            if not addresses_state[bytes_addr]:
                addresses_state[bytes_addr] = AddressState.get_default(bytes_addr)
                addresses_state[bytes_addr]._data.balance = genesis_balance.balance

        for address in addresses_state:
            if not addresses_state[address]:
                addresses_state[address] = AddressState.get_default(address)

        header_hash = tmp_header_hash
        hash_path = []
        while True:
            if parent_headerhash == header_hash:
                break
            block = self.get_block(header_hash)
            if not block:
                break
            hash_path.append(header_hash)
            header_hash = block.prev_headerhash
            if block.block_number == 0:
                break

        for header_hash in hash_path[-1::-1]:
            block = self.get_block(header_hash)

            for tx_pbdata in block.transactions:
                tx = Transaction.from_pbdata(tx_pbdata)
                tx.apply_on_state(addresses_state)

        return addresses_state
Beispiel #29
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, 0, -1):
            tx = Transaction.from_pbdata(block.transactions[tx_idx])
            tx.revert_state_changes(addresses_state, self.state)

        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)
Beispiel #30
0
Datei: cli.py Projekt: fanff/QRL
def tx_sign(ctx, src, txblob):
    """
    Sign a tx blob
    """
    txbin = bytes(hstr2bin(txblob))
    pbdata = qrl_pb2.Transaction()
    pbdata.ParseFromString(txbin)
    tx = Transaction.from_pbdata(pbdata)

    address_src, address_xmss = _select_wallet(ctx, src)
    tx.sign(address_xmss)

    txblob = bin2hstr(tx.pbdata.SerializeToString())
    print(txblob)
Beispiel #31
0
def tx_sign(ctx, src, txblob):
    """
    Sign a tx blob
    """
    txbin = bytes(hstr2bin(txblob))
    pbdata = qrl_pb2.Transaction()
    pbdata.ParseFromString(txbin)
    tx = Transaction.from_pbdata(pbdata)

    address_src, address_xmss = _select_wallet(ctx, src)
    tx.sign(address_xmss)

    txblob = bin2hstr(tx.pbdata.SerializeToString())
    print(txblob)
Beispiel #32
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
Beispiel #33
0
    def update_vote_metadata(self, block, batch):
        if len(block.transactions) == 0:
            return

        total_stake_amount = self.stake_validators_tracker.get_total_stake_amount()
        voted_weight = 0
        # FIXME: Inconsistency in the keys/types
        for protobuf_txn in block.vote:
            vote = Transaction.from_pbdata(protobuf_txn)
            voted_weight += self.stake_validators_tracker.get_stake_balance(vote.txfrom)

        self._db.put(b'vote_'+str(block.block_number).encode(),
                     [voted_weight,
                      total_stake_amount], batch)
Beispiel #34
0
    def validate(self, state, future_blocks: OrderedDict) -> bool:
        if self.is_duplicate(state):
            logger.warning('Duplicate Block #%s %s', self.block_number,
                           bin2hstr(self.headerhash))
            return False

        parent_block = state.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 PoWValidator().validate_mining_nonce(state, 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():
                return False

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

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

        return True
Beispiel #35
0
    def validate(self) -> bool:
        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
        except Exception as e:
            logger.warning('Exception %s', e)
            return False

        return self.blockheader.validate(fee_reward, coinbase_amount)
Beispiel #36
0
Datei: cli.py Projekt: fanff/QRL
def tx_inspect(ctx, txblob):
    """
    Inspected a transaction blob
    """
    tx = None
    try:
        txbin = bytes(hstr2bin(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)
Beispiel #37
0
Datei: cli.py Projekt: fanff/QRL
def tx_transfer(ctx, src, dst, amount, fee):
    """
    Transfer coins from src to dst
    """
    if not ctx.obj.remote:
        click.echo('This command is unsupported for local wallets')
        return

    try:
        address_src, src_xmss = _select_wallet(ctx, src)
        if not src_xmss:
            click.echo("A local wallet is required to sign the transaction")
            quit(1)

        address_src_pk = src_xmss.pk()
        address_src_otsidx = src_xmss.get_index()
        address_dst = dst.encode()
        # FIXME: This could be problematic. Check
        amount_shor = int(amount * 1.e9)
        fee_shor = int(fee * 1.e9)
    except Exception as e:
        click.echo("Error validating arguments")
        quit(1)

    try:
        channel = grpc.insecure_channel(ctx.obj.node_public_address)
        stub = qrl_pb2_grpc.PublicAPIStub(channel)
        transferCoinsReq = qrl_pb2.TransferCoinsReq(address_from=address_src,
                                                    address_to=address_dst,
                                                    amount=amount_shor,
                                                    fee=fee_shor,
                                                    xmss_pk=address_src_pk,
                                                    xmss_ots_index=address_src_otsidx)

        transferCoinsResp = stub.TransferCoins(transferCoinsReq, timeout=5)

        tx = Transaction.from_pbdata(transferCoinsResp.transaction_unsigned)
        tx.sign(src_xmss)

        pushTransactionReq = qrl_pb2.PushTransactionReq(transaction_signed=tx.pbdata)
        pushTransactionResp = stub.PushTransaction(pushTransactionReq, timeout=5)

        print(pushTransactionResp.some_response)
    except Exception as e:
        print("Error {}".format(str(e)))
Beispiel #38
0
    def update_tx_metadata(self, block, batch):
        if len(block.transactions) == 0:
            return

        # TODO (cyyber): Move To State Cache, instead of writing directly
        for protobuf_txn in block.transactions:
            txn = Transaction.from_pbdata(protobuf_txn)
            self._db.put(bin2hstr(txn.txhash),
                         [txn.to_json(), block.block_number, block.timestamp],
                         batch)
            # FIXME: Being updated without batch, need to fix,
            if txn.subtype == qrl_pb2.Transaction.TRANSFERTOKEN:
                self.update_token_metadata(txn)
            if txn.subtype == qrl_pb2.Transaction.TOKEN:
                self.create_token_metadata(txn)

            self.increase_txn_count(txn.txfrom)

        self.update_last_tx(block, batch)
Beispiel #39
0
    def update_last_tx(self, block, batch):
        if len(block.transactions) == 0:
            return
        last_txn = []

        try:
            last_txn = self._db.get('last_txn')
        except:  # noqa
            pass

        for protobuf_txn in block.transactions[-20:]:
            txn = Transaction.from_pbdata(protobuf_txn)
            if txn.subtype == qrl_pb2.Transaction.COINBASE:
                continue
            last_txn.insert(0, [txn.to_json(),
                                block.block_number,
                                block.timestamp])

        del last_txn[20:]
        self._db.put('last_txn', last_txn, batch)
Beispiel #40
0
Datei: cli.py Projekt: fanff/QRL
def tx_push(ctx, txblob):
    tx = None
    try:
        txbin = bytes(hstr2bin(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)

    channel = grpc.insecure_channel(ctx.obj.node_public_address)
    stub = qrl_pb2_grpc.PublicAPIStub(channel)
    pushTransactionReq = qrl_pb2.PushTransactionReq(transaction_signed=tx.pbdata)
    pushTransactionResp = stub.PushTransaction(pushTransactionReq, timeout=5)
    print(pushTransactionResp.some_response)
Beispiel #41
0
    def validate_block(self, block, address_txn) -> bool:
        len_transactions = len(block.transactions)

        if len_transactions < 1:
            return False

        coinbase_tx = Transaction.from_pbdata(block.transactions[0])
        coinbase_tx.validate()

        if not self.validate_mining_nonce(block):
            return False

        if coinbase_tx.subtype != qrl_pb2.Transaction.COINBASE:
            return False

        if not coinbase_tx.validate():
            return False

        coinbase_tx.apply_on_state(address_txn)

        addr_from_pk_state = address_txn[coinbase_tx.txto]
        addr_from_pk = Transaction.get_slave(coinbase_tx)
        if addr_from_pk:
            addr_from_pk_state = address_txn[addr_from_pk]

        if not coinbase_tx.validate_extended(address_txn[coinbase_tx.txto],
                                             addr_from_pk_state,
                                             []):
            return False

        # TODO: check block reward must be equal to coinbase amount

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

            if tx.subtype == qrl_pb2.Transaction.COINBASE:
                return False

            if not tx.validate():  # TODO: Move this validation, before adding txn to pool
                return False

            addr_from_pk_state = address_txn[tx.txfrom]
            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.txfrom], addr_from_pk_state, []):
                return False

            expected_nonce = address_txn[tx.txfrom].nonce + 1

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

            if tx.ots_key_reuse(address_txn[tx.txfrom], tx.ots_key):
                logger.warning('pubkey reuse detected: invalid tx %s', tx.txhash)
                logger.warning('subtype: %s', tx.subtype)
                return False

            tx.apply_on_state(address_txn)

        return True
Beispiel #42
0
Datei: cli.py Projekt: fanff/QRL
def slave_tx_generate(ctx, src, addr_from, number_of_slaves, access_type, fee, pk, otsidx):
    """
    Generates Slave Transaction for the wallet
    """
    try:
        address_src, src_xmss = _select_wallet(ctx, src)
        if len(addr_from.strip()) == 0:
            addr_from = address_src
        if src_xmss:
            address_src_pk = src_xmss.pk()
            address_src_otsidx = src_xmss.get_index()
        else:
            address_src_pk = pk.encode()
            address_src_otsidx = int(otsidx)

        fee_shor = int(fee * 1.e9)
    except Exception as e:
        click.echo("Error validating arguments")
        quit(1)

    slave_xmss = []
    slave_pks = []
    access_types = []
    slave_xmss_seed = []
    if number_of_slaves > 100:
        click.echo("Error: Max Limit for the number of slaves is 100")
        quit(1)

    for i in range(number_of_slaves):
        print("Generating Slave #"+str(i+1))
        xmss = XMSS(config.dev.xmss_tree_height)
        slave_xmss.append(xmss)
        slave_xmss_seed.append(xmss.get_seed())
        slave_pks.append(xmss.pk())
        access_types.append(access_type)
        print("Successfully Generated Slave %s/%s" % (str(i + 1), number_of_slaves))

    channel = grpc.insecure_channel(ctx.obj.node_public_address)
    stub = qrl_pb2_grpc.PublicAPIStub(channel)
    # FIXME: This could be problematic. Check
    slaveTxnReq = qrl_pb2.SlaveTxnReq(address_from=addr_from,
                                      slave_pks=slave_pks,
                                      access_types=access_types,
                                      fee=fee_shor,
                                      xmss_pk=address_src_pk,
                                      xmss_ots_index=address_src_otsidx)

    try:
        slaveTxnResp = stub.GetSlaveTxn(slaveTxnReq, timeout=5)
        tx = Transaction.from_pbdata(slaveTxnResp.transaction_unsigned)
        tx.sign(src_xmss)
        with open('slaves.json', 'w') as f:
            json.dump([src_xmss.get_address(), slave_xmss_seed, tx.to_json()], f)
        click.echo('Successfully created slaves.json')
        click.echo('Move slaves.json file from current directory to the mining node inside ~/.qrl/')
    except grpc.RpcError as e:
        click.echo(e.details())
        quit(1)
    except Exception as e:
        click.echo("Unhandled error: {}".format(str(e)))
        quit(1)
Beispiel #43
0
 def remove_tx_in_block_from_pool(self, block_obj: Block):
     for protobuf_tx in block_obj.transactions:
         tx = Transaction.from_pbdata(protobuf_tx)
         for txn in self.transaction_pool:
             if tx.txhash == txn.txhash:
                 self.remove_tx_from_pool(txn)