def test_revert_slave_txn(self):
        tx = SlaveTransaction.create(**self.params)
        tx.sign(self.alice)
        addresses_state = dict(self.addresses_state)
        addresses_state[self.alice.address].pbdata.balance = 100
        state_container = StateContainer(addresses_state=addresses_state,
                                         tokens=Indexer(b'token', None),
                                         slaves=Indexer(b'slave', None),
                                         lattice_pk=Indexer(
                                             b'lattice_pk', None),
                                         multi_sig_spend_txs=dict(),
                                         votes_stats=dict(),
                                         block_number=1,
                                         total_coin_supply=100,
                                         current_dev_config=config.dev,
                                         write_access=True,
                                         my_db=self.state._db,
                                         batch=None)
        tx.apply(self.state, state_container)
        tx.revert(self.state, state_container)

        self.assertEqual(addresses_state[self.alice.address].balance, 100)
        storage_key = state_container.paginated_tx_hash.generate_key(
            self.alice.address, 1)
        self.assertIn(storage_key, state_container.paginated_tx_hash.key_value)
        self.assertEqual(
            [], state_container.paginated_tx_hash.key_value[storage_key])

        self.assertIn((tx.addr_from, tx.slave_pks[0]),
                      state_container.slaves.data)
        data = state_container.slaves.data[(tx.addr_from, tx.slave_pks[0])]
        self.assertIsInstance(data, SlaveMetadata)
        self.assertEqual(tx.access_types[0], data.access_type)
        self.assertEqual(tx.txhash, data.tx_hash)
Ejemplo n.º 2
0
    def create_block(self, prev_hash, mining_address=None):
        if not mining_address:
            mining_address = self.alice_xmss.address
        transactions = []
        block_prev = self.qrlnode.get_block_from_hash(prev_hash)
        block_idx = block_prev.block_number + 1

        if block_idx == 1:
            slave_tx = SlaveTransaction.create(slave_pks=[self.bob_xmss.pk],
                                               access_types=[0],
                                               fee=0,
                                               xmss_pk=self.alice_xmss.pk)
            slave_tx.sign(self.alice_xmss)
            slave_tx._data.nonce = 1
            transactions = [slave_tx]

        time_offset = 60
        if block_idx % 2 == 0:
            time_offset += 2

        self.time_mock.return_value = self.time_mock.return_value + time_offset
        self.ntp_mock.return_value = self.ntp_mock.return_value + time_offset

        block_new = Block.create(block_number=block_idx,
                                 prev_headerhash=block_prev.headerhash,
                                 prev_timestamp=block_prev.timestamp,
                                 transactions=transactions,
                                 miner_address=mining_address)

        while not self.qrlnode._chain_manager.validate_mining_nonce(blockheader=block_new.blockheader):
            block_new.set_nonces(block_new.mining_nonce + 1, 0)

        return block_new
Ejemplo n.º 3
0
def slave_tx_generate(ctx, src, master, number_of_slaves, access_type, fee, pk,
                      ots_key_index):
    """
    Generates Slave Transaction for the wallet
    """
    try:
        _, src_xmss = _select_wallet(ctx, src)

        ots_key_index = validate_ots_index(ots_key_index, src_xmss)
        src_xmss.set_ots_index(ots_key_index)

        if src_xmss:
            address_src_pk = src_xmss.pk
        else:
            address_src_pk = pk.encode()

        master_addr = None
        if master:
            master_addr = parse_qaddress(master)
        fee_shor = _quanta_to_shor(fee)
    except Exception as e:
        click.echo("Error validating arguments: {}".format(e))
        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))

    try:
        tx = SlaveTransaction.create(slave_pks=slave_pks,
                                     access_types=access_types,
                                     fee=fee_shor,
                                     xmss_pk=address_src_pk,
                                     master_addr=master_addr)
        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 Exception as e:
        click.echo("Unhandled error: {}".format(str(e)))
        quit(1)
Ejemplo n.º 4
0
 def create_slave_tx(self, slave_pks: list, access_types: list, fee: int,
                     xmss_pk: bytes,
                     master_addr: bytes) -> SlaveTransaction:
     return SlaveTransaction.create(slave_pks=slave_pks,
                                    access_types=access_types,
                                    fee=fee,
                                    xmss_pk=xmss_pk,
                                    master_addr=master_addr)
Ejemplo n.º 5
0
 def generate_slave_tx(self,
                       signer_pk: bytes,
                       slave_pk_list: list,
                       master_addr=None):
     return SlaveTransaction.create(slave_pks=slave_pk_list,
                                    access_types=[0] * len(slave_pk_list),
                                    fee=0,
                                    xmss_pk=signer_pk,
                                    master_addr=master_addr)
Ejemplo n.º 6
0
 def test_broadcast_tx(self, m_reactor, m_logger):
     # broadcast_tx() should handle all Transaction Types
     self.factory.broadcast_tx(MessageTransaction())
     self.factory.broadcast_tx(TransferTransaction())
     self.factory.broadcast_tx(TokenTransaction())
     self.factory.broadcast_tx(TransferTokenTransaction())
     self.factory.broadcast_tx(SlaveTransaction())
     with self.assertRaises(ValueError):
         m_tx = Mock(autospec=TransferTransaction, txhash=bhstr2bin('deadbeef'))
         self.factory.broadcast_tx(m_tx)
Ejemplo n.º 7
0
    def test_validate_custom(self, m_logger):
        """
        SlaveTransaction._validate_custom() checks for the following things:
        1. if you specify more than 100 slave_pks at once
        2. if len(slave_pks) != len(access_types)
        3. access_types can only be 0, 1
        """
        # Unequal length slave_pks and access_types
        params = self.params.copy()
        params["slave_pks"] = [self.slave.pk]
        params["access_types"] = [0, 1]
        with self.assertRaises(ValueError):
            SlaveTransaction.create(**params)

        # access_type is a weird, undefined number
        params = self.params.copy()
        params["access_types"] = [5]
        with self.assertRaises(ValueError):
            SlaveTransaction.create(**params)
    def test_revert_state_changes_empty_addresses_state(
            self, m_logger, m_apply_state_PK, m_revert_state_PK):
        tx = SlaveTransaction.create(**self.params)
        tx.sign(self.alice)
        addresses_state = {}
        tx.revert_state_changes(addresses_state,
                                self.unused_chain_manager_mock)

        self.assertEqual({}, addresses_state)
        m_revert_state_PK.assert_called_once()
Ejemplo n.º 9
0
    def test_validate_tx(self, m_logger):
        tx = SlaveTransaction.create(**self.params)
        tx.sign(self.alice)

        self.assertTrue(tx.validate_or_raise())

        tx._data.transaction_hash = b'abc'

        # Should fail, as we have modified with invalid transaction_hash
        with self.assertRaises(ValueError):
            tx.validate_or_raise()
Ejemplo n.º 10
0
    def test_validate_custom(self, m_logger):
        """
        SlaveTransaction._validate_custom() checks for the following things:
        1. if you specify more than 100 slave_pks at once
        2. if len(slave_pks) != len(access_types)
        3. access_types can only be 0, 1
        """
        # We're going to need all the XMSS trees we can get here
        bob = get_bob_xmss()

        # Too many slave_pks
        with patch('qrl.core.txs.SlaveTransaction.config',
                   autospec=True) as m_config:
            m_config.dev.transaction_multi_output_limit = 2
            params = self.params.copy()
            params["slave_pks"] = [self.alice.pk, bob.pk, self.slave.pk]
            params["access_types"] = [0, 0, 0]

            with self.assertRaises(ValueError):
                SlaveTransaction.create(**params)

        # Unequal length slave_pks and access_types
        params = self.params.copy()
        params["slave_pks"] = [self.slave.pk]
        params["access_types"] = [0, 1]
        with self.assertRaises(ValueError):
            SlaveTransaction.create(**params)

        # access_type is a weird, undefined number
        params = self.params.copy()
        params["access_types"] = [5]
        with self.assertRaises(ValueError):
            SlaveTransaction.create(**params)
Ejemplo n.º 11
0
    def relay_slave_txn(self, slave_pks: list, access_types: list, fee: int,
                        master_qaddress, signer_address: str, ots_index: int):
        self.authenticate()
        index, xmss = self._get_wallet_index_xmss(signer_address, ots_index)

        tx = SlaveTransaction.create(
            slave_pks=slave_pks,
            access_types=access_types,
            fee=fee,
            xmss_pk=xmss.pk,
            master_addr=self.qaddress_to_address(master_qaddress))

        self._push_transaction(tx, xmss)
        self._wallet.set_ots_index(index, xmss.ots_index)

        return self.to_plain_transaction(tx.pbdata)
Ejemplo n.º 12
0
    def test_validate_extended(self, m_validate_slave, m_logger):
        """
        SlaveTransaction.validate_extended checks for:
        1. valid master/slave
        2. negative fee,
        3. addr_from has enough funds for the fee
        4. addr_from ots_key reuse
        """
        m_addr_from_state = Mock(autospec=AddressState,
                                 name='addr_from State',
                                 balance=100)

        m_addr_from_pk_state = Mock(autospec=AddressState,
                                    name='addr_from_pk State')
        m_addr_from_pk_state.ots_key_reuse.return_value = False

        tx = SlaveTransaction.create(**self.params)
        tx.sign(self.alice)

        result = tx.validate_extended(m_addr_from_state, m_addr_from_pk_state)
        self.assertTrue(result)

        # Invalid master XMSS/slave XMSS relationship
        m_validate_slave.return_value = False
        result = tx.validate_extended(m_addr_from_state, m_addr_from_pk_state)
        self.assertFalse(result)
        m_validate_slave.return_value = True

        # fee = -1
        with patch('qrl.core.txs.SlaveTransaction.SlaveTransaction.fee',
                   new_callable=PropertyMock) as m_fee:
            m_fee.return_value = -1
            result = tx.validate_extended(m_addr_from_state,
                                          m_addr_from_pk_state)
            self.assertFalse(result)

        # balance = 0, cannot pay the Transaction fee
        m_addr_from_state.balance = 0
        result = tx.validate_extended(m_addr_from_state, m_addr_from_pk_state)
        self.assertFalse(result)
        m_addr_from_state.balance = 100

        # addr_from_pk has used this OTS key before
        m_addr_from_pk_state.ots_key_reuse.return_value = True
        result = tx.validate_extended(m_addr_from_state, m_addr_from_pk_state)
        self.assertFalse(result)
Ejemplo n.º 13
0
def get_slaves(alice_ots_index, txn_nonce):
    # [master_address: bytes, slave_seeds: list, slave_txn: json]

    slave_xmss = get_slave_xmss()
    alice_xmss = get_alice_xmss()

    alice_xmss.set_ots_index(alice_ots_index)
    slave_txn = SlaveTransaction.create([slave_xmss.pk], [1], 0, alice_xmss.pk)
    slave_txn._data.nonce = txn_nonce
    slave_txn.sign(alice_xmss)

    slave_data = json.loads(
        json.dumps([
            bin2hstr(alice_xmss.address), [slave_xmss.extended_seed],
            slave_txn.to_json()
        ]))
    slave_data[0] = bytes(hstr2bin(slave_data[0]))
    return slave_data
Ejemplo n.º 14
0
    def relay_slave_txn_by_slave(self, slave_pks: list, access_types: list,
                                 fee: int, master_qaddress):
        self.authenticate()
        index, group_index, slave_index, slave_xmss = self.get_slave_xmss(
            master_qaddress)
        if slave_index == -1:
            raise Exception("No Slave Found")

        tx = SlaveTransaction.create(
            slave_pks=slave_pks,
            access_types=access_types,
            fee=fee,
            xmss_pk=slave_xmss.pk,
            master_addr=self.qaddress_to_address(master_qaddress))

        self.sign_and_push_transaction(tx, slave_xmss, index, group_index,
                                       slave_index)

        return self.to_plain_transaction(tx.pbdata)
    def test_apply_state_changes(self, m_logger, m_apply_state_PK,
                                 m_revert_state_PK):
        tx = SlaveTransaction.create(**self.params)
        tx.sign(self.alice)
        addresses_state = self.generate_addresses_state(tx)
        tx.apply_state_changes(addresses_state)

        self.assertEqual(addresses_state[self.alice.address].balance, 99)
        self.assertEqual(
            [tx.txhash],
            addresses_state[self.alice.address].transaction_hashes)
        self.assertEqual(
            [], addresses_state[self.slave.address].transaction_hashes)
        addresses_state[
            self.alice.address].add_slave_pks_access_type.assert_called_once()
        addresses_state[
            self.slave.address].add_slave_pks_access_type.assert_not_called()

        m_apply_state_PK.assert_called_once()
Ejemplo n.º 16
0
    def test_bad_tx(self, mock_logger):
        source = Mock()
        source.factory = Mock()
        source.factory.master_mr = Mock()
        source.factory.master_mr.isRequested = Mock()
        source.factory.add_unprocessed_txn = Mock()

        channel = Observable(source)

        self.tx_manager = P2PTxManagement()
        self.tx_manager.new_channel(channel)

        tx = SlaveTransaction.create(slave_pks=[],
                                     access_types=[],
                                     fee=1,
                                     xmss_pk=bytes(67))

        event = qrllegacy_pb2.LegacyMessage(
            func_name=qrllegacy_pb2.LegacyMessage.TX, txData=tx.pbdata)

        channel.notify(event, force_delivery=True)
        source.factory.master_mr.isRequested.assert_not_called()
        source.factory.add_unprocessed_txn.assert_not_called()
    def test_revert_state_changes(self, m_logger, m_apply_state_PK,
                                  m_revert_state_PK):
        tx = SlaveTransaction.create(**self.params)
        tx.sign(self.alice)
        addresses_state = self.generate_addresses_state(tx)
        addresses_state[self.alice.address].balance = 99
        addresses_state[self.alice.address].transaction_hashes = [tx.txhash]
        tx.revert_state_changes(addresses_state,
                                self.unused_chain_manager_mock)

        self.assertEqual(addresses_state[self.alice.address].balance, 100)
        self.assertEqual(
            [], addresses_state[self.alice.address].transaction_hashes)
        self.assertEqual(
            [], addresses_state[self.slave.address].transaction_hashes)
        addresses_state[
            self.alice.
            address].remove_slave_pks_access_type.assert_called_once()
        addresses_state[
            self.slave.address].remove_slave_pks_access_type.assert_not_called(
            )

        m_revert_state_PK.assert_called_once()
Ejemplo n.º 18
0
 def test_create_validate(self, m_logger):
     """Default self.params should result in a valid SlaveTransaction"""
     tx = SlaveTransaction.create(**self.params)
     tx.sign(self.alice)
     result = tx.validate_or_raise()
     self.assertTrue(result)
Ejemplo n.º 19
0
    def test_add_block(self, mock_difficulty_tracker_get):
        """
        Add block_1 on genesis block (that registers Bob as Alice's slave)
        Add a competing fork_block on genesis block (without the SlaveTransaction)
        Add block_2 on fork_block (without the SlaveTransaction)
        Bob should be free from slavery now.
        """
        mock_difficulty_tracker_get.return_value = ask_difficulty_tracker('2')
        self.chain_manager.load(self.genesis_block)

        # Add block_1 on genesis block.
        slave_tx = SlaveTransaction.create(slave_pks=[bob.pk],
                                           access_types=[0],
                                           fee=0,
                                           xmss_pk=alice.pk)
        slave_tx.sign(alice)
        slave_tx._data.nonce = 1
        self.assertTrue(slave_tx.validate())
        with patch('qrl.core.misc.ntp.getTime') as time_mock:
            time_mock.return_value = 1615270948  # Very high to get an easy difficulty

            block_1 = Block.create(
                block_number=1,
                prev_headerhash=self.genesis_block.headerhash,
                prev_timestamp=self.genesis_block.timestamp,
                transactions=[slave_tx],
                miner_address=alice.address)
            block_1.set_nonces(2, 0)
            # Uncomment only to determine the correct mining_nonce of above blocks
            # from qrl.core.PoWValidator import PoWValidator
            # while not PoWValidator().validate_mining_nonce(self.state, block_1.blockheader, False):
            #     block_1.set_nonces(block_1.mining_nonce + 1)
            #     print(block_1.mining_nonce)
            self.assertTrue(block_1.validate(self.chain_manager, {}))
            result = self.chain_manager.add_block(block_1)

        self.assertTrue(result)
        self.assertEqual(self.chain_manager.last_block, block_1)

        # Yes, Bob is Alice's slave.
        alice_state = self.chain_manager.get_address_state(alice.address)
        self.assertEqual(len(alice_state.slave_pks_access_type), 1)
        self.assertTrue(str(bob.pk) in alice_state.slave_pks_access_type)

        # Add fork block on genesis block
        with patch('qrl.core.misc.ntp.getTime') as time_mock:
            time_mock.return_value = 1715270948  # Very high to get an easy difficulty
            fork_block = Block.create(
                block_number=1,
                prev_headerhash=self.genesis_block.headerhash,
                prev_timestamp=self.genesis_block.timestamp,
                transactions=[],
                miner_address=bob.address)

            fork_block.set_nonces(4, 0)
            # Uncomment only to determine the correct mining_nonce of above blocks
            # from qrl.core.PoWValidator import PoWValidator
            # while not PoWValidator().validate_mining_nonce(self.state, fork_block.blockheader, False):
            #     fork_block.set_nonces(fork_block.mining_nonce + 1)
            #     print(fork_block.mining_nonce)
            self.assertTrue(fork_block.validate(self.chain_manager, {}))
            result = self.chain_manager.add_block(fork_block)

        self.assertTrue(result)
        self.assertEqual(self.chain_manager.last_block, block_1)

        fork_block = self.state.get_block(fork_block.headerhash)
        self.assertIsNotNone(fork_block)

        # Add block_2 on fork_block.
        with patch('qrl.core.misc.ntp.getTime') as time_mock:
            time_mock.return_value = 1815270948  # Very high to get an easy difficulty
            block_2 = fork_block.create(block_number=2,
                                        prev_headerhash=fork_block.headerhash,
                                        prev_timestamp=fork_block.timestamp,
                                        transactions=[],
                                        miner_address=bob.address)

            block_2.set_nonces(1, 0)
            # Uncomment only to determine the correct mining_nonce of above blocks
            # from qrl.core.PoWValidator import PoWValidator
            # while not PoWValidator().validate_mining_nonce(state, block_2.blockheader, False):
            #     block_2.set_nonces(block_2.mining_nonce + 1, 0)
            #     print(block_2.mining_nonce)
            self.assertTrue(block_2.validate(self.chain_manager, {}))
            result = self.chain_manager.add_block(block_2)

        self.assertTrue(result)
        self.assertEqual(self.chain_manager.last_block.block_number,
                         block_2.block_number)
        self.assertEqual(self.chain_manager.last_block.serialize(),
                         block_2.serialize())

        # Now we are on the forked chain, Bob is no longer Alice's slave.
        alice_state = self.chain_manager.get_address_state(alice.address)
        self.assertFalse(str(bob.pk) in alice_state.slave_pks_access_type)
Ejemplo n.º 20
0
    def test_validate_extended(self, m_validate_slave, m_logger):
        """
        SlaveTransaction._validate_extended checks for:
        1. valid master/slave
        2. negative fee,
        3. addr_from has enough funds for the fee
        4. addr_from ots_key reuse
        """
        alice_address_state = OptimizedAddressState.get_default(
            self.alice.address)
        alice_address_state.pbdata.balance = 100
        addresses_state = {alice_address_state.address: alice_address_state}

        tx = SlaveTransaction.create(**self.params)
        tx.sign(self.alice)

        state_container = StateContainer(addresses_state=addresses_state,
                                         tokens=Indexer(b'token', None),
                                         slaves=Indexer(b'slave', None),
                                         lattice_pk=Indexer(
                                             b'lattice_pk', None),
                                         multi_sig_spend_txs=dict(),
                                         votes_stats=dict(),
                                         block_number=1,
                                         total_coin_supply=100,
                                         current_dev_config=config.dev,
                                         write_access=True,
                                         my_db=self.state._db,
                                         batch=None)
        result = tx._validate_extended(state_container)
        self.assertTrue(result)

        # Invalid master XMSS/slave XMSS relationship
        m_validate_slave.return_value = False
        result = tx.validate_all(state_container)
        self.assertFalse(result)
        m_validate_slave.return_value = True

        # fee = -1
        with patch('qrl.core.txs.SlaveTransaction.SlaveTransaction.fee',
                   new_callable=PropertyMock) as m_fee:
            m_fee.return_value = -1
            result = tx._validate_custom()
            self.assertFalse(result)

        # balance = 0, cannot pay the Transaction fee
        alice_address_state.pbdata.balance = 0
        result = tx._validate_extended(state_container)
        self.assertFalse(result)
        alice_address_state.pbdata.balance = 100

        addresses_state = {self.alice.address: alice_address_state}
        # addr_from_pk has used this OTS key before
        state_container.paginated_bitfield.set_ots_key(
            addresses_state, alice_address_state.address, tx.ots_key)
        result = tx.validate_all(state_container)
        self.assertFalse(result)

        bob = get_bob_xmss()
        # Too many slave_pks
        with patch('qrl.core.config', autospec=True) as m_config:
            m_config.dev = config.dev.create(config.dev.prev_state_key,
                                             config.dev.current_state_key, b'',
                                             10, True, True)
            m_config.dev.pbdata.transaction.multi_output_limit = 2
            state_container.current_dev_config = m_config.dev
            params = self.params.copy()
            params["slave_pks"] = [self.alice.pk, bob.pk, self.slave.pk]
            params["access_types"] = [0, 0, 0]

            tx = SlaveTransaction.create(**params)
            self.assertFalse(tx._validate_extended(state_container))